diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 88876412..7d34282f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -926,11 +926,11 @@ bool DivEngine::load(unsigned char* f, size_t slen) { } logD("%d name %s (%d)\n",i,sample->name.c_str(),sample->length); if (ds.version<0x0b) { - sample->rate=4; + sample->rate=22050; sample->pitch=0; sample->vol=0; } else { - sample->rate=reader.readC(); + sample->rate=fileToDivRate(reader.readC()); sample->pitch=reader.readC(); sample->vol=reader.readC(); } @@ -1127,7 +1127,7 @@ SafeWriter* DivEngine::save() { for (DivSample* i: song.sample) { w->writeI(i->length); w->writeString(i->name,true); - w->writeC(i->rate); + w->writeC(divToFileRate(i->rate)); w->writeC(i->pitch); w->writeC(i->vol); w->writeC(i->depth); @@ -1549,6 +1549,48 @@ const int sampleRates[6]={ 4000, 8000, 11025, 16000, 22050, 32000 }; +int DivEngine::fileToDivRate(int frate) { + if (frate<0) frate=0; + if (frate>5) frate=5; + return sampleRates[frate]; +} + +int DivEngine::divToFileRate(int drate) { + if (drate>26000) { + return 5; + } else if (drate>18000) { + return 4; + } else if (drate>14000) { + return 3; + } else if (drate>9500) { + return 2; + } else if (drate>6000) { + return 1; + } else { + return 0; + } + return 4; +} + +int DivEngine::getEffectiveSampleRate(int rate) { + if (rate<1) return 0; + switch (song.system) { + case DIV_SYSTEM_YMU759: + return 8000; + case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS_EXT: + return 1278409/(1280000/rate); + case DIV_SYSTEM_PCE: + return 1789773/(1789773/rate); + case DIV_SYSTEM_ARCADE: + return (31250*MIN(255,(rate*255/31250)))/255; + case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: + return 18518; + default: + break; + } + return rate; +} + void DivEngine::previewSample(int sample) { isBusy.lock(); if (sample<0 || sample>(int)song.sample.size()) { @@ -1558,7 +1600,7 @@ void DivEngine::previewSample(int sample) { return; } blip_clear(bb[2]); - blip_set_rates(bb[2],sampleRates[song.sample[sample]->rate],got.rate); + blip_set_rates(bb[2],song.sample[sample]->rate,got.rate); prevSample[2]=0; sPreview.pos=0; sPreview.sample=sample; @@ -1772,20 +1814,9 @@ bool DivEngine::addSampleFromFile(const char* path) { sample->data[index++]=averaged^(((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8)?0x8000:0); } delete[] buf; - // 4000, 8000, 11025, 16000, 22050, 32000 - if (si.samplerate>26000) { - sample->rate=5; - } else if (si.samplerate>18000) { - sample->rate=4; - } else if (si.samplerate>14000) { - sample->rate=3; - } else if (si.samplerate>9500) { - sample->rate=2; - } else if (si.samplerate>6000) { - sample->rate=1; - } else { - sample->rate=0; - } + sample->rate=si.samplerate; + if (sample->rate<4000) sample->rate=4000; + if (sample->rate>32000) sample->rate=32000; song.sample.push_back(sample); song.sampleLen=sampleCount+1; diff --git a/src/engine/engine.h b/src/engine/engine.h index a55791c3..1bcc3d44 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -184,6 +184,13 @@ class DivEngine { // get sys name const char* getSystemName(DivSystem sys); + + // convert sample rate format + int fileToDivRate(int frate); + int divToFileRate(int drate); + + // get effective sample rate + int getEffectiveSampleRate(int rate); // is FM system bool isFMSystem(DivSystem sys); diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 6ecc14c8..4cd663d1 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -9,9 +9,6 @@ static unsigned short chanOffs[8]={ static unsigned short opOffs[4]={ 0x00, 0x08, 0x10, 0x18 }; -static int pcmRates[6]={ - 65,65,90,131,180,255 -}; static bool isOutput[8][4]={ // 1 3 2 4 {false,false,false,true}, @@ -217,7 +214,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { break; } chan[c.chan].pcm.pos=0; - chan[c.chan].pcm.freq=pcmRates[parent->song.sample[chan[c.chan].pcm.sample]->rate]; + chan[c.chan].pcm.freq=MIN(255,(parent->song.sample[chan[c.chan].pcm.sample]->rate*255)/31250); break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index ca647b1f..988511b3 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -5,9 +5,6 @@ #include "genesisshared.h" -static int dacRates[6]={ - 160,160,116,80,58,40 -}; static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; @@ -179,7 +176,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } dacPos=0; dacPeriod=0; - dacRate=dacRates[parent->song.sample[dacSample]->rate]; + dacRate=1280000/parent->song.sample[dacSample]->rate; break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index f3f81171..1b24241a 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -37,10 +37,6 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) } } -static int dacRates[6]={ - 4000, 8000, 11025, 16000, 22050, 32000 -}; - static unsigned char noiseTable[256]={ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, @@ -170,7 +166,7 @@ int DivPlatformNES::dispatch(DivCommand c) { } dacPos=0; dacPeriod=0; - dacRate=dacRates[parent->song.sample[dacSample]->rate]; + dacRate=parent->song.sample[dacSample]->rate; break; } else if (c.chan==3) { // noise chan[c.chan].baseFreq=c.value; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 306de39a..1d12fb51 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -76,10 +76,6 @@ static unsigned char noiseFreq[12]={ 4,13,15,18,21,23,25,27,29,31,0,2 }; -static int dacRates[6]={ - 224,224,162,112,81,56 -}; - void DivPlatformPCE::tick() { for (int i=0; i<6; i++) { chan[i].std.next(); @@ -149,7 +145,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { } chan[c.chan].dacPos=0; chan[c.chan].dacPeriod=0; - chan[c.chan].dacRate=dacRates[parent->song.sample[chan[c.chan].dacSample]->rate]; + chan[c.chan].dacRate=1789773/parent->song.sample[chan[c.chan].dacSample]->rate; break; } chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 80db23a0..47b71341 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -3,10 +3,6 @@ #include #include -const int sampleRates[6]={ - 4000, 8000, 11025, 16000, 22050, 32000 -}; - bool DivSample::save(const char* path) { SNDFILE* f; SF_INFO si; @@ -15,7 +11,7 @@ bool DivSample::save(const char* path) { if (length<1) return false; si.channels=1; - si.samplerate=sampleRates[rate]; + si.samplerate=rate; if (depth==16) { si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV; } else { diff --git a/src/engine/sample.h b/src/engine/sample.h index 58c88140..d01b3af3 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -14,7 +14,7 @@ struct DivSample { DivSample(): name(""), length(0), - rate(0), + rate(32000), vol(0), pitch(0), depth(16), diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 8b2fd588..13aa4385 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -92,10 +92,6 @@ const char* noteNames[120]={ "C-9", "C#9", "D-9", "D#9", "E-9", "F-9", "F#9", "G-9", "G#9", "A-9", "A#9", "B-9" }; -const char* rateLabel[6]={ - "4000Hz", "8000Hz", "11025Hz", "16000Hz", "22050Hz", "32000Hz" -}; - const char* pitchLabel[11]={ "1/6", "1/5", "1/4", "1/3", "1/2", "1x", "2x", "3x", "4x", "5x", "6x" }; @@ -941,10 +937,11 @@ void FurnaceGUI::drawSampleEdit() { } else { DivSample* sample=e->song.sample[curSample]; ImGui::InputText("Name",&sample->name); - if (ImGui::SliderInt("Rate",&sample->rate,0,5,rateLabel[sample->rate])) { - if (sample->rate<0) sample->rate=0; - if (sample->rate>5) sample->rate=5; + if (ImGui::SliderInt("Rate",&sample->rate,4000,32000,"%dHz")) { + if (sample->rate<4000) sample->rate=4000; + if (sample->rate>32000) sample->rate=32000; } + ImGui::Text("effective rate: %dHz",e->getEffectiveSampleRate(sample->rate)); if (ImGui::SliderScalar("Volume",ImGuiDataType_S8,&sample->vol,&_ZERO,&_ONE_HUNDRED,fmt::sprintf("%d%%%%",sample->vol*2).c_str())) { if (sample->vol<0) sample->vol=0; if (sample->vol>100) sample->vol=100;