improve audio export options - UNTESTED/UNFINISHED
This commit is contained in:
parent
e5026e43aa
commit
008fe4b6b8
8 changed files with 112 additions and 60 deletions
|
|
@ -98,6 +98,28 @@ enum DivMIDIModes {
|
|||
DIV_MIDI_MODE_LIGHT_SHOW
|
||||
};
|
||||
|
||||
struct DivAudioExportOptions {
|
||||
DivAudioExportModes mode;
|
||||
int sampleRate;
|
||||
int chans;
|
||||
int loops;
|
||||
double fadeOut;
|
||||
int orderBegin, orderEnd;
|
||||
bool channelMask[DIV_MAX_CHANS];
|
||||
DivAudioExportOptions():
|
||||
mode(DIV_EXPORT_MODE_ONE),
|
||||
sampleRate(44100),
|
||||
chans(2),
|
||||
loops(0),
|
||||
fadeOut(0.0),
|
||||
orderBegin(-1),
|
||||
orderEnd(-1) {
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
channelMask[i]=true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DivChannelState {
|
||||
std::vector<DivDelayedCommand> delayed;
|
||||
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
|
||||
|
|
@ -457,6 +479,7 @@ class DivEngine {
|
|||
DivAudioEngines audioEngine;
|
||||
DivAudioExportModes exportMode;
|
||||
double exportFadeOut;
|
||||
int exportOutputs;
|
||||
DivConfig conf;
|
||||
FixedQueue<DivNoteEvent,8192> pendingNotes;
|
||||
// bitfield
|
||||
|
|
@ -670,7 +693,7 @@ class DivEngine {
|
|||
// export to text
|
||||
SafeWriter* saveText(bool separatePatterns=true);
|
||||
// export to an audio file
|
||||
bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0);
|
||||
bool saveAudio(const char* path, DivAudioExportOptions options);
|
||||
// wait for audio export to finish
|
||||
void waitAudioFile();
|
||||
// stop audio file export
|
||||
|
|
@ -1360,6 +1383,7 @@ class DivEngine {
|
|||
audioEngine(DIV_AUDIO_NULL),
|
||||
exportMode(DIV_EXPORT_MODE_ONE),
|
||||
exportFadeOut(0.0),
|
||||
exportOutputs(2),
|
||||
cmdStreamInt(NULL),
|
||||
midiBaseChan(0),
|
||||
midiPoly(true),
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ void DivEngine::runExportThread() {
|
|||
SF_INFO si;
|
||||
SFWrapper sfWrap;
|
||||
si.samplerate=got.rate;
|
||||
si.channels=2;
|
||||
si.channels=exportOutputs;
|
||||
si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
|
||||
|
||||
sf=sfWrap.doOpen(exportPath.c_str(),SFM_WRITE,&si);
|
||||
|
|
@ -55,10 +55,12 @@ void DivEngine::runExportThread() {
|
|||
return;
|
||||
}
|
||||
|
||||
float* outBuf[3];
|
||||
outBuf[0]=new float[EXPORT_BUFSIZE];
|
||||
outBuf[1]=new float[EXPORT_BUFSIZE];
|
||||
outBuf[2]=new float[EXPORT_BUFSIZE*2];
|
||||
float* outBuf[DIV_MAX_OUTPUTS];
|
||||
float* outBufFinal;
|
||||
for (int i=0; i<exportOutputs; i++) {
|
||||
outBuf[i]=new float[EXPORT_BUFSIZE];
|
||||
}
|
||||
outBufFinal=new float[EXPORT_BUFSIZE*exportOutputs];
|
||||
|
||||
// take control of audio output
|
||||
deinitAudioBackend();
|
||||
|
|
@ -68,24 +70,27 @@ void DivEngine::runExportThread() {
|
|||
|
||||
while (playing) {
|
||||
size_t total=0;
|
||||
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
|
||||
nextBuf(NULL,outBuf,0,exportOutputs,EXPORT_BUFSIZE);
|
||||
if (totalProcessed>EXPORT_BUFSIZE) {
|
||||
logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE);
|
||||
totalProcessed=EXPORT_BUFSIZE;
|
||||
}
|
||||
int fi=0;
|
||||
for (int i=0; i<(int)totalProcessed; i++) {
|
||||
total++;
|
||||
if (isFadingOut) {
|
||||
double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples));
|
||||
outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]))*mul;
|
||||
outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]))*mul;
|
||||
for (int j=0; j<exportOutputs; j++) {
|
||||
outBufFinal[fi++]=MAX(-1.0f,MIN(1.0f,outBuf[j][i]))*mul;
|
||||
}
|
||||
if (++curFadeOutSample>=fadeOutSamples) {
|
||||
playing=false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]));
|
||||
outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]));
|
||||
for (int j=0; j<exportOutputs; j++) {
|
||||
outBufFinal[fi++]=MAX(-1.0f,MIN(1.0f,outBuf[j][i]));
|
||||
}
|
||||
if (lastLoopPos>-1 && i>=lastLoopPos && totalLoops>=exportLoopCount) {
|
||||
logD("start fading out...");
|
||||
isFadingOut=true;
|
||||
|
|
@ -94,15 +99,16 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
}
|
||||
|
||||
if (sf_writef_float(sf,outBuf[2],total)!=(int)total) {
|
||||
if (sf_writef_float(sf,outBufFinal,total)!=(int)total) {
|
||||
logE("error: failed to write entire buffer!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] outBuf[0];
|
||||
delete[] outBuf[1];
|
||||
delete[] outBuf[2];
|
||||
delete[] outBufFinal;
|
||||
for (int i=0; i<exportOutputs; i++) {
|
||||
delete[] outBuf[i];
|
||||
}
|
||||
|
||||
if (sfWrap.doClose()!=0) {
|
||||
logE("could not close audio file!");
|
||||
|
|
@ -369,18 +375,17 @@ void DivEngine::runExportThread() {
|
|||
#endif
|
||||
|
||||
bool DivEngine::shallSwitchCores() {
|
||||
// TODO: detect whether we should
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime) {
|
||||
bool DivEngine::saveAudio(const char* path, DivAudioExportOptions options) {
|
||||
#ifndef HAVE_SNDFILE
|
||||
logE("Furnace was not compiled with libsndfile. cannot export!");
|
||||
return false;
|
||||
#else
|
||||
exportPath=path;
|
||||
exportMode=mode;
|
||||
exportFadeOut=fadeOutTime;
|
||||
exportMode=options.mode;
|
||||
exportFadeOut=options.fadeOut;
|
||||
if (exportMode!=DIV_EXPORT_MODE_ONE) {
|
||||
// remove extension
|
||||
String lowerCase=exportPath;
|
||||
|
|
@ -412,7 +417,12 @@ bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode,
|
|||
}
|
||||
}
|
||||
|
||||
exportLoopCount=loops;
|
||||
got.rate=options.sampleRate;
|
||||
exportOutputs=options.chans;
|
||||
if (exportOutputs<1) exportOutputs=1;
|
||||
if (exportOutputs>DIV_MAX_OUTPUTS) exportOutputs=DIV_MAX_OUTPUTS;
|
||||
|
||||
exportLoopCount=options.loops+1;
|
||||
exportThread=new std::thread(_runExportThread,this);
|
||||
return true;
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue