int main(int argc, char *argv[]) { FMOD::System *system = 0; FMOD::Sound *sound = 0; FMOD::Channel *channel = 0; FMOD_RESULT result; FMOD_CREATESOUNDEXINFO exinfo; int key, driver, recorddriver, numdrivers, count; unsigned int version; /* Create a System object and initialize. */ result = FMOD::System_Create(&system); ERRCHECK(result); result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION); return 0; } /* System initialization */ printf("---------------------------------------------------------\n"); printf("Select OUTPUT type\n"); printf("---------------------------------------------------------\n"); printf("1 : OSS - Open Sound System\n"); printf("2 : ALSA - Advanced Linux Sound Architecture\n"); printf("3 : ESD - Enlightenment Sound Daemon\n"); printf("4 : PULSEAUDIO - Pulse Audio Sound Server\n"); printf("---------------------------------------------------------\n"); printf("Press a corresponding number or ESC to quit\n"); do { key = getch(); } while (key != 27 && key < '1' && key > '5'); switch (key) { case '1' : result = system->setOutput(FMOD_OUTPUTTYPE_OSS); break; case '2' : result = system->setOutput(FMOD_OUTPUTTYPE_ALSA); break; case '3' : result = system->setOutput(FMOD_OUTPUTTYPE_ESD); break; case '4' : result = system->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO); break; default : return 1; } ERRCHECK(result); /* Enumerate playback devices */ result = system->getNumDrivers(&numdrivers); ERRCHECK(result); printf("---------------------------------------------------------\n"); printf("Choose a PLAYBACK driver\n"); printf("---------------------------------------------------------\n"); for (count=0; count < numdrivers; count++) { char name[256]; result = system->getDriverInfo(count, name, 256, 0); ERRCHECK(result); printf("%d : %s\n", count + 1, name); } printf("---------------------------------------------------------\n"); printf("Press a corresponding number or ESC to quit\n"); do { key = getch(); if (key == 27) { return 0; } driver = key - '1'; } while (driver < 0 || driver >= numdrivers); result = system->setDriver(driver); ERRCHECK(result); /* Enumerate record devices */ result = system->getRecordNumDrivers(&numdrivers); ERRCHECK(result); printf("---------------------------------------------------------\n"); printf("Choose a RECORD driver\n"); printf("---------------------------------------------------------\n"); for (count=0; count < numdrivers; count++) { char name[256]; result = system->getRecordDriverInfo(count, name, 256, 0); ERRCHECK(result); printf("%d : %s\n", count + 1, name); } printf("---------------------------------------------------------\n"); printf("Press a corresponding number or ESC to quit\n"); recorddriver = 0; do { key = getch(); if (key == 27) { return 0; } recorddriver = key - '1'; } while (recorddriver < 0 || recorddriver >= numdrivers); printf("\n"); result = system->init(32, FMOD_INIT_NORMAL, 0); ERRCHECK(result); memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = 2; exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.defaultfrequency = 44100; exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 5; result = system->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound); ERRCHECK(result); printf("===================================================================\n"); printf("Recording example. Copyright (c) Firelight Technologies 2004-2011.\n"); printf("===================================================================\n"); printf("\n"); printf("Press 'r' to record a 5 second segment of audio and write it to a wav file.\n"); printf("Press 'p' to play the 5 second segment of audio.\n"); printf("Press 'l' to turn looping on/off.\n"); printf("Press 's' to stop recording and playback.\n"); printf("Press 'w' to save the 5 second segment to a wav file.\n"); printf("Press 'Esc' to quit\n"); printf("\n"); /* Main loop. */ do { static FMOD::Channel *channel = 0; static bool looping = false; bool recording = false; bool playing = false; unsigned int recordpos = 0; unsigned int playpos = 0; unsigned int length; if (kbhit()) { key = getch(); switch (key) { case 'r' : case 'R' : { result = system->recordStart(recorddriver, sound, looping); ERRCHECK(result); break; } case 'p' : case 'P' : { if (looping) { sound->setMode(FMOD_LOOP_NORMAL); } else { sound->setMode(FMOD_LOOP_OFF); } ERRCHECK(result); result = system->playSound(FMOD_CHANNEL_REUSE, sound, false, &channel); ERRCHECK(result); break; } case 'l' : case 'L' : { looping = !looping; break; } case 's' : case 'S' : { result = system->recordStop(recorddriver); if (channel) { channel->stop(); channel = 0; } break; } case 'w' : case 'W' : { printf("Writing to record.wav ... \r"); SaveToWav(sound); Sleep(500); break; } } } sound->getLength(&length, FMOD_TIMEUNIT_PCM); ERRCHECK(result); system->isRecording(recorddriver, &recording); ERRCHECK(result); system->getRecordPosition(recorddriver, &recordpos); ERRCHECK(result); if (channel) { channel->isPlaying(&playing); ERRCHECK(result); channel->getPosition(&playpos, FMOD_TIMEUNIT_PCM); ERRCHECK(result); } printf("State: %-19s. Record pos = %6d : Play pos = %6d : Loop %-3s\r", recording ? playing ? "Recording / playing" : "Recording" : playing ? "Playing" : "Idle", recordpos, playpos, looping ? "On" : "Off"); fflush(stdout); system->update(); fflush(stdout); Sleep(10); } while (key != 27); printf("\n"); /* Shut down */ result = sound->release(); ERRCHECK(result); result = system->release(); ERRCHECK(result); return 0; }
/*============================================================================== Record example Copyright (c), Firelight Technologies Pty, Ltd 2004-2014. This example shows how to record continuously, and play back the same data as closely to the record cursor as possible without stuttering. ==============================================================================*/ #include "fmod.hpp" #include "common.h" #define LATENCY_MS (50) /* Some devices will require higher latency to avoid glitches */ int FMOD_Main() { FMOD::System *system = 0; FMOD::Sound *sound = 0; FMOD::Channel *channel = 0; FMOD_RESULT result = FMOD_OK; unsigned int version = 0; unsigned int soundlength = 0; bool dspenabled = false; void *extradriverdata = 0; unsigned int recordpos = 0; unsigned int recorddelta = 0; unsigned int minrecorddelta = (unsigned int)-1; unsigned int lastrecordpos = 0; unsigned int samplesrecorded = 0; unsigned int playpos = 0; float smootheddelta = 0; FMOD_CREATESOUNDEXINFO exinfo; Common_Init(&extradriverdata); /* Create a System object and initialize. */ result = FMOD::System_Create(&system); ERRCHECK(result); result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION); } result = system->init(100, FMOD_INIT_NORMAL, extradriverdata); ERRCHECK(result); int recordrate; int recordchannels; result = system->getRecordDriverInfo(0, NULL, NULL, 0, 0, &recordrate, 0, &recordchannels); ERRCHECK(result); unsigned int adjustedlatency = (recordrate * LATENCY_MS) / 1000; unsigned int driftthreshold = adjustedlatency / 2; /* Create user sound to record into. */ memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = recordchannels; exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.defaultfrequency = recordrate; exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 5; /* 5 second buffer, doesnt really matter how big this is, but not too small of course. */ result = system->createSound(0, FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &sound); ERRCHECK(result); result = system->recordStart(0, sound, true); ERRCHECK(result); result = sound->getLength(&soundlength, FMOD_TIMEUNIT_PCM); ERRCHECK(result); /* Main loop */ do { Common_Update(); if (Common_BtnPress(BTN_ACTION1)) { FMOD_REVERB_PROPERTIES propon = FMOD_PRESET_CONCERTHALL; FMOD_REVERB_PROPERTIES propoff = FMOD_PRESET_OFF; dspenabled = !dspenabled; result = system->setReverbProperties(0, dspenabled ? &propon : &propoff); ERRCHECK(result); } result = system->update(); ERRCHECK(result); system->getRecordPosition(0, &recordpos); ERRCHECK(result); recorddelta = (recordpos >= lastrecordpos) ? (recordpos - lastrecordpos) : (recordpos + soundlength - lastrecordpos); lastrecordpos = recordpos; samplesrecorded += recorddelta; if (samplesrecorded >= adjustedlatency && !channel) { result = system->playSound(sound, 0, false, &channel); ERRCHECK(result); } if (channel && recorddelta) { /* If the record driver steps the position of the record cursor in larger increments than the user defined latency value, then we should increase our latency value to match. */ if (recorddelta < minrecorddelta) { minrecorddelta = recorddelta; if (adjustedlatency < recorddelta) { adjustedlatency = recorddelta; } } result = channel->getPosition(&playpos, FMOD_TIMEUNIT_PCM); ERRCHECK(result); /* Smooth total */ { const float dampratio = 0.97f; static float total = 0; total *= dampratio; total += (recordpos >= playpos) ? (recordpos - playpos) : (recordpos + soundlength - playpos); smootheddelta = total * (1.0f - dampratio); } if (smootheddelta < (adjustedlatency - driftthreshold) || smootheddelta > soundlength / 2) /* If play cursor is catching up to record (or passed it), slow playback down */ { channel->setFrequency(recordrate - (recordrate / 50)); /* Decrease speed by 2% */ } else if (smootheddelta > (adjustedlatency + driftthreshold)) /* If play cursor is falling too far behind record, speed playback up */ { channel->setFrequency(recordrate + (recordrate / 50)); /* Increase speed by 2% */ } else { channel->setFrequency(recordrate); /* Otherwise set to normal rate */ } } Common_Draw("=================================================="); Common_Draw("Record Example."); Common_Draw("Copyright (c) Firelight Technologies 2004-2014."); Common_Draw("=================================================="); Common_Draw(""); Common_Draw("Adjust LATENCY define to compensate for stuttering"); Common_Draw(""); Common_Draw("Press %s to %s DSP effect", Common_BtnStr(BTN_ACTION1), dspenabled ? "disable" : "enable"); Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT)); Common_Draw(""); Common_Draw("Default playback latency: %4d (%dms)", (recordrate * LATENCY_MS) / 1000, LATENCY_MS); Common_Draw("Current playback latency: %4d (%dms)", (int)smootheddelta, (int)smootheddelta * 1000 / recordrate); Common_Draw("Record position: %6d", recordpos); Common_Draw("Play Position: %6d", playpos); Common_Sleep(10); } while (!Common_BtnPress(BTN_QUIT)); /* Shut down */ result = sound->release(); ERRCHECK(result); result = system->release(); ERRCHECK(result); Common_Close(); return 0; }
int FMOD_Main() { FMOD::Channel *channel = NULL; unsigned int samplesRecorded = 0; unsigned int samplesPlayed = 0; bool dspEnabled = false; void *extraDriverData = NULL; Common_Init(&extraDriverData); /* Create a System object and initialize. */ FMOD::System *system = NULL; FMOD_RESULT result = FMOD::System_Create(&system); ERRCHECK(result); unsigned int version = 0; result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION); } result = system->init(100, FMOD_INIT_NORMAL, extraDriverData); ERRCHECK(result); int numDrivers = 0; result = system->getRecordNumDrivers(NULL, &numDrivers); ERRCHECK(result); if (numDrivers == 0) { Common_Fatal("No recording devices found/plugged in! Aborting."); } /* Determine latency in samples. */ int nativeRate = 0; int nativeChannels = 0; result = system->getRecordDriverInfo(DEVICE_INDEX, NULL, 0, NULL, &nativeRate, NULL, &nativeChannels, NULL); ERRCHECK(result); unsigned int driftThreshold = (nativeRate * DRIFT_MS) / 1000; /* The point where we start compensating for drift */ unsigned int desiredLatency = (nativeRate * LATENCY_MS) / 1000; /* User specified latency */ unsigned int adjustedLatency = desiredLatency; /* User specified latency adjusted for driver update granularity */ int actualLatency = desiredLatency; /* Latency measured once playback begins (smoothened for jitter) */ /* Create user sound to record into, then start recording. */ FMOD_CREATESOUNDEXINFO exinfo = {0}; exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = nativeChannels; exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.defaultfrequency = nativeRate; exinfo.length = nativeRate * sizeof(short) * nativeChannels; /* 1 second buffer, size here doesn't change latency */ FMOD::Sound *sound = NULL; result = system->createSound(0, FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &sound); ERRCHECK(result); result = system->recordStart(DEVICE_INDEX, sound, true); ERRCHECK(result); unsigned int soundLength = 0; result = sound->getLength(&soundLength, FMOD_TIMEUNIT_PCM); ERRCHECK(result); /* Main loop */ do { Common_Update(); /* Add a DSP effect -- just for fun */ if (Common_BtnPress(BTN_ACTION1)) { FMOD_REVERB_PROPERTIES propOn = FMOD_PRESET_CONCERTHALL; FMOD_REVERB_PROPERTIES propOff = FMOD_PRESET_OFF; dspEnabled = !dspEnabled; result = system->setReverbProperties(0, dspEnabled ? &propOn : &propOff); ERRCHECK(result); } result = system->update(); ERRCHECK(result); /* Determine how much has been recorded since we last checked */ unsigned int recordPos = 0; result = system->getRecordPosition(DEVICE_INDEX, &recordPos); if (result != FMOD_ERR_RECORD_DISCONNECTED) { ERRCHECK(result); } static unsigned int lastRecordPos = 0; unsigned int recordDelta = (recordPos >= lastRecordPos) ? (recordPos - lastRecordPos) : (recordPos + soundLength - lastRecordPos); lastRecordPos = recordPos; samplesRecorded += recordDelta; static unsigned int minRecordDelta = (unsigned int)-1; if (recordDelta && (recordDelta < minRecordDelta)) { minRecordDelta = recordDelta; /* Smallest driver granularity seen so far */ adjustedLatency = (recordDelta <= desiredLatency) ? desiredLatency : recordDelta; /* Adjust our latency if driver granularity is high */ } /* Delay playback until our desired latency is reached. */ if (!channel && samplesRecorded >= adjustedLatency) { result = system->playSound(sound, 0, false, &channel); ERRCHECK(result); } if (channel) { /* Stop playback if recording stops. */ bool isRecording = false; result = system->isRecording(DEVICE_INDEX, &isRecording); if (result != FMOD_ERR_RECORD_DISCONNECTED) { ERRCHECK(result); } if (!isRecording) { result = channel->setPaused(true); ERRCHECK(result); } /* Determine how much has been played since we last checked. */ unsigned int playPos = 0; result = channel->getPosition(&playPos, FMOD_TIMEUNIT_PCM); ERRCHECK(result); static unsigned int lastPlayPos = 0; unsigned int playDelta = (playPos >= lastPlayPos) ? (playPos - lastPlayPos) : (playPos + soundLength - lastPlayPos); lastPlayPos = playPos; samplesPlayed += playDelta; /* Compensate for any drift. */ int latency = samplesRecorded - samplesPlayed; actualLatency = (0.97f * actualLatency) + (0.03f * latency); int playbackRate = nativeRate; if (actualLatency < (adjustedLatency - driftThreshold)) { /* Play position is catching up to the record position, slow playback down by 2% */ playbackRate = nativeRate - (nativeRate / 50); } else if (actualLatency > (adjustedLatency + driftThreshold)) { /* Play position is falling behind the record position, speed playback up by 2% */ playbackRate = nativeRate + (nativeRate / 50); } channel->setFrequency((float)playbackRate); ERRCHECK(result); } Common_Draw("=================================================="); Common_Draw("Record Example."); Common_Draw("Copyright (c) Firelight Technologies 2004-2015."); Common_Draw("=================================================="); Common_Draw(""); Common_Draw("Adjust LATENCY define to compensate for stuttering"); Common_Draw("Current value is %dms", LATENCY_MS); Common_Draw(""); Common_Draw("Press %s to %s DSP effect", Common_BtnStr(BTN_ACTION1), dspEnabled ? "disable" : "enable"); Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT)); Common_Draw(""); Common_Draw("Adjusted latency: %4d (%dms)", adjustedLatency, adjustedLatency * 1000 / nativeRate); Common_Draw("Actual latency: %4d (%dms)", actualLatency, actualLatency * 1000 / nativeRate); Common_Draw(""); Common_Draw("Recorded: %5d (%ds)", samplesRecorded, samplesRecorded / nativeRate); Common_Draw("Played: %5d (%ds)", samplesPlayed, samplesPlayed / nativeRate); Common_Sleep(10); } while (!Common_BtnPress(BTN_QUIT)); /* Shut down */ result = sound->release(); ERRCHECK(result); result = system->release(); ERRCHECK(result); Common_Close(); return 0; }
int main(int argc, char *argv[]) { FMOD::System *system = 0; FMOD::Sound *sound = 0; FMOD_RESULT result; FMOD_CREATESOUNDEXINFO exinfo; int key, recorddriver, numdrivers, count; unsigned int version; FILE *fp; unsigned int datalength = 0, soundlength; /* Create a System object and initialize. */ result = FMOD::System_Create(&system); ERRCHECK(result); result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION); return 0; } /* System initialization */ printf("---------------------------------------------------------\n"); printf("Select OUTPUT type\n"); printf("---------------------------------------------------------\n"); printf("1 : DirectSound\n"); printf("2 : Windows Multimedia WaveOut\n"); printf("3 : ASIO\n"); printf("---------------------------------------------------------\n"); printf("Press a corresponding number or ESC to quit\n"); do { key = _getch(); } while (key != 27 && key < '1' && key > '5'); switch (key) { case '1' : result = system->setOutput(FMOD_OUTPUTTYPE_DSOUND); break; case '2' : result = system->setOutput(FMOD_OUTPUTTYPE_WINMM); break; case '3' : result = system->setOutput(FMOD_OUTPUTTYPE_ASIO); break; default : return 1; } ERRCHECK(result); /* Enumerate record devices */ result = system->getRecordNumDrivers(&numdrivers); ERRCHECK(result); printf("---------------------------------------------------------\n"); printf("Choose a RECORD driver\n"); printf("---------------------------------------------------------\n"); for (count=0; count < numdrivers; count++) { char name[256]; result = system->getRecordDriverInfo(count, name, 256, 0); ERRCHECK(result); printf("%d : %s\n", count + 1, name); } printf("---------------------------------------------------------\n"); printf("Press a corresponding number or ESC to quit\n"); recorddriver = 0; do { key = _getch(); if (key == 27) { return 0; } recorddriver = key - '1'; } while (recorddriver < 0 || recorddriver >= numdrivers); printf("\n"); result = system->init(32, FMOD_INIT_NORMAL, 0); ERRCHECK(result); memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = 1; exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.defaultfrequency = 44100; exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 2; result = system->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound); ERRCHECK(result); printf("========================================================================\n"); printf("Record to disk example. Copyright (c) Firelight Technologies 2004-2014.\n"); printf("========================================================================\n"); printf("\n"); printf("Press a key to start recording to record.wav\n"); printf("\n"); _getch(); result = system->recordStart(recorddriver, sound, true); ERRCHECK(result); printf("Press 'Esc' to quit\n"); printf("\n"); fp = fopen("record.wav", "wb"); if (!fp) { printf("ERROR : could not open record.wav for writing.\n"); return 1; } /* Write out the wav header. As we don't know the length yet it will be 0. */ WriteWavHeader(fp, sound, datalength); result = sound->getLength(&soundlength, FMOD_TIMEUNIT_PCM); ERRCHECK(result); /* Main loop. */ do { static unsigned int lastrecordpos = 0; unsigned int recordpos = 0; if (_kbhit()) { key = _getch(); } system->getRecordPosition(recorddriver, &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(lastrecordpos * exinfo.numchannels * 2, blocklength * exinfo.numchannels * 2, &ptr1, &ptr2, &len1, &len2); /* * exinfo.numchannels * 2 = stereo 16bit. 1 sample = 4 bytes. */ /* Write it to disk. */ if (ptr1 && len1) { datalength += fwrite(ptr1, 1, len1, fp); } if (ptr2 && len2) { datalength += fwrite(ptr2, 1, len2, fp); } /* Unlock the sound to allow FMOD to use it again. */ sound->unlock(ptr1, ptr2, len1, len2); } lastrecordpos = recordpos; printf("%-23s. Record buffer pos = %6d : Record time = %02d:%02d\r", (timeGetTime() / 500) & 1 ? "Recording to record.wav" : "", recordpos, datalength / exinfo.defaultfrequency / exinfo.numchannels / 2 / 60, (datalength / exinfo.defaultfrequency / exinfo.numchannels / 2) % 60); system->update(); Sleep(10); } while (key != 27); printf("\n"); /* Write back the wav header now that we know its length. */ WriteWavHeader(fp, sound, datalength); fclose(fp); /* Shut down */ result = sound->release(); ERRCHECK(result); result = system->release(); ERRCHECK(result); return 0; }
int main(int argc, char *argv[]) { FMOD::System *system = 0; FMOD::Sound *sound = 0; FMOD_RESULT result; FMOD_CREATESOUNDEXINFO exinfo; int key, recorddriver, numdrivers, count; unsigned int version; FILE *fp; unsigned int datalength = 0, soundlength; bool iscoreaudio = false; /* Create a System object and initialize. */ result = FMOD::System_Create(&system); ERRCHECK(result); result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION); return 0; } result = system->setOutput(FMOD_OUTPUTTYPE_COREAUDIO); ERRCHECK(result); /* Enumerate record devices */ result = system->getRecordNumDrivers(&numdrivers); ERRCHECK(result); printf("---------------------------------------------------------\n"); printf("Choose a RECORD driver\n"); printf("---------------------------------------------------------\n"); for (count=0; count < numdrivers; count++) { char name[256]; result = system->getRecordDriverInfo(count, name, 256, 0); ERRCHECK(result); printf("%d : %s\n", count + 1, name); } printf("---------------------------------------------------------\n"); printf("Press a corresponding number or ESC to quit\n"); recorddriver = 0; do { key = getch(); if (key == 27) { return 0; } recorddriver = key - '1'; } while (recorddriver < 0 || recorddriver >= numdrivers); printf("\n"); result = system->init(32, FMOD_INIT_NORMAL, 0); ERRCHECK(result); memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = 2; exinfo.defaultfrequency = 44100; if (iscoreaudio) { exinfo.format = FMOD_SOUND_FORMAT_PCMFLOAT; exinfo.length = exinfo.defaultfrequency * sizeof(float) * exinfo.numchannels * 2; } else { exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 2; } result = system->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_OPENUSER, &exinfo, &sound); ERRCHECK(result); printf("========================================================================\n"); printf("Record to disk example. Copyright (c) Firelight Technologies 2004-2014.\n"); printf("========================================================================\n"); printf("\n"); printf("Press a key to start recording to record.wav\n"); printf("\n"); getch(); result = system->recordStart(recorddriver, sound, true); ERRCHECK(result); printf("Press 'Esc' to quit\n"); printf("\n"); fp = fopen("record.wav", "wb"); if (!fp) { printf("ERROR : could not open record.wav for writing.\n"); return 1; } /* Write out the wav header. As we don't know the length yet it will be 0. */ WriteWavHeader(fp, sound, datalength); result = sound->getLength(&soundlength, FMOD_TIMEUNIT_PCM); ERRCHECK(result); /* Main loop. */ do { static unsigned int lastrecordpos = 0; unsigned int recordpos = 0; if (kbhit()) { key = getch(); } system->getRecordPosition(recorddriver, &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. */ if(iscoreaudio) { sound->lock(lastrecordpos * 8, blocklength * 8, &ptr1, &ptr2, &len1, &len2); /* *8 = stereo 32bit. 1 sample = 8 bytes. */ } else { sound->lock(lastrecordpos * 4, blocklength * 4, &ptr1, &ptr2, &len1, &len2); /* *4 = stereo 16bit. 1 sample = 4 bytes. */ } /* Write it to disk. */ if (ptr1 && len1) { #ifdef __BIG_ENDIAN__ if (exinfo.format == FMOD_SOUND_FORMAT_PCM16) { signed short *wptr = (signed short *)ptr1; for (int count = 0; count < len1 >> 1; count++) { wptr[count] = SWAPENDIAN_WORD(wptr[count]); } } else if (exinfo.format == FMOD_SOUND_FORMAT_PCMFLOAT) { float *fptr = (float *)ptr1; for (int count = 0; count < len1 >> 2; count++) { SWAPENDIAN_FLOAT(fptr[count]); } } #endif datalength += fwrite(ptr1, 1, len1, fp); } if (ptr2 && len2) { #ifdef __BIG_ENDIAN__ if (exinfo.format == FMOD_SOUND_FORMAT_PCM16) { signed short *wptr = (signed short *)ptr2; for (int count = 0; count < len2 >> 1; count++) { wptr[count] = SWAPENDIAN_WORD(wptr[count]); } } else if (exinfo.format == FMOD_SOUND_FORMAT_PCMFLOAT) { float *fptr = (float *)ptr2; for (int count = 0; count < len2 >> 2; count++) { SWAPENDIAN_FLOAT(fptr[count]); } } #endif datalength += fwrite(ptr2, 1, len2, fp); } /* Unlock the sound to allow FMOD to use it again. */ sound->unlock(ptr1, ptr2, len1, len2); } lastrecordpos = recordpos; printf("\rRecord buffer pos = %6d : Record time = %02d:%02d", recordpos, datalength / exinfo.defaultfrequency / 4 / 60, (datalength / exinfo.defaultfrequency / 4) % 60); fflush(stdout); system->update(); Sleep(10); } while (key != 27); printf("\n"); /* Write back the wav header now that we know its length. */ WriteWavHeader(fp, sound, datalength); fclose(fp); /* Shut down */ result = sound->release(); ERRCHECK(result); result = system->release(); ERRCHECK(result); return 0; }
int main(int argc, char *argv[]) { FMOD::System *system = 0; FMOD::Sound *sound = 0; FMOD::Channel *channel = 0; FMOD::DSP *dsp = 0; FMOD_RESULT result; FMOD_CREATESOUNDEXINFO exinfo; FMOD_SPEAKERMODE speakermode; FMOD_CAPS caps; int key, numdrivers; unsigned int version; unsigned int datalength = 0, soundlength; char name[256]; unsigned int adjustedlatency; /* Create a System object and initialize. */ result = FMOD::System_Create(&system); ERRCHECK(result); result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION); return 0; } /* System initialization (recommended startup sequence) */ result = system->getNumDrivers(&numdrivers); ERRCHECK(result); if (numdrivers == 0) { result = system->setOutput(FMOD_OUTPUTTYPE_NOSOUND); ERRCHECK(result); } else { result = system->getDriverCaps(0, &caps, 0, &speakermode); ERRCHECK(result); result = system->setSpeakerMode(speakermode); /* Set the user selected speaker mode. */ ERRCHECK(result); if (caps & FMOD_CAPS_HARDWARE_EMULATED) /* The user has the 'Acceleration' slider set to off! This is really bad for latency!. */ { /* You might want to warn the user about this. */ result = system->setDSPBufferSize(1024, 10); ERRCHECK(result); } #ifdef LOWLATENCY else { result = system->setDSPBufferSize(256, 4); } #endif result = system->getDriverInfo(0, name, 256, 0); ERRCHECK(result); if (strstr(name, "SigmaTel")) /* Sigmatel sound devices crackle for some reason if the format is PCM 16bit. PCM floating point output seems to solve it. */ { result = system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0, FMOD_DSP_RESAMPLER_LINEAR); ERRCHECK(result); } } result = system->init(100, FMOD_INIT_NORMAL, 0); if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) /* Ok, the speaker mode selected isn't supported by this soundcard. Switch it back to stereo... */ { result = system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); ERRCHECK(result); result = system->init(100, FMOD_INIT_NORMAL, 0);/* ... and re-init. */ ERRCHECK(result); } /* System initialization complete (recommended startup sequence) */ /* Create user sound to record into. Set it to loop for playback. */ memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); exinfo.numchannels = 1; exinfo.format = FMOD_SOUND_FORMAT_PCM16; exinfo.defaultfrequency = RECORDRATE; exinfo.length = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 5; /* 5 second buffer, doesnt really matter how big this is, but not too small of course. */ result = system->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &sound); ERRCHECK(result); printf("========================================================================\n"); printf("Record with realtime playback example.\n"); printf("Copyright (c) Firelight Technologies 2004-2014.\n"); printf("\n"); printf("Try #define LOWLATENCY to reduce latency for more modern machines!\n"); printf("========================================================================\n"); printf("\n"); printf("Press a key to start recording. Playback will start %d samples (%d ms) later.\n", LATENCY, LATENCY * 1000 / RECORDRATE); printf("\n"); _getch(); printf("Press 'E' to toggle an effect on/off.\n"); printf("Press 'Esc' to quit\n"); printf("\n"); result = system->recordStart(0, sound, true); ERRCHECK(result); result = sound->getLength(&soundlength, FMOD_TIMEUNIT_PCM); ERRCHECK(result); /* Create a DSP effect to play with. */ result = system->createDSPByType(FMOD_DSP_TYPE_FLANGE, &dsp); ERRCHECK(result); result = dsp->setParameter(FMOD_DSP_FLANGE_RATE, 4.0f); ERRCHECK(result); result = dsp->setBypass(true); ERRCHECK(result); adjustedlatency = LATENCY; /* This might change depending on record block size. */ /* Main loop. */ do { static unsigned int lastrecordpos = 0, samplesrecorded = 0; unsigned int recordpos = 0, recorddelta; key = 0; if (_kbhit()) { key = _getch(); } if (key == 'e' || key == 'E') { bool bypass; dsp->getBypass(&bypass); dsp->setBypass(!bypass); if (bypass) { FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_CONCERTHALL; system->setReverbProperties(&prop); } else { FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_OFF; system->setReverbProperties(&prop); } printf("\n\n *** TURN DSP EFFECT %s ** \n\n", bypass ? "ON" : "OFF"); } system->getRecordPosition(0, &recordpos); ERRCHECK(result); recorddelta = recordpos >= lastrecordpos ? recordpos - lastrecordpos : recordpos + soundlength - lastrecordpos; samplesrecorded += recorddelta; if (samplesrecorded >= adjustedlatency && !channel) { result = system->playSound(FMOD_CHANNEL_FREE, sound, 0, &channel); ERRCHECK(result); result = channel->addDSP(dsp, 0); ERRCHECK(result); } if (channel && recorddelta) { unsigned int playrecorddelta; unsigned int playpos = 0; int adjusting = 0; float smootheddelta; float dampratio = 0.97f; static unsigned int minrecorddelta = (unsigned int)-1; /* If the record driver steps the position of the record cursor in larger increments than the user defined latency value, then we should increase our latency value to match. */ if (recorddelta < minrecorddelta) { minrecorddelta = recorddelta; if (adjustedlatency < recorddelta) { adjustedlatency = recorddelta; } } channel->getPosition(&playpos, FMOD_TIMEUNIT_PCM); playrecorddelta = recordpos >= playpos ? recordpos - playpos : recordpos + soundlength - playpos; /* Smooth total */ { static float total = 0; total = total * dampratio; total += playrecorddelta; smootheddelta = total * (1.0f - dampratio); } if (smootheddelta < adjustedlatency - DRIFTTHRESHOLD || smootheddelta > soundlength / 2) /* if play cursor is catching up to record (or passed it), slow playback down */ { channel->setFrequency(RECORDRATE - (RECORDRATE / 50)); /* Decrease speed by 2% */ adjusting = 1; } else if (smootheddelta > adjustedlatency + DRIFTTHRESHOLD) /* if play cursor is falling too far behind record, speed playback up */ { channel->setFrequency(RECORDRATE + (RECORDRATE / 50)); /* Increase speed by 2% */ adjusting = 2; } else { channel->setFrequency(RECORDRATE); /* Otherwise set to normal rate */ adjusting = 0; } printf("REC %5d (REC delta %5d) : PLAY %5d, PLAY/REC diff %5d %s\r", recordpos, recorddelta, playpos, (int)smootheddelta, adjusting == 1 ? "DECREASE SPEED" : adjusting == 2 ? "INCREASE SPEED" : " "); } lastrecordpos = recordpos; system->update(); Sleep(10); } while (key != 27); printf("\n"); /* Shut down */ result = sound->release(); ERRCHECK(result); result = system->release(); ERRCHECK(result); return 0; }