Advertisement
Guest User

Untitled

a guest
Dec 6th, 2016
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.19 KB | None | 0 0
  1. /*==============================================================================
  2. Record example
  3. Copyright (c), Firelight Technologies Pty, Ltd 2004-2016.
  4.  
  5. This example shows how to record continuously and play back the same data while
  6. keeping a specified latency between the two. This is achieved by delaying the
  7. start of playback until the specified number of milliseconds has been recorded.
  8. At runtime the playback speed will be slightly altered to compensate for any
  9. drift in either play or record drivers.
  10. ==============================================================================*/
  11. #include "fmod.hpp"
  12. #include "common.h"
  13.  
  14. #define LATENCY_MS      (50) /* Some devices will require higher latency to avoid glitches */
  15. #define DRIFT_MS        (1)
  16. #define DEVICE_INDEX    (0)
  17.  
  18. int FMOD_Main()
  19. {
  20.     FMOD::Channel *channel = NULL;
  21.     unsigned int samplesRecorded = 0;
  22.     unsigned int samplesPlayed = 0;
  23.     bool dspEnabled = false;
  24.  
  25.     void *extraDriverData = NULL;
  26.     Common_Init(&extraDriverData);
  27.  
  28.     /*
  29.         Create a System object and initialize.
  30.     */
  31.     FMOD::System *system = NULL;
  32.     FMOD_RESULT result = FMOD::System_Create(&system);
  33.     ERRCHECK(result);
  34.  
  35.     unsigned int version = 0;
  36.     result = system->getVersion(&version);
  37.     ERRCHECK(result);
  38.  
  39.     if (version < FMOD_VERSION)
  40.     {
  41.         Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION);
  42.     }
  43.  
  44.     result = system->init(100, FMOD_INIT_NORMAL, extraDriverData);
  45.     ERRCHECK(result);
  46.  
  47.     int numDrivers = 0;
  48.     result = system->getRecordNumDrivers(NULL, &numDrivers);
  49.     ERRCHECK(result);
  50.  
  51.     if (numDrivers == 0)
  52.     {
  53.         Common_Fatal("No recording devices found/plugged in!  Aborting.");
  54.     }
  55.  
  56.     /*
  57.         Determine latency in samples.
  58.     */
  59.     int nativeRate = 0;
  60.     int nativeChannels = 0;
  61.     result = system->getRecordDriverInfo(DEVICE_INDEX, NULL, 0, NULL, &nativeRate, NULL, &nativeChannels, NULL);
  62.     ERRCHECK(result);
  63.  
  64.     unsigned int driftThreshold = (nativeRate * DRIFT_MS) / 1000;       /* The point where we start compensating for drift */
  65.     unsigned int desiredLatency = (nativeRate * LATENCY_MS) / 1000;     /* User specified latency */
  66.     unsigned int adjustedLatency = desiredLatency;                      /* User specified latency adjusted for driver update granularity */
  67.     int actualLatency = desiredLatency;                                 /* Latency measured once playback begins (smoothened for jitter) */
  68.  
  69.     /*
  70.         Create user sound to record into, then start recording.
  71.     */
  72.     FMOD_CREATESOUNDEXINFO exinfo = {0};
  73.     exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO);
  74.     exinfo.numchannels      = nativeChannels;
  75.     exinfo.format           = FMOD_SOUND_FORMAT_PCM16;
  76.     exinfo.defaultfrequency = nativeRate;
  77.     exinfo.length           = nativeRate * sizeof(short) * nativeChannels; /* 1 second buffer, size here doesn't change latency */
  78.    
  79.     FMOD::Sound *sound = NULL;
  80.     result = system->createSound(0, FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &sound);
  81.     ERRCHECK(result);
  82.  
  83.     result = system->recordStart(DEVICE_INDEX, sound, true);
  84.     ERRCHECK(result);
  85.  
  86.     unsigned int soundLength = 0;
  87.     result = sound->getLength(&soundLength, FMOD_TIMEUNIT_PCM);
  88.     ERRCHECK(result);
  89.  
  90.  
  91.      // This is defined outside the loop
  92.     FMOD::DSP* dsp = 0;
  93.  
  94.  
  95.     /*
  96.         Main loop
  97.     */
  98.     do
  99.     {
  100.         Common_Update();
  101.  
  102.         /*
  103.             Add a DSP effect -- just for fun
  104.         */
  105.         if (Common_BtnPress(BTN_ACTION1))
  106.         {
  107.             FMOD_REVERB_PROPERTIES propOn = FMOD_PRESET_CONCERTHALL;
  108.             FMOD_REVERB_PROPERTIES propOff = FMOD_PRESET_OFF;
  109.  
  110.             dspEnabled = !dspEnabled;
  111.  
  112.             result = system->setReverbProperties(0, dspEnabled ? &propOn : &propOff);
  113.             ERRCHECK(result);
  114.         }
  115.  
  116.         result = system->update();
  117.         ERRCHECK(result);
  118.        
  119.         /*
  120.             Determine how much has been recorded since we last checked
  121.         */
  122.         unsigned int recordPos = 0;
  123.         result = system->getRecordPosition(DEVICE_INDEX, &recordPos);
  124.         if (result != FMOD_ERR_RECORD_DISCONNECTED)
  125.         {
  126.             ERRCHECK(result);
  127.         }
  128.  
  129.         static unsigned int lastRecordPos = 0;
  130.         unsigned int recordDelta = (recordPos >= lastRecordPos) ? (recordPos - lastRecordPos) : (recordPos + soundLength - lastRecordPos);
  131.         lastRecordPos = recordPos;
  132.         samplesRecorded += recordDelta;
  133.  
  134.         static unsigned int minRecordDelta = (unsigned int)-1;
  135.         if (recordDelta && (recordDelta < minRecordDelta))
  136.         {
  137.             minRecordDelta = recordDelta; /* Smallest driver granularity seen so far */
  138.             adjustedLatency = (recordDelta <= desiredLatency) ? desiredLatency : recordDelta; /* Adjust our latency if driver granularity is high */
  139.         }
  140.        
  141.         /*
  142.             Delay playback until our desired latency is reached.
  143.         */
  144.         if (!channel && samplesRecorded >= adjustedLatency)
  145.         {
  146.             result = system->playSound(sound, 0, false, &channel);
  147.             ERRCHECK(result);
  148.  
  149.             system->createDSPByType(FMOD_DSP_TYPE_FFT, &dsp);
  150.             channel->addDSP(FMOD_DSP_PARAMETER_DATA_TYPE_FFT, dsp);
  151.             dsp->setActive(true);
  152.  
  153.         }
  154.  
  155.         if (channel)
  156.         {
  157.             /*
  158.                 Stop playback if recording stops.
  159.             */
  160.             bool isRecording = false;
  161.             result = system->isRecording(DEVICE_INDEX, &isRecording);
  162.             if (result != FMOD_ERR_RECORD_DISCONNECTED)
  163.             {
  164.                 ERRCHECK(result);
  165.             }
  166.  
  167.             if (!isRecording)
  168.             {
  169.                 result = channel->setPaused(true);
  170.                 ERRCHECK(result);
  171.             }
  172.  
  173.             /*
  174.                 Determine how much has been played since we last checked.
  175.             */
  176.             unsigned int playPos = 0;
  177.             result = channel->getPosition(&playPos, FMOD_TIMEUNIT_PCM);
  178.             ERRCHECK(result);
  179.  
  180.             static unsigned int lastPlayPos = 0;
  181.             unsigned int playDelta = (playPos >= lastPlayPos) ? (playPos - lastPlayPos) : (playPos + soundLength - lastPlayPos);
  182.             lastPlayPos = playPos;
  183.             samplesPlayed += playDelta;
  184.            
  185.             /*
  186.                 Compensate for any drift.
  187.             */
  188.             int latency = samplesRecorded - samplesPlayed;
  189.             actualLatency = (0.97f * actualLatency) + (0.03f * latency);
  190.  
  191.             int playbackRate = nativeRate;
  192.             if (actualLatency < (int)(adjustedLatency - driftThreshold))
  193.             {
  194.                 /* Play position is catching up to the record position, slow playback down by 2% */
  195.                 playbackRate = nativeRate - (nativeRate / 50);
  196.             }
  197.             else if (actualLatency > (int)(adjustedLatency + driftThreshold))
  198.             {
  199.                 /* Play position is falling behind the record position, speed playback up by 2% */
  200.                 playbackRate = nativeRate + (nativeRate / 50);
  201.             }
  202.  
  203.             channel->setFrequency((float)playbackRate);
  204.             ERRCHECK(result);
  205.         }
  206.  
  207.         Common_Draw("==================================================");
  208.         Common_Draw("Record Example.");
  209.         Common_Draw("Copyright (c) Firelight Technologies 2004-2016.");
  210.         Common_Draw("==================================================");
  211.         Common_Draw("");
  212.         Common_Draw("Adjust LATENCY define to compensate for stuttering");
  213.         Common_Draw("Current value is %dms", LATENCY_MS);
  214.         Common_Draw("");
  215.         Common_Draw("Press %s to %s DSP effect", Common_BtnStr(BTN_ACTION1), dspEnabled ? "disable" : "enable");
  216.         Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
  217.         Common_Draw("");
  218.         Common_Draw("Adjusted latency: %4d (%dms)", adjustedLatency, adjustedLatency * 1000 / nativeRate);
  219.         Common_Draw("Actual latency:   %4d (%dms)", actualLatency, actualLatency * 1000 / nativeRate);
  220.         Common_Draw("");
  221.         Common_Draw("Recorded: %5d (%ds)", samplesRecorded, samplesRecorded / nativeRate);
  222.         Common_Draw("Played:   %5d (%ds)", samplesPlayed, samplesPlayed / nativeRate);
  223.  
  224.  
  225.         if (dsp)
  226.         {
  227.             // This is in the loop
  228.             FMOD_DSP_PARAMETER_FFT *fft; // FMOD_DSP_FFT_DOMINANT_FREQ
  229.             dsp->getParameterData(FMOD_DSP_FFT_SPECTRUMDATA, (void **)&fft, 0, 0, 0);
  230.  
  231.             Common_Draw("Channels %d", fft->numchannels);
  232.             for (int channelz = 0; channelz < fft->numchannels; channelz++)
  233.             {
  234.                 Common_Draw("count %f", channelz);
  235.                 for (int bin = 0; bin < fft->length; bin++)
  236.                 {
  237.                     float val = fft->spectrum[channelz][bin];
  238.                     Common_Draw("FFT  %f", val);
  239.                 }
  240.             }
  241.          }  
  242.            
  243.              Common_Sleep(10);
  244.     } while (!Common_BtnPress(BTN_QUIT));
  245.  
  246.     /*
  247.         Shut down
  248.     */
  249.     result = sound->release();
  250.     ERRCHECK(result);
  251.     result = system->release();
  252.     ERRCHECK(result);
  253.  
  254.     Common_Close();
  255.  
  256.     return 0;
  257. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement