template <> int
SpeexResamplerProcess<float>(SpeexResamplerState* aResampler,
                             uint32_t aChannel,
                             const float* aInput, uint32_t* aIn,
                             float* aOutput, uint32_t* aOut)
{
  NS_ASSERTION(*aOut <= SPEEX_RESAMPLER_PROCESS_MAX_OUTPUT, "Bad aOut");
  return speex_resampler_process_float(aResampler, aChannel, aInput, aIn, aOutput, aOut);
}
Esempio n. 2
0
void AudioInput::addMic(const void *data, unsigned int nsamp) {
	while (nsamp > 0) {
		unsigned int left = qMin(nsamp, iMicLength - iMicFilled);

		imfMic(pfMicInput + iMicFilled, data, left, iMicChannels);

		iMicFilled += left;
		nsamp -= left;

		if (nsamp > 0) {
			if (eMicFormat == SampleFloat)
				data = reinterpret_cast<const float *>(data) + left * iMicChannels;
			else
				data = reinterpret_cast<const short *>(data) + left * iMicChannels;
		}

		if (iMicFilled == iMicLength) {
			iMicFilled = 0;

			float *ptr = srsMic ? pfOutput : pfMicInput;
			if (srsMic) {
				spx_uint32_t inlen = iMicLength;
				spx_uint32_t outlen = iFrameSize;
				speex_resampler_process_float(srsMic, 0, pfMicInput, &inlen, pfOutput, &outlen);
			}
			const float mul = 32768.f;
			for (int j=0;j<iFrameSize;++j)
				psMic[j] = static_cast<short>(ptr[j] * mul);

			if (iEchoChannels > 0) {
				JitterBufferPacket jbp;
				jbp.data = reinterpret_cast<char *>(psSpeaker);
				jbp.len = iFrameSize * sizeof(short);
				jbp.timestamp = 0;
				jbp.span = 0;
				jbp.sequence = 0;
				jbp.user_data = 0;

				spx_int32_t offs;

				jitter_buffer_get(jb, &jbp, 10, &offs);
				jitter_buffer_tick(jb);
			}
			encodeAudioFrame();
		}
	}
}
Esempio n. 3
0
int
WebAudioUtils::SpeexResamplerProcess(SpeexResamplerState* aResampler,
                                     uint32_t aChannel,
                                     const int16_t* aIn, uint32_t* aInLen,
                                     float* aOut, uint32_t* aOutLen)
{
  nsAutoTArray<AudioDataValue, WEBAUDIO_BLOCK_SIZE*4> tmp;
#ifdef MOZ_SAMPLE_TYPE_S16
  tmp.SetLength(*aOutLen);
  int result = speex_resampler_process_int(aResampler, aChannel, aIn, aInLen, tmp.Elements(), aOutLen);
  ConvertAudioSamples(tmp.Elements(), aOut, *aOutLen);
  return result;
#else
  tmp.SetLength(*aInLen);
  ConvertAudioSamples(aIn, tmp.Elements(), *aInLen);
  int result = speex_resampler_process_float(aResampler, aChannel, tmp.Elements(), aInLen, aOut, aOutLen);
  return result;
#endif
}
//==============================================================================
std::vector<float> AudioAnalysisManager::resamplePlot(std::vector<float> v)
{
    std::vector<float> resampledSignal;
    resampledSignal.resize(512);
    
    float *inF;
    inF = new float[v.size()];
    float *outF;
    outF = new float[v.size()];
    
    for (int i = 0;i < v.size();i++)
    {
        inF[i] = (float) v[i];
    }
    
    SpeexResamplerState *resampler;
    
    
    int err = 0;
    
    resampler = speex_resampler_init(1, (spx_uint32_t) v.size(), 512, 0, &err);
    
    
    spx_uint32_t inLen = (spx_uint32_t) v.size();
    spx_uint32_t outLen = (spx_uint32_t) 512;
    
    err = speex_resampler_process_float(resampler, 0, inF, &inLen, outF, &outLen);
    
    
    
    for (int i = 0;i < resampledSignal.size();i++)
    {
        resampledSignal[i] = outF[i];
    }
    
    delete [] inF;
    delete [] outF;
    
    speex_resampler_destroy(resampler);
    
    return resampledSignal;
}
Esempio n. 5
0
void AudioInput::addEcho(const void *data, unsigned int nsamp) {
	while (nsamp > 0) {
		unsigned int left = qMin(nsamp, iEchoLength - iEchoFilled);

		imfEcho(pfEchoInput + iEchoFilled, data, left, iEchoChannels);

		iEchoFilled += left;
		nsamp -= left;

		if (nsamp > 0) {
			if (eEchoFormat == SampleFloat)
				data = reinterpret_cast<const float *>(data) + left * iEchoChannels;
			else
				data = reinterpret_cast<const short *>(data) + left * iEchoChannels;
		}

		if (iEchoFilled == iEchoLength) {
			iEchoFilled = 0;

			STACKVAR(short, outbuff, iFrameSize);
			float *ptr = srsEcho ? pfOutput : pfEchoInput;
			if (srsEcho) {
				spx_uint32_t inlen = iEchoLength;
				spx_uint32_t outlen = iFrameSize;
				speex_resampler_process_float(srsEcho, 0, pfEchoInput, &inlen, pfOutput, &outlen);
			}
			const float mul = 32768.f;
			for (int j=0;j<iFrameSize;++j)
				outbuff[j] = static_cast<short>(ptr[j] * mul);

			JitterBufferPacket jbp;
			jbp.data = reinterpret_cast<char *>(outbuff);
			jbp.len = iFrameSize * sizeof(short);
			jbp.timestamp = ++iJitterSeq * 10;
			jbp.span = 10;
			jbp.sequence = static_cast<unsigned short>(iJitterSeq);
			jbp.user_data = 0;

			jitter_buffer_put(jb, &jbp);
		}
	}
}
Esempio n. 6
0
ThreadSharedFloatArrayBufferList*
AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext, uint32_t aRate,
                                            uint32_t* aLength)
{
  if (mResampledChannels && mResampledChannelsRate == aRate) {
    // return cached data
    *aLength = mResampledChannelsLength;
    return mResampledChannels;
  }

  if (!mSharedChannels) {
    // Steal JS data
    mSharedChannels =
      StealJSArrayDataIntoThreadSharedFloatArrayBufferList(aJSContext, mJSChannels);
  }

  if (mSampleRate == aRate) {
    *aLength = mLength;
    return mSharedChannels;
  }

  mResampledChannels = new ThreadSharedFloatArrayBufferList(NumberOfChannels());

  double newLengthD = ceil(Duration()*aRate);
  uint32_t newLength = uint32_t(newLengthD);
  *aLength = newLength;
  double size = sizeof(float)*NumberOfChannels()*newLengthD;
  if (size != uint32_t(size)) {
    return mResampledChannels;
  }
  float* outputData = static_cast<float*>(malloc(uint32_t(size)));
  if (!outputData) {
    nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mContext->GetParentObject());
    nsIDocument* doc = nullptr;
    if (pWindow) {
      doc = pWindow->GetExtantDoc();
    }
    nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
                                    "Media",
                                    doc,
                                    nsContentUtils::eDOM_PROPERTIES,
                                    "MediaBufferSourceNodeResampleOutOfMemory");
    return mResampledChannels;
  }

  SpeexResamplerState* resampler = speex_resampler_init(NumberOfChannels(),
                                                        mSampleRate,
                                                        aRate,
                                                        SPEEX_RESAMPLER_QUALITY_DEFAULT,
                                                        nullptr);

  for (uint32_t i = 0; i < NumberOfChannels(); ++i) {
    const float* inputData = mSharedChannels->GetData(i);
    uint32_t inSamples = mLength;
    uint32_t outSamples = newLength;

    speex_resampler_process_float(resampler, i,
                                  inputData, &inSamples,
                                  outputData, &outSamples);

    mResampledChannels->SetData(i, i == 0 ? outputData : nullptr, outputData);
    outputData += newLength;
  }

  speex_resampler_destroy(resampler);

  mResampledChannelsRate = aRate;
  mResampledChannelsLength = newLength;
  return mResampledChannels;
}
Esempio n. 7
0
bool AudioOutputSample::needSamples(unsigned int snum) {
	// Forward the buffer
	for (unsigned int i=iLastConsume;i<iBufferFilled;++i)
		pfBuffer[i-iLastConsume]=pfBuffer[i];
	iBufferFilled -= iLastConsume;
	iLastConsume = snum;

	// Check if we can satisfy request with current buffer
	if (iBufferFilled >= snum)
		return true;

	// Calculate the required buffersize to hold the results
	unsigned int iInputFrames = static_cast<unsigned int>(ceilf(static_cast<float>(snum * sfHandle->samplerate()) / static_cast<float>(iOutSampleRate)));
	unsigned int iInputSamples = iInputFrames * sfHandle->channels();

	float *pOut;
	bool mix = sfHandle->channels() > 1;
	STACKVAR(float, fOut, iInputSamples);
	STACKVAR(float, fMix, iInputFrames);

	bool eof = false;
	sf_count_t read;
	do {
		resizeBuffer(iBufferFilled + snum);

		// If we need to resample or mix write to the buffer on stack
		pOut = (srs || mix) ? fOut : pfBuffer + iBufferFilled;

		// Try to read all samples needed to satifsy this request
		if ((read = sfHandle->read(pOut, iInputSamples)) < iInputSamples) {
			if (sfHandle->error() != SF_ERR_NO_ERROR || !bLoop) {
				// We reached the eof or encountered an error, stuff with zeroes
				memset(pOut, 0, sizeof(float) * (iInputSamples - read));
				read = iInputSamples;
				eof = true;
			} else {
				sfHandle->seek(SEEK_SET, 0);
			}
		}

		if (mix) { // Mix the channels (only two channels)
			read /= 2;
			// If we need to resample after this write to extra buffer
			pOut = srs ? fMix : pfBuffer + iBufferFilled;
			for (unsigned int i = 0; i < read; i++)
				pOut[i] = (fOut[i*2] + fOut[i*2 + 1]) * 0.5f;

		}

		spx_uint32_t inlen = static_cast<unsigned int>(read);
		spx_uint32_t outlen = snum;
		if (srs) // If necessary resample
			speex_resampler_process_float(srs, 0, pOut, &inlen, pfBuffer + iBufferFilled, &outlen);

		iBufferFilled += outlen;
	} while (iBufferFilled < snum);

	if (eof && !bEof) {
		emit playbackFinished();
		bEof = true;
	}

	return !eof;
}
Esempio n. 8
0
void AudioInput::addMic(const void *data, unsigned int nsamp) {
	while (nsamp > 0) {
		unsigned int left = min(nsamp, iMicLength - iMicFilled);

		imfMic(pfMicInput + iMicFilled, data, left, iMicChannels);

		iMicFilled += left;
		nsamp -= left;

		if (nsamp > 0) {
			if (eMicFormat == SampleFloat)
				data = reinterpret_cast<const float *>(data) + left * iMicChannels;
			else
				data = reinterpret_cast<const short *>(data) + left * iMicChannels;
		}

		if (iMicFilled == iMicLength) {
			iMicFilled = 0;

			float *ptr = srsMic ? pfOutput : pfMicInput;
			if (srsMic) {
				spx_uint32_t inlen = iMicLength;
				spx_uint32_t outlen = iFrameSize;
				speex_resampler_process_float(srsMic, 0, pfMicInput, &inlen, pfOutput, &outlen);
			}
			const float mul = 32768.f;
			for (int j=0;j<iFrameSize;++j)
				psMic[j] = static_cast<short>(ptr[j] * mul);


			if (iEchoChannels > 0) {
				short *echo = NULL;

				//获取回音数据
				{
					MutexLocker l(&qmEcho);

					if (qlEchoFrames.empty()) {
						iJitterSeq = 0;
						iMinBuffered = 1000;
					} else {
						iMinBuffered = min(iMinBuffered, qlEchoFrames.size());

						if ((iJitterSeq > 100) && (iMinBuffered > 1)) {
							iJitterSeq = 0;
							iMinBuffered = 1000;
							delete [] qlEchoFrames.front();
							qlEchoFrames.pop_front();
						}
						echo = qlEchoFrames.front();
						qlEchoFrames.pop_front();
					}
				}

				if (echo) {
					if (psSpeaker)
						delete [] psSpeaker;
					psSpeaker = echo;
				}
			}
			encodeAudioFrame();
		}
	}
}
Esempio n. 9
0
void AudioInput::addMic(const void *data, unsigned int nsamp) {
	while (nsamp > 0) {
		// Make sure we don't overrun the frame buffer
		const unsigned int left = qMin(nsamp, iMicLength - iMicFilled);

		// Append mix into pfMicInput frame buffer (converts 16bit pcm->float if necessary)
		imfMic(pfMicInput + iMicFilled, data, left, iMicChannels);

		iMicFilled += left;
		nsamp -= left;

		// If new samples are left offset data pointer to point at the first one for next iteration
		if (nsamp > 0) {
			if (eMicFormat == SampleFloat)
				data = reinterpret_cast<const float *>(data) + left * iMicChannels;
			else
				data = reinterpret_cast<const short *>(data) + left * iMicChannels;
		}

		if (iMicFilled == iMicLength) {
			// Frame complete
			iMicFilled = 0;

			// If needed resample frame
			float *ptr = srsMic ? pfOutput : pfMicInput;

			if (srsMic) {
				spx_uint32_t inlen = iMicLength;
				spx_uint32_t outlen = iFrameSize;
				speex_resampler_process_float(srsMic, 0, pfMicInput, &inlen, pfOutput, &outlen);
			}

			// Convert float to 16bit PCM
			const float mul = 32768.f;
			for (int j = 0; j < iFrameSize; ++j)
				psMic[j] = static_cast<short>(qBound(-32768.f, (ptr[j] * mul), 32767.f));

			// If we have echo chancellation enabled...
			if (iEchoChannels > 0) {
				short *echo = NULL;

				{
					QMutexLocker l(&qmEcho);

					if (qlEchoFrames.isEmpty()) {
						iJitterSeq = 0;
						iMinBuffered = 1000;
					} else {
						// Compensate for drift between the microphone and the echo source
						iMinBuffered = qMin(iMinBuffered, qlEchoFrames.count());

						if ((iJitterSeq > 100) && (iMinBuffered > 1)) {
							iJitterSeq = 0;
							iMinBuffered = 1000;
							delete [] qlEchoFrames.takeFirst();
						}
						echo = qlEchoFrames.takeFirst();
					}
				}

				if (echo) {
					// We have echo data for the current frame, remember that
					delete [] psSpeaker;
					psSpeaker = echo;
				}
			}

			// Encode and send frame
			encodeAudioFrame();
		}
	}
}
Esempio n. 10
0
void
MediaDecodeTask::Decode()
{
    MOZ_ASSERT(!mThreadPool == NS_IsMainThread(),
               "We should be on the main thread only if we don't have a thread pool");

    mBufferDecoder->BeginDecoding(NS_GetCurrentThread());

    // Tell the decoder reader that we are not going to play the data directly,
    // and that we should not reject files with more channels than the audio
    // bakend support.
    mDecoderReader->SetIgnoreAudioOutputFormat();

    mDecoderReader->OnDecodeThreadStart();

    VideoInfo videoInfo;
    nsAutoPtr<MetadataTags> tags;
    nsresult rv = mDecoderReader->ReadMetadata(&videoInfo, getter_Transfers(tags));
    if (NS_FAILED(rv)) {
        ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
        return;
    }

    if (!mDecoderReader->HasAudio()) {
        ReportFailureOnMainThread(WebAudioDecodeJob::NoAudio);
        return;
    }

    while (mDecoderReader->DecodeAudioData()) {
        // consume all of the buffer
        continue;
    }

    mDecoderReader->OnDecodeThreadFinish();

    MediaQueue<AudioData>& audioQueue = mDecoderReader->AudioQueue();
    uint32_t frameCount = audioQueue.FrameCount();
    uint32_t channelCount = videoInfo.mAudioChannels;
    uint32_t sampleRate = videoInfo.mAudioRate;

    if (!frameCount || !channelCount || !sampleRate) {
        ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
        return;
    }

    const uint32_t destSampleRate = mDecodeJob.mContext->SampleRate();
    AutoResampler resampler;

    uint32_t resampledFrames = frameCount;
    if (sampleRate != destSampleRate) {
        resampledFrames = static_cast<uint32_t>(
                              static_cast<uint64_t>(destSampleRate) *
                              static_cast<uint64_t>(frameCount) /
                              static_cast<uint64_t>(sampleRate)
                          );

        resampler = speex_resampler_init(channelCount,
                                         sampleRate,
                                         destSampleRate,
                                         SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
        speex_resampler_skip_zeros(resampler);
        resampledFrames += speex_resampler_get_output_latency(resampler);
    }

    // Allocate the channel buffers.  Note that if we end up resampling, we may
    // write fewer bytes than mResampledFrames to the output buffer, in which
    // case mWriteIndex will tell us how many valid samples we have.
    static const fallible_t fallible = fallible_t();
    bool memoryAllocationSuccess = true;
    if (!mDecodeJob.mChannelBuffers.SetLength(channelCount)) {
        memoryAllocationSuccess = false;
    } else {
        for (uint32_t i = 0; i < channelCount; ++i) {
            mDecodeJob.mChannelBuffers[i] = new(fallible) float[resampledFrames];
            if (!mDecodeJob.mChannelBuffers[i]) {
                memoryAllocationSuccess = false;
                break;
            }
        }
    }
    if (!memoryAllocationSuccess) {
        ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
        return;
    }

    nsAutoPtr<AudioData> audioData;
    while ((audioData = audioQueue.PopFront())) {
        audioData->EnsureAudioBuffer(); // could lead to a copy :(
        AudioDataValue* bufferData = static_cast<AudioDataValue*>
                                     (audioData->mAudioBuffer->Data());

        if (sampleRate != destSampleRate) {
            const uint32_t expectedOutSamples = static_cast<uint32_t>(
                                                    static_cast<uint64_t>(destSampleRate) *
                                                    static_cast<uint64_t>(audioData->mFrames) /
                                                    static_cast<uint64_t>(sampleRate)
                                                );
#ifdef MOZ_SAMPLE_TYPE_S16
            AudioDataValue* resampledBuffer = new(fallible) AudioDataValue[channelCount * expectedOutSamples];
#endif

            for (uint32_t i = 0; i < audioData->mChannels; ++i) {
                uint32_t inSamples = audioData->mFrames;
                uint32_t outSamples = expectedOutSamples;

#ifdef MOZ_SAMPLE_TYPE_S16
                speex_resampler_process_int(resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
                                            &resampledBuffer[i * expectedOutSamples],
                                            &outSamples);

                ConvertAudioSamples(&resampledBuffer[i * expectedOutSamples],
                                    mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
                                    outSamples);
#else
                speex_resampler_process_float(resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
                                              mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
                                              &outSamples);
#endif

                if (i == audioData->mChannels - 1) {
                    mDecodeJob.mWriteIndex += outSamples;
                    MOZ_ASSERT(mDecodeJob.mWriteIndex <= resampledFrames);
                }
            }

#ifdef MOZ_SAMPLE_TYPE_S16
            delete[] resampledBuffer;
#endif
        } else {
            for (uint32_t i = 0; i < audioData->mChannels; ++i) {
                ConvertAudioSamples(&bufferData[i * audioData->mFrames],
                                    mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
                                    audioData->mFrames);

                if (i == audioData->mChannels - 1) {
                    mDecodeJob.mWriteIndex += audioData->mFrames;
                }
            }
        }
    }

    if (sampleRate != destSampleRate) {
        int inputLatency = speex_resampler_get_input_latency(resampler);
        int outputLatency = speex_resampler_get_output_latency(resampler);
        AudioDataValue* zero = (AudioDataValue*)calloc(inputLatency, sizeof(AudioDataValue));

#ifdef MOZ_SAMPLE_TYPE_S16
        AudioDataValue* resampledBuffer = new(fallible) AudioDataValue[channelCount * outputLatency];
        if (!resampledBuffer || !zero) {
#else
        if (!zero) {
#endif
            // Out of memory!
            ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
            return;
        }

        for (uint32_t i = 0; i < channelCount; ++i) {
            uint32_t inSamples = inputLatency;
            uint32_t outSamples = outputLatency;

#ifdef MOZ_SAMPLE_TYPE_S16
            speex_resampler_process_int(resampler, i, zero, &inSamples,
                                        &resampledBuffer[i * outputLatency],
                                        &outSamples);

            ConvertAudioSamples(&resampledBuffer[i * outputLatency],
                                mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
                                outSamples);
#else
            speex_resampler_process_float(resampler, i, zero, &inSamples,
                                          mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
                                          &outSamples);
#endif

            if (i == channelCount - 1) {
                mDecodeJob.mWriteIndex += outSamples;
                MOZ_ASSERT(mDecodeJob.mWriteIndex <= resampledFrames);
            }
        }

        free(zero);

#ifdef MOZ_SAMPLE_TYPE_S16
        delete[] resampledBuffer;
#endif
    }

    mPhase = PhaseEnum::AllocateBuffer;
    RunNextPhase();
}

void
MediaDecodeTask::AllocateBuffer()
{
    MOZ_ASSERT(NS_IsMainThread());

    if (!mDecodeJob.AllocateBuffer()) {
        ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
        return;
    }

    mPhase = PhaseEnum::Done;
    CallbackTheResult();
}
Esempio n. 11
0
int main(int argc, char **argv) {

	CALLGRIND_STOP_INSTRUMENTATION;
	CALLGRIND_ZERO_STATS;

	QCoreApplication a(argc, argv);

	QFile f((argc >= 2) ? argv[1] : "wb_male.wav");
	if (! f.open(QIODevice::ReadOnly)) {
		qFatal("Failed to open file!");
	}
	f.seek(36 + 8);

	QFile o("output.raw");
	if (!(RUNNING_ON_VALGRIND))
		if (! o.open(QIODevice::WriteOnly))
			qFatal("Failed to open output!");

	QFile vf((argc >= 3) ? argv[2] : "verify.raw");
	if (! vf.open(QIODevice::ReadOnly)) {
		qWarning("Failed to open validate file!");
	}

	QDataStream out(&o);
	QDataStream verify(&vf);

	const int iFrameSize = 320;

	QVector<QByteArray> v;
	while (1) {
		QByteArray qba = f.read(iFrameSize * 2);
		if (qba.size() != iFrameSize * 2)
			break;
		v.append(qba);
	}

	int nframes = v.size();


	qWarning("Ready to process %d frames of %d samples", nframes, iFrameSize);

	QVector<short *> qvInShort;
	QVector<float *> qvIn;
	QVector<float *> qvDirect;
	QVector<float *> qvInterpolate;
	QVector<float *> qvInterpolateMC;
	QVector<short *> qvInterpolateShort;
	QVector<float *> qv8;
	QVector<float *> qv96;

	const float sfraq1 = tfreq1 / 16000.0f;
	float fOutSize1 = iFrameSize * sfraq1;
	int iOutSize1 = lroundf(fOutSize1);

	const float sfraq2 = tfreq2 / 16000.0f;
	float fOutSize2 = iFrameSize * sfraq2;
	int iOutSize2 = lroundf(fOutSize2);

	int iOutSize8 = iFrameSize / 2;
	int iOutSize96 = iFrameSize * 6;

	if (RUNNING_ON_VALGRIND)
		nframes = qMin(nframes, 10);

	QVector<float> fInput(nframes * iFrameSize);
	QVector<float> fDirect(nframes * iOutSize1);
	QVector<float> fInterpolate(nframes * iOutSize2);
	QVector<float> fInterpolateMC(nframes * iOutSize2);
	QVector<short> sInterpolate(nframes * iOutSize2);
	QVector<float> f96(nframes * iOutSize96);
	QVector<float> f8(nframes *iOutSize8);

	for (int i=0;i<nframes;i++) {
		short *s = reinterpret_cast<short *>(v[i].data());
		float *f = fInput.data() + i * iFrameSize;

		for (int j=0;j<iFrameSize;j++)
			f[j]=s[j]+20;

		qvInShort.append(s);
		qvIn.append(f);
		qvDirect.append(fDirect.data() + i * iOutSize1);
		qvInterpolate.append(fInterpolate.data() + i * iOutSize2);
		qvInterpolateMC.append(fInterpolateMC.data() + i * iOutSize2);
		qvInterpolateShort.append(sInterpolate.data() + i * iOutSize2);
		qv8.append(f8.data() + i * iOutSize8);
		qv96.append(f96.data() + i * iOutSize96);
	}

	int err;
	SpeexResamplerState *srs1 = speex_resampler_init(1, 16000, lroundf(tfreq1), qual, &err);
	SpeexResamplerState *srs2 = speex_resampler_init(1, 16000, lroundf(tfreq2), qual, &err);
	SpeexResamplerState *srs2i = speex_resampler_init(1, 16000, lroundf(tfreq2), qual, &err);
	SpeexResamplerState *srss = speex_resampler_init(3, 16000, lroundf(tfreq2), qual, &err);

	SpeexResamplerState *srsto96 = speex_resampler_init(1, 16000, 96000, 5, &err);
	SpeexResamplerState *srs8to96 = speex_resampler_init(1, 8000, 96000, qual, &err);
	SpeexResamplerState *srs96to8 = speex_resampler_init(1, 96000, 8000, qual, &err);


#ifdef Q_OS_WIN
	if (!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS))
		qWarning("Application: Failed to set priority!");
#endif

	int len;
	spx_uint32_t inlen;
	spx_uint32_t outlen;

	Timer t;
	quint64 e;

	if (! RUNNING_ON_VALGRIND) {
#ifndef Q_OS_WIN
		struct sched_param sp;
		sp.sched_priority = sched_get_priority_max(SCHED_FIFO);

		cpu_set_t cpuset;
		CPU_ZERO(&cpuset);
		CPU_SET(1, &cpuset);

		if (sched_setscheduler(getpid(), SCHED_FIFO, &sp) != 0)
			qWarning("No realtime.");
		if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0)
			qWarning("No mlock.");
		if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
			qWarning("No affinity");

		sched_yield();
#endif

		for (int i=0;i<nframes;++i) {
			inlen = iFrameSize;
			outlen = iOutSize96;
			speex_resampler_process_float(srsto96, 0, qvIn[i], &inlen, qv96[i], &outlen);
		}

		QVector<unsigned long long> qvTimes;
		QPair<unsigned long long, unsigned long long> ci;

		for (int j=0;j<loops;j++) {
			t.restart();
			for (int i=0;i<nframes;i++) {
				inlen = iFrameSize;
				outlen = iOutSize1;
				speex_resampler_process_float(srs1, 0, qvIn[i], &inlen, qvDirect[i], &outlen);
			}
			e = t.elapsed();
			qvTimes.append(e);
		}
		ci = confint(qvTimes);
		qWarning("Direct:      %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count(), qvTimes.count());

		qvTimes.clear();

		for (int j=0;j<loops;j++) {
			t.restart();
			for (int i=0;i<nframes;i++) {
				inlen = iFrameSize;
				outlen = iOutSize2;
				speex_resampler_process_float(srs2, 0, qvIn[i], &inlen, qvInterpolate[i], &outlen);
			}
			e = t.elapsed();
			qvTimes.append(e);
		}
		ci = confint(qvTimes);
		qWarning("Interpolate: %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count());

		qvTimes.clear();
		for (int j=0;j<loops;j++) {
			t.restart();
			for (int i=0;i<nframes;i++) {
				inlen = iOutSize96;
				outlen = iOutSize8;
				speex_resampler_process_float(srs96to8, 0, qv96[i], &inlen, qv8[i], &outlen);
			}
			e = t.elapsed();
			qvTimes.append(e);
		}
		ci = confint(qvTimes);
		qWarning("96 => 8:     %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count());

		qvTimes.clear();
		t.restart();
		for (int j=0;j<loops;j++) {
			t.restart();
			for (int i=0;i<nframes;i++) {
				inlen = iOutSize8;
				outlen = iOutSize96;
				speex_resampler_process_float(srs8to96, 0, qv8[i], &inlen, qv96[i], &outlen);
			}
			e = t.elapsed();
			qvTimes.append(e);
		}
		ci = confint(qvTimes);
		qWarning("8 => 96:     %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count());

		speex_resampler_reset_mem(srs1);
		speex_resampler_reset_mem(srs2);
	}

	t.restart();
	CALLGRIND_START_INSTRUMENTATION;

	for (int i=0;i<nframes;i++) {
		inlen = iFrameSize;
		outlen = iOutSize1;
		speex_resampler_process_float(srs1, 0, qvIn[i], &inlen, qvDirect[i], &outlen);

		inlen = iFrameSize;
		outlen = iOutSize2;
		speex_resampler_process_float(srs2, 0, qvIn[i], &inlen, qvInterpolate[i], &outlen);

		inlen = iFrameSize;
		outlen = iOutSize2;
		speex_resampler_process_int(srs2i, 0, qvInShort[i], &inlen, qvInterpolateShort[i], &outlen);

		inlen = iFrameSize / 4;
		outlen = iOutSize2 / 4;
		speex_resampler_process_interleaved_float(srss, qvIn[i], &inlen, qvInterpolateMC[i], &outlen);
	}
	e = t.elapsed();

#ifdef Q_OS_WIN
	if (!SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS))
		qWarning("Application: Failed to reset priority!");
#endif

	const int freq[10] = { 22050, 32000, 11025, 16000, 48000, 41000, 8000, 96000, 11025, 1600 };

	QVector<float> fMagic;

	for (int f=0;f<10;f++) {
		float fbuff[32767];
		speex_resampler_set_rate(srs1, 16000, freq[f]);
		for (int q = 0;q < 10;q++) {
			speex_resampler_set_quality(srs1, (3*q) % 7);
			inlen = iFrameSize;
			outlen = 32767;
			speex_resampler_process_float(srs1, 0, qvIn[(f*10+q) % nframes], &inlen, fbuff, &outlen);
			for (int j=0;j<outlen;j++)
				fMagic.append(fbuff[j]);
		}
		inlen = iFrameSize;
		outlen = 32767;
		speex_resampler_process_float(srs1, 0, NULL, &inlen, fbuff, &outlen);
		for (int j=0;j<outlen;j++)
			fMagic.append(fbuff[j]);
	}

	// Cropped magic test
	for (int f=0;f<10;f++) {
		float fbuff[32767];
		speex_resampler_set_rate(srs1, 16000, freq[f]);
		for (int q = 0;q < 10;q++) {
			speex_resampler_set_quality(srs1, (3*q) % 7);
			inlen = iFrameSize;
			outlen = 16;
			speex_resampler_process_float(srs1, 0, qvIn[(f*10+q) % nframes], &inlen, fbuff, &outlen);
			for (int j=0;j<outlen;j++)
				fMagic.append(fbuff[j]);
		}
		inlen = iFrameSize;
		outlen = 32767;
		speex_resampler_process_float(srs1, 0, NULL, &inlen, fbuff, &outlen);
		for (int j=0;j<outlen;j++)
			fMagic.append(fbuff[j]);
	}


	CALLGRIND_STOP_INSTRUMENTATION;

	qWarning("Used %llu usec", e);
	qWarning("%.2f times realtime", (20000ULL * nframes) / (e * 1.0));

	if (! RUNNING_ON_VALGRIND) {
		QVector<float> vDirect;
		QVector<float> vInterpolate;
		QVector<short> vsInterpolate;
		QVector<float> vMagic;
		QVector<float> vInterpolateMC;

		out << fDirect << fInterpolate << sInterpolate << fMagic << fInterpolateMC;

		if (vf.isOpen()) {
			verify >> vDirect >> vInterpolate >> vsInterpolate >> vMagic >> vInterpolateMC;

			double rmsd = veccomp(vDirect, fDirect, "SRS1");
			double rmsi = veccomp(vInterpolate, fInterpolate, "SRS2");
			veccomp(vsInterpolate, sInterpolate, "SRS2i");
			veccomp(vMagic, fMagic, "Magic");
			veccomp(vInterpolateMC, fInterpolateMC, "MC");
			qWarning("Direct: %g", rmsd);
			qWarning("Interp: %g", rmsi);
		} else {