5

My goal is to play local file while recording device's microphone input with low-latency. I've come to Superpowered library, because from the documentation it provides low-latency feature. I've created the player using SuperpoweredAdvancedAudioPlayer and SuperpoweredAndroidAudioIO and it plays fine.

SuperpoweredAndroidAudioIO has the construcor with parameters boolean enableInput, boolean enableOutput. Currently I'm using enableInput == false and enableOutput == true. When I put these parameters to true - no effect.

I wonder if it is possible to record file and play other file simultaneously?

Also there is SuperpoweredRecorder class in library but it says not for direct writing to disk. And need to use createWAV, fwrite, closeWAV methods. I've tried implement Recorder separately but the quality is not good (it is two-three times faster than real recording + sound is distored). Here is the simplest piece of code for recording I used:

void SuperpoweredFileRecorder::start(const char *destinationPath) {
    file = createWAV(destinationPath, sampleRate, 2);
    audioIO = new SuperpoweredAndroidAudioIO(sampleRate, bufferSize, true, false, audioProcessing, NULL, bufferSize); // Start audio input/output.
}

void SuperpoweredFileRecorder::stop() {
    closeWAV(file);
    audioIO->stop();
}

static bool audioProcessing(void *clientdata, short int *audioInputOutput, int numberOfSamples, int samplerate) {
    fwrite(audioInputOutput, sizeof(short int), numberOfSamples, file);
    return false;
}

Probably I cannot use Superpowered for that purpose and need to just make recording with OpenSL ES directly.

Thanks in advance!

kasurd
  • 476
  • 7
  • 16

3 Answers3

6

After experiments I found the solution.

  1. SuperpoweredRecorder works fine for recording tracks;
  2. I've created to separate SuperpoweredAndroidAudioIO sources - one for playback and another for recorder. After some synchronization manipulation it works well (I minimized latency to very low level, so it suits my needs).

I post some code snippet with the idea I implemented:

https://bitbucket.org/snippets/kasurd/Mynnp/nativesuperpoweredrecorder-with

Hope it helps somebody!

kasurd
  • 476
  • 7
  • 16
5

You can do this with one instance of the SuperpoweredAndroidAudioIO with enableInput and enableOutput set to true.

The audio processing callback (audioProcessing() in your case) receives audio (microphone) in the audioInputOutput parameter. Just pass that to your SuperpoweredRecorder, and it will write it onto disk.

After that, do your SuperpoweredAdvancedAudioPlayer processing, and convert the result into audioInputOutput. That will go to the audio output.

So it's like, in pseudo-code:

audioProcessing(audioInputOutput) {
   recorder->process(audioInputOutput)
   player->process(some_buffer)
   float_to_short_int(some_buffer, audioInputOutput)
}

Never do any fwrite in the audio processing callback, as it must complete within a very short time, and disk operations may be too slow.

Gabor Szanto
  • 1,329
  • 8
  • 12
  • Thanks, Gabor for the comment. I'd started with this approach, but then it appeared that I need two-three playbacks and one recorder simultaneously. I decided to switch to separate SuperpoweredAndroidAudioIO. Will your approach work for my case as well? – kasurd May 23 '16 at 12:55
  • Yes, of course. Multiple players can process into the same buffer. The process() method has the bufferAdd parameter, just set it to true, and use the same buffer for all. – Gabor Szanto May 24 '16 at 12:03
  • Can you please explain how you write the output of audio after applying effects in a file ? – arslan haktic Feb 18 '17 at 13:04
  • Hi Gabor, would you maybe mind explaining in short how you would differentiate between a callback from the input and a callback from the output for audioProcessing? My issue is that as soon as I set bufferAdd to true, the output from the player becomes complete gibberish. If I set it to false, I can hear the file play back normally. – ItWillDo Sep 07 '17 at 08:30
  • 1
    With Superpowered there is only one callback, not separated for input and output. The buffer for the callback will contain the audio input, and that must be overwritten for the output. bufferAdd means "add the player's output to the contents of this buffer, do not overwrite". If that's gibberish, then the buffer may have gibberish content or the player didn't touch the buffer (returned false when process()). – Gabor Szanto Sep 07 '17 at 09:08
  • Hey Gabor, thanks for the comment as I got it working now. I think I was just looking at it from a different perspective but it makes a lot more sense now! – ItWillDo Sep 07 '17 at 20:31
0

For me this works when I double the numberOfSamples

fwrite(audioInputOutput, sizeof(short int), numberOfSamples * 2, file);

This will lead to a clear stereo output

Sn0wfreeze
  • 1,959
  • 3
  • 18
  • 32