Revert "Revert "prepare to add file out - does not compile!""
This reverts commit ada8e71884
.
This commit is contained in:
parent
ada8e71884
commit
7490ed89a1
|
@ -30,6 +30,7 @@ set(ENGINE_SOURCES
|
||||||
src/log.cpp
|
src/log.cpp
|
||||||
|
|
||||||
extern/Nuked-OPN2/ym3438.c
|
extern/Nuked-OPN2/ym3438.c
|
||||||
|
extern/Nuked-OPM/opm.c
|
||||||
src/engine/platform/sound/sn76496.cpp
|
src/engine/platform/sound/sn76496.cpp
|
||||||
src/engine/platform/sound/gb/apu.c
|
src/engine/platform/sound/gb/apu.c
|
||||||
src/engine/platform/sound/gb/timing.c
|
src/engine/platform/sound/gb/timing.c
|
||||||
|
|
99
src/audio/file.cpp
Normal file
99
src/audio/file.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include <sndfile.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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; j<desc.bufsize; j++) {
|
||||||
|
for (size_t i=0; i<desc.outChans; i++) {
|
||||||
|
fbuf[j*desc.outChans+i]=outBufs[i][j];
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void* TAAudioFile::getContext() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TAAudioFile::quit() {
|
||||||
|
if (!initialized) return false;
|
||||||
|
|
||||||
|
if (file!=NULL) {
|
||||||
|
sf_close(file);
|
||||||
|
file=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (running) {
|
||||||
|
running=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<desc.outChans; i++) {
|
||||||
|
delete[] outBufs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] outBufs;
|
||||||
|
|
||||||
|
initialized=false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TAAudioFile::setRun(bool run) {
|
||||||
|
if (!initialized) return false;
|
||||||
|
SDL_PauseAudioDevice(ai,!run);
|
||||||
|
running=run;
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TAAudioFile::init(TAAudioDesc& request, TAAudioDesc& response) {
|
||||||
|
if (initialized) return false;
|
||||||
|
|
||||||
|
TAAudioDesc desc=request;
|
||||||
|
|
||||||
|
if (desc.inChans>0) 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<desc.outChans; i++) {
|
||||||
|
outBufs[i]=new float[desc.bufsize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response=desc;
|
||||||
|
initialized=true;
|
||||||
|
return true;
|
||||||
|
}
|
18
src/audio/file.h
Normal file
18
src/audio/file.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "taAudio.h"
|
||||||
|
#include <sndfile.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
|
@ -5,6 +5,7 @@
|
||||||
#ifdef HAVE_JACK
|
#ifdef HAVE_JACK
|
||||||
#include "../audio/jack.h"
|
#include "../audio/jack.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "../audio/file.h"
|
||||||
#include "platform/genesis.h"
|
#include "platform/genesis.h"
|
||||||
#include "platform/genesisext.h"
|
#include "platform/genesisext.h"
|
||||||
#include "platform/sms.h"
|
#include "platform/sms.h"
|
||||||
|
@ -678,6 +679,10 @@ DivWavetable* DivEngine::getWave(int index) {
|
||||||
return song.wave[index];
|
return song.wave[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivEngine::setLoops(int loops) {
|
||||||
|
remainingLoops=loops;
|
||||||
|
}
|
||||||
|
|
||||||
void DivEngine::play() {
|
void DivEngine::play() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -703,6 +708,9 @@ bool DivEngine::init() {
|
||||||
case DIV_AUDIO_SDL:
|
case DIV_AUDIO_SDL:
|
||||||
output=new TAAudioSDL;
|
output=new TAAudioSDL;
|
||||||
break;
|
break;
|
||||||
|
case DIV_AUDIO_FILE:
|
||||||
|
output=new TAAudioFile;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
logE("invalid audio engine!\n");
|
logE("invalid audio engine!\n");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -13,7 +13,8 @@ enum DivStatusView {
|
||||||
|
|
||||||
enum DivAudioEngines {
|
enum DivAudioEngines {
|
||||||
DIV_AUDIO_JACK=0,
|
DIV_AUDIO_JACK=0,
|
||||||
DIV_AUDIO_SDL
|
DIV_AUDIO_SDL,
|
||||||
|
DIV_AUDIO_FILE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivChannelState {
|
struct DivChannelState {
|
||||||
|
@ -58,12 +59,15 @@ class DivEngine {
|
||||||
int chans;
|
int chans;
|
||||||
bool playing;
|
bool playing;
|
||||||
bool speedAB;
|
bool speedAB;
|
||||||
int ticks, cycles, curRow, curOrder;
|
bool endOfSong;
|
||||||
|
int ticks, cycles, curRow, curOrder, remainingLoops;
|
||||||
int changeOrd, changePos, totalTicks, totalCmds, lastCmds, cmdsPerSecond;
|
int changeOrd, changePos, totalTicks, totalCmds, lastCmds, cmdsPerSecond;
|
||||||
DivStatusView view;
|
DivStatusView view;
|
||||||
DivChannelState chan[17];
|
DivChannelState chan[17];
|
||||||
DivAudioEngines audioEngine;
|
DivAudioEngines audioEngine;
|
||||||
|
|
||||||
|
String outName;
|
||||||
|
|
||||||
short vibTable[64];
|
short vibTable[64];
|
||||||
|
|
||||||
blip_buffer_t* bb[2];
|
blip_buffer_t* bb[2];
|
||||||
|
@ -76,7 +80,8 @@ class DivEngine {
|
||||||
void processRow(int i, bool afterDelay);
|
void processRow(int i, bool afterDelay);
|
||||||
void nextOrder();
|
void nextOrder();
|
||||||
void nextRow();
|
void nextRow();
|
||||||
void nextTick();
|
// returns true if end of song.
|
||||||
|
bool nextTick();
|
||||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
void renderSamples();
|
void renderSamples();
|
||||||
|
@ -94,12 +99,18 @@ class DivEngine {
|
||||||
// play
|
// play
|
||||||
void play();
|
void play();
|
||||||
|
|
||||||
|
// set remaining loops. -1 means loop forever.
|
||||||
|
void setLoops(int loops);
|
||||||
|
|
||||||
// set the audio system.
|
// set the audio system.
|
||||||
void setAudio(DivAudioEngines which);
|
void setAudio(DivAudioEngines which);
|
||||||
|
|
||||||
// set the view mode.
|
// set the view mode.
|
||||||
void setView(DivStatusView which);
|
void setView(DivStatusView which);
|
||||||
|
|
||||||
|
// open audio output file.
|
||||||
|
bool openAudioOut(String filename);
|
||||||
|
|
||||||
// initialize the engine.
|
// initialize the engine.
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
|
@ -107,10 +118,12 @@ class DivEngine {
|
||||||
chans(0),
|
chans(0),
|
||||||
playing(false),
|
playing(false),
|
||||||
speedAB(false),
|
speedAB(false),
|
||||||
|
endOfSong(false),
|
||||||
ticks(0),
|
ticks(0),
|
||||||
cycles(0),
|
cycles(0),
|
||||||
curRow(0),
|
curRow(0),
|
||||||
curOrder(0),
|
curOrder(0),
|
||||||
|
remainingLoops(-1),
|
||||||
changeOrd(-1),
|
changeOrd(-1),
|
||||||
changePos(0),
|
changePos(0),
|
||||||
totalTicks(0),
|
totalTicks(0),
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#include "dispatch.h"
|
#include "dispatch.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
#include "../ta-log.h"
|
||||||
|
|
||||||
void DivEngine::nextOrder() {
|
void DivEngine::nextOrder() {
|
||||||
curRow=0;
|
curRow=0;
|
||||||
if (++curOrder>=song.ordersLen) {
|
if (++curOrder>=song.ordersLen) {
|
||||||
|
endOfSong=true;
|
||||||
curOrder=0;
|
curOrder=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,9 +520,11 @@ void DivEngine::nextRow() {
|
||||||
}
|
}
|
||||||
if (changeOrd>=0) {
|
if (changeOrd>=0) {
|
||||||
curRow=changePos;
|
curRow=changePos;
|
||||||
|
if (changeOrd<=curOrder) endOfSong=true;
|
||||||
curOrder=changeOrd;
|
curOrder=changeOrd;
|
||||||
if (curOrder>=song.ordersLen) {
|
if (curOrder>=song.ordersLen) {
|
||||||
curOrder=0;
|
curOrder=0;
|
||||||
|
endOfSong=true;
|
||||||
}
|
}
|
||||||
changeOrd=-1;
|
changeOrd=-1;
|
||||||
}
|
}
|
||||||
|
@ -543,7 +547,8 @@ void DivEngine::nextRow() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivEngine::nextTick() {
|
bool DivEngine::nextTick() {
|
||||||
|
bool ret=false;
|
||||||
if (song.customTempo) {
|
if (song.customTempo) {
|
||||||
cycles=dispatch->rate/song.hz;
|
cycles=dispatch->rate/song.hz;
|
||||||
} else {
|
} else {
|
||||||
|
@ -648,6 +653,10 @@ void DivEngine::nextTick() {
|
||||||
cmdsPerSecond=totalCmds-lastCmds;
|
cmdsPerSecond=totalCmds-lastCmds;
|
||||||
lastCmds=totalCmds;
|
lastCmds=totalCmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret=endOfSong;
|
||||||
|
endOfSong=false;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) {
|
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 runLeft=runtotal;
|
||||||
size_t runPos=0;
|
size_t runPos=0;
|
||||||
while (runLeft) {
|
while (runLeft) {
|
||||||
if (runLeft>=cycles) {
|
if (!remainingLoops) {
|
||||||
runLeft-=cycles;
|
memset(bbIn[0]+runPos,0,runLeft*sizeof(short));
|
||||||
dispatch->acquire(bbIn[0],bbIn[1],runPos,cycles);
|
memset(bbIn[1]+runPos,0,runLeft*sizeof(short));
|
||||||
runPos+=cycles;
|
|
||||||
nextTick();
|
|
||||||
} else {
|
|
||||||
dispatch->acquire(bbIn[0],bbIn[1],runPos,runLeft);
|
|
||||||
cycles-=runLeft;
|
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
src/main.cpp
25
src/main.cpp
|
@ -1,4 +1,6 @@
|
||||||
|
#include <exception>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
#include "ta-log.h"
|
#include "ta-log.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
|
|
||||||
|
@ -98,6 +100,26 @@ bool pWarranty(String) {
|
||||||
return false;
|
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) {
|
bool needsValue(String param) {
|
||||||
for (size_t i=0; i<params.size(); i++) {
|
for (size_t i=0; i<params.size(); i++) {
|
||||||
if (params[i].name==param) {
|
if (params[i].name==param) {
|
||||||
|
@ -111,9 +133,12 @@ void initParams() {
|
||||||
params.push_back(TAParam("h","help",false,pHelp,"","display this help"));
|
params.push_back(TAParam("h","help",false,pHelp,"","display this help"));
|
||||||
|
|
||||||
params.push_back(TAParam("a","audio",true,pAudio,"jack|sdl","set audio engine (SDL by default)"));
|
params.push_back(TAParam("a","audio",true,pAudio,"jack|sdl","set audio engine (SDL by default)"));
|
||||||
|
params.push_back(TAParam("o","output",true,pOutput,"<filename>","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("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("v","view",true,pView,"pattern|commands|nothing","set visualization (pattern by default)"));
|
||||||
|
|
||||||
|
params.push_back(TAParam("l","loops",true,pLoops,"<count>","set number of loops (-1 means loop forever)"));
|
||||||
|
|
||||||
params.push_back(TAParam("V","version",false,pVersion,"","view information about Furnace."));
|
params.push_back(TAParam("V","version",false,pVersion,"","view information about Furnace."));
|
||||||
params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer."));
|
params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer."));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue