diff --git a/demos/bruno_time.fur b/demos/bruno_time.fur index 7905bed61..351a6e1f9 100644 Binary files a/demos/bruno_time.fur and b/demos/bruno_time.fur differ diff --git a/papers/format.md b/papers/format.md index a9b7166bb..e17345119 100644 --- a/papers/format.md +++ b/papers/format.md @@ -69,7 +69,8 @@ size | description 128 | sound chip parameters (TODO) ??? | song name ??? | song author - 24 | reserved for compatibility flags + 4f | A-4 tuning + 20 | reserved 4?? | pointers to instruments 4?? | pointers to wavetables 4?? | pointers to samples diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 953f0fc74..7f62a886e 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -144,6 +144,11 @@ class DivDispatch { * the engine shall resample to the output rate. */ int rate; + + /** + * the actual chip's clock. + */ + int chipClock; /** * fill a buffer with sound data. @@ -288,4 +293,11 @@ class DivDispatch { virtual ~DivDispatch(); }; + +#define NOTE_PERIODIC(x) parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true) +#define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false) + +#define COLOR_NTSC (315000000.0/88.0) +#define COLOR_PAL (283.75*15625.0+25.0) + #endif diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 6fdc39444..7156f1d2f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1355,8 +1355,14 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.author=reader.readString(); logI("%s by %s\n",ds.name.c_str(),ds.author.c_str()); + if (ds.version>=33) { + ds.tuning=reader.readF(); + } else { + reader.readI(); + } + // reserved - for (int i=0; i<24; i++) reader.readC(); + for (int i=0; i<20; i++) reader.readC(); // pointers reader.read(insPtr,ds.insLen*4); @@ -1699,9 +1705,11 @@ SafeWriter* DivEngine::saveFur() { w->writeString(song.name,false); // song author w->writeString(song.author,false); + + w->writeF(song.tuning); // reserved - for (int i=0; i<24; i++) { + for (int i=0; i<20; i++) { w->writeC(0); } @@ -3886,6 +3894,13 @@ void DivEngine::playSub(bool preserveDrift) { } } +int DivEngine::calcBaseFreq(double clock, double divider, int note, bool period) { + double base=(period?(song.tuning*0.0625):song.tuning)*pow(2.0,(float)(note+3)/12.0); + return period? + round((clock/base)/divider): + base*(divider/clock); +} + int DivEngine::calcFreq(int base, int pitch, bool period) { return period? int(base*pow(2,-(double)pitch/(12.0*128.0))/(98.0+globalPitch*6.0)*98.0): @@ -4014,7 +4029,7 @@ void DivEngine::previewSample(int sample, int note) { blip_clear(samp_bb); double rate=song.sample[sample]->rate; if (note>=0) { - rate=(440.0*pow(2.0,(double)(note+3)/12.0)); + rate=(song.tuning*pow(2.0,(double)(note+3)/12.0)); if (rate<=0) rate=song.sample[sample]->rate; } blip_set_rates(samp_bb,rate,got.rate); @@ -4045,7 +4060,7 @@ void DivEngine::previewWave(int wave, int note) { return; } blip_clear(samp_bb); - blip_set_rates(samp_bb,song.wave[wave]->len*(27.5*pow(2.0,(double)(note+3)/12.0)),got.rate); + blip_set_rates(samp_bb,song.wave[wave]->len*((song.tuning*0.0625)*pow(2.0,(double)(note+3)/12.0)),got.rate); samp_prevSample=0; sPreview.pos=0; sPreview.sample=-1; diff --git a/src/engine/engine.h b/src/engine/engine.h index 3cdef106d..a0ff5678c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -11,8 +11,8 @@ #include #include -#define DIV_VERSION "0.5pre3" -#define DIV_ENGINE_VERSION 32 +#define DIV_VERSION "0.5pre4" +#define DIV_ENGINE_VERSION 33 enum DivStatusView { DIV_STATUS_NOTHING=0, @@ -260,6 +260,9 @@ class DivEngine { void setConf(String key, double value); void setConf(String key, String value); + // calculate base frequency/period + int calcBaseFreq(double clock, double divider, int note, bool period); + // calculate frequency/period int calcFreq(int base, int pitch, bool period=false); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 80a06483a..6ed9f6c84 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -2,8 +2,8 @@ #include "../engine.h" #include -#define FREQ_BASE 6843.0f #define AMIGA_DIVIDER 8 +#define CHIP_DIVIDER 16 void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; hgetIns(chan[c.chan].ins); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } chan[c.chan].sample=ins->amiga.initSample; if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { @@ -151,7 +151,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { chan[c.chan].keyOn=true; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=round(FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -174,7 +174,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0)))/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -243,10 +243,11 @@ void DivPlatformAmiga::notifyInsDeletion(void* ins) { void DivPlatformAmiga::setPAL(bool pal) { if (pal) { - rate=3546895/AMIGA_DIVIDER; + chipClock=COLOR_PAL*4.0/5.0; } else { - rate=3579545/AMIGA_DIVIDER; + chipClock=COLOR_NTSC; } + rate=chipClock/AMIGA_DIVIDER; } int DivPlatformAmiga::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 43e3090a6..2823f32fe 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -330,7 +330,7 @@ void DivPlatformArcade::tick() { if (chan[i].freqChanged) { chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64; if (chan[i].furnacePCM) { - chan[i].pcm.freq=MIN(255,((440.0*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250); + chan[i].pcm.freq=MIN(255,((parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250); if (dumpWrites && i>=8) { addWrite(0x10007+((i-8)<<3),chan[i].pcm.freq); } diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 4bc3328ff..0a422f144 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -7,7 +7,7 @@ #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } -#define PSG_FREQ_BASE 6848.0f +#define CHIP_DIVIDER 8 void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) { if (ayBufLengetIns(chan[c.chan].ins); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -193,7 +193,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -216,7 +216,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; break; } @@ -357,10 +357,11 @@ void DivPlatformAY8910::notifyInsDeletion(void* ins) { void DivPlatformAY8910::setPAL(bool pal) { if (pal) { - rate=221681; + chipClock=COLOR_PAL*2.0/5.0; } else { - rate=223722; + chipClock=COLOR_NTSC/2.0; } + rate=chipClock/8; } int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 5641c7a5d..bdae663c0 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -7,7 +7,7 @@ #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } -#define PSG_FREQ_BASE 6848.0f +#define CHIP_DIVIDER 8 void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) { if (ayBufLengetIns(chan[c.chan].ins); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -220,7 +220,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -243,7 +243,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; break; } @@ -392,10 +392,11 @@ void DivPlatformAY8930::notifyInsDeletion(void* ins) { void DivPlatformAY8930::setPAL(bool pal) { if (pal) { - rate=221681; + chipClock=COLOR_PAL*2.0/5.0; } else { - rate=223722; + chipClock=COLOR_NTSC/2.0; } + rate=chipClock/8; } int DivPlatformAY8930::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index b5760a3a5..b86ed32b5 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -2,10 +2,10 @@ #include "../engine.h" #include -#define FREQ_BASE 277.0f - #define rWrite(a,v) if (!skipRegisterWrites) {sid.write(a,v); if (dumpWrites) {addWrite(a,v);} } +#define CHIP_FREQBASE 524288 + void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; igetIns(chan[c.chan].ins); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(FREQ_BASE*pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -170,7 +170,7 @@ int DivPlatformC64::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=round(FREQ_BASE*pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_FREQUENCY(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -207,7 +207,7 @@ int DivPlatformC64::dispatch(DivCommand c) { rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=round(FREQ_BASE*pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)))/12.0f))); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -357,10 +357,11 @@ void DivPlatformC64::setChipModel(bool is6581) { void DivPlatformC64::setPAL(bool pal) { if (pal) { - rate=985248; + rate=COLOR_PAL*2.0/9.0; } else { - rate=1022727; + rate=COLOR_NTSC*2.0/7.0; } + chipClock=rate; } int DivPlatformC64::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 702139f30..069150b4c 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -5,7 +5,7 @@ #define rWrite(a,v) if (!skipRegisterWrites) {GB_apu_write(gb,a,v); if (dumpWrites) {addWrite(a,v);} } #define immWrite(a,v) {GB_apu_write(gb,a,v); if (dumpWrites) {addWrite(a,v);} } -#define FREQ_BASE 8015.85f +#define CHIP_DIVIDER 16 void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; ichan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -261,7 +261,7 @@ int DivPlatformGB::dispatch(DivCommand c) { } case DIV_CMD_LEGATO: if (c.chan==3) break; - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)))/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -356,7 +356,8 @@ int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, bool pal) { parent=p; dumpWrites=false; skipRegisterWrites=false; - rate=262144; + chipClock=4194304; + rate=chipClock/16; gb=new GB_gameboy_t; reset(); return 4; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index d45205778..28667ebee 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -9,6 +9,8 @@ static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; +#define CHIP_FREQBASE 9440540 + void DivPlatformGenesis::acquire(short* bufL, short* bufR, size_t start, size_t len) { static short o[2]; static int os[2]; @@ -104,15 +106,15 @@ void DivPlatformGenesis::tick() { if (chan[i].std.hadArp) { if (!chan[i].inPorta) { if (chan[i].std.arpMode) { - chan[i].baseFreq=644.0f*pow(2.0f,((float)chan[i].std.arp/12.0f)); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); } else { - chan[i].baseFreq=644.0f*pow(2.0f,((float)(chan[i].note+(signed char)chan[i].std.arp)/12.0f)); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); } } chan[i].freqChanged=true; } else { if (chan[i].std.arpMode && chan[i].std.finishedArp) { - chan[i].baseFreq=644.0f*pow(2.0f,((float)chan[i].note/12.0f)); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } @@ -307,7 +309,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } dacPos=0; dacPeriod=0; - chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; chan[c.chan].furnaceDac=true; } else { // compatible mode @@ -365,7 +367,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; } @@ -428,7 +430,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=644.0f*pow(2.0f,((float)c.value2/12.0f)); + int destFreq=NOTE_FREQUENCY(c.value2); int newFreq; bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -471,7 +473,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; break; @@ -638,10 +640,12 @@ void DivPlatformGenesis::notifyInsDeletion(void* ins) { void DivPlatformGenesis::setPAL(bool pal) { if (pal) { - rate=211125; + chipClock=COLOR_PAL*12.0/7.0; } else { - rate=213068; + chipClock=COLOR_NTSC*15.0/7.0; } + psg.setPAL(pal); + rate=chipClock/36; } int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 7f354d452..078ca38bf 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -4,6 +4,8 @@ #include "genesisshared.h" +#define CHIP_FREQBASE 9440540 + int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformGenesis::dispatch(c); @@ -54,7 +56,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - opChan[ch].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); + opChan[ch].baseFreq=NOTE_FREQUENCY(c.value); opChan[ch].freqChanged=true; } opChan[ch].keyOn=true; @@ -108,7 +110,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=644.0f*pow(2.0f,((float)c.value2/12.0f)); + int destFreq=NOTE_FREQUENCY(c.value2); int newFreq; bool return2=false; if (destFreq>opChan[ch].baseFreq) { @@ -141,7 +143,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - opChan[ch].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); + opChan[ch].baseFreq=NOTE_FREQUENCY(c.value); opChan[ch].freqChanged=true; break; } diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index e5c8c8673..a02a72b62 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -4,8 +4,7 @@ #include #include -#define FREQ_BASE 3424.0f -#define FREQ_BASE_PAL 3180.0f +#define CHIP_DIVIDER 16 #define rWrite(a,v) if (!skipRegisterWrites) {apu_wr_reg(nes,a,v); if (dumpWrites) {addWrite(a,v);} } @@ -97,16 +96,16 @@ void DivPlatformNES::tick() { } else { if (!chan[i].inPorta) { if (chan[i].std.arpMode) { - chan[i].baseFreq=round(freqBase/pow(2.0f,((float)(chan[i].std.arp)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); } else { - chan[i].baseFreq=round(freqBase/pow(2.0f,((float)(chan[i].note+chan[i].std.arp)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); } } } chan[i].freqChanged=true; } else { if (chan[i].std.arpMode && chan[i].std.finishedArp) { - chan[i].baseFreq=round(freqBase/pow(2.0f,((float)(chan[i].note)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } @@ -190,7 +189,7 @@ int DivPlatformNES::dispatch(DivCommand c) { } dacPos=0; dacPeriod=0; - chan[c.chan].baseFreq=440.0f*pow(2.0f,((float)(c.value+3)/12.0f)); + chan[c.chan].baseFreq=parent->song.tuning*pow(2.0f,((float)(c.value+3)/12.0f)); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; @@ -220,7 +219,7 @@ int DivPlatformNES::dispatch(DivCommand c) { } } else { if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(freqBase/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } } if (c.value!=DIV_NOTE_NULL) { @@ -273,7 +272,7 @@ int DivPlatformNES::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=round(freqBase/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -309,7 +308,7 @@ int DivPlatformNES::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: if (c.chan==3) break; - chan[c.chan].baseFreq=round(freqBase/pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)))/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -377,16 +376,15 @@ bool DivPlatformNES::keyOffAffectsArp(int ch) { void DivPlatformNES::setPAL(bool pal) { if (pal) { - rate=1662607; - freqBase=FREQ_BASE_PAL; + rate=COLOR_PAL*3.0/8.0; apuType=1; nes->apu.type=apuType; } else { - rate=1789773; - freqBase=FREQ_BASE; + rate=COLOR_NTSC/2.0; apuType=0; nes->apu.type=apuType; } + chipClock=rate; } void DivPlatformNES::notifyInsDeletion(void* ins) { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 3249da985..52814fee0 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -41,7 +41,6 @@ class DivPlatformNES: public DivDispatch { unsigned char apuType; struct NESAPU* nes; - float freqBase; friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 2b957928d..06a1b2fd2 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -13,7 +13,7 @@ rWrite(a,v); \ } -#define FREQ_BASE 1712.0f*2 +#define CHIP_DIVIDER 32 void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; hgetIns(chan[i].ins); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); if (chan[i].furnaceDac) { - chan[i].dacRate=1789773/chan[i].freq; + chan[i].dacRate=chipClock/chan[i].freq; if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dacRate); } if (chan[i].freq>4095) chan[i].freq=4095; @@ -186,7 +186,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPos=0; chan[c.chan].dacPeriod=0; if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -215,7 +215,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; chWrite(c.chan,0x07,chan[c.chan].noise?(0x80|noiseFreq[chan[c.chan].note%12]):0); @@ -270,7 +270,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { rWrite(0x08,c.value); break; case DIV_CMD_NOTE_PORTA: { - int destFreq=round(FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -311,7 +311,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)))/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -398,10 +398,11 @@ void DivPlatformPCE::notifyInsDeletion(void* ins) { void DivPlatformPCE::setPAL(bool pal) { if (pal) { // technically there is no PAL PC Engine but oh well... - rate=1773448/6; + chipClock=COLOR_PAL*4.0/5.0; } else { - rate=1789773/6; + chipClock=COLOR_NTSC; } + rate=chipClock/12; } int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 6cc341a1e..fb678ac81 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -6,7 +6,7 @@ #define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } -#define PSG_FREQ_BASE 122240.0f +#define CHIP_DIVIDER 2 void DivPlatformSAA1099::acquire(short* bufL, short* bufR, size_t start, size_t len) { if (saaBufLengetIns(chan[c.chan].ins); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -171,7 +171,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value*(8-chan[c.chan].freqH); @@ -202,7 +202,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; break; } @@ -308,11 +308,8 @@ void DivPlatformSAA1099::notifyInsDeletion(void* ins) { } void DivPlatformSAA1099::setPAL(bool pal) { - if (pal) { - rate=250000; - } else { - rate=250000; - } + chipClock=8000000; + rate=chipClock/32; } int DivPlatformSAA1099::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 70d3d4bf7..4a0e03d7d 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -2,10 +2,10 @@ #include "../engine.h" #include -#define FREQ_BASE 1712.0f - #define rWrite(v) {if (!skipRegisterWrites) {sn->write(v); if (dumpWrites) {addWrite(0x200,v);}}} +#define CHIP_DIVIDER 64 + void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) { sn->sound_stream_update(bufL+start,len); } @@ -25,14 +25,14 @@ void DivPlatformSMS::tick() { } if (chan[i].std.hadArp) { if (chan[i].std.arpMode) { - chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].std.arp)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); } else { - chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].note+chan[i].std.arp)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); } chan[i].freqChanged=true; } else { if (chan[i].std.arpMode && chan[i].std.finishedArp) { - chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].note)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } @@ -93,7 +93,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -130,7 +130,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=round(FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -154,7 +154,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { updateSNMode=true; break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0)))/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -223,10 +223,11 @@ void DivPlatformSMS::notifyInsDeletion(void* ins) { void DivPlatformSMS::setPAL(bool pal) { if (pal) { - rate=221681; + chipClock=COLOR_PAL*4.0/5.0; } else { - rate=223722; + chipClock=COLOR_NTSC; } + rate=chipClock/16; } int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, bool pal) { diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index ebd587cc0..fb39940fa 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -9,12 +9,12 @@ void DivPlatformTIA::acquire(short* bufL, short* bufR, size_t start, size_t len) tia.process(bufL+start,len); } -unsigned char dealWithFreq(unsigned char shape, int base, int pitch) { +unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pitch) { if (base&0x80000000 && ((base&0x7fffffff)<32)) { return base&0x1f; } int bp=base+pitch; - double mult=0.25*27.5*pow(2.0,double(768+bp)/(256.0*12.0)); + double mult=0.25*(parent->song.tuning*0.0625)*pow(2.0,double(768+bp)/(256.0*12.0)); switch (shape) { case 1: // buzzy return ceil(31400/(30.6*mult))-1; diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index 180e20351..2828b00e8 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -20,6 +20,8 @@ class DivPlatformTIA: public DivDispatch { bool isMuted[2]; TIASound tia; friend void putDispatchChan(void*,int,int); + + unsigned char dealWithFreq(unsigned char shape, int base, int pitch); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 0ffd4775e..4196a1e44 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -11,6 +11,8 @@ static unsigned char konOffs[4]={ 1, 2, 5, 6 }; +#define CHIP_DIVIDER 32 + void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; @@ -57,15 +59,15 @@ void DivPlatformYM2610::tick() { if (chan[i].std.hadArp) { if (!chan[i].inPorta) { if (chan[i].std.arpMode) { - chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].std.arp)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); } else { - chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].note+chan[i].std.arp)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); } } chan[i].freqChanged=true; } else { if (chan[i].std.arpMode && chan[i].std.finishedArp) { - chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].note)/12.0f))); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } @@ -165,15 +167,15 @@ void DivPlatformYM2610::tick() { if (chan[i].std.hadArp) { if (!chan[i].inPorta) { if (chan[i].std.arpMode) { - chan[i].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)chan[i].std.arp/12.0f)); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); } else { - chan[i].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)(chan[i].note+(signed char)chan[i].std.arp)/12.0f)); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); } } chan[i].freqChanged=true; } else { if (chan[i].std.arpMode && chan[i].std.finishedArp) { - chan[i].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)chan[i].note/12.0f)); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } @@ -278,19 +280,19 @@ void DivPlatformYM2610::tick() { } int DivPlatformYM2610::octave(int freq) { - if (freq>=FM_FREQ_BASE*128) { + if (freq>=622.0f*128) { return 128; - } else if (freq>=FM_FREQ_BASE*64) { + } else if (freq>=622.0f*64) { return 64; - } else if (freq>=FM_FREQ_BASE*32) { + } else if (freq>=622.0f*32) { return 32; - } else if (freq>=FM_FREQ_BASE*16) { + } else if (freq>=622.0f*16) { return 16; - } else if (freq>=FM_FREQ_BASE*8) { + } else if (freq>=622.0f*8) { return 8; - } else if (freq>=FM_FREQ_BASE*4) { + } else if (freq>=622.0f*4) { return 4; - } else if (freq>=FM_FREQ_BASE*2) { + } else if (freq>=622.0f*2) { return 2; } else { return 1; @@ -299,19 +301,19 @@ int DivPlatformYM2610::octave(int freq) { } int DivPlatformYM2610::toFreq(int freq) { - if (freq>=FM_FREQ_BASE*128) { + if (freq>=622.0f*128) { return 0x3800|((freq>>7)&0x7ff); - } else if (freq>=FM_FREQ_BASE*64) { + } else if (freq>=622.0f*64) { return 0x3000|((freq>>6)&0x7ff); - } else if (freq>=FM_FREQ_BASE*32) { + } else if (freq>=622.0f*32) { return 0x2800|((freq>>5)&0x7ff); - } else if (freq>=FM_FREQ_BASE*16) { + } else if (freq>=622.0f*16) { return 0x2000|((freq>>4)&0x7ff); - } else if (freq>=FM_FREQ_BASE*8) { + } else if (freq>=622.0f*8) { return 0x1800|((freq>>3)&0x7ff); - } else if (freq>=FM_FREQ_BASE*4) { + } else if (freq>=622.0f*4) { return 0x1000|((freq>>2)&0x7ff); - } else if (freq>=FM_FREQ_BASE*2) { + } else if (freq>=622.0f*2) { return 0x800|((freq>>1)&0x7ff); } else { return freq&0x7ff; @@ -351,7 +353,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (c.chan>3) { // PSG if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -397,7 +399,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -479,7 +481,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } case DIV_CMD_NOTE_PORTA: { if (c.chan>3) { // PSG - int destFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value2/12.0f))); + int destFreq=NOTE_PERIODIC(c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -502,7 +504,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } - int destFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value2/12.0f)); + int destFreq=NOTE_FREQUENCY(c.value2); int newFreq; bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -539,9 +541,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { if (c.chan>3) { // PSG - chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } else { - chan[c.chan].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); } chan[c.chan].freqChanged=true; break; @@ -794,11 +796,8 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, bool pal) { for (int i=0; i<13; i++) { isMuted[i]=false; } - if (pal) { - rate=500000; - } else { - rate=500000; - } + chipClock=8000000; + rate=chipClock/16; iface.parent=parent; iface.sampleBank=0; fm=new ymfm::ym2610(iface); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 71072edad..055dfeda3 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -46,7 +46,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - opChan[ch].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f)); + opChan[ch].baseFreq=NOTE_FREQUENCY(c.value); opChan[ch].freqChanged=true; } opChan[ch].keyOn=true; @@ -102,7 +102,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value2/12.0f)); + int destFreq=NOTE_FREQUENCY(c.value2); int newFreq; bool return2=false; if (destFreq>opChan[ch].baseFreq) { @@ -135,7 +135,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - opChan[ch].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f)); + opChan[ch].baseFreq=NOTE_FREQUENCY(c.value); opChan[ch].freqChanged=true; break; } diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 169db0d79..d7c792d07 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -26,5 +26,4 @@ static int orderedOps[4]={ #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } -#define FM_FREQ_BASE 622.0f -#define PSG_FREQ_BASE 7640.0f +#define CHIP_FREQBASE 9509775 \ No newline at end of file diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 22aed29b4..a8a2052fa 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1005,6 +1005,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } if (!playing) { + if (out!=NULL) { + memcpy(oscBuf[0],out[0],size*sizeof(float)); + memcpy(oscBuf[1],out[1],size*sizeof(float)); + oscSize=size; + } isBusy.unlock(); return; } @@ -1139,7 +1144,6 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi while (metroPos>=1) metroPos--; } - // TODO: improve memcpy(oscBuf[0],out[0],size*sizeof(float)); memcpy(oscBuf[1],out[1],size*sizeof(float)); oscSize=size; diff --git a/src/engine/song.h b/src/engine/song.h index d05975a83..e19469467 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -106,6 +106,7 @@ struct DivSong { bool pal; bool customTempo; int hz, patLen, ordersLen, insLen, waveLen, sampleLen; + float tuning; // compatibility flags bool limitSlides; // limit slide range @@ -151,6 +152,7 @@ struct DivSong { insLen(0), waveLen(0), sampleLen(0), + tuning(440.0f), limitSlides(false) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f76e270e5..04342ec2c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -569,6 +569,16 @@ void FurnaceGUI::drawSongInfo() { ImGui::SameLine(); ImGui::Text("NTSC"); } + + ImGui::Text("Tuning (A-4)"); + ImGui::SameLine(); + float tune=e->song.tuning; + ImGui::SetNextItemWidth(120.0f*dpiScale); + if (ImGui::InputFloat("##Tuning",&tune,1.0f,3.0f,"%g")) { + if (tune<220.0f) tune=220.0f; + if (tune>660.0f) tune=660.0f; + e->song.tuning=tune; + } } if (ImGui::IsWindowFocused()) curWindow=GUI_WINDOW_SONG_INFO; ImGui::End(); @@ -1980,19 +1990,20 @@ void FurnaceGUI::drawMixer() { void FurnaceGUI::drawOsc() { if (!oscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); if (ImGui::Begin("Oscilloscope",&oscOpen)) { - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); float values[512]; for (int i=0; i<512; i++) { int pos=i*e->oscSize/512; values[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; } + //ImGui::SetCursorPos(ImVec2(0,0)); ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); - ImGui::PopStyleVar(4); } + ImGui::PopStyleVar(4); ImGui::End(); }