Skip to content

Instantly share code, notes, and snippets.

@royshil
Created October 13, 2014 07:08
Show Gist options
  • Save royshil/d45d867cca0ecf7aa21a to your computer and use it in GitHub Desktop.
Save royshil/d45d867cca0ecf7aa21a to your computer and use it in GitHub Desktop.
This is a simple Qt wrapper around SoundTouch - a very nice Audio Time-Scale library.
/*
* SoundUtils.cpp
*
* Created on: Oct 9, 2014
* Author: roy_shilkrot
*/
#include <QDebug>
#include <QBuffer>
#define SOUNDTOUCH_INTEGER_SAMPLES 1
#undef SOUNDTOUCH_FLOAT_SAMPLES
#include <soundtouch/SoundTouch.h> //TODO this exposes SoundTouch to outer compilation units... better abstract it
using namespace soundtouch;
class SoundUtils {
private:
soundtouch::SoundTouch pSoundTouch;
SoundUtils(SoundUtils const&) {}
SoundUtils& operator=(SoundUtils const&);
protected:
virtual ~SoundUtils() {}
SoundUtils() {}
public:
static SoundUtils* Instance() {
static SoundUtils* m_pInstance;
if(!m_pInstance) m_pInstance = new SoundUtils;
assert(m_pInstance != NULL);
return m_pInstance;
}
/**
* setup SoundTouch to change tempo and/or sample rate
* @param inSampleRate the incoming sample rate
* @param inChannels the number of channels
* @param tempChange the tempo change in percent
* @param outSampleRate the desired output sample rate
*/
void setup(int inSampleRate, int inChannels, float tempoChange, int outSampleRate);
/**
* process the samples according to the setup (change tempo and/or samples rate)
* @param samples the samples to process S16_LE
* @param nSamples the number of samples
* @param nChannels the number of channels
* @param sampleSizeBytes the size of one sample in bytes
* @param runningBuf the output buffer
*/
int process(const short * samples,
int nSamples,
int nChannels,
int sampleSizeBytes,
QBuffer* runningBuf);
/**
* trim the silence at the beginning and end
* @param in the incoming buffer
* @param numsamples the number of PCM samples
* @param out the output buffer
*/
int trim(QBuffer* in, int numsamples, QBuffer* out);
};
// Sets the 'SoundTouch' object up according to parameters
void SoundUtils::setup(int inSampleRate, int inChannels, float tempoChange, int outSampleRate)
{
static int last_inSampleRate = -1;
static int last_inChannels = -1;
static int last_tempChange = 0.0f;
static int last_outSampleRate = -1;
if(inSampleRate == last_inSampleRate &&
inChannels == last_inChannels &&
tempoChange == last_tempChange &&
outSampleRate == last_outSampleRate) {
return; //parameters are the same - no need to 'setup' again
}
last_inSampleRate = inSampleRate;
last_inChannels = inChannels;
last_tempChange = tempoChange;
last_outSampleRate = outSampleRate;
pSoundTouch.setSampleRate(inSampleRate);
pSoundTouch.setChannels(inChannels);
pSoundTouch.setTempoChange(tempoChange);
if(inSampleRate != outSampleRate)
pSoundTouch.setRate((float)inSampleRate / (float)outSampleRate);
pSoundTouch.setSetting(SETTING_USE_QUICKSEEK, 1);
{
// use settings for speech processing
pSoundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
pSoundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
pSoundTouch.setSetting(SETTING_OVERLAP_MS, 8);
}
}
#define BUFF_SIZE 16384
// Processes the sound
int SoundUtils::process(const short * samples,
int nSamples,
int nChannels,
int sampleSizeBytes,
QBuffer* runningBuf)
{
int buffSizeSamples;
SAMPLETYPE* sampleBuffer = new SAMPLETYPE[BUFF_SIZE];
assert(nChannels > 0);
buffSizeSamples = BUFF_SIZE / nChannels;
int totSamples;
// Process samples
{
pSoundTouch.putSamples(samples, nSamples);
do
{
nSamples = pSoundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
totSamples += nSamples;
// qDebug() << "proccessed " << nSamples;
runningBuf->write(reinterpret_cast<char*>(sampleBuffer), nSamples * sampleSizeBytes);
// qDebug() << "runningBuf " << runningBuf->size();
} while (nSamples != 0);
}
pSoundTouch.flush();
do
{
nSamples = pSoundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
totSamples += nSamples;
runningBuf->write(reinterpret_cast<char*>(sampleBuffer), nSamples * sampleSizeBytes);
// qDebug() << "runningBuf " << runningBuf->size();
} while (nSamples != 0);
delete sampleBuffer;
// qDebug() << "done processing";
return totSamples;
}
int SoundUtils::trim(QBuffer* in, int numsamples, QBuffer* out)
{
int i = 0;
in->open(QIODevice::ReadOnly);
const short* pBuf = reinterpret_cast<const short*>(in->data().data());
for (i = 0; i < numsamples && abs(pBuf[i]) <= 10; ++i); // qDebug() << pBuf[i];
qDebug() << "start silence " << i;
int start_silence = i;
for (i = numsamples - 1; i >= 0 && abs(pBuf[i]) <= 10; --i); // qDebug() << pBuf[i];
qDebug() << "end silence " << i;
int end_silence = i;
out->open(QIODevice::WriteOnly);
out->write(in->data().mid(start_silence * sizeof(short),(end_silence - start_silence) * sizeof(short)));
return end_silence - start_silence;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment