0
0

I can successfully record 24-bit wav files with FMOD Ex, but have not discovered the secret to playing them back. Using the C++ Windows "Playstream" example (and various modifications thereof using, e.g,

gSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM24, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); )

that I have tried), 24-bit wav files play back with a loud hiss, suggesting that the buffer size or number of buffers is incorrect.

Your help would be most gratefully appreciated.

(P.S.: This is the first post I have ever made for help in over 25 years of programming!)

  • You must to post comments
0
0

FMOD plays back 24bit wav files without an issue (last time I checked) so I would assume it is the way it is written out.

I assume you’re using the savetowav() function we provide to write out the 24bit data? That might be the issue. You can of course test the .wav file in media player. This would tell you if it was the record process or the playback process that had the problem.

  • You must to post comments
0
0

Brett:

Thanks very much for your response. No, I am not using th "the savetowav() function", no can I find it listed in any of the FMOD or FMOD Ex docs. But, you were correct, the problem is with the way I am writing data to disk. Shamelessly taking my lead from the "recording" example, I do the following (aabreviated):

rec_system->setOutput(FMOD_OUTPUTTYPE_DSOUND);
result = rec_system->setRecordDriver (driver=0);
result = rec_system->init (32, FMOD_INIT_NORMAL, 0);
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO);
exinfo.numchannels      = (int) wChannels;  // 1 = mono, 2 = stereo
exinfo.defaultfrequency = (int) dwSamplesPerSec;

if (wBitsPerSample == 8) {
    nBytesPerSample     = 1;
    exinfo.format       = FMOD_SOUND_FORMAT_PCM8;
    exinfo.length       = 
        exinfo.defaultfrequency * sizeof (BYTE) * exinfo.numchannels *
        nBytesPerSample;    // 1
}

if (wBitsPerSample == 16) {
    nBytesPerSample     = 2;
    exinfo.format       = FMOD_SOUND_FORMAT_PCM16;
    exinfo.length       = 
        exinfo.defaultfrequency * sizeof (short) * exinfo.numchannels *
        nBytesPerSample;    // 2

}

if (wBitsPerSample == 24) {
    nBytesPerSample     = 3;
    exinfo.format       = FMOD_SOUND_FORMAT_PCM24;
    exinfo.length       = 
        exinfo.defaultfrequency * sizeof (short) * exinfo.numchannels * 
        nBytesPerSample;    // 3
}

result = rec_system->createSound (0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound);
  • You must to post comments
0
0

Brett:

Thanks very much for your response. No, I am not using the "the savetowav() function", nor can I find it listed in any of the FMOD or FMOD Ex docs. But, you were correct, the problem is with the way I am writing data to disk. Shamelessly taking my lead from the "recording" example, I do the following (abbreviated):

rec_system->setOutput(FMOD_OUTPUTTYPE_DSOUND);
result = rec_system->setRecordDriver (driver=0);
result = rec_system->init (32, FMOD_INIT_NORMAL, 0);
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO);
exinfo.numchannels      = (int) wChannels;  // 1 = mono, 2 = stereo
exinfo.defaultfrequency = (int) dwSamplesPerSec;

if (wBitsPerSample == 8) {
    nBytesPerSample     = 1;
    exinfo.format       = FMOD_SOUND_FORMAT_PCM8;
    exinfo.length       = 
        exinfo.defaultfrequency * sizeof (BYTE) *                       exinfo.numchannels *
        nBytesPerSample;    // 1
}

if (wBitsPerSample == 16) {
    nBytesPerSample     = 2;
    exinfo.format       = FMOD_SOUND_FORMAT_PCM16;
    exinfo.length       = 
        exinfo.defaultfrequency * sizeof (short) * exinfo.numchannels *
        nBytesPerSample;    // 2

}

if (wBitsPerSample == 24) {
    nBytesPerSample     = 3;
    exinfo.format       = FMOD_SOUND_FORMAT_PCM24;
    exinfo.length       = 
        exinfo.defaultfrequency * sizeof (short) * exinfo.numchannels * 
        nBytesPerSample;    // 3
}

result = rec_system->createSound (0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound);

Then, in a separate thread, when data us received:

rec_system->getRecordPosition (&recordpos);
ERRCHECK(result);

    if (recordpos != lastrecordpos) {
        void *ptr1, *ptr2;

        int blocklength;
        unsigned int len1, len2;

        blocklength = (int) recordpos - (int) lastrecordpos;

        if (blocklength < 0) {
            blocklength += soundlength;
        }

// Lock the sound to get access to the raw data.
sound->lock (

// offset = Offset in bytes to the position you want to lock in the sample buffer.
// * exinfo.numchannels * 2 = stereo 16bit
lastrecordpos * exinfo.numchannels * nBytesPerSample,

// length = Number of bytes you want to lock in the sample buffer.
// 1 sample = 4 bytes.
blocklength * exinfo.numchannels * nBytesPerSample,

            &ptr1, &ptr2, &len1, &len2);   // * exinfo.numchannels * 2 = stereo 16bit.  1 sample = 4 bytes. 

// Write it to disk.
if (ptr1 && len1) {
if (!bTestRecord) {
datalength += fwrite (ptr1, 1, len1, fp);
}
// DisplayRecordDBMeters (ptr1, len1);
}

        if (ptr2 && len2) {
            if (!bTestRecord) {
                datalength += fwrite (ptr2, 1, len2, fp);
            }

// DisplayRecordDBMeters (ptr2, len2);
}

// Unlock the sound to allow FMOD to use it again.
sound->unlock (ptr1, ptr2, len1, len2);
}

    lastrecordpos = recordpos;

    rec_system->update();

This works fine for 8 and 16-bit data, but not for 24-bit data. Evidently I am not interpreting the sound->lock instruction correctly, so that either

lastrecordpos * exinfo.numchannels * nBytesPerSample

or

blocklength * exinfo.numchannels * nBytesPerSample

is incorrect.

Your suggesstions would be highly appreciated.

Thanks a lot.

  • You must to post comments
0
0

The fmod side will be ok, it is when you write out a wave file, if it is not 8 or 16bit pcm, you have to use WAVE_FORMAT_EXTENSIBLE.

Here is a bit of code we use to load waveformatextensible, it should be enough to show you how to write it out.

[code:1yd1t197]
if ((waveformat->channels > 2 || (waveformat->format != FMOD_SOUND_FORMAT_PCM8 && waveformat->format != FMOD_SOUND_FORMAT_PCM16)))
{
pcmwf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
}
else
{
pcmwf.Format.wFormatTag = WAVE_FORMAT_PCM;
}

pcmwf.Format.nChannels            = waveformat->channels;
pcmwf.Format.wBitsPerSample       = bits;
pcmwf.Format.nBlockAlign          = pcmwf.Format.nChannels * pcmwf.Format.wBitsPerSample / 8;
pcmwf.Format.nSamplesPerSec       = DEFAULT_FREQUENCY;
pcmwf.Format.nAvgBytesPerSec      = pcmwf.Format.nSamplesPerSec * pcmwf.Format.nBlockAlign;

if (pcmwf.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
{
    pcmwf.Format.cbSize               = 22;
    pcmwf.Samples.wValidBitsPerSample = bits;
    pcmwf.dwChannelMask = 0;

    if (waveformat->format == FMOD_SOUND_FORMAT_PCMFLOAT)
    {
        memcpy(&pcmwf.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID));
    }
    else
    {
        memcpy(&pcmwf.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID));
    }        
}

[/code:1yd1t197]

  • You must to post comments
0
0

Brett:

You, Sir, are a Hero-Genius. Whatever you are getting paid is not enough.

Finally realizing, as you pointed out, that I had to use a different wave header format to write 24-bit wav files to disk, I set about fathoming the arcane details of the MS WAVEFORMATEXTENSIBLE structure, and then wrote my own header routine, which miraculously worked the first time out, and I can now record, save, and playback 24 bit, 32 bit, and floating-point file formats.

My question now is this: when I go to port this code from the PC to the MAC, will I have to expect to change anything in order for 24-bit wav files to play on the MAC (using the identical FMOD routines), given that the 24-bit wave header is written using the WAVEFORMATEXTENSIBLE format concocted by Microsoft?

Thanks again, and best regards,

John Freeman

  • You must to post comments
Showing 5 results
Your Answer

Please first to submit.