mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 21:15:11 +00:00
changes to sample rate storage
as of now we store and use the actual sample rate as opposed to an index fo a fixed rate table. this allows for more flexibility in a future file format...
This commit is contained in:
parent
830e880a57
commit
7ba8607270
9 changed files with 66 additions and 49 deletions
|
@ -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);
|
logD("%d name %s (%d)\n",i,sample->name.c_str(),sample->length);
|
||||||
if (ds.version<0x0b) {
|
if (ds.version<0x0b) {
|
||||||
sample->rate=4;
|
sample->rate=22050;
|
||||||
sample->pitch=0;
|
sample->pitch=0;
|
||||||
sample->vol=0;
|
sample->vol=0;
|
||||||
} else {
|
} else {
|
||||||
sample->rate=reader.readC();
|
sample->rate=fileToDivRate(reader.readC());
|
||||||
sample->pitch=reader.readC();
|
sample->pitch=reader.readC();
|
||||||
sample->vol=reader.readC();
|
sample->vol=reader.readC();
|
||||||
}
|
}
|
||||||
|
@ -1127,7 +1127,7 @@ SafeWriter* DivEngine::save() {
|
||||||
for (DivSample* i: song.sample) {
|
for (DivSample* i: song.sample) {
|
||||||
w->writeI(i->length);
|
w->writeI(i->length);
|
||||||
w->writeString(i->name,true);
|
w->writeString(i->name,true);
|
||||||
w->writeC(i->rate);
|
w->writeC(divToFileRate(i->rate));
|
||||||
w->writeC(i->pitch);
|
w->writeC(i->pitch);
|
||||||
w->writeC(i->vol);
|
w->writeC(i->vol);
|
||||||
w->writeC(i->depth);
|
w->writeC(i->depth);
|
||||||
|
@ -1549,6 +1549,48 @@ const int sampleRates[6]={
|
||||||
4000, 8000, 11025, 16000, 22050, 32000
|
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) {
|
void DivEngine::previewSample(int sample) {
|
||||||
isBusy.lock();
|
isBusy.lock();
|
||||||
if (sample<0 || sample>(int)song.sample.size()) {
|
if (sample<0 || sample>(int)song.sample.size()) {
|
||||||
|
@ -1558,7 +1600,7 @@ void DivEngine::previewSample(int sample) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
blip_clear(bb[2]);
|
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;
|
prevSample[2]=0;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
sPreview.sample=sample;
|
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);
|
sample->data[index++]=averaged^(((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8)?0x8000:0);
|
||||||
}
|
}
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
// 4000, 8000, 11025, 16000, 22050, 32000
|
sample->rate=si.samplerate;
|
||||||
if (si.samplerate>26000) {
|
if (sample->rate<4000) sample->rate=4000;
|
||||||
sample->rate=5;
|
if (sample->rate>32000) sample->rate=32000;
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
song.sample.push_back(sample);
|
song.sample.push_back(sample);
|
||||||
song.sampleLen=sampleCount+1;
|
song.sampleLen=sampleCount+1;
|
||||||
|
|
|
@ -184,6 +184,13 @@ class DivEngine {
|
||||||
|
|
||||||
// get sys name
|
// get sys name
|
||||||
const char* getSystemName(DivSystem sys);
|
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
|
// is FM system
|
||||||
bool isFMSystem(DivSystem sys);
|
bool isFMSystem(DivSystem sys);
|
||||||
|
|
|
@ -9,9 +9,6 @@ static unsigned short chanOffs[8]={
|
||||||
static unsigned short opOffs[4]={
|
static unsigned short opOffs[4]={
|
||||||
0x00, 0x08, 0x10, 0x18
|
0x00, 0x08, 0x10, 0x18
|
||||||
};
|
};
|
||||||
static int pcmRates[6]={
|
|
||||||
65,65,90,131,180,255
|
|
||||||
};
|
|
||||||
static bool isOutput[8][4]={
|
static bool isOutput[8][4]={
|
||||||
// 1 3 2 4
|
// 1 3 2 4
|
||||||
{false,false,false,true},
|
{false,false,false,true},
|
||||||
|
@ -217,7 +214,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
chan[c.chan].pcm.pos=0;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
|
|
||||||
#include "genesisshared.h"
|
#include "genesisshared.h"
|
||||||
|
|
||||||
static int dacRates[6]={
|
|
||||||
160,160,116,80,58,40
|
|
||||||
};
|
|
||||||
static unsigned char konOffs[6]={
|
static unsigned char konOffs[6]={
|
||||||
0, 1, 2, 4, 5, 6
|
0, 1, 2, 4, 5, 6
|
||||||
};
|
};
|
||||||
|
@ -179,7 +176,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
dacPos=0;
|
dacPos=0;
|
||||||
dacPeriod=0;
|
dacPeriod=0;
|
||||||
dacRate=dacRates[parent->song.sample[dacSample]->rate];
|
dacRate=1280000/parent->song.sample[dacSample]->rate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||||
|
|
|
@ -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]={
|
static unsigned char noiseTable[256]={
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4,
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4,
|
||||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 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;
|
dacPos=0;
|
||||||
dacPeriod=0;
|
dacPeriod=0;
|
||||||
dacRate=dacRates[parent->song.sample[dacSample]->rate];
|
dacRate=parent->song.sample[dacSample]->rate;
|
||||||
break;
|
break;
|
||||||
} else if (c.chan==3) { // noise
|
} else if (c.chan==3) { // noise
|
||||||
chan[c.chan].baseFreq=c.value;
|
chan[c.chan].baseFreq=c.value;
|
||||||
|
|
|
@ -76,10 +76,6 @@ static unsigned char noiseFreq[12]={
|
||||||
4,13,15,18,21,23,25,27,29,31,0,2
|
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() {
|
void DivPlatformPCE::tick() {
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
@ -149,7 +145,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
chan[c.chan].dacPos=0;
|
chan[c.chan].dacPos=0;
|
||||||
chan[c.chan].dacPeriod=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;
|
break;
|
||||||
}
|
}
|
||||||
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
|
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sndfile.h>
|
#include <sndfile.h>
|
||||||
|
|
||||||
const int sampleRates[6]={
|
|
||||||
4000, 8000, 11025, 16000, 22050, 32000
|
|
||||||
};
|
|
||||||
|
|
||||||
bool DivSample::save(const char* path) {
|
bool DivSample::save(const char* path) {
|
||||||
SNDFILE* f;
|
SNDFILE* f;
|
||||||
SF_INFO si;
|
SF_INFO si;
|
||||||
|
@ -15,7 +11,7 @@ bool DivSample::save(const char* path) {
|
||||||
if (length<1) return false;
|
if (length<1) return false;
|
||||||
|
|
||||||
si.channels=1;
|
si.channels=1;
|
||||||
si.samplerate=sampleRates[rate];
|
si.samplerate=rate;
|
||||||
if (depth==16) {
|
if (depth==16) {
|
||||||
si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV;
|
si.format=SF_FORMAT_PCM_16|SF_FORMAT_WAV;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct DivSample {
|
||||||
DivSample():
|
DivSample():
|
||||||
name(""),
|
name(""),
|
||||||
length(0),
|
length(0),
|
||||||
rate(0),
|
rate(32000),
|
||||||
vol(0),
|
vol(0),
|
||||||
pitch(0),
|
pitch(0),
|
||||||
depth(16),
|
depth(16),
|
||||||
|
|
|
@ -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"
|
"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]={
|
const char* pitchLabel[11]={
|
||||||
"1/6", "1/5", "1/4", "1/3", "1/2", "1x", "2x", "3x", "4x", "5x", "6x"
|
"1/6", "1/5", "1/4", "1/3", "1/2", "1x", "2x", "3x", "4x", "5x", "6x"
|
||||||
};
|
};
|
||||||
|
@ -941,10 +937,11 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
} else {
|
} else {
|
||||||
DivSample* sample=e->song.sample[curSample];
|
DivSample* sample=e->song.sample[curSample];
|
||||||
ImGui::InputText("Name",&sample->name);
|
ImGui::InputText("Name",&sample->name);
|
||||||
if (ImGui::SliderInt("Rate",&sample->rate,0,5,rateLabel[sample->rate])) {
|
if (ImGui::SliderInt("Rate",&sample->rate,4000,32000,"%dHz")) {
|
||||||
if (sample->rate<0) sample->rate=0;
|
if (sample->rate<4000) sample->rate=4000;
|
||||||
if (sample->rate>5) sample->rate=5;
|
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 (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<0) sample->vol=0;
|
||||||
if (sample->vol>100) sample->vol=100;
|
if (sample->vol>100) sample->vol=100;
|
||||||
|
|
Loading…
Reference in a new issue