Created
October 13, 2014 07:08
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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