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; }
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; }