TEST (AudioDataTest, FrameMutatorBounds) {
  KeyFinder::AudioData a;
  a.setChannels(2);
  a.addToFrameCount(10);
  ASSERT_THROW(a.getSampleByFrame(-1, 0), KeyFinder::Exception);
  ASSERT_THROW(a.getSampleByFrame(10, 0), KeyFinder::Exception);
  ASSERT_THROW(a.getSampleByFrame( 0,-1), KeyFinder::Exception);
  ASSERT_THROW(a.getSampleByFrame( 0, 2), KeyFinder::Exception);
}
TEST (AudioDataTest, SampleInitialisation) {
  KeyFinder::AudioData a;
  a.addToSampleCount(100);
  ASSERT_EQ(100, a.getSampleCount());
  // init values
  for (int i = 0; i < 100; i++) {
    ASSERT_FLOAT_EQ(0.0, a.getSample(i));
  }
}
TEST (LowPassFilterTest, InsistsOnMonophonicAudio) {
    KeyFinder::AudioData a;
    a.setChannels(2);
    a.setFrameRate(frameRate);
    a.addToSampleCount(frameRate);

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    ASSERT_THROW(lpf->filter(a, w), KeyFinder::Exception);
    a.reduceToMono();
    ASSERT_NO_THROW(lpf->filter(a, w));
    delete lpf;
}
TEST (LowPassFilterTest, InitialisesNullBuffer) {
    KeyFinder::AudioData a;
    a.setChannels(1);
    a.setFrameRate(frameRate);
    a.addToSampleCount(frameRate);

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    std::vector<double>* nullPtr = NULL;
    ASSERT_EQ(nullPtr, w.lpfBuffer);
    lpf->filter(a, w);
    ASSERT_NE(nullPtr, w.lpfBuffer);
}
TEST (LowPassFilterTest, WorksOnRepetitiveWaves) {
    // make two sine waves, but this time, several seconds long
    unsigned int samples = frameRate * 5;
    KeyFinder::AudioData a;
    a.setChannels(1);
    a.setFrameRate(frameRate);
    a.addToSampleCount(samples);
    for (unsigned int i = 0; i < samples; i++) {
        float sample = 0.0;
        sample += sine_wave(i, highFrequency, frameRate, magnitude); // high freq
        sample += sine_wave(i, lowFrequency, frameRate, magnitude); // low freq
        a.setSample(i, sample);
        // ensure repetition of sine waves is perfect...
        if (i >= frameRate) {
            ASSERT_NEAR(a.getSample(i), a.getSample(i - frameRate), tolerance);
        }
    }

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    lpf->filter(a, w);
    delete lpf;

    // test for lower wave only
    for (unsigned int i = 0; i < samples; i++) {
        float expected = sine_wave(i, lowFrequency, frameRate, magnitude);
        ASSERT_NEAR(expected, a.getSample(i), tolerance);
    }
}
Beispiel #6
0
KeyFinderResultWrapper keyDetectionProcess(const AsyncFileObject& object){

  KeyFinderResultWrapper result;
  result.batchRow = object.batchRow;

  // initialise stream and decode file into it.
  KeyFinder::AudioData* audio = NULL;
  AudioFileDecoder* decoder = NULL;
  try{
    decoder = AudioFileDecoder::getDecoder();
  }catch(KeyFinder::Exception& e){
    delete decoder;
    result.errorMessage = QString(e.what().c_str());
    return result;
  }

  try{
    audio = decoder->decodeFile(object.filePath);
    delete decoder;
  }catch(KeyFinder::Exception& e){
    delete audio;
    delete decoder;
    result.errorMessage = QString(e.what().c_str());
    return result;
  }

  // make audio stream monaural ahead of downsample to reduce load
  audio->reduceToMono();

  // downsample if necessary
  if(object.prefs.getDFactor() > 1){
    Downsampler* ds = Downsampler::getDownsampler(object.prefs.getDFactor(),audio->getFrameRate(),object.prefs.getLastFreq());
    try{
      audio = ds->downsample(audio,object.prefs.getDFactor());
    }catch(KeyFinder::Exception& e){
      delete audio;
      delete ds;
      result.errorMessage = QString(e.what().c_str());
      return result;
    }
    delete ds;
  }

  KeyFinder::KeyFinder* kf = LibKeyFinderSingleton::getInstance()->getKeyFinder();
  result.core = kf->findKey(*audio, object.prefs.core);

  delete audio;

  return result;
}
TEST (AudioDataTest, DownsamplerResamplesIntegralRelationship) {
  KeyFinder::AudioData a;
  a.setChannels(1);
  a.setFrameRate(100);
  a.addToSampleCount(10);
  for (unsigned int i = 0; i < 5; i++)
    a.setSample(i, 100.0);
  for (unsigned int i = 5; i < 10; i++)
    a.setSample(i, 500.0);

  a.downsample(5);

  ASSERT_EQ(20, a.getFrameRate());
  ASSERT_EQ(2, a.getSampleCount());
  ASSERT_FLOAT_EQ(100.0, a.getSample(0));
  ASSERT_FLOAT_EQ(500.0, a.getSample(1));
}
TEST (AudioDataTest, SampleMutatorBounds) {
  KeyFinder::AudioData a;
  a.addToSampleCount(5);
  ASSERT_THROW(a.getSample(-1), KeyFinder::Exception);
  ASSERT_THROW(a.getSample(5), KeyFinder::Exception);

  ASSERT_THROW(a.setSample(-1, 1.0), KeyFinder::Exception);
  ASSERT_THROW(a.setSample(5, 1.0), KeyFinder::Exception);

  ASSERT_THROW(a.setSample(0, INFINITY), KeyFinder::Exception);
  ASSERT_THROW(a.setSample(0, NAN), KeyFinder::Exception);
}
TEST (AudioDataTest, DownsamplerInsistsOnMonophonicAudio) {
  KeyFinder::AudioData a;
  a.setChannels(2);
  a.setFrameRate(100);
  a.addToSampleCount(10);

  ASSERT_THROW(a.downsample(5), KeyFinder::Exception);
  a.reduceToMono();
  ASSERT_NO_THROW(a.downsample(5));
}
TEST (AudioDataTest, MakeMono) {
  KeyFinder::AudioData a;
  a.setChannels(2);
  a.addToSampleCount(20);
  for (int i = 0; i < 10; i++) {
    a.setSample(i * 2, 100.0);
  }
  a.reduceToMono();
  ASSERT_EQ(10, a.getSampleCount());
  for (int i = 0; i < 10; i++) {
    ASSERT_FLOAT_EQ(50.0, a.getSample(i));
  }
}
Beispiel #11
0
TEST(AudioDataTest, SamplesBasic){
  KeyFinder::AudioData a;
  a.addToSampleCount(100);
  ASSERT_EQ(100, a.getSampleCount());
  // init values
  for(int i=0; i<100; i++){
    ASSERT_EQ(0.0, a.getSample(i));
  }
  a.setSample(0, 10.0);
  ASSERT_EQ(10.0, a.getSample(0));
}
TEST (LowPassFilterTest, DoesntAlterAudioMetadata) {
    KeyFinder::AudioData a;
    a.setChannels(1);
    a.setFrameRate(frameRate);
    a.addToSampleCount(frameRate);

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    lpf->filter(a, w);
    delete lpf;

    ASSERT_EQ(1, a.getChannels());
    ASSERT_EQ(frameRate, a.getFrameRate());
    ASSERT_EQ(frameRate, a.getSampleCount());
}
TEST (AudioDataTest, DownsamplerResamplesSineWave) {
  unsigned int frameRate = 10000;
  unsigned int frames = frameRate * 4;
  float freq = 20;
  float magnitude = 32768.0;
  unsigned int factor = 5;

  KeyFinder::AudioData a;
  a.setChannels(1);
  a.setFrameRate(frameRate);
  a.addToSampleCount(frames);
  for (unsigned int i = 0; i < frames; i++)
    a.setSample(i, sine_wave(i, freq, frameRate, magnitude));

  a.downsample(factor);

  unsigned int newFrameRate = frameRate / factor;
  unsigned int newFrames = frames / factor;

  ASSERT_EQ(newFrameRate, a.getFrameRate());
  ASSERT_EQ(newFrames, a.getSampleCount());
  for (unsigned int i = 0; i < newFrames; i++)
    ASSERT_NEAR(sine_wave(i, freq, newFrameRate, magnitude), a.getSample(i), magnitude * 0.05);
}
TEST (LowPassFilterTest, KillsHigherFreqs) {
    // make a high frequency sine wave, one second long
    KeyFinder::AudioData a;
    a.setChannels(1);
    a.setFrameRate(frameRate);
    a.addToSampleCount(frameRate);
    for (unsigned int i = 0; i < frameRate; i++) {
        a.setSample(i, sine_wave(i, highFrequency, frameRate, magnitude));
    }

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    lpf->filter(a, w);
    delete lpf;

    // test for near silence
    for (unsigned int i = 0; i < frameRate; i++) {
        ASSERT_NEAR(0.0, a.getSample(i), tolerance);
    }
}
TEST (LowPassFilterTest, MaintainsLowerFreqs) {
    // make a low frequency sine wave, one second long
    KeyFinder::AudioData a;
    a.setChannels(1);
    a.setFrameRate(frameRate);
    a.addToSampleCount(frameRate);
    for (unsigned int i = 0; i < frameRate; i++) {
        a.setSample(i, sine_wave(i, lowFrequency, frameRate, magnitude));
    }

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    lpf->filter(a, w);
    delete lpf;

    // test for near perfect reproduction
    for (unsigned int i = 0; i < frameRate; i++) {
        float expected = sine_wave(i, lowFrequency, frameRate, magnitude);
        ASSERT_NEAR(expected, a.getSample(i), tolerance);
    }
}
TEST (LowPassFilterTest, DoesBothAtOnce) {
    // make two sine waves, one second long
    KeyFinder::AudioData a;
    a.setChannels(1);
    a.setFrameRate(frameRate);
    a.addToSampleCount(frameRate);
    for (unsigned int i = 0; i < frameRate; i++) {
        float sample = 0.0;
        sample += sine_wave(i, highFrequency, frameRate, magnitude); // high freq
        sample += sine_wave(i, lowFrequency, frameRate, magnitude); // low freq
        a.setSample(i, sample);
    }

    KeyFinder::LowPassFilter* lpf = new KeyFinder::LowPassFilter(filterOrder, frameRate, cornerFrequency, filterFFT);
    KeyFinder::Workspace w;
    lpf->filter(a, w);
    delete lpf;

    // test for lower wave only
    for (unsigned int i = 0; i < frameRate; i++) {
        float expected = sine_wave(i, lowFrequency, frameRate, magnitude);
        ASSERT_NEAR(expected, a.getSample(i), tolerance);
    }
}
TEST (AudioDataTest, DiscardFromFront) {
  KeyFinder::AudioData a;

  a.setChannels(1);
  a.setFrameRate(1);

  ASSERT_THROW(a.discardFramesFromFront(1), KeyFinder::Exception);
  a.addToFrameCount(10);
  ASSERT_THROW(a.discardFramesFromFront(11), KeyFinder::Exception);
  ASSERT_NO_THROW(a.discardFramesFromFront(0));
  a.setSampleByFrame(5, 0, 10.0);
  ASSERT_NO_THROW(a.discardFramesFromFront(5));
  ASSERT_EQ(5, a.getFrameCount());
  ASSERT_FLOAT_EQ(10.0, a.getSampleByFrame(0, 0));
}
Beispiel #18
0
KeyFinder::AudioData* LibAvDecoder::decodeFile(const QString& filePath, const int maxDuration){

  QMutexLocker codecMutexLocker(&codecMutex); // mutex the preparatory section of this method

  AVCodec *codec = NULL;
  AVFormatContext *fCtx = NULL;
  AVCodecContext *cCtx = NULL;
  AVDictionary* dict = NULL;

  // convert filepath
#ifdef Q_OS_WIN
  const wchar_t* filePathWc = reinterpret_cast<const wchar_t*>(filePath.constData());
  const char* filePathCh = utf16_to_utf8(filePathWc);
#else
  QByteArray encodedPath = QFile::encodeName(filePath);
  const char* filePathCh = encodedPath;
#endif

  // open file
  int openInputResult = avformat_open_input(&fCtx, filePathCh, NULL, NULL);
  if(openInputResult != 0){
    throw KeyFinder::Exception(GuiStrings::getInstance()->libavCouldNotOpenFile(openInputResult).toLocal8Bit().constData());
  }

  if(avformat_find_stream_info(fCtx, NULL) < 0){
    av_close_input_file(fCtx);
    throw KeyFinder::Exception(GuiStrings::getInstance()->libavCouldNotFindStreamInformation().toLocal8Bit().constData());
  }
  int audioStream = -1;
  for(int i=0; i<(signed)fCtx->nb_streams; i++){
    if(fCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
      audioStream = i;
      break;
    }
  }
  if(audioStream == -1){
    av_close_input_file(fCtx);
    throw KeyFinder::Exception(GuiStrings::getInstance()->libavCouldNotFindAudioStream().toLocal8Bit().constData());
  }

  // Determine duration
  int durationSeconds = fCtx->duration / AV_TIME_BASE;
  int durationMinutes = durationSeconds / 60;
  // First condition is a hack for bizarre overestimation of some MP3s
  if(durationMinutes < 720 && durationSeconds > maxDuration * 60){
    av_close_input_file(fCtx);
    throw KeyFinder::Exception(GuiStrings::getInstance()->durationExceedsPreference(durationMinutes, durationSeconds % 60, maxDuration).toLocal8Bit().constData());
  }

  // Determine stream codec
  cCtx = fCtx->streams[audioStream]->codec;
  codec = avcodec_find_decoder(cCtx->codec_id);
  if(codec == NULL){
    av_close_input_file(fCtx);
    throw KeyFinder::Exception(GuiStrings::getInstance()->libavUnsupportedCodec().toLocal8Bit().constData());
  }

  // Open codec
  int codecOpenResult = avcodec_open2(cCtx, codec, &dict);
  if(codecOpenResult < 0){
    av_close_input_file(fCtx);
    throw KeyFinder::Exception(GuiStrings::getInstance()->libavCouldNotOpenCodec(codec->long_name, codecOpenResult).toLocal8Bit().constData());
  }

  ReSampleContext* rsCtx = av_audio_resample_init(
        cCtx->channels, cCtx->channels,
        cCtx->sample_rate, cCtx->sample_rate,
        AV_SAMPLE_FMT_S16, cCtx->sample_fmt,
        0, 0, 0, 0);
  if(rsCtx == NULL){
    avcodec_close(cCtx);
    av_close_input_file(fCtx);
    throw KeyFinder::Exception(GuiStrings::getInstance()->libavCouldNotCreateResampleContext().toLocal8Bit().constData());
  }

  qDebug("Decoding %s (%s, %d)", filePathCh, av_get_sample_fmt_name(cCtx->sample_fmt), cCtx->sample_rate);

  codecMutexLocker.unlock();

  // Prep buffer
  KeyFinder::AudioData *audio = new KeyFinder::AudioData();
  audio->setFrameRate(cCtx->sample_rate);
  audio->setChannels(cCtx->channels);
  // Decode stream
  AVPacket avpkt;
  int badPacketCount = 0;
  int badPacketThreshold = 100;
  while(true){
    av_init_packet(&avpkt);
    if(av_read_frame(fCtx, &avpkt) < 0)
      break;
    if(avpkt.stream_index == audioStream){
      try{
        int result = decodePacket(cCtx, rsCtx, &avpkt, audio);
        if(result != 0){
          if(badPacketCount < badPacketThreshold){
            badPacketCount++;
          }else{
            avcodec_close(cCtx);
            av_close_input_file(fCtx);
            throw KeyFinder::Exception(GuiStrings::getInstance()->libavTooManyBadPackets(badPacketThreshold).toLocal8Bit().constData());
          }
        }
      }catch(KeyFinder::Exception& e){
        throw e;
      }
    }
    av_free_packet(&avpkt);
  }

  codecMutexLocker.relock();
  audio_resample_close(rsCtx);
  int codecCloseResult = avcodec_close(cCtx);
  if(codecCloseResult < 0){
    qCritical("Error closing audio codec: %s (%d)", codec->long_name, codecCloseResult);
  }
  codecMutexLocker.unlock();

  av_close_input_file(fCtx);
  return audio;
}
Beispiel #19
0
KeyFinder::AudioData* LibAvDecoder::decodeFile(const QString& filePath){

  QMutexLocker codecMutexLocker(&codecMutex); // mutex the preparatory section of this method

  AVCodec *codec = NULL;
  AVFormatContext *fCtx = NULL;
  AVCodecContext *cCtx = NULL;
  AVDictionary* dict = NULL;

  // convert filepath
#ifdef Q_OS_WIN
  const wchar_t* filePathWc = reinterpret_cast<const wchar_t*>(filePath.constData());
  const char* filePathCh = utf16_to_utf8(filePathWc);
#else
  QByteArray encodedPath = QFile::encodeName(filePath);
  const char* filePathCh = encodedPath;
#endif

  // open file
  int openInputResult = avformat_open_input(&fCtx, filePathCh, NULL, NULL);
  if(openInputResult != 0){
    std::ostringstream ss;
    ss << "Could not open audio file (" << openInputResult << ")";
    throw KeyFinder::Exception(ss.str());
  }

  if(avformat_find_stream_info(fCtx,NULL) < 0){
    throw KeyFinder::Exception("Could not find stream information");
  }
  int audioStream = -1;
  for(int i=0; i<(signed)fCtx->nb_streams; i++){
    if(fCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
      audioStream = i;
      break;
    }
  }
  if(audioStream == -1){
    throw KeyFinder::Exception("Could not find an audio stream");
  }

  // Determine stream codec
  cCtx = fCtx->streams[audioStream]->codec;
  codec = avcodec_find_decoder(cCtx->codec_id);
  if(codec == NULL){
    throw KeyFinder::Exception("Audio stream has unsupported codec");
  }

  // Open codec
  int codecOpenResult = avcodec_open2(cCtx, codec, &dict);
  if(codecOpenResult < 0){
    std::ostringstream ss;
    ss << "Could not open audio codec: " << codec->long_name << " (" << codecOpenResult << ")";
    throw KeyFinder::Exception(ss.str());
  }

  ReSampleContext* rsCtx = av_audio_resample_init(
        cCtx->channels, cCtx->channels,
        cCtx->sample_rate, cCtx->sample_rate,
        AV_SAMPLE_FMT_S16, cCtx->sample_fmt,
        0, 0, 0, 0);
  if(rsCtx == NULL){
    throw KeyFinder::Exception("Could not create ReSampleContext");
  }

  qDebug("Decoding %s (%s, %d)", filePathCh, av_get_sample_fmt_name(cCtx->sample_fmt), cCtx->sample_rate);

  codecMutexLocker.unlock();

  // Prep buffer
  KeyFinder::AudioData *audio = new KeyFinder::AudioData();
  audio->setFrameRate(cCtx->sample_rate);
  audio->setChannels(cCtx->channels);
  // Decode stream
  AVPacket avpkt;
  int badPacketCount = 0;
  while(true){
    av_init_packet(&avpkt);
    if(av_read_frame(fCtx, &avpkt) < 0)
      break;
    if(avpkt.stream_index == audioStream){
      try{
        int result = decodePacket(cCtx, rsCtx, &avpkt, audio);
        if(result != 0){
          if(badPacketCount < 100){
            badPacketCount++;
          }else{
            throw KeyFinder::Exception("100 bad packets");
          }
        }
      }catch(KeyFinder::Exception& e){
        throw e;
      }
    }
    av_free_packet(&avpkt);
  }

  codecMutexLocker.relock();
  audio_resample_close(rsCtx);
  int codecCloseResult = avcodec_close(cCtx);
  if(codecCloseResult < 0){
    qCritical("Error closing audio codec: %s (%d)", codec->long_name, codecCloseResult);
  }
  codecMutexLocker.unlock();

  av_close_input_file(fCtx);
  return audio;
}
TEST (AudioDataTest, FrameAccessBeforeChannelsInitialised) {
  KeyFinder::AudioData a;
  a.addToSampleCount(4);
  ASSERT_THROW(a.getSampleByFrame(0, 0), KeyFinder::Exception);
}
TEST (AudioDataTest, ConstructorWorks) {
  KeyFinder::AudioData a;
  ASSERT_EQ(0, a.getChannels());
  ASSERT_EQ(0, a.getFrameRate());
  ASSERT_EQ(0, a.getSampleCount());
}
TEST (AudioDataTest, SampleMutator) {
  KeyFinder::AudioData a;
  a.addToSampleCount(1);
  a.setSample(0, 10.0);
  ASSERT_FLOAT_EQ(10.0, a.getSample(0));
}
TEST (AudioDataTest, DownsamplerResamplesNonintegralRelationship) {
  KeyFinder::AudioData a;
  a.setChannels(1);
  a.setFrameRate(100);
  a.addToSampleCount(12);
  for (unsigned int i = 0; i < 5; i++)
    a.setSample(i, 100.0);
  for (unsigned int i = 5; i < 10; i++)
    a.setSample(i, 500.0);
  for (unsigned int i = 10; i < 12; i++)
    a.setSample(i, 1000.0);

  a.downsample(5);

  ASSERT_EQ(3, a.getSampleCount());
  ASSERT_FLOAT_EQ(100.0, a.getSample(0));
  ASSERT_FLOAT_EQ(500.0, a.getSample(1));
  // this doesn't make total mathematical sense but I'm taking a shortcut for performance
  ASSERT_FLOAT_EQ(1000.0, a.getSample(2));
}
TEST (AudioDataTest, FrameRate) {
  KeyFinder::AudioData a;
  a.setFrameRate(44100);
  ASSERT_EQ(44100, a.getFrameRate());
  ASSERT_THROW(a.setFrameRate(0), KeyFinder::Exception);
}
TEST (AudioDataTest, Iterators) {
  KeyFinder::AudioData a;
  a.setChannels(1);
  a.setFrameRate(1);
  a.addToSampleCount(10);

  a.setSample(0, 10.0);
  a.setSample(1, 20.0);
  a.setSample(3, 50.0);

  a.resetIterators(); // this is required before each use

  ASSERT_FLOAT_EQ(10.0, a.getSampleAtReadIterator());
  a.setSampleAtWriteIterator(15.0);
  ASSERT_FLOAT_EQ(15.0, a.getSampleAtReadIterator());

  a.advanceReadIterator();
  a.advanceWriteIterator();
  ASSERT_FLOAT_EQ(20.0, a.getSampleAtReadIterator());
  a.setSampleAtWriteIterator(25.0);
  ASSERT_FLOAT_EQ(25.0, a.getSampleAtReadIterator());

  a.advanceReadIterator(2);
  a.advanceWriteIterator(2);
  ASSERT_FLOAT_EQ(50.0, a.getSampleAtReadIterator());
  a.setSampleAtWriteIterator(55.0);
  ASSERT_FLOAT_EQ(55.0, a.getSampleAtReadIterator());

  a.resetIterators();
  ASSERT_FLOAT_EQ(15.0, a.getSampleAtReadIterator());
  a.setSampleAtWriteIterator(150.0);
  ASSERT_FLOAT_EQ(150.0, a.getSampleAtReadIterator());

  ASSERT_TRUE(a.readIteratorWithinUpperBound());
  ASSERT_TRUE(a.writeIteratorWithinUpperBound());
  a.advanceReadIterator(10);
  a.advanceWriteIterator(10);
  ASSERT_FALSE(a.readIteratorWithinUpperBound());
  ASSERT_FALSE(a.writeIteratorWithinUpperBound());
}
TEST (AudioDataTest, PrependToInitialised) {
  KeyFinder::AudioData a;
  KeyFinder::AudioData b;

  a.setChannels(1);
  a.setFrameRate(1);
  ASSERT_THROW(a.prepend(b), KeyFinder::Exception);

  b.setChannels(2);
  b.setFrameRate(1);
  ASSERT_THROW(a.prepend(b), KeyFinder::Exception);

  b.setChannels(1);
  b.setFrameRate(2);
  ASSERT_THROW(a.prepend(b), KeyFinder::Exception);

  b.setChannels(1);
  b.setFrameRate(1);
  ASSERT_NO_THROW(a.prepend(b));

  a.addToFrameCount(1);
  b.addToFrameCount(1);
  a.setSampleByFrame(0, 0, 10.0);
  b.setSampleByFrame(0, 0, 20.0);

  a.prepend(b);
  ASSERT_EQ(2, a.getFrameCount());
  ASSERT_FLOAT_EQ(20.0, a.getSampleByFrame(0, 0));
  ASSERT_FLOAT_EQ(10.0, a.getSampleByFrame(1, 0));
}
TEST (AudioDataTest, PrependToNew) {
  KeyFinder::AudioData a;
  KeyFinder::AudioData b;

  ASSERT_NO_THROW(a.prepend(b));
  ASSERT_EQ(0, a.getChannels());
  ASSERT_EQ(0, a.getFrameRate());

  b.setChannels(1);
  b.setFrameRate(1);
  b.addToFrameCount(1);

  ASSERT_NO_THROW(a.prepend(b));
  ASSERT_EQ(1, a.getChannels());
  ASSERT_EQ(1, a.getFrameRate());
  ASSERT_EQ(1, a.getFrameCount());
}
TEST (AudioDataTest, FrameMutator) {
  KeyFinder::AudioData a;
  a.setChannels(4);
  a.addToFrameCount(5);
  ASSERT_EQ(5, a.getFrameCount());
  ASSERT_EQ(20, a.getSampleCount());

  a.setSample(6, 10.0);
  ASSERT_FLOAT_EQ(10.0, a.getSample(6));
  ASSERT_FLOAT_EQ(10.0, a.getSampleByFrame(1, 2));
  a.setSampleByFrame(1, 2, 20.0);
  ASSERT_FLOAT_EQ(20.0, a.getSample(6));
  ASSERT_FLOAT_EQ(20.0, a.getSampleByFrame(1, 2));
}
TEST (AudioDataTest, SliceFromBack) {
  KeyFinder::AudioData a;
  a.setChannels(1);
  a.setFrameRate(1);

  KeyFinder::AudioData* b = NULL;
  KeyFinder::AudioData* nullPtr = NULL;

  ASSERT_THROW(b = a.sliceSamplesFromBack(1), KeyFinder::Exception);
  ASSERT_EQ(nullPtr, b);

  a.addToFrameCount(10);
  ASSERT_THROW(b = a.sliceSamplesFromBack(11), KeyFinder::Exception);
  ASSERT_EQ(nullPtr, b);

  a.resetIterators();
  float v = 0;
  while (a.writeIteratorWithinUpperBound()) {
    a.setSampleAtWriteIterator(v);
    a.advanceWriteIterator();
    v += 1.0;
  }

  ASSERT_NO_THROW(b = a.sliceSamplesFromBack(5));
  ASSERT_NE(nullPtr, b);
  ASSERT_EQ(5, a.getSampleCount());
  ASSERT_EQ(5, b->getSampleCount());
  ASSERT_FLOAT_EQ(5.0, b->getSample(0));
  ASSERT_FLOAT_EQ(9.0, b->getSample(4));
  delete b;
}
TEST (AudioDataTest, Channels) {
  KeyFinder::AudioData a;
  a.setChannels(2);
  ASSERT_EQ(2, a.getChannels());
  ASSERT_THROW(a.setChannels(0), KeyFinder::Exception);
}