Merge branch 'master' of https://github.com/tildearrow/furnace into n163
# Conflicts: # CMakeLists.txt # papers/doc/7-systems/README.md # src/engine/dispatchContainer.cpp # src/gui/gui.cpp # src/gui/insEdit.cpp
This commit is contained in:
commit
2eaa6ed0ce
66 changed files with 7735 additions and 5410 deletions
|
|
@ -47,6 +47,7 @@
|
|||
#include "platform/lynx.h"
|
||||
#include "platform/bubsyswsg.h"
|
||||
#include "platform/n163.h"
|
||||
#include "platform/pet.h"
|
||||
#include "platform/dummy.h"
|
||||
#include "../ta-log.h"
|
||||
#include "song.h"
|
||||
|
|
@ -279,6 +280,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_N163:
|
||||
dispatch=new DivPlatformN163;
|
||||
break;
|
||||
case DIV_SYSTEM_PET:
|
||||
dispatch=new DivPlatformPET;
|
||||
break;
|
||||
default:
|
||||
logW("this system is not supported yet! using dummy platform.\n");
|
||||
dispatch=new DivPlatformDummy;
|
||||
|
|
|
|||
|
|
@ -584,6 +584,7 @@ void DivEngine::renderSamples() {
|
|||
void DivEngine::createNew(const int* description) {
|
||||
quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.unload();
|
||||
song=DivSong();
|
||||
if (description!=NULL) {
|
||||
|
|
@ -602,6 +603,7 @@ void DivEngine::createNew(const int* description) {
|
|||
}
|
||||
recalcChans();
|
||||
renderSamples();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
initDispatch();
|
||||
isBusy.lock();
|
||||
|
|
@ -612,9 +614,11 @@ void DivEngine::createNew(const int* description) {
|
|||
void DivEngine::changeSystem(int index, DivSystem which) {
|
||||
quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.system[index]=which;
|
||||
song.systemFlags[index]=0;
|
||||
recalcChans();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
initDispatch();
|
||||
isBusy.lock();
|
||||
|
|
@ -635,11 +639,13 @@ bool DivEngine::addSystem(DivSystem which) {
|
|||
}
|
||||
quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.system[song.systemLen]=which;
|
||||
song.systemVol[song.systemLen]=64;
|
||||
song.systemPan[song.systemLen]=0;
|
||||
song.systemFlags[song.systemLen++]=0;
|
||||
recalcChans();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
initDispatch();
|
||||
isBusy.lock();
|
||||
|
|
@ -660,12 +666,14 @@ bool DivEngine::removeSystem(int index) {
|
|||
}
|
||||
quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.system[index]=DIV_SYSTEM_NULL;
|
||||
song.systemLen--;
|
||||
for (int i=index; i<song.systemLen; i++) {
|
||||
song.system[i]=song.system[i+1];
|
||||
}
|
||||
recalcChans();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
initDispatch();
|
||||
isBusy.lock();
|
||||
|
|
@ -1029,6 +1037,7 @@ void DivEngine::previewSample(int sample, int note) {
|
|||
rate=(song.tuning*pow(2.0,(double)(note+3)/12.0)*((double)song.sample[sample]->centerRate/8363.0));
|
||||
if (rate<=0) rate=song.sample[sample]->rate;
|
||||
}
|
||||
if (rate<100) rate=100;
|
||||
blip_set_rates(samp_bb,rate,got.rate);
|
||||
samp_prevSample=0;
|
||||
sPreview.pos=0;
|
||||
|
|
@ -1057,7 +1066,9 @@ void DivEngine::previewWave(int wave, int note) {
|
|||
return;
|
||||
}
|
||||
blip_clear(samp_bb);
|
||||
blip_set_rates(samp_bb,song.wave[wave]->len*((song.tuning*0.0625)*pow(2.0,(double)(note+3)/12.0)),got.rate);
|
||||
double rate=song.wave[wave]->len*((song.tuning*0.0625)*pow(2.0,(double)(note+3)/12.0));
|
||||
if (rate<100) rate=100;
|
||||
blip_set_rates(samp_bb,rate,got.rate);
|
||||
samp_prevSample=0;
|
||||
sPreview.pos=0;
|
||||
sPreview.sample=-1;
|
||||
|
|
@ -1211,8 +1222,10 @@ int DivEngine::addInstrument(int refChan) {
|
|||
int insCount=(int)song.ins.size();
|
||||
ins->name=fmt::sprintf("Instrument %d",insCount);
|
||||
ins->type=getPreferInsType(refChan);
|
||||
saveLock.lock();
|
||||
song.ins.push_back(ins);
|
||||
song.insLen=insCount+1;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return insCount;
|
||||
}
|
||||
|
|
@ -1227,6 +1240,9 @@ enum DivInsFormats {
|
|||
DIV_INSFORMAT_SBI,
|
||||
};
|
||||
|
||||
// TODO: re-organize this function to:
|
||||
// - support replacing instruments
|
||||
// - support instrument formats which contain multiple instruments
|
||||
bool DivEngine::addInstrumentFromFile(const char* path) {
|
||||
warnings="";
|
||||
|
||||
|
|
@ -1351,7 +1367,7 @@ bool DivEngine::addInstrumentFromFile(const char* path) {
|
|||
}
|
||||
}
|
||||
|
||||
// TDOO these really should be refactored to separate functions/cpp files per instrument file type.
|
||||
// TDOO these really should be re-organized to separate functions per instrument file type.
|
||||
switch (format) {
|
||||
case DIV_INSFORMAT_DMP: {
|
||||
// this is a ridiculous mess
|
||||
|
|
@ -1934,15 +1950,18 @@ bool DivEngine::addInstrumentFromFile(const char* path) {
|
|||
}
|
||||
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
int insCount=(int)song.ins.size();
|
||||
song.ins.push_back(ins);
|
||||
song.insLen=insCount+1;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::delInstrument(int index) {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
if (index>=0 && index<(int)song.ins.size()) {
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
disCont[i].dispatch->notifyInsDeletion(song.ins[index]);
|
||||
|
|
@ -1961,15 +1980,18 @@ void DivEngine::delInstrument(int index) {
|
|||
}
|
||||
}
|
||||
}
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
}
|
||||
|
||||
int DivEngine::addWave() {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
DivWavetable* wave=new DivWavetable;
|
||||
int waveCount=(int)song.wave.size();
|
||||
song.wave.push_back(wave);
|
||||
song.waveLen=waveCount+1;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return waveCount;
|
||||
}
|
||||
|
|
@ -2085,30 +2107,36 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
}
|
||||
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
int waveCount=(int)song.wave.size();
|
||||
song.wave.push_back(wave);
|
||||
song.waveLen=waveCount+1;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::delWave(int index) {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
if (index>=0 && index<(int)song.wave.size()) {
|
||||
delete song.wave[index];
|
||||
song.wave.erase(song.wave.begin()+index);
|
||||
song.waveLen=song.wave.size();
|
||||
}
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
}
|
||||
|
||||
int DivEngine::addSample() {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
DivSample* sample=new DivSample;
|
||||
int sampleCount=(int)song.sample.size();
|
||||
sample->name=fmt::sprintf("Sample %d",sampleCount);
|
||||
song.sample.push_back(sample);
|
||||
song.sampleLen=sampleCount+1;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
isBusy.unlock();
|
||||
return sampleCount;
|
||||
|
|
@ -2186,8 +2214,10 @@ bool DivEngine::addSampleFromFile(const char* path) {
|
|||
if (sample->centerRate<4000) sample->centerRate=4000;
|
||||
if (sample->centerRate>64000) sample->centerRate=64000;
|
||||
sf_close(f);
|
||||
saveLock.lock();
|
||||
song.sample.push_back(sample);
|
||||
song.sampleLen=sampleCount+1;
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
isBusy.unlock();
|
||||
return sampleCount;
|
||||
|
|
@ -2195,12 +2225,14 @@ bool DivEngine::addSampleFromFile(const char* path) {
|
|||
|
||||
void DivEngine::delSample(int index) {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
if (index>=0 && index<(int)song.sample.size()) {
|
||||
delete song.sample[index];
|
||||
song.sample.erase(song.sample.begin()+index);
|
||||
song.sampleLen=song.sample.size();
|
||||
renderSamples();
|
||||
}
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
}
|
||||
|
||||
|
|
@ -2229,11 +2261,14 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
|||
}
|
||||
}
|
||||
if (where) { // at the end
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
song.orders.ord[i][song.ordersLen]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
saveLock.unlock();
|
||||
} else { // after current order
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
for (int j=song.ordersLen; j>curOrder; j--) {
|
||||
song.orders.ord[i][j]=song.orders.ord[i][j-1];
|
||||
|
|
@ -2241,6 +2276,7 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
|||
song.orders.ord[i][curOrder+1]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
saveLock.unlock();
|
||||
curOrder++;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
|
|
@ -2277,11 +2313,14 @@ void DivEngine::deepCloneOrder(bool where) {
|
|||
}
|
||||
}
|
||||
if (where) { // at the end
|
||||
saveLock.lock();
|
||||
for (int i=0; i<chans; i++) {
|
||||
song.orders.ord[i][song.ordersLen]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
saveLock.unlock();
|
||||
} else { // after current order
|
||||
saveLock.lock();
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=song.ordersLen; j>curOrder; j--) {
|
||||
song.orders.ord[i][j]=song.orders.ord[i][j-1];
|
||||
|
|
@ -2289,6 +2328,7 @@ void DivEngine::deepCloneOrder(bool where) {
|
|||
song.orders.ord[i][curOrder+1]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
saveLock.unlock();
|
||||
curOrder++;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
|
|
@ -2300,12 +2340,14 @@ void DivEngine::deepCloneOrder(bool where) {
|
|||
void DivEngine::deleteOrder() {
|
||||
if (song.ordersLen<=1) return;
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
for (int j=curOrder; j<song.ordersLen; j++) {
|
||||
song.orders.ord[i][j]=song.orders.ord[i][j+1];
|
||||
}
|
||||
}
|
||||
song.ordersLen--;
|
||||
saveLock.unlock();
|
||||
if (curOrder>=song.ordersLen) curOrder=song.ordersLen-1;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
|
|
@ -2319,11 +2361,13 @@ void DivEngine::moveOrderUp() {
|
|||
isBusy.unlock();
|
||||
return;
|
||||
}
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder-1];
|
||||
song.orders.ord[i][curOrder-1]^=song.orders.ord[i][curOrder];
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder-1];
|
||||
}
|
||||
saveLock.unlock();
|
||||
curOrder--;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
|
|
@ -2337,11 +2381,13 @@ void DivEngine::moveOrderDown() {
|
|||
isBusy.unlock();
|
||||
return;
|
||||
}
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder+1];
|
||||
song.orders.ord[i][curOrder+1]^=song.orders.ord[i][curOrder];
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder+1];
|
||||
}
|
||||
saveLock.unlock();
|
||||
curOrder++;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
|
|
@ -2368,9 +2414,11 @@ bool DivEngine::moveInsUp(int which) {
|
|||
if (which<1 || which>=(int)song.ins.size()) return false;
|
||||
isBusy.lock();
|
||||
DivInstrument* prev=song.ins[which];
|
||||
saveLock.lock();
|
||||
song.ins[which]=song.ins[which-1];
|
||||
song.ins[which-1]=prev;
|
||||
exchangeIns(which,which-1);
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2379,8 +2427,10 @@ bool DivEngine::moveWaveUp(int which) {
|
|||
if (which<1 || which>=(int)song.wave.size()) return false;
|
||||
isBusy.lock();
|
||||
DivWavetable* prev=song.wave[which];
|
||||
saveLock.lock();
|
||||
song.wave[which]=song.wave[which-1];
|
||||
song.wave[which-1]=prev;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2389,8 +2439,10 @@ bool DivEngine::moveSampleUp(int which) {
|
|||
if (which<1 || which>=(int)song.sample.size()) return false;
|
||||
isBusy.lock();
|
||||
DivSample* prev=song.sample[which];
|
||||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which-1];
|
||||
song.sample[which-1]=prev;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2399,9 +2451,11 @@ bool DivEngine::moveInsDown(int which) {
|
|||
if (which<0 || which>=((int)song.ins.size())-1) return false;
|
||||
isBusy.lock();
|
||||
DivInstrument* prev=song.ins[which];
|
||||
saveLock.lock();
|
||||
song.ins[which]=song.ins[which+1];
|
||||
song.ins[which+1]=prev;
|
||||
exchangeIns(which,which+1);
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2410,8 +2464,10 @@ bool DivEngine::moveWaveDown(int which) {
|
|||
if (which<0 || which>=((int)song.wave.size())-1) return false;
|
||||
isBusy.lock();
|
||||
DivWavetable* prev=song.wave[which];
|
||||
saveLock.lock();
|
||||
song.wave[which]=song.wave[which+1];
|
||||
song.wave[which+1]=prev;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2420,8 +2476,10 @@ bool DivEngine::moveSampleDown(int which) {
|
|||
if (which<0 || which>=((int)song.sample.size())-1) return false;
|
||||
isBusy.lock();
|
||||
DivSample* prev=song.sample[which];
|
||||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which+1];
|
||||
song.sample[which+1]=prev;
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2462,7 +2520,9 @@ void DivEngine::setOrder(unsigned char order) {
|
|||
|
||||
void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.systemFlags[system]=flags;
|
||||
saveLock.unlock();
|
||||
disCont[system].dispatch->setFlags(song.systemFlags[system]);
|
||||
disCont[system].setRates(got.rate);
|
||||
if (restart && isPlaying()) {
|
||||
|
|
@ -2473,6 +2533,7 @@ void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) {
|
|||
|
||||
void DivEngine::setSongRate(float hz, bool pal) {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.pal=!pal;
|
||||
song.hz=hz;
|
||||
// what?
|
||||
|
|
@ -2487,6 +2548,7 @@ void DivEngine::setSongRate(float hz, bool pal) {
|
|||
divider=50;
|
||||
}
|
||||
}
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
}
|
||||
|
||||
|
|
@ -2536,6 +2598,20 @@ void DivEngine::synchronized(const std::function<void()>& what) {
|
|||
isBusy.unlock();
|
||||
}
|
||||
|
||||
void DivEngine::lockSave(const std::function<void()>& what) {
|
||||
saveLock.lock();
|
||||
what();
|
||||
saveLock.unlock();
|
||||
}
|
||||
|
||||
void DivEngine::lockEngine(const std::function<void()>& what) {
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
what();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
}
|
||||
|
||||
TAAudioDesc& DivEngine::getAudioDescWant() {
|
||||
return want;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class DivEngine {
|
|||
std::map<String,String> conf;
|
||||
std::queue<DivNoteEvent> pendingNotes;
|
||||
bool isMuted[DIV_MAX_CHANS];
|
||||
std::mutex isBusy;
|
||||
std::mutex isBusy, saveLock;
|
||||
String configPath;
|
||||
String configFile;
|
||||
String lastError;
|
||||
|
|
@ -278,7 +278,8 @@ class DivEngine {
|
|||
// save as .dmf.
|
||||
SafeWriter* saveDMF(unsigned char version);
|
||||
// save as .fur.
|
||||
SafeWriter* saveFur();
|
||||
// if notPrimary is true then the song will not be altered
|
||||
SafeWriter* saveFur(bool notPrimary=false);
|
||||
// build a ROM file (TODO).
|
||||
// specify system to build ROM for.
|
||||
SafeWriter* buildROM(int sys);
|
||||
|
|
@ -620,6 +621,12 @@ class DivEngine {
|
|||
// perform secure/sync operation
|
||||
void synchronized(const std::function<void()>& what);
|
||||
|
||||
// perform secure/sync song operation
|
||||
void lockSave(const std::function<void()>& what);
|
||||
|
||||
// perform secure/sync song operation (and lock audio too)
|
||||
void lockEngine(const std::function<void()>& what);
|
||||
|
||||
// get audio desc want
|
||||
TAAudioDesc& getAudioDescWant();
|
||||
|
||||
|
|
|
|||
|
|
@ -733,10 +733,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
|
||||
if (active) quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.unload();
|
||||
song=ds;
|
||||
recalcChans();
|
||||
renderSamples();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
if (active) {
|
||||
initDispatch();
|
||||
|
|
@ -1028,6 +1030,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
reader.read(samplePtr,ds.sampleLen*4);
|
||||
for (int i=0; i<numberOfPats; i++) patPtr.push_back(reader.readI());
|
||||
|
||||
logD("reading orders (%d)...\n",ds.ordersLen);
|
||||
for (int i=0; i<tchans; i++) {
|
||||
for (int j=0; j<ds.ordersLen; j++) {
|
||||
ds.orders.ord[i][j]=reader.readC();
|
||||
|
|
@ -1067,6 +1070,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
// read instruments
|
||||
for (int i=0; i<ds.insLen; i++) {
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
logD("reading instrument %d at %x...\n",i,insPtr[i]);
|
||||
reader.seek(insPtr[i],SEEK_SET);
|
||||
|
||||
if (ins->readInsData(reader,ds.version)!=DIV_DATA_SUCCESS) {
|
||||
|
|
@ -1082,6 +1086,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
// read wavetables
|
||||
for (int i=0; i<ds.waveLen; i++) {
|
||||
DivWavetable* wave=new DivWavetable;
|
||||
logD("reading wavetable %d at %x...\n",i,wavePtr[i]);
|
||||
reader.seek(wavePtr[i],SEEK_SET);
|
||||
|
||||
if (wave->readWaveData(reader,ds.version)!=DIV_DATA_SUCCESS) {
|
||||
|
|
@ -1109,6 +1114,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
reader.readI();
|
||||
DivSample* sample=new DivSample;
|
||||
logD("reading sample %d at %x...\n",i,samplePtr[i]);
|
||||
|
||||
sample->name=reader.readString();
|
||||
sample->samples=reader.readI();
|
||||
|
|
@ -1182,6 +1188,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
for (int i: patPtr) {
|
||||
reader.seek(i,SEEK_SET);
|
||||
reader.read(magic,4);
|
||||
logD("reading pattern in %x...\n",i);
|
||||
if (strcmp(magic,"PATR")!=0) {
|
||||
logE("%x: invalid pattern header!\n",i);
|
||||
lastError="invalid pattern header!";
|
||||
|
|
@ -1194,6 +1201,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
int index=reader.readS();
|
||||
reader.readI();
|
||||
|
||||
logD("- %d, %d\n",chan,index);
|
||||
|
||||
DivPattern* pat=ds.pat[chan].getPattern(index,true);
|
||||
for (int j=0; j<ds.patLen; j++) {
|
||||
pat->data[j][0]=reader.readS();
|
||||
|
|
@ -1219,10 +1228,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
|
||||
if (active) quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.unload();
|
||||
song=ds;
|
||||
recalcChans();
|
||||
renderSamples();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
if (active) {
|
||||
initDispatch();
|
||||
|
|
@ -1583,10 +1594,12 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
|
||||
if (active) quitDispatch();
|
||||
isBusy.lock();
|
||||
saveLock.lock();
|
||||
song.unload();
|
||||
song=ds;
|
||||
recalcChans();
|
||||
renderSamples();
|
||||
saveLock.unlock();
|
||||
isBusy.unlock();
|
||||
if (active) {
|
||||
initDispatch();
|
||||
|
|
@ -1728,7 +1741,8 @@ bool DivEngine::load(unsigned char* f, size_t slen) {
|
|||
return false;
|
||||
}
|
||||
|
||||
SafeWriter* DivEngine::saveFur() {
|
||||
SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||
saveLock.lock();
|
||||
int insPtr[256];
|
||||
int wavePtr[256];
|
||||
int samplePtr[256];
|
||||
|
|
@ -1736,8 +1750,10 @@ SafeWriter* DivEngine::saveFur() {
|
|||
size_t ptrSeek;
|
||||
warnings="";
|
||||
|
||||
song.isDMF=false;
|
||||
song.version=DIV_ENGINE_VERSION;
|
||||
if (!notPrimary) {
|
||||
song.isDMF=false;
|
||||
song.version=DIV_ENGINE_VERSION;
|
||||
}
|
||||
|
||||
SafeWriter* w=new SafeWriter;
|
||||
w->init();
|
||||
|
|
@ -1967,6 +1983,7 @@ SafeWriter* DivEngine::saveFur() {
|
|||
w->writeI(i);
|
||||
}
|
||||
|
||||
saveLock.unlock();
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
@ -2026,6 +2043,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
lastError="this system is not possible on .dmf";
|
||||
return NULL;
|
||||
}
|
||||
saveLock.lock();
|
||||
warnings="";
|
||||
song.version=version;
|
||||
song.isDMF=true;
|
||||
|
|
@ -2257,7 +2275,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeC(16);
|
||||
w->write(i->data16,i->length16);
|
||||
}
|
||||
|
||||
|
||||
saveLock.unlock();
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
|
|||
if (s->samples>0) {
|
||||
chan[i].audDat=s->data8[chan[i].audPos++];
|
||||
if (chan[i].audPos>=s->samples || chan[i].audPos>=131071) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].audPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
|
|||
urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80);
|
||||
}
|
||||
if (++dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
|
|
@ -162,7 +162,7 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
|
|||
urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80);
|
||||
}
|
||||
if (++dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
rWrite(0x4011,((unsigned char)s->data8[dacPos]+0x80)>>1);
|
||||
}
|
||||
if (++dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
|
|
|
|||
|
|
@ -189,9 +189,6 @@ const char* DivPlatformOPL::getEffectName(unsigned char effect) {
|
|||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xy: Set PSG noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3));
|
||||
chan[i].dacPos++;
|
||||
if (chan[i].dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].dacSample=-1;
|
||||
|
|
|
|||
285
src/engine/platform/pet.cpp
Normal file
285
src/engine/platform/pet.cpp
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "pet.h"
|
||||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#define rWrite(a,v) {regPool[(a)]=(v)&0xff; if((a)==10) {chan.sreg=(v); chan.cnt=2;}}
|
||||
|
||||
#define CHIP_DIVIDER 16
|
||||
#define SAMP_DIVIDER 4
|
||||
|
||||
const char* regCheatSheet6522[]={
|
||||
"T2L", "08",
|
||||
"SR", "0A",
|
||||
"ACR", "0B",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformPET::getRegisterSheet() {
|
||||
return regCheatSheet6522;
|
||||
}
|
||||
|
||||
const char* DivPlatformPET::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
return "10xx: Change waveform";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformPET::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
// high-level emulation of 6522 shift register for now
|
||||
int t2=regPool[8]*2+4;
|
||||
if (((regPool[11]>>2)&7)==4) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
int cycs=SAMP_DIVIDER;
|
||||
while (cycs>0) {
|
||||
int adv=MIN(cycs,chan.cnt);
|
||||
chan.cnt-=adv;
|
||||
cycs-=adv;
|
||||
if (chan.cnt==0) {
|
||||
chan.out=(chan.sreg&1)*32767;
|
||||
chan.sreg=(chan.sreg>>1)|((chan.sreg&1)<<7);
|
||||
chan.cnt=t2;
|
||||
}
|
||||
}
|
||||
bufL[h]=chan.out;
|
||||
bufR[h]=chan.out;
|
||||
}
|
||||
} else {
|
||||
chan.out=0;
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
bufL[h]=0;
|
||||
bufR[h]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformPET::writeOutVol() {
|
||||
if (chan.active && !isMuted && chan.outVol>0) {
|
||||
if (regPool[11]!=16) {
|
||||
rWrite(11,16);
|
||||
rWrite(10,chan.wave);
|
||||
}
|
||||
} else {
|
||||
rWrite(11,0);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformPET::tick() {
|
||||
chan.std.next();
|
||||
if (chan.std.hadVol) {
|
||||
chan.outVol=chan.std.vol&chan.vol;
|
||||
writeOutVol();
|
||||
}
|
||||
if (chan.std.hadArp) {
|
||||
if (!chan.inPorta) {
|
||||
if (chan.std.arpMode) {
|
||||
chan.baseFreq=NOTE_PERIODIC(chan.std.arp);
|
||||
} else {
|
||||
chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp);
|
||||
}
|
||||
}
|
||||
chan.freqChanged=true;
|
||||
} else {
|
||||
if (chan.std.arpMode && chan.std.finishedArp) {
|
||||
chan.baseFreq=NOTE_PERIODIC(chan.note);
|
||||
chan.freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan.std.hadWave) {
|
||||
if (chan.wave!=chan.std.wave) {
|
||||
chan.wave=chan.std.wave;
|
||||
rWrite(10,chan.wave);
|
||||
}
|
||||
}
|
||||
if (chan.freqChanged || chan.keyOn || chan.keyOff) {
|
||||
chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true);
|
||||
if (chan.freq>257) chan.freq=257;
|
||||
if (chan.freq<2) chan.freq=2;
|
||||
rWrite(8,chan.freq-2);
|
||||
if (chan.keyOn) {
|
||||
if (!chan.std.willVol) {
|
||||
chan.outVol=chan.vol;
|
||||
writeOutVol();
|
||||
}
|
||||
chan.keyOn=false;
|
||||
}
|
||||
if (chan.keyOff) {
|
||||
rWrite(11,0);
|
||||
chan.keyOff=false;
|
||||
}
|
||||
chan.freqChanged=false;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformPET::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan.ins);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan.baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan.freqChanged=true;
|
||||
chan.note=c.value;
|
||||
}
|
||||
chan.active=true;
|
||||
chan.keyOn=true;
|
||||
chan.std.init(ins);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan.active=false;
|
||||
chan.keyOff=true;
|
||||
chan.std.init(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan.std.release();
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan.ins!=c.value || c.value2==1) {
|
||||
chan.ins=c.value;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan.vol!=c.value) {
|
||||
chan.vol=c.value;
|
||||
if (!chan.std.hadVol) {
|
||||
chan.outVol=chan.vol;
|
||||
writeOutVol();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
return chan.vol;
|
||||
break;
|
||||
case DIV_CMD_PITCH:
|
||||
chan.pitch=c.value;
|
||||
chan.freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_WAVE:
|
||||
chan.wave=c.value;
|
||||
rWrite(10,chan.wave);
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan.baseFreq) {
|
||||
chan.baseFreq+=c.value;
|
||||
if (chan.baseFreq>=destFreq) {
|
||||
chan.baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan.baseFreq-=c.value;
|
||||
if (chan.baseFreq<=destFreq) {
|
||||
chan.baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan.freqChanged=true;
|
||||
if (return2) {
|
||||
chan.inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan.baseFreq=NOTE_PERIODIC(c.value+((chan.std.willArp && !chan.std.arpMode)?(chan.std.arp):(0)));
|
||||
chan.freqChanged=true;
|
||||
chan.note=c.value;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan.active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins));
|
||||
}
|
||||
chan.inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 1;
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformPET::muteChannel(int ch, bool mute) {
|
||||
isMuted=mute;
|
||||
writeOutVol();
|
||||
}
|
||||
|
||||
void DivPlatformPET::forceIns() {
|
||||
chan.insChanged=true;
|
||||
chan.freqChanged=true;
|
||||
writeOutVol();
|
||||
}
|
||||
|
||||
void* DivPlatformPET::getChanState(int ch) {
|
||||
return &chan;
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformPET::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformPET::getRegisterPoolSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void DivPlatformPET::reset() {
|
||||
memset(regPool,0,16);
|
||||
chan=Channel();
|
||||
}
|
||||
|
||||
bool DivPlatformPET::isStereo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DivPlatformPET::notifyInsDeletion(void* ins) {
|
||||
chan.std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
|
||||
void DivPlatformPET::poke(unsigned int addr, unsigned short val) {
|
||||
rWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformPET::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformPET::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
chipClock=1000000;
|
||||
rate=chipClock/SAMP_DIVIDER; // = 250000kHz
|
||||
isMuted=false;
|
||||
reset();
|
||||
return 1;
|
||||
}
|
||||
|
||||
DivPlatformPET::~DivPlatformPET() {
|
||||
}
|
||||
82
src/engine/platform/pet.h
Normal file
82
src/engine/platform/pet.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _PET_H
|
||||
#define _PET_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "../macroInt.h"
|
||||
|
||||
class DivPlatformPET: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, note;
|
||||
unsigned char ins;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
|
||||
int vol, outVol, wave;
|
||||
unsigned char sreg;
|
||||
int cnt;
|
||||
short out;
|
||||
DivMacroInt std;
|
||||
Channel():
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
vol(1),
|
||||
outVol(1),
|
||||
wave(0b00001111),
|
||||
sreg(0),
|
||||
cnt(0),
|
||||
out(0) {}
|
||||
};
|
||||
Channel chan;
|
||||
bool isMuted;
|
||||
|
||||
unsigned char regPool[16];
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsDeletion(void* ins);
|
||||
bool isStereo();
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
~DivPlatformPET();
|
||||
private:
|
||||
void writeOutVol();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -54,7 +54,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
}
|
||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||
if (chan[i].pcm.pos>=(s->samples<<8)) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].pcm.pos=s->loopStart<<8;
|
||||
} else {
|
||||
chan[i].pcm.sample=-1;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
}
|
||||
rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80);
|
||||
if (dacPos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ const char* DivPlatformVERA::getEffectName(unsigned char effect) {
|
|||
return "20xx: Change waveform";
|
||||
break;
|
||||
case 0x22:
|
||||
return "22xx: Set duty cycle (0 to 63)";
|
||||
return "22xx: Set duty cycle (0 to 3F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -97,7 +97,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
}
|
||||
chan[16].pcm.pos++;
|
||||
if (chan[16].pcm.pos>=s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->samples) {
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[16].pcm.pos=s->loopStart;
|
||||
} else {
|
||||
chan[16].pcm.sample=-1;
|
||||
|
|
|
|||
|
|
@ -371,6 +371,7 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
}
|
||||
break;
|
||||
case DIV_SYSTEM_BUBSYS_WSG:
|
||||
case DIV_SYSTEM_PET:
|
||||
switch (effect) {
|
||||
case 0x10: // select waveform
|
||||
dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal));
|
||||
|
|
@ -1617,7 +1618,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
return;
|
||||
}
|
||||
|
||||
logD("attempts: %d\n",attempts);
|
||||
//logD("attempts: %d\n",attempts);
|
||||
if (attempts>=100) {
|
||||
logE("hang detected! stopping! at %d seconds %d micro\n",totalSeconds,totalTicks);
|
||||
freelance=false;
|
||||
|
|
|
|||
|
|
@ -179,6 +179,121 @@ bool DivSample::resize(unsigned int count) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DivSample::strip(unsigned int begin, unsigned int end) {
|
||||
if (begin>samples) begin=samples;
|
||||
if (end>samples) end=samples;
|
||||
int count=samples-(end-begin);
|
||||
if (count<=0) return resize(0);
|
||||
if (depth==8) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
if (begin>0) {
|
||||
memcpy(data8,oldData8,begin);
|
||||
}
|
||||
if (samples-end>0) {
|
||||
memcpy(data8+begin,oldData8+end,samples-end);
|
||||
}
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
if (begin>0) {
|
||||
memcpy(data16,oldData16,sizeof(short)*begin);
|
||||
}
|
||||
if (samples-end>0) {
|
||||
memcpy(&(data16[begin]),&(oldData16[end]),sizeof(short)*(samples-end));
|
||||
}
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DivSample::trim(unsigned int begin, unsigned int end) {
|
||||
int count=end-begin;
|
||||
if (count==0) return true;
|
||||
if (begin==0 && end==samples) return true;
|
||||
if (depth==8) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
memcpy(data8,oldData8+begin,count);
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
memcpy(data16,&(oldData16[begin]),sizeof(short)*count);
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: for clipboard
|
||||
bool DivSample::insert(unsigned int pos, unsigned int length) {
|
||||
unsigned int count=samples+length;
|
||||
if (depth==8) {
|
||||
if (data8!=NULL) {
|
||||
signed char* oldData8=data8;
|
||||
data8=NULL;
|
||||
initInternal(8,count);
|
||||
if (pos>0) {
|
||||
memcpy(data8,oldData8,pos);
|
||||
}
|
||||
if (count-pos-length>0) {
|
||||
memcpy(data8+pos+length,oldData8+pos,count-pos-length);
|
||||
}
|
||||
delete[] oldData8;
|
||||
} else {
|
||||
initInternal(8,count);
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
} else if (depth==16) {
|
||||
if (data16!=NULL) {
|
||||
short* oldData16=data16;
|
||||
data16=NULL;
|
||||
initInternal(16,count);
|
||||
memcpy(data16,oldData16,sizeof(short)*count);
|
||||
delete[] oldData16;
|
||||
} else {
|
||||
initInternal(16,count);
|
||||
}
|
||||
samples=count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define RESAMPLE_BEGIN \
|
||||
if (samples<1) return true; \
|
||||
int finalCount=(double)samples*(r/(double)rate); \
|
||||
|
|
@ -199,6 +314,8 @@ bool DivSample::resize(unsigned int count) {
|
|||
}
|
||||
|
||||
#define RESAMPLE_END \
|
||||
if (loopStart>=0) loopStart=(double)loopStart*(r/(double)rate); \
|
||||
rate=r; \
|
||||
samples=finalCount; \
|
||||
if (depth==16) { \
|
||||
delete[] oldData16; \
|
||||
|
|
@ -229,8 +346,6 @@ bool DivSample::resampleNone(double r) {
|
|||
}
|
||||
}
|
||||
|
||||
rate=r;
|
||||
|
||||
RESAMPLE_END;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -270,8 +385,6 @@ bool DivSample::resampleLinear(double r) {
|
|||
}
|
||||
}
|
||||
|
||||
rate=r;
|
||||
|
||||
RESAMPLE_END;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -326,8 +439,6 @@ bool DivSample::resampleCubic(double r) {
|
|||
}
|
||||
}
|
||||
|
||||
rate=r;
|
||||
|
||||
RESAMPLE_END;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -380,7 +491,7 @@ bool DivSample::resampleBlep(double r) {
|
|||
}
|
||||
}
|
||||
} else if (depth==8) {
|
||||
memset(data8,0,finalCount*sizeof(short));
|
||||
memset(data8,0,finalCount);
|
||||
for (int i=0; i<finalCount; i++) {
|
||||
if (posInt<samples) {
|
||||
int result=data8[i]+oldData8[posInt];
|
||||
|
|
@ -417,8 +528,6 @@ bool DivSample::resampleBlep(double r) {
|
|||
}
|
||||
}
|
||||
|
||||
rate=r;
|
||||
|
||||
RESAMPLE_END;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -486,8 +595,6 @@ bool DivSample::resampleSinc(double r) {
|
|||
}
|
||||
}
|
||||
|
||||
rate=r;
|
||||
|
||||
RESAMPLE_END;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,33 @@ struct DivSample {
|
|||
*/
|
||||
bool resize(unsigned int count);
|
||||
|
||||
/**
|
||||
* remove part of the sample data.
|
||||
* @warning do not attempt to strip a sample outside of a synchronized block!
|
||||
* @param start the beginning.
|
||||
* @param end the end.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool strip(unsigned int begin, unsigned int end);
|
||||
|
||||
/**
|
||||
* clip the sample data to specified boundaries.
|
||||
* @warning do not attempt to trim a sample outside of a synchronized block!
|
||||
* @param start the beginning.
|
||||
* @param end the end.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool trim(unsigned int begin, unsigned int end);
|
||||
|
||||
/**
|
||||
* insert silence at specified position.
|
||||
* @warning do not attempt to do this outside of a synchronized block!
|
||||
* @param pos the beginning.
|
||||
* @param length how many samples to insert.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool insert(unsigned int pos, unsigned int length);
|
||||
|
||||
/**
|
||||
* change the sample rate.
|
||||
* @warning do not attempt to resample outside of a synchronized block!
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue