0
0

Hi,

I’m trying to export a recorded sound to a wav file for storage.

Knowing next to nothing about the wav file structure (well that’s bragging as I know absolutely nothing about it), I’ve been messing around with a combination of the offlinedecoding- and recordtodisk example apps, taking the writeWavHeader function from the latter and the sound->readData loop from the former.

But I can’t get it to work because the readData returns 0 in the read parameter.

[code:2h1bfiag]
bytesRead = 0;
do
{
result = sound->readData((char *)data, CHUNKSIZE, &read);

 fwrite((char *)data, read, 1, toFile);

 bytesRead   += read;
NSLog(@"Read %d and Written %d bytes of %d to output.raw", read, bytesRead, length);

}
while (result == FMOD_OK && read == CHUNKSIZE);
[/code:2h1bfiag]

CUNKSIZE is set to 4096. I know there is data in the sound object, because I can play it back. The length is set appropriately using

[code:2h1bfiag]
result = sound->getLength(&soundLength, FMOD_TIMEUNIT_PCM);
[/code:2h1bfiag]

The sound object is created as follows:

[code:2h1bfiag]
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); /// Required.
exinfo.numchannels = 1; // Number of channels in the sound.
exinfo.format = FMOD_SOUND_FORMAT_PCM16; // Data format of sound.
exinfo.defaultfrequency = 12000;
exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * maxSecondsToRecord;
ERRCHECK(result);
result = system->createSound(NULL, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound);
[/code:2h1bfiag]

Ideas anyone?

  • You must to post comments
0
0

You used FMOD_OPENUSER, this means you’re supposed to fill in the read callback – are you trying to load a wave file from disk or create your own data? You dont seem to have any callbacks. Even if you did, why would you feed your own data into fmod just to retrieve it again with readData?

  • You must to post comments
0
0

Thx for the swift respons Brett,

I use FMOD_OPEN_USER because I record into it first with recordStart and recordStop. This works fine and I can play back the sound using playSound, so I know there’s audio data in the sound object (getLength returns the length too). But once it’s been recorded I want to be able to store the recording for future retrieval into a FMOD::Sound, hence the export and the readData. I want to store it either in a wav file or preferably as a blob in the sqlite database (the key point being that I need to be able to retrieve it into a FMOD::Sound at a later stage).

Is there a better way of doing this? If not, what mode do I need to set the sound object to in order to be able to access it with readData? (fyi I tried FMOD_OPENONLY, but then the application crashed with a "bad parameter sent to function" message). Do I need to lock and unlock the chunks I’m reading even if the recording was stopped?

  • You must to post comments
0
0

I figured it out.

I needed to use the approach taken in the recordtodisk example (sound->lock and unlock as opposed to the sound->readData approach taken in the offlinedecoding example).

If anyone’s interested in how to save a recorded sound that’s been created with the FMOD_OPENUSER flag, but doesn’t want to use CPU resources on it during recording like the recordtodisk sample does, the following code works.

Declaring the sound

[code:5909aar6]
// Setting up exinfo struct for recording

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 * maxSecondsToRecord;
ERRCHECK(result);

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

Then record into it using

[code:5909aar6]
result = system->recordStart(0, sound, loopFlag);
[/code:5909aar6]

…and stop it and get its length with:

[code:5909aar6]
result = system->recordStop(0);
result = sound->getLength(&length, FMOD_TIMEUNIT_PCM);
[/code:5909aar6]

…then write the wav header file

[code:5909aar6]
void writeWavHeader(FILE *file, FMOD::Sound *sound, int length) {
int channels;
int bits;
float rate;
FMOD_SOUND_FORMAT format;
FMOD_MODE mode;

if (!sound) {
    return;
}

fseek(file, 0, SEEK_SET);

sound->getFormat(NULL, &format, &channels, &bits);
sound->getDefaults(&rate, NULL, NULL, NULL);

{

// WAV Structures

    typedef struct
    {
        signed char id[4];
        int         size;
    } RiffChunk;

    struct
    {
        RiffChunk       chunk           __PACKED;
        unsigned short  wFormatTag      __PACKED;    // format type  
        unsigned short  nChannels       __PACKED;    // number of channels (i.e. mono, stereo...)  
        unsigned int    nSamplesPerSec  __PACKED;    // sample rate  
        unsigned int    nAvgBytesPerSec __PACKED;    // for buffer estimation  
        unsigned short  nBlockAlign     __PACKED;    // block size of data  
        unsigned short  wBitsPerSample  __PACKED;    // number of bits per sample of mono data 
    } __PACKED FmtChunk  = { {{'f','m','t',' '}, sizeof(FmtChunk) - sizeof(RiffChunk) }, 1, channels, (int)rate, (int)rate * channels * bits / 8, 1 * channels * bits / 8, bits };

    struct
    {
        RiffChunk   chunk;
    } DataChunk = { {{'d','a','t','a'}, length } };

    struct
    {
        RiffChunk   chunk;
        signed char rifftype[4];
    } WavHeader = { {{'R','I','F','F'}, sizeof(FmtChunk) + sizeof(RiffChunk) + length }, {'W','A','V','E'} };


// Write out the WAV header

    fwrite(&WavHeader, sizeof(WavHeader), 1, file);
    fwrite(&FmtChunk, sizeof(FmtChunk), 1, file);
    fwrite(&DataChunk, sizeof(DataChunk), 1, file);
}

}
[/code:5909aar6]

…and finally write raw sound data to the file

[code:5909aar6]
void writeSoundToRaw(FILE *toFile, FMOD::Sound *sound, unsigned int length) {
const unsigned int CHUNKSIZE = 4096;
FMOD_RESULT result = FMOD_OK;

unsigned int        bytesRead   = 0;
void           *ptr1        = NULL;
void           *ptr2        = NULL;

unsigned int    len1        = 0;
unsigned int    len2        = 0;


bytesRead = 0;
do
{

    result = sound->lock(bytesRead, CHUNKSIZE, &ptr1, &ptr2, &len1, &len2);
    ERRCHECK(result);

    if (ptr1 && len1) {
        bytesRead += fwrite(ptr1, 1, len1, toFile);
    }
    if (ptr2 && len2) {
        bytesRead += fwrite(ptr2, 1, len2, toFile);
    }
    result = sound->unlock(ptr1, ptr2, len1, len2);
    ERRCHECK(result);


    NSLog(@"Written %d bytes of %d to wav file", bytesRead, length);
}
while (result == FMOD_OK && bytesRead < length);


if (toFile)
{
    fclose(toFile);
    toFile = NULL;
NSLog(@"Sound object written to file");
}

}
[/code:5909aar6]

…and that’s pretty much it.

Oh yeah, and you HAVE TO make the following declaration inside your implementation block in your .m file:

[code:5909aar6]

define PACKED __attribute((packed)) // gcc packed

[/code:5909aar6][/code]

  • You must to post comments
0
0

This all works fine for sounds loaded from another WAV, as I tested.
But I need to load from DLS. Select subSound from it. And then save the sound to a file.

I just tried to do this. No success.
Then I just replaced the sound with an external wav sound. With no code change. All works.

When I say no success, I mean File is created, it contains some data.
But when I try to play it, I see that it’s much shorter than the original sound, and sounds absolutely different from the original sound.

  • You must to post comments
Showing 4 results
Your Answer

Please first to submit.