From 45b202b85b7b797ce428ad5189f29eabef6187d2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 7 Dec 2021 03:52:41 -0500 Subject: [PATCH] prepare to add file out - does not compile! --- CMakeLists.txt | 1 + src/audio/file.cpp | 99 +++++++++++++++++++++++++++++++++++++++++ src/audio/file.h | 18 ++++++++ src/engine/engine.cpp | 8 ++++ src/engine/engine.h | 19 ++++++-- src/engine/playback.cpp | 38 ++++++++++++---- src/main.cpp | 25 +++++++++++ 7 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 src/audio/file.cpp create mode 100644 src/audio/file.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 12bc768c..06e9f078 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ set(ENGINE_SOURCES src/log.cpp extern/Nuked-OPN2/ym3438.c +extern/Nuked-OPM/opm.c src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/gb/apu.c src/engine/platform/sound/gb/timing.c diff --git a/src/audio/file.cpp b/src/audio/file.cpp new file mode 100644 index 00000000..1b22dcaa --- /dev/null +++ b/src/audio/file.cpp @@ -0,0 +1,99 @@ +#include +#include +#include "file.h" +#include "taAudio.h" + +void TAAudioFile::onProcess(unsigned char* buf, int nframes) { + if (audioProcCallback!=NULL) { + audioProcCallback(audioProcCallbackUser,inBufs,outBufs,desc.inChans,desc.outChans,desc.bufsize); + } + /* + float* fbuf=(float*)buf; + for (size_t j=0; j0) return false; + + memset(si,0,sizeof(SF_INFO)); + si.channels=request.outChans; + si.samplerate=request.rate; + switch (request.outFormat) { + case TA_AUDIO_FORMAT_F32: + si.format=SF_FORMAT_FLOAT; + break; + case TA_AUDIO_FORMAT_F64: + si.format=SF_FORMAT_DOUBLE; + break; + case TA_AUDIO_FORMAT_U8: + si.format=SF_FORMAT_PCM_U8; + break; + case TA_AUDIO_FORMAT_S8: + si.format=SF_FORMAT_PCM_S8; + break; + case TA_AUDIO_FORMAT_S16: + si.format=SF_FORMAT_PCM_16; + break; + case TA_AUDIO_FORMAT_S32: + si.format=SF_FORMAT_PCM_32; + break; + default: + return false; + } + si.format|=SF_FORMAT_WAV; + + file=sf_open(request.name.c_str(),SFM_WRITE,&si); + if (file==NULL) return false; + + if (desc.outChans>0) { + outBufs=new float*[desc.outChans]; + for (int i=0; i + +class TAAudioFile: public TAAudio { + float** iInBufs; + float** iOutBufs; + + SNDFILE* file; + SF_INFO si; + + public: + void onProcess(unsigned char* buf, int nframes); + + void* getContext(); + bool quit(); + bool setRun(bool run); + bool init(TAAudioDesc& request, TAAudioDesc& response); +}; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index a697ca59..ecc7d597 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -5,6 +5,7 @@ #ifdef HAVE_JACK #include "../audio/jack.h" #endif +#include "../audio/file.h" #include "platform/genesis.h" #include "platform/genesisext.h" #include "platform/sms.h" @@ -678,6 +679,10 @@ DivWavetable* DivEngine::getWave(int index) { return song.wave[index]; } +void DivEngine::setLoops(int loops) { + remainingLoops=loops; +} + void DivEngine::play() { } @@ -703,6 +708,9 @@ bool DivEngine::init() { case DIV_AUDIO_SDL: output=new TAAudioSDL; break; + case DIV_AUDIO_FILE: + output=new TAAudioFile; + break; default: logE("invalid audio engine!\n"); return false; diff --git a/src/engine/engine.h b/src/engine/engine.h index 79f0d948..858efd98 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -13,7 +13,8 @@ enum DivStatusView { enum DivAudioEngines { DIV_AUDIO_JACK=0, - DIV_AUDIO_SDL + DIV_AUDIO_SDL, + DIV_AUDIO_FILE }; struct DivChannelState { @@ -58,12 +59,15 @@ class DivEngine { int chans; bool playing; bool speedAB; - int ticks, cycles, curRow, curOrder; + bool endOfSong; + int ticks, cycles, curRow, curOrder, remainingLoops; int changeOrd, changePos, totalTicks, totalCmds, lastCmds, cmdsPerSecond; DivStatusView view; DivChannelState chan[17]; DivAudioEngines audioEngine; + String outName; + short vibTable[64]; blip_buffer_t* bb[2]; @@ -76,7 +80,8 @@ class DivEngine { void processRow(int i, bool afterDelay); void nextOrder(); void nextRow(); - void nextTick(); + // returns true if end of song. + bool nextTick(); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal); void renderSamples(); @@ -94,12 +99,18 @@ class DivEngine { // play void play(); + // set remaining loops. -1 means loop forever. + void setLoops(int loops); + // set the audio system. void setAudio(DivAudioEngines which); // set the view mode. void setView(DivStatusView which); + // open audio output file. + bool openAudioOut(String filename); + // initialize the engine. bool init(); @@ -107,10 +118,12 @@ class DivEngine { chans(0), playing(false), speedAB(false), + endOfSong(false), ticks(0), cycles(0), curRow(0), curOrder(0), + remainingLoops(-1), changeOrd(-1), changePos(0), totalTicks(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index de0bf1d7..30445a08 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1,9 +1,11 @@ #include "dispatch.h" #include "engine.h" +#include "../ta-log.h" void DivEngine::nextOrder() { curRow=0; if (++curOrder>=song.ordersLen) { + endOfSong=true; curOrder=0; } } @@ -518,9 +520,11 @@ void DivEngine::nextRow() { } if (changeOrd>=0) { curRow=changePos; + if (changeOrd<=curOrder) endOfSong=true; curOrder=changeOrd; if (curOrder>=song.ordersLen) { curOrder=0; + endOfSong=true; } changeOrd=-1; } @@ -543,7 +547,8 @@ void DivEngine::nextRow() { } } -void DivEngine::nextTick() { +bool DivEngine::nextTick() { + bool ret=false; if (song.customTempo) { cycles=dispatch->rate/song.hz; } else { @@ -648,6 +653,10 @@ void DivEngine::nextTick() { cmdsPerSecond=totalCmds-lastCmds; lastCmds=totalCmds; } + + ret=endOfSong; + endOfSong=false; + return ret; } void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) { @@ -664,15 +673,26 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi size_t runLeft=runtotal; size_t runPos=0; while (runLeft) { - if (runLeft>=cycles) { - runLeft-=cycles; - dispatch->acquire(bbIn[0],bbIn[1],runPos,cycles); - runPos+=cycles; - nextTick(); - } else { - dispatch->acquire(bbIn[0],bbIn[1],runPos,runLeft); - cycles-=runLeft; + if (!remainingLoops) { + memset(bbIn[0]+runPos,0,runLeft*sizeof(short)); + memset(bbIn[1]+runPos,0,runLeft*sizeof(short)); break; + } else { + if (runLeft>=cycles) { + runLeft-=cycles; + dispatch->acquire(bbIn[0],bbIn[1],runPos,cycles); + runPos+=cycles; + if (nextTick()) { + if (remainingLoops>0) { + remainingLoops--; + if (!remainingLoops) logI("end of song!\n"); + } + } + } else { + dispatch->acquire(bbIn[0],bbIn[1],runPos,runLeft); + cycles-=runLeft; + break; + } } } diff --git a/src/main.cpp b/src/main.cpp index 2076940a..d9fc003d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,6 @@ +#include #include +#include #include "ta-log.h" #include "engine/engine.h" @@ -98,6 +100,26 @@ bool pWarranty(String) { return false; } +bool pLoops(String val) { + try { + int count=std::stoi(val); + if (count<0) { + e.setLoops(-1); + } else { + e.setLoops(count+1); + } + } catch (std::exception& e) { + logE("loop count shall be a number.\n"); + return false; + } + return true; +} + +bool pOutput(String val) { + e.setAudio(DIV_AUDIO_FILE); + return e.openAudioOut(val); +} + bool needsValue(String param) { for (size_t i=0; i","output audio to file")); params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)")); params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (pattern by default)")); + params.push_back(TAParam("l","loops",true,pLoops,"","set number of loops (-1 means loop forever)")); + params.push_back(TAParam("V","version",false,pVersion,"","view information about Furnace.")); params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer.")); }