AVSStereoSoundTouch(PClip _child, float _tempo, float _rate, float _pitch, const AVSValue* args, IScriptEnvironment* env)
: GenericVideoFilter(_child), 
  tempo(_tempo/100.0f), rate(_rate/100.0f), pitch(_pitch/100.0f)
{
//  last_nch = vi.AudioChannels();
  
  dstbuffer = new SFLOAT[BUFFERSIZE * vi.AudioChannels()];

  sample_multiplier  = tempo / pitch;  // Do it the same way the library does it!
  sample_multiplier *= pitch * rate;

  sampler = new SoundTouch();

  sampler->setRate(rate);
  sampler->setTempo(tempo);
  sampler->setPitch(pitch);
  sampler->setChannels(2);
  sampler->setSampleRate(vi.audio_samples_per_second);
  AVSsoundtouch::setSettings(sampler, args, env);

  vi.num_audio_samples = (__int64)((long double)vi.num_audio_samples / sample_multiplier);

  next_sample = 0;  // Next output sample
  inputReadOffset = 0;  // Next input sample
  dst_samples_filled = 0;

}
void *vc_soundtouch_create(int rate, float pitch)
{
    SoundTouch *st;
    st = new SoundTouch();
    if (st) {
        st->setChannels(1);
        st->setSampleRate(rate);
        st->setPitchSemiTones(pitch);
        st->setSetting(SETTING_USE_QUICKSEEK, 1);
        st->setSetting(SETTING_USE_AA_FILTER, 1);
    }
    return st;
}
Exemple #3
0
void* audioConsumerNoStretch(void* param)
{
    soundTouch.setSampleRate(GameFreq);
    soundTouch.setChannels(2);
    soundTouch.setSetting( SETTING_USE_QUICKSEEK, 1 );
    soundTouch.setSetting( SETTING_USE_AA_FILTER, 1 );
    double speedFactor = static_cast<double>(speed_factor)/100.0;
    soundTouch.setTempo(speedFactor);

    soundTouch.setRate((double)GameFreq/(double)OutputFreq);
    queueData* currQueueData = NULL;
    struct timespec prevTime;

    int lastSpeedFactor = speed_factor;

    //How long to wait for some data
    struct timespec waitTime;
    waitTime.tv_sec = 1;
    waitTime.tv_nsec = 0;

    while(!shutdown)
    {
        struct threadmsg msg;

        clock_gettime(CLOCK_MONOTONIC_RAW, &prevTime);
        int result = thread_queue_get(&audioConsumerQueue, &waitTime, &msg);

        if( result != ETIMEDOUT )
        {
            currQueueData = (queueData*)msg.data;
            int dataLength = currQueueData->lenght;

            if(lastSpeedFactor != speed_factor)
            {
                lastSpeedFactor = speed_factor;
                double speedFactor = static_cast<double>(speed_factor)/100.0;
                soundTouch.setTempo(speedFactor);
            }


            processAudio(currQueueData->data, dataLength);

            free(currQueueData->data);
            free(currQueueData);
        }
    }

    return 0;
}
static void ChangePcmTone(FILE *inFile, FILE *outFile, float TempoChange, float PitchSemiTones, float RateChange)
{
	SoundTouch soundTouch;

	// Setup the 'SoundTouch' object for processing the sound

	soundTouch.setSampleRate(8000);
	soundTouch.setChannels(1);

	soundTouch.setTempoChange(TempoChange);
	soundTouch.setPitchSemiTones(PitchSemiTones); //’˝œÚ «x÷·¿≠≥§£¨4±»Ωœ¿ÌœÎ
	soundTouch.setRateChange(RateChange);     //’˝œÚ «x÷·¿≠≥§£¨50

	//soundTouch.setTempoChange(20);
	//soundTouch.setPitchSemiTones(6.0f); //’˝œÚ «x÷·¿≠≥§£¨4±»Ωœ¿ÌœÎ
	//soundTouch.setRateChange(0);     //’˝œÚ «x÷·¿≠≥§£¨50

	//soundTouch.setTempoChange(1.0);
	//soundTouch.setPitchSemiTones(20);
	//soundTouch.setRateChange(-2.0);

	soundTouch.setSetting(SETTING_USE_QUICKSEEK, 0);
	soundTouch.setSetting(SETTING_USE_AA_FILTER, 1);
	soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
	soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
	soundTouch.setSetting(SETTING_OVERLAP_MS, 8);

#if 0
	if (params->speech)
	{
		// use settings for speech processing
		soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
		soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
		soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
		fprintf(stderr, "Tune processing parameters for speech processing.\n");
	}
#endif
	// Process the sound
	process(&soundTouch, inFile, outFile);	
	fflush(outFile);
}
Exemple #5
0
void* audioConsumerStretch(void* param)
{
   /*
   static int sequenceLenMS = 63;
   static int seekWindowMS = 16;
   static int overlapMS = 7;*/

   soundTouch.setSampleRate((uint)GameFreq);
   soundTouch.setChannels(2);
   soundTouch.setSetting( SETTING_USE_QUICKSEEK, 1 );
   soundTouch.setSetting( SETTING_USE_AA_FILTER, 1 );
   //soundTouch.setSetting( SETTING_SEQUENCE_MS, sequenceLenMS );
   //soundTouch.setSetting( SETTING_SEEKWINDOW_MS, seekWindowMS );
   //soundTouch.setSetting( SETTING_OVERLAP_MS, overlapMS );

   soundTouch.setRate((double)GameFreq/(double)OutputFreq);
   double speedFactor = static_cast<double>(speed_factor)/100.0;
   soundTouch.setTempo(speedFactor);
   
   double bufferMultiplier = (double)OutputFreq/DEFAULT_FREQUENCY;

   int maxQueueSize = (int)(TargetSecondaryBuffers + 30.0*bufferMultiplier);
   int minQueueSize = (int)(TargetSecondaryBuffers*bufferMultiplier);
   bool drainQueue = false;

   //Sound queue ran dry, device is running slow
   int ranDry = 0;

   //adjustment used when a device running too slow
   double slowAdjustment = 1.0;
   double currAdjustment = 1.0;

   //how quickly to return to original speed
   const double returnSpeed = 0.10;
   const double minSlowValue = 0.2;
   const double maxSlowValue = 3.0;
   const float maxSpeedUpRate = 0.5;
   const float slowRate = 0.05;
   queueData* currQueueData = NULL;
    struct timespec prevTime;
    struct timespec currTime;

   //How long to wait for some data
   struct timespec waitTime;
   waitTime.tv_sec = 1;
   waitTime.tv_nsec = 0;

   int feedTimeWindowSize = 50;
   int feedTimeIndex = 0;
   bool feedTimesSet = false;
   float feedTimes[feedTimeWindowSize];
   float gameTimes[feedTimeWindowSize];
   float averageGameTime = 0.01666;
   float averageFeedTime = 0.01666;

   while(!shutdown)
   {
      int slesQueueLength = lock.limit - lock.value;

      ranDry = slesQueueLength < minQueueSize;

      struct threadmsg msg;

      clock_gettime(CLOCK_MONOTONIC_RAW, &prevTime);
      int result = thread_queue_get(&audioConsumerQueue, &waitTime, &msg);

      if( result != ETIMEDOUT )
      {
         int threadQueueLength = thread_queue_length(&audioConsumerQueue);

         currQueueData = (queueData*)msg.data;
         int dataLength = currQueueData->lenght;

         float temp =  averageGameTime/averageFeedTime;

          // Only start running algorithm once enough samples are built
          if(lock.count <= lock.limit)
          {
              double speedFactor = static_cast<double>(speed_factor)/100.0;
              soundTouch.setTempo(speedFactor);

              processAudio(currQueueData->data, dataLength);

              free(currQueueData->data);
              free(currQueueData);

              //Useful logging
              //if(slesQueueLength == 0)
              //{
              //DebugMessage(M64MSG_ERROR, "sles_length=%d, min_size=%d, count=%d",
              //             slesQueueLength, minQueueSize, lock.count);
              //}
          }
          else{
              //Game is running too fast speed up audio
              if ((slesQueueLength > maxQueueSize || drainQueue) && !ranDry) {
                  drainQueue = true;
                  currAdjustment = temp +
                                   (float) (slesQueueLength - minQueueSize) / (float) (lock.limit - minQueueSize) *
                                   maxSpeedUpRate;
              }
                  //Device can't keep up with the game or we have too much in the queue after slowing it down
              else if (ranDry) {
                  drainQueue = false;
                  currAdjustment = temp - slowRate;
              }
              else if (!ranDry && slesQueueLength < maxQueueSize) {
                  currAdjustment = temp;
              }

              //Allow the tempo to slow quickly with no minimum value change, but restore original tempo more slowly.
              if (currAdjustment > minSlowValue && currAdjustment < maxSlowValue) {
                  slowAdjustment = currAdjustment;
                  static const int increments = 4;
                  //Adjust tempo in x% increments so it's more steady
                  int temp2 = ((int) (slowAdjustment * 100)) / increments;
                  temp2 *= increments;
                  slowAdjustment = ((double) temp2) / 100;

                  soundTouch.setTempo(slowAdjustment);
              }

              processAudio(currQueueData->data, dataLength);

              free(currQueueData->data);
              free(currQueueData);

              //Useful logging
              //if(slesQueueLength == 0)
              //{
              //DebugMessage(M64MSG_ERROR, "sles_length=%d, thread_length=%d, dry=%d, slow_adj=%f, curr_adj=%f, temp=%f, feed_time=%f, game_time=%f, min_size=%d, count=%d",
              //             slesQueueLength, threadQueueLength, ranDry, slowAdjustment, currAdjustment, temp, averageFeedTime, averageGameTime, minQueueSize, lock.count);
              //}

              //We don't want to calculate the average until we give everything a time to settle.
              //Calculate rates
              clock_gettime(CLOCK_MONOTONIC_RAW, &currTime);

              //Figure out how much to slow down by
              float timeDiff = TimeDiff(&currTime, &prevTime);

              //sometimes this ends up as less than 0, not sure how
              if (timeDiff > 0) {
                  feedTimes[feedTimeIndex] = timeDiff;
              }

              averageFeedTime = GetAverageTime(feedTimes, feedTimesSet ? feedTimeWindowSize : (feedTimeIndex + 1));

              gameTimes[feedTimeIndex] = (float) dataLength / (float) N64_SAMPLE_BYTES / (float) GameFreq;
              averageGameTime = GetAverageTime(gameTimes, feedTimesSet ? feedTimeWindowSize : (feedTimeIndex + 1));

              ++feedTimeIndex;
              if (feedTimeIndex == feedTimeWindowSize) {
                  feedTimeIndex = 0;
                  feedTimesSet = true;
              }
          }
      }
   }

   return 0;
}
Exemple #6
0
void SoundTouch_setSampleRate(void *stouch, unsigned int sampleRate) 
{
    SoundTouch *soundTouch = (SoundTouch *)stouch;
    soundTouch->setSampleRate(sampleRate); 
}