summaryrefslogtreecommitdiff
path: root/src/audioextractor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/audioextractor.cc')
-rw-r--r--src/audioextractor.cc478
1 files changed, 250 insertions, 228 deletions
diff --git a/src/audioextractor.cc b/src/audioextractor.cc
index c249949..eb86b2f 100644
--- a/src/audioextractor.cc
+++ b/src/audioextractor.cc
@@ -35,260 +35,282 @@
#define INSTRUMENT_VERSION "2.0"
-typedef struct {
- SNDFILE *fh;
- float *data;
+typedef struct
+{
+ SNDFILE *fh;
+ float *data;
} audiodata_t;
AudioExtractor::AudioExtractor(Selections &s, QObject *parent)
- : QObject(parent), selections(s)
+ : QObject(parent), selections(s)
{
}
void AudioExtractor::exportSelections()
{
- int samplerate = -1;
- emit setMaximumProgress(selections.ids().size() + 1/* for xml writing*/);
- int progress = 0;
- emit progressUpdate(progress++);
- qApp->processEvents();
-
- // Open all input audio files:
- audiodata_t audiodata[audiofiles.size()];
-
- int idx = 0;
- AudioFileList::iterator j = audiofiles.begin();
- while(j != audiofiles.end()) {
- QString file = j->first;
-
- SF_INFO sf_info;
- audiodata[idx].fh = sf_open(file.toStdString().c_str(), SFM_READ, &sf_info);
- if(!audiodata[idx].fh) {
- printf("Load error '%s'\n", file.toStdString().c_str());
- return;
- }
-
- if(samplerate == -1) {
- // Store the first samplerate we meet
- samplerate = sf_info.samplerate;
- }
-
- audiodata[idx].data = NULL;
-
- j++;
- idx++;
- }
-
- idx = 1;
- QVector<sel_id_t> sels = selections.ids();
-
- // Sort selections by velocity
- for(int v1 = 0; v1 < sels.size(); v1++) {
- for(int v2 = 0; v2 < sels.size(); v2++) {
-
- Selection sel1 = selections.get(sels[v1]);
- Selection sel2 = selections.get(sels[v2]);
-
- if(sel1.energy < sel2.energy) {
- sel_id_t vtmp = sels[v1];
- sels[v1] = sels[v2];
- sels[v2] = vtmp;
- }
- }
- }
-
- if(samplerate == -1) {
- // For some reason we never got a samplerate. Set it to 44k1Hz
- samplerate = 44100;
- }
-
- // Iterate and write audio files
- QVector<sel_id_t>::iterator si = sels.begin();
- while(si != sels.end()) {
- Selection sel = selections.get(*si);
- size_t offset = sel.from;
- size_t size = sel.to - sel.from;
- size_t fadein = sel.fadein;
- size_t fadeout = sel.fadeout;
-
-
- // Read all input audio file chunks:
- for(int i = 0; i < audiofiles.size(); i++) {
-
- // Clear out old buffer (if one exists)
- if(audiodata[i].data) {
- delete audiodata[i].data;
- audiodata[i].data = NULL;
- }
-
- SNDFILE *fh = audiodata[i].fh;
-
- sf_seek(fh, offset, SEEK_SET);
-
- float *data = new float[size];
- sf_read_float(fh, data, size);
-
- // Apply linear fadein
- for(size_t fi = 0; fi < fadein; fi++) {
- float val = ((float)fi / (float)fadein);
- if(fi < size) data[fi] *= val;
- }
-
- // Apply fadeout
- for(size_t fo = 0; fo < fadeout; fo++) {
- float val = 1.0 - ((float)fo / (float)fadeout);
- if( (((size - fadeout) + fo) < size) &&
- (((size - fadeout) + fo) >= 0) ) {
- data[(size - fadeout) + fo] *= val;
- }
- }
-
- audiodata[i].data = data;
- }
-
- // Create output path:
- QString path = exportpath + "/" + prefix + "/samples";
- QDir d;
- d.mkpath(path);
-
- // Write all sample chunks to single output file:
- QString file = path + "/" + QString::number(idx) + "-" + prefix + ".wav";
-
- SF_INFO sf_info;
- sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
- sf_info.samplerate = samplerate;
- sf_info.channels = audiofiles.size();
-
- SNDFILE *ofh = sf_open(file.toStdString().c_str(), SFM_WRITE, &sf_info);
- if(!ofh) {
- printf("Open for write error...\n");
- return;
- }
-
- for(size_t ob = 0; ob < size; ob++) {
- float obuf[audiofiles.size()];
- for(int ai = 0; ai < audiofiles.size(); ai++) {
- obuf[ai] = audiodata[ai].data[ob];
- }
- sf_write_float(ofh, obuf, audiofiles.size());
- }
- sf_close(ofh);
-
- idx++;
- si++;
-
- emit progressUpdate(progress++);
- qApp->processEvents();
- }
-
- // Close all input audio files:
- for(int i = 0; i < audiofiles.size(); i++) {
- if(audiodata[i].data) {
- delete audiodata[i].data;
- audiodata[i].data = NULL;
- }
-
- sf_close(audiodata[i].fh);
- }
-
- QDomDocument doc;
- QDomProcessingInstruction header =
- doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
- doc.appendChild(header);
-
- QDomElement instrument = doc.createElement("instrument");
- instrument.setAttribute("version", INSTRUMENT_VERSION);
- instrument.setAttribute("name", prefix);
- doc.appendChild(instrument);
-
- QDomElement samples = doc.createElement("samples");
- instrument.appendChild(samples);
-
- {
- // Do the adding to the xml file one sample at the time.
- int index = 0;
- QVector<sel_id_t>::iterator si = sels.begin();
- while(si != sels.end()) {
- index++;
-
- Selection i = selections.get(*si);
- i.name = prefix + "-" + QString::number(index);
-
- QDomElement sample = doc.createElement("sample");
- sample.setAttribute("name", i.name);
- sample.setAttribute("power", QString::number(i.energy));
- samples.appendChild(sample);
-
- selections.update(*si, i);
-
- int channelnum = 1; // Filechannel numbers are 1-based.
- AudioFileList::iterator j = audiofiles.begin();
- while(j != audiofiles.end()) {
-
- QString file = j->first;
- QString name = j->second;
-
- QDomElement audiofile = doc.createElement("audiofile");
- audiofile.setAttribute("file", "samples/" +
- QString::number(index) + "-" + prefix + ".wav");
- audiofile.setAttribute("channel", name);
- audiofile.setAttribute("filechannel", QString::number(channelnum));
- sample.appendChild(audiofile);
- channelnum++;
- j++;
- }
-
- si++;
- }
- }
-
- QFile xmlfile(exportpath + "/" + prefix + "/" + prefix + ".xml");
- xmlfile.open(QIODevice::WriteOnly);
- xmlfile.write(doc.toByteArray());
- xmlfile.close();
-
- emit progressUpdate(progress++);
- qApp->processEvents();
+ int samplerate = -1;
+ emit setMaximumProgress(selections.ids().size() + 1/* for xml writing*/);
+ int progress = 0;
+ emit progressUpdate(progress++);
+ qApp->processEvents();
+
+ // Open all input audio files:
+ audiodata_t audiodata[audiofiles.size()];
+
+ int idx = 0;
+ AudioFileList::iterator j = audiofiles.begin();
+ while(j != audiofiles.end())
+ {
+ QString file = j->first;
+
+ SF_INFO sf_info;
+ audiodata[idx].fh = sf_open(file.toStdString().c_str(), SFM_READ, &sf_info);
+ if(!audiodata[idx].fh)
+ {
+ printf("Load error '%s'\n", file.toStdString().c_str());
+ return;
+ }
+
+ if(samplerate == -1)
+ {
+ // Store the first samplerate we meet
+ samplerate = sf_info.samplerate;
+ }
+
+ audiodata[idx].data = NULL;
+
+ j++;
+ idx++;
+ }
+
+ idx = 1;
+ QVector<sel_id_t> sels = selections.ids();
+
+ // Sort selections by velocity
+ for(int v1 = 0; v1 < sels.size(); v1++)
+ {
+ for(int v2 = 0; v2 < sels.size(); v2++)
+ {
+ Selection sel1 = selections.get(sels[v1]);
+ Selection sel2 = selections.get(sels[v2]);
+
+ if(sel1.energy < sel2.energy)
+ {
+ sel_id_t vtmp = sels[v1];
+ sels[v1] = sels[v2];
+ sels[v2] = vtmp;
+ }
+ }
+ }
+
+ if(samplerate == -1)
+ {
+ // For some reason we never got a samplerate. Set it to 44k1Hz
+ samplerate = 44100;
+ }
+
+ // Iterate and write audio files
+ QVector<sel_id_t>::iterator si = sels.begin();
+ while(si != sels.end())
+ {
+ Selection sel = selections.get(*si);
+ size_t offset = sel.from;
+ size_t size = sel.to - sel.from;
+ size_t fadein = sel.fadein;
+ size_t fadeout = sel.fadeout;
+
+
+ // Read all input audio file chunks:
+ for(int i = 0; i < audiofiles.size(); i++)
+ {
+ // Clear out old buffer (if one exists)
+ if(audiodata[i].data)
+ {
+ delete audiodata[i].data;
+ audiodata[i].data = NULL;
+ }
+
+ SNDFILE *fh = audiodata[i].fh;
+
+ sf_seek(fh, offset, SEEK_SET);
+
+ float *data = new float[size];
+ sf_read_float(fh, data, size);
+
+ // Apply linear fadein
+ for(size_t fi = 0; fi < fadein; fi++)
+ {
+ float val = ((float)fi / (float)fadein);
+ if(fi < size) data[fi] *= val;
+ }
+
+ // Apply fadeout
+ for(size_t fo = 0; fo < fadeout; fo++)
+ {
+ float val = 1.0 - ((float)fo / (float)fadeout);
+ if( (((size - fadeout) + fo) < size) &&
+ (((size - fadeout) + fo) >= 0) )
+ {
+ data[(size - fadeout) + fo] *= val;
+ }
+ }
+
+ audiodata[i].data = data;
+ }
+
+ // Create output path:
+ QString path = exportpath + "/" + prefix + "/samples";
+ QDir d;
+ d.mkpath(path);
+
+ // Write all sample chunks to single output file:
+ QString file = path + "/" + QString::number(idx) + "-" + prefix + ".wav";
+
+ SF_INFO sf_info;
+ sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
+ sf_info.samplerate = samplerate;
+ sf_info.channels = audiofiles.size();
+
+ SNDFILE *ofh = sf_open(file.toStdString().c_str(), SFM_WRITE, &sf_info);
+ if(!ofh)
+ {
+ printf("Open for write error...\n");
+ return;
+ }
+
+ for(size_t ob = 0; ob < size; ob++)
+ {
+ float obuf[audiofiles.size()];
+ for(int ai = 0; ai < audiofiles.size(); ai++)
+ {
+ obuf[ai] = audiodata[ai].data[ob];
+ }
+ sf_write_float(ofh, obuf, audiofiles.size());
+ }
+ sf_close(ofh);
+
+ idx++;
+ si++;
+
+ emit progressUpdate(progress++);
+ qApp->processEvents();
+ }
+
+ // Close all input audio files:
+ for(int i = 0; i < audiofiles.size(); i++)
+ {
+ if(audiodata[i].data)
+ {
+ delete audiodata[i].data;
+ audiodata[i].data = NULL;
+ }
+
+ sf_close(audiodata[i].fh);
+ }
+
+ QDomDocument doc;
+ QDomProcessingInstruction header =
+ doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
+ doc.appendChild(header);
+
+ QDomElement instrument = doc.createElement("instrument");
+ instrument.setAttribute("version", INSTRUMENT_VERSION);
+ instrument.setAttribute("name", prefix);
+ doc.appendChild(instrument);
+
+ QDomElement samples = doc.createElement("samples");
+ instrument.appendChild(samples);
+
+ {
+ // Do the adding to the xml file one sample at the time.
+ int index = 0;
+ QVector<sel_id_t>::iterator si = sels.begin();
+ while(si != sels.end())
+ {
+ index++;
+
+ Selection i = selections.get(*si);
+ i.name = prefix + "-" + QString::number(index);
+
+ QDomElement sample = doc.createElement("sample");
+ sample.setAttribute("name", i.name);
+ sample.setAttribute("power", QString::number(i.energy));
+ samples.appendChild(sample);
+
+ selections.update(*si, i);
+
+ int channelnum = 1; // Filechannel numbers are 1-based.
+ AudioFileList::iterator j = audiofiles.begin();
+ while(j != audiofiles.end())
+ {
+ QString file = j->first;
+ QString name = j->second;
+
+ QDomElement audiofile = doc.createElement("audiofile");
+ audiofile.setAttribute("file", "samples/" +
+ QString::number(index) + "-" + prefix + ".wav");
+ audiofile.setAttribute("channel", name);
+ audiofile.setAttribute("filechannel", QString::number(channelnum));
+ sample.appendChild(audiofile);
+ channelnum++;
+ j++;
+ }
+
+ si++;
+ }
+ }
+
+ QFile xmlfile(exportpath + "/" + prefix + "/" + prefix + ".xml");
+ xmlfile.open(QIODevice::WriteOnly);
+ xmlfile.write(doc.toByteArray());
+ xmlfile.close();
+
+ emit progressUpdate(progress++);
+ qApp->processEvents();
}
void AudioExtractor::addFile(QString file, QString name)
{
- QPair<QString, QString> pair;
- pair.first = file;
- pair.second = name;
- audiofiles.push_back(pair);
+ QPair<QString, QString> pair;
+ pair.first = file;
+ pair.second = name;
+ audiofiles.push_back(pair);
}
void AudioExtractor::removeFile(QString file, QString name)
{
- AudioFileList::iterator j = audiofiles.begin();
- while(j != audiofiles.end()) {
- if(file == j->first/* && name == j->second*/) {
- audiofiles.erase(j);
- return;
- }
- j++;
- }
+ AudioFileList::iterator j = audiofiles.begin();
+ while(j != audiofiles.end())
+ {
+ if(file == j->first/* && name == j->second*/)
+ {
+ audiofiles.erase(j);
+ return;
+ }
+ j++;
+ }
}
void AudioExtractor::setOutputPrefix(const QString &p)
{
- prefix = p;
+ prefix = p;
}
void AudioExtractor::setExportPath(const QString &path)
{
- exportpath = path;
+ exportpath = path;
}
void AudioExtractor::changeName(QString file, QString name)
{
- AudioFileList::iterator j = audiofiles.begin();
- while(j != audiofiles.end()) {
- if(file == j->first) {
- j->second = name;
- return;
- }
- j++;
- }
+ AudioFileList::iterator j = audiofiles.begin();
+ while(j != audiofiles.end())
+ {
+ if(file == j->first)
+ {
+ j->second = name;
+ return;
+ }
+ j++;
+ }
}