0
0

Hello,

I’d like to record audio from the microphone of the iphone, apply a DSP filter on it, and then save it to a file.

I look around in this forum and try some code snippets, but i can’t make it work :-(

I start with the recordtodisk example, and add this few lines to the startRecord function :

[code:1ds6i8nt]result = system->recordStart(0, sound, true);
ERRCHECK(result);

/** ADDED LINES **/
bool active = false;

//play sound with pitch shifting
result = system->playSound(FMOD_CHANNEL_REUSE, sound, false, &channel);
ERRCHECK(result);

//create dsp
result = system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dspptich);
ERRCHECK(result);

result = dspptich->getActive(&active);
ERRCHECK(result);

result = dspptich->setParameter(FMOD_DSP_PITCHSHIFT_PITCH, 2.0f);
ERRCHECK(result);

result = channel->addDSP(dspptich, NULL);
ERRCHECK(result); [/code:1ds6i8nt]

for info, the initialization is like that :

[code:1ds6i8nt]result = system->init(1, FMOD_INIT_NORMAL | FMOD_INIT_ENABLE_PROFILE, NULL);
ERRCHECK(result);

memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));

exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO);
exinfo.numchannels      = 1;
exinfo.format           = FMOD_SOUND_FORMAT_PCM16;
exinfo.defaultfrequency = 8000;
exinfo.length           = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * RECORD_LENGTH_SECS;

bytesPerSample = sizeof(short) * exinfo.numchannels;
bytesPerSecond = exinfo.defaultfrequency * bytesPerSample;

result = system->createSound(NULL, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound);
ERRCHECK(result);[/code:1ds6i8nt]

I can heard the voice with the pitch effect in almost real time (but a low volume) , but if i try to play the recorded file (using AVAudioPlayer), the sound keep its normal pitch.

What am i doing wrong ??
Thank you for your help !

  • You must to post comments
0
0

If you are simply writing the recording out to disk it will not include the DSP effect.

There are two things you could do to record the output including any DSP effects. The simplest is set the output mode to wave writer. This will dump a fill containing everything that would have come out the speakers (however you will get no output).

The other option is to insert a custom DSP that saves the audio data to disk. You would insert this DSP anywhere you would like to record from in the DSP network. Logically something like:
(custom dsp) <- (pitch shifter) <- (recording sound)

You should be able to find plenty of resources by searching the forum for custom DSP examples. There is also the "dsp_custom" example we ship for the iPhone.

  • You must to post comments
0
0

Thank you for your help Mathew :)

I tried the WAVE WRITER method, but when i active this as output, it make my app crash every time with the error "FMOD error! (37) An invalid parameter was passed to this function."
It seems that it’s the recordStart function which cause the crash.

[code:e0tyoaan] //SET OUTPUT
char cDest[200] = {0};

[[NSString stringWithFormat:@&quot;%@/record.wav&quot;, [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]] getCString:cDest maxLength:200 encoding:NSASCIIStringEncoding];    

system-&gt;setOutput(FMOD_OUTPUTTYPE_WAVWRITER);
ERRCHECK(result);

result = system-&gt;init(1, FMOD_INIT_NORMAL | FMOD_INIT_ENABLE_PROFILE, cDest);
ERRCHECK(result);  [/code:e0tyoaan]

[code:e0tyoaan] result = system->recordStart(0, sound, true);
ERRCHECK(result);

/** ADDED LINES **/

[NSThread sleepForTimeInterval:0.06f];

 bool        active  = false;

//play sound with pitch shifting
result = system-&gt;playSound(FMOD_CHANNEL_FREE, sound, false, &amp;channel);
ERRCHECK(result);

//create dsp
result = system-&gt;createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &amp;dspptich);
ERRCHECK(result);

result = dspptich-&gt;getActive(&amp;active);
ERRCHECK(result);

result = dspptich-&gt;setParameter(FMOD_DSP_PITCHSHIFT_PITCH, 2.0f);
ERRCHECK(result); 

result = channel-&gt;addDSP(dspptich, NULL);
ERRCHECK(result); [/code:e0tyoaan]

Thank you!

  • You must to post comments
0
0

I finally try the other method, with the custom DSP. Everything seems to go well except when i play the .wav file. The sound is almost inaudible, like it’s very very slow…

My DSP callback function look like that

[code:1boeaxnm]FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;

//retreive ref to the main object
ViewController *userdata;
thisdsp->getUserData((void **)&userdata);

/*
This loop assumes inchannels = outchannels, which it will be if the DSP is created with ‘0’
as the number of channels in FMOD_DSP_DESCRIPTION.
Specifying an actual channel count will mean you have to take care of any number of channels coming in,
but outputting the number of channels specified. Generally it is best to keep the channel
count at 0 for maximum compatibility.
*/

if (userdata.isRecording) {


int dpp = 0;

unsigned int count, count2;

for (count = 0; count &lt; length; count++)
{

    for (count2 = 0; count2 &lt; outchannels; count2++)
    {             
          // Just copy the data to the outbuffer, no matter what it is
          outbuffer[(count * outchannels) + count2] = inbuffer[(count * inchannels) + count2];

          // This is what we calculate to output to the file
          float valu = inbuffer[(count * inchannels) + count2] * 32767.0;

          //make sure it doesnt round off to a over-max value
          if (valu &gt; 32767)
             valu = 32767;
          if (valu &lt; -32768)
             valu = -32768;

          short writ = (short)valu;

          fwrite((const char *)&amp;writ, 1, sizeof(writ), userdata.outFile);

          userdata.dataLength += dpp;
    }


} 

}

return FMOD_OK; [/code:1boeaxnm]

What am i doing wrong ??
thank you!

  • You must to post comments
0
0

Ok firstly I shouldn’t have recommended using wave writer since you are using recording. You need to use the CoreAudio output mode to get access to the recording device. You are getting invalid param on recordStart because there are no recording devices available for wave writer.

For the DSP, I noticed dpp is 0, so dataLength won’t increment. Also are you writing out the wave header correctly? There is an example of this with the "recordToDisk" example. Otherwise your code should work from what I can see.

  • You must to post comments
0
0

Thank you mathew, it work’s !

I indeed forget to increment dpp, and also make a mistake with the default frequency of the Sound object (keep 8000 like the recordtodisk example insteed of 44100).

  • You must to post comments
0
0

After all I have still a little problem:

After about 60 seconds, the sound start to stutter progressively and then shut down completely. I can heard this when outputing on the speaker and on the .wav file. I saw this topic http://52.88.2.202/forum/viewtopic.php … ht=stutter and try to optimize the fwrite’s calls in my DSP callbacks like that but it changes nothing :

[code:1whrguhk]FMOD_RESULT F_CALLBACK myDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
{
//unsigned int userdata = 0;
//char name[256] = {0};
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;

FmodRecorder *userdata;
thisdsp-&gt;getUserData((void **)&amp;userdata);


/*
 This loop assumes inchannels = outchannels, which it will be if the DSP is created with '0' 
 as the number of channels in FMOD_DSP_DESCRIPTION.  
 Specifying an actual channel count will mean you have to take care of any number of channels coming in,
 but outputting the number of channels specified.  Generally it is best to keep the channel 
 count at 0 for maximum compatibility.
 */

if (!userdata.isRecording) {
    return FMOD_OK; 
}




int dpp = 0;

unsigned int count, count2;

//create buffer to limit fwrite calls
short buffer[length*outchannels];


for (count = 0; count &lt; length; count++)
{

    for (count2 = 0; count2 &lt; outchannels; count2++)
    {             
        // Just copy the data to the outbuffer, no matter what it is
        outbuffer[(count * outchannels) + count2] = inbuffer[(count * inchannels) + count2];


        // This is what we calculate to output to the file
        float valu = inbuffer[(count * inchannels) + count2] * 32767.0;

        //make sure it doesnt round off to a over-max value
        if (valu &gt; 32767)
            valu = 32767;
        if (valu &lt; -32768)
            valu = -32768;

        short writ = (short)valu;

        buffer[(count * outchannels) + count2] = writ;

        //dpp = fwrite((const char *)&amp;writ, 1, sizeof(writ), userdata.outFile);
        //userdata.dataLength += dpp;

    }


} 

dpp = fwrite((const char *)&amp;buffer, sizeof(short), length*outchannels, userdata.outFile);
userdata.dataLength += length*outchannels*sizeof(short);

if (userdata.recordStart == 0) {
    userdata.recordStart = [NSDate timeIntervalSinceReferenceDate];
}

return FMOD_OK; 

}[/code:1whrguhk]

Is it because I ask to much to the CPU ? I don’t need to have a perfect real time processing, just to have the final wav file available as soon as possible for the user (this why I want to start processing while it’s recorded). Is there a way to let more time to the CPU to process data ?

Thank you !

  • You must to post comments
0
0

You can use getCPUUsage to determine if you are overloading the processor, if any of the values go over 100% you are going to have problems. Let me know if that is your issue.

Also it’s possible you are tripping over the record buffer, i.e. the distance between the record and play heads have crossed. There is discussion about that issue here: http://52.88.2.202/forum/viewtopic.php?t=13220

  • You must to post comments
0
0

Hi mathew, thank you for your answer, it help me a lot. However i still have a little problem.

Using getCPUUsage give always values under 100%.

I managed to have a far better result by changing the value of the global samplerate using setSoftwareFormat (I set it to 44100). The recorded sound doesn’t stutter and slow anymore, but there are still random micro-cut. So at the end the entire sound is shorter than it should.
I tried to use the methods on the thread you link, but it seems to not solve this problem.

I need to have a very time-accurate recording, because I synchronise the resulting sound with other medias as soon as the recording is complete.

Where do you think this problem come from ? Is there a solution to not have these micro-cuts, or at least to correct them in real time ?

Thank you for your help!

  • You must to post comments
0
0

If you are getting some glitches ensure that the record position is always ahead of the read position. You can check this by comparing System::getRecordPosition with Channel::getPosition, perhaps this is your problem.

  • You must to post comments
Showing 9 results
Your Answer

Please first to submit.