diff options
Diffstat (limited to 'src/audioextractor.cc')
-rw-r--r-- | src/audioextractor.cc | 478 |
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++; + } } |