Ambiera Forum

Discussions, Help and Support.

Ambiera Forum > irrKlang
Can recorder.RecordedAudioData be accessed from memory?

tr32
Registered User
Quote
2015-03-10 01:08:02

I am trying to adapt your Memory Playback (C) example to capture recorded audio in an array, do something with that array somewhere else, and use the array later for playback.

Recording and playback with the recorder from a mic etc works fine.

I declare

engine0 = new ISoundEngine();
engine1 = new ISoundEngine();
recorder0 = new IAudioRecorder(engine0);
recorder1 = new IAudioRecorder(engine1);

under the class, then after recording and having stopped it -

recorder0.AddSoundSourceFromRecordedAudio(rec_sound0);

(which I also use for playback successfully)

then -

SoundDataArray1 = new byte[recorder0.RecordedAudioData.Length];

Array.Copy(recorder0.RecordedAudioData, SoundDataArray1, recorder0.RecordedAudioData.Length);
soundsource1 = engine1.AddSoundSourceFromMemory(SoundDataArray1, rec_sound1);
sound1 = engine1.Play2D(soundsource1, loop_flag, false, false);

But there is no sound, and -

if (sound1 == null)
{
System.Windows.Forms.MessageBox.Show("No sound!");
}

produces the above message.

However, recorder0.RecordedAudioData can be used like a normal array, to get the length, to copy it to another array, writing the content of SoundDataArray1 to a file is no problem.

Not using a separate engine1 doesn't help. Replacing

soundsource1 = engine1.AddSoundSourceFromMemory(SoundDataArray1, rec_sound1);

with

soundsource1 = engine1.AddSoundSourceFromMemory(recorder0.RecordedAudioData, rec_sound1);

doesn't help either.

engine1.Play2D(rec_sound1, loop_flag); as in your example doesn't work either.

As soon as I replace SoundDataArray1 with SoundDataArray (the declared array in your example) it is played back.

But as a soundsource it is not recognised. What am I doing wrong? I greatly appreciate any input.

I'm using Win 7, VS Express 2012, C, irrKlang-32bit-1.5.0.


tr32
Registered User
Quote
2015-03-10 15:09:59

I found a solution.

Instead of -

soundsource1 = engine1.AddSoundSourceFromMemory(SoundDataArray1, rec_sound1);

it has to be -

soundsource1 = engine1.AddSoundSourceFromPCMData(SoundDataArray1, rec_sound1, af);
engine1.Play2D(rec_sound1, loop_flag);

assuming that SoundDataArray1 has been copied from recorder0.RecordedAudioData as in my original post. rec_sound1 can be played back many times.

However, if the code is -

soundsource1 = engine1.AddSoundSourceFromPCMData(SoundDataArray1, rec_sound1, af);
sound1 = engine1.Play2D(soundsource1, loop_flag, false, false);

then sound1 is only available the first time, it cannot be played a second time.

Am I still missing something?


niko
Moderator
Quote
2015-03-11 05:36:49

If you are using AddSoundSourceFromMemory, then it is expecting an actual file, but what you get from recording your audio is PCM data, so you should be using AddSoundSourceFromPCMData.

I'm not sure what 'af' is, but maybe you are adding the sound source all the time with the same name? This might be a problem, be sure to set a unique name for every sound source you are adding.


tr32
Registered User
Quote
2015-03-12 00:11:55

Thanks niko.

'af' stands for audioFormat, which I define via the recorder.AudioFormat method.

I got it working by declaring engine = new ISoundEngine() in the method which handles the array copying etc.

I didn't hit on this solution straight away because when it comes to playing back sound directly from a recording using engine.Play2D(rec_sound, loop_flag) with no further arrays in between, in other words adding the sound from memory to the engine, the engine can be declared globally after initialising the window (ie, after InitializeComponent()).

But when using AddSoundSourceFromPCMData it seems the engine has to be declared inside the actual method handling the array creation and the playback from that.

Which is not a problem in this case, but there could be a time when a global declaration might be the thing to do. Unless of course there is some way around it which I haven’t discovered yet.

And yes, I do use a unique name for every soundsource.


niko
Moderator
Quote
2015-03-12 09:33:55

Hm, it's difficult to say. Could you maybe post some more, contiguous code? Alternatively, you can also send it to me via mail (Support -> Contact)


tr32
Registered User
Quote
2015-03-13 02:25:25

Sure.

CASE 1 - record sound, playback sound, directly from memory:
(the 'etc.' stands for unrelated stuff)
(loop_flag is set to 'false')

public partial class playrecSoundWin : Window
{
static string rec_sound0 = "recording0";
public static ISoundEngine engine0;
public static IAudioRecorder recorder0;
etc.

public playrecSoundWin()
{
InitializeComponent();

engine0 = new ISoundEngine();
recorder0 = new IAudioRecorder(engine0);
etc.

private void startRecBtn_Click(object sender, RoutedEventArgs e)
{
engine0.RemoveAllSoundSources(); //otherwise no further recording takes place
recorder0.StartRecordingBufferedAudio();
}
private void stopRecBtn_Click(object sender, RoutedEventArgs e)
{
if (recorder0 != null)
{
recorder0.StopRecordingAudio();
}
}

private void startPlayBtn_Click(object sender, RoutedEventArgs e)
{
recorder0.AddSoundSourceFromRecordedAudio(rec_sound0);
engine0.Play2D(rec_sound0, loop_flag);
}

No problem, can be repeated over and over.


CASE 2 - record sound, copy sound to array, playback sound:

public partial class playrecSoundWin : Window
{
static string rec_sound0 = "recording0";
static string rec_sound1 = "recording1";

public static ISoundEngine engine0, engine1;
public static ISound sound1;
public static ISoundSource soundsource1;
public static IAudioRecorder recorder0;

public playrecSoundWin()
{
InitializeComponent();

engine0 = new ISoundEngine(); //Note: cannot do this for engine1 here!
recorder0 = new IAudioRecorder(engine0);
etc.

Start and Stop recording is the same as CASE 1, and then:

private void startPlayBtn_Click(object sender, RoutedEventArgs e)
{
recorder0.AddSoundSourceFromRecordedAudio(rec_sound0);
af = recorder0.AudioFormat;

SoundDataArray1 = new byte[recorder0.RecordedAudioData.Length];
Array.Copy(recorder0.RecordedAudioData, SoundDataArray1, recorder0.RecordedAudioData.Length);

engine1 = new ISoundEngine(); //Note: now engine1 must be declared
soundsource1 = engine1.AddSoundSourceFromPCMData(SoundDataArray1, rec_sound1, af);
sound1 = engine1.Play2D(soundsource1, loop_flag, false, false);
}

Then sound1 can be used for changing volume, speed, checking whether it is finished, etc etc, and the entire operation can be repeated many times.

However, had I defined engine1 as in CASE 1 there is no sound1, it never gets instantiated.

I also tested this case in a loop where the whole recording and playback is called over and over again, and according to TaskManager > Performance there is no notable memory use increase, so the disposal of engine1 etc must be quite efficient nevertheless.

Still, what is the underlying difference between CASE 1 and 2?

Thanks for all your time!


niko
Moderator
Quote
2015-03-14 09:16:56

I don't still quite understand the question, sorry. This is all a bit confusing - "had I defined engine1 as in CASE 1" - what?

It is basically always a good idea to only have one sound engine. You never would need more than one. It should be possible to create everything with one instance. Maybe something gets confused between the two instances in your code and causing this, just a guess.


tr32
Registered User
Quote
2015-03-14 23:35:57

In CASE 1 the sound engine is declared after InitializeComponent().

In CASE 2 the sound engine is declared inside the method where the playback is handled. Here it is engine1 which is declared inside the method.

That’s the difference between CASE 1 and 2, and I wonder why this should be so.

If I declare engine1 after InitializeComponent() (as I do with engine0) it won’t play at all. If I use only one sound engine, that is the engine0 I use for recording, sound1 only plays once; it cannot be played more than once.

I tried it again, just to make sure after your suggestion that only one sound engine should be used.


Create reply:


Posted by: (you are not logged in)


Enter the missing letter in: "Int?rnational" (you are not logged in)


Text:

 

  

Possible Codes


Feature Code
Link [url] www.example.com [/url]
Bold [b]bold text[/b]
Image [img]http://www.example.com/image.jpg[/img]
Quote [quote]quoted text[/quote]
Code [code]source code[/code]

Emoticons


   






Copyright© Ambiera e.U. all rights reserved.
Privacy Policy | Terms and Conditions | Imprint | Contact