Merge branch 'master' of https://github.com/tildearrow/furnace into getSampleMemOffset
This commit is contained in:
commit
e9b6b441e3
466 changed files with 378861 additions and 345914 deletions
|
|
@ -193,6 +193,4 @@ void DivEngine::factoryReset() {
|
|||
if (i>0) path+=fmt::sprintf(".%d",i);
|
||||
deleteFile(path.c_str());
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,6 +564,8 @@ struct DivChannelModeHints {
|
|||
// - 18: inc linear
|
||||
// - 19: inc bent
|
||||
// - 20: direct
|
||||
// - 21: warning
|
||||
// - 22: error
|
||||
unsigned char type[4];
|
||||
// up to 4
|
||||
unsigned char count;
|
||||
|
|
|
|||
|
|
@ -932,11 +932,14 @@ void DivEngine::delUnusedWaves() {
|
|||
}
|
||||
|
||||
void DivEngine::delUnusedSamples() {
|
||||
if (song.sample.empty()) return;
|
||||
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
|
||||
bool isUsed[256];
|
||||
memset(isUsed,0,256*sizeof(bool));
|
||||
bool* isUsed=new bool[song.sample.size()];
|
||||
memset(isUsed,0,song.sample.size()*sizeof(bool));
|
||||
int isUsedMax=((int)song.sample.size())-1;
|
||||
|
||||
// scan in instruments
|
||||
for (DivInstrument* i: song.ins) {
|
||||
|
|
@ -1018,10 +1021,10 @@ void DivEngine::delUnusedSamples() {
|
|||
if (!isUsed[i]) {
|
||||
delSampleUnsafe(i,false);
|
||||
// rotate
|
||||
for (int j=i; j<255; j++) {
|
||||
for (int j=i; j<isUsedMax; j++) {
|
||||
isUsed[j]=isUsed[j+1];
|
||||
}
|
||||
isUsed[255]=true;
|
||||
isUsed[isUsedMax]=true;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
|
@ -1029,6 +1032,8 @@ void DivEngine::delUnusedSamples() {
|
|||
// render
|
||||
renderSamples();
|
||||
|
||||
delete[] isUsed;
|
||||
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
}
|
||||
|
|
@ -2707,7 +2712,7 @@ void DivEngine::delInstrument(int index) {
|
|||
}
|
||||
|
||||
int DivEngine::addWave() {
|
||||
if (song.wave.size()>=256) {
|
||||
if (song.wave.size()>=32768) {
|
||||
lastError=_("too many wavetables!");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -2724,7 +2729,7 @@ int DivEngine::addWave() {
|
|||
}
|
||||
|
||||
int DivEngine::addWavePtr(DivWavetable* which) {
|
||||
if (song.wave.size()>=256) {
|
||||
if (song.wave.size()>=32768) {
|
||||
lastError=_("too many wavetables!");
|
||||
delete which;
|
||||
return -1;
|
||||
|
|
@ -2901,7 +2906,7 @@ void DivEngine::delWave(int index) {
|
|||
}
|
||||
|
||||
int DivEngine::addSample() {
|
||||
if (song.sample.size()>=256) {
|
||||
if (song.sample.size()>=32768) {
|
||||
lastError=_("too many samples!");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -2924,7 +2929,7 @@ int DivEngine::addSample() {
|
|||
}
|
||||
|
||||
int DivEngine::addSamplePtr(DivSample* which) {
|
||||
if (song.sample.size()>=256) {
|
||||
if (song.sample.size()>=32768) {
|
||||
lastError=_("too many samples!");
|
||||
delete which;
|
||||
return -1;
|
||||
|
|
@ -3847,7 +3852,7 @@ bool DivEngine::initAudioBackend() {
|
|||
if (audioEngine==DIV_AUDIO_SDL) {
|
||||
String audioDriver=getConfString("sdlAudioDriver","");
|
||||
if (!audioDriver.empty()) {
|
||||
SDL_SetHint("SDL_HINT_AUDIODRIVER",audioDriver.c_str());
|
||||
SDL_SetHint(SDL_HINT_AUDIODRIVER,audioDriver.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -4072,7 +4077,7 @@ bool DivEngine::preInit(bool noSafeMode) {
|
|||
#ifdef HAVE_SDL2
|
||||
String audioDriver=getConfString("sdlAudioDriver","");
|
||||
if (!audioDriver.empty()) {
|
||||
SDL_SetHint("SDL_HINT_AUDIODRIVER",audioDriver.c_str());
|
||||
SDL_SetHint(SDL_HINT_AUDIODRIVER,audioDriver.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ class DivWorkPool;
|
|||
|
||||
#define DIV_UNSTABLE
|
||||
|
||||
#define DIV_VERSION "dev231"
|
||||
#define DIV_ENGINE_VERSION 231
|
||||
#define DIV_VERSION "dev233"
|
||||
#define DIV_ENGINE_VERSION 233
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -577,13 +577,13 @@ class DivEngine {
|
|||
DivWorkPool* renderPool;
|
||||
|
||||
// MIDI stuff
|
||||
std::function<int(const TAMidiMessage&)> midiCallback=[](const TAMidiMessage&) -> int {return -2;};
|
||||
std::function<int(const TAMidiMessage&)> midiCallback=[](const TAMidiMessage&) -> int {return -3;};
|
||||
|
||||
void processRowPre(int i);
|
||||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES);
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
|
@ -675,6 +675,8 @@ class DivEngine {
|
|||
friend class DivExportSAPR;
|
||||
friend class DivExportTiuna;
|
||||
friend class DivExportZSM;
|
||||
friend class DivExportiPod;
|
||||
friend class DivExportGRUB;
|
||||
|
||||
public:
|
||||
DivSong song;
|
||||
|
|
@ -726,7 +728,7 @@ class DivEngine {
|
|||
// - x to add x+1 ticks of trailing
|
||||
// - -1 to auto-determine trailing
|
||||
// - -2 to add a whole loop of trailing
|
||||
SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false, int trailingTicks=-1, bool dpcm07=false);
|
||||
SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false, int trailingTicks=-1, bool dpcm07=false, int correctedRate=44100);
|
||||
// dump to TIunA.
|
||||
SafeWriter* saveTiuna(const bool* sysToExport, const char* baseLabel, int firstBankSize, int otherBankSize);
|
||||
// dump command stream.
|
||||
|
|
@ -1336,7 +1338,7 @@ class DivEngine {
|
|||
void setMidiVolExp(float value);
|
||||
|
||||
// set MIDI input callback
|
||||
// if the specified function returns -2, note feedback will be inhibited.
|
||||
// if the specified function returns -3, note feedback will be inhibited.
|
||||
void setMidiCallback(std::function<int(const TAMidiMessage&)> what);
|
||||
|
||||
// send MIDI message
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "export/sapr.h"
|
||||
#include "export/tiuna.h"
|
||||
#include "export/zsm.h"
|
||||
#include "export/ipod.h"
|
||||
#include "export/grub.h"
|
||||
|
||||
DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) {
|
||||
DivROMExport* exporter=NULL;
|
||||
|
|
@ -39,6 +41,12 @@ DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) {
|
|||
case DIV_ROM_SAP_R:
|
||||
exporter=new DivExportSAPR;
|
||||
break;
|
||||
case DIV_ROM_IPOD:
|
||||
exporter=new DivExportiPod;
|
||||
break;
|
||||
case DIV_ROM_GRUB:
|
||||
exporter=new DivExportGRUB;
|
||||
break;
|
||||
default:
|
||||
exporter=new DivROMExport;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ enum DivROMExportOptions {
|
|||
DIV_ROM_ZSM,
|
||||
DIV_ROM_TIUNA,
|
||||
DIV_ROM_SAP_R,
|
||||
DIV_ROM_IPOD,
|
||||
DIV_ROM_GRUB,
|
||||
|
||||
DIV_ROM_MAX
|
||||
};
|
||||
|
|
|
|||
204
src/engine/export/grub.cpp
Normal file
204
src/engine/export/grub.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 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 "grub.h"
|
||||
#include "../engine.h"
|
||||
#include "../ta-log.h"
|
||||
#include <fmt/printf.h>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
void DivExportGRUB::run() {
|
||||
bool grubExportBin=conf.getBool("exportBin",false);
|
||||
|
||||
int BEEPER=-1;
|
||||
int IGNORED=0;
|
||||
|
||||
// Locate system index.
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (e->song.system[i] == DIV_SYSTEM_PCSPKR) {
|
||||
if (BEEPER>=0) {
|
||||
IGNORED++;
|
||||
logAppendf("Ignoring duplicate Beeper id %d",i);
|
||||
break;
|
||||
}
|
||||
BEEPER=i;
|
||||
logAppendf("PC Speaker detected as chip id %d",i);
|
||||
break;
|
||||
} else {
|
||||
IGNORED++;
|
||||
logAppendf("Ignoring chip id %d, system id %d",i,(int)e->song.system[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (BEEPER<0) {
|
||||
logAppendf("ERROR: Could not find PC Speaker/Beeper");
|
||||
failed=true;
|
||||
running=false;
|
||||
return;
|
||||
}
|
||||
if (IGNORED>0) {
|
||||
logAppendf("WARNING: GRUB export ignoring unsup sys count: %d",IGNORED);
|
||||
}
|
||||
|
||||
size_t tickCount=0;
|
||||
|
||||
e->stop();
|
||||
e->repeatPattern=false;
|
||||
e->setOrder(0);
|
||||
|
||||
logAppend("playing and logging register writes...");
|
||||
|
||||
int oldFreq = 0;
|
||||
int freq = 0;
|
||||
|
||||
e->synchronizedSoft([&]() {
|
||||
double origRate = e->got.rate;
|
||||
double rate = MIN(e->curSubSong->hz,1000.0);
|
||||
logAppendf("export rate is %d hz",(int)rate);
|
||||
int tempo = (int)(60000.0/(1000.0/rate));
|
||||
e->got.rate=rate;
|
||||
|
||||
// Determine loop point.
|
||||
int loopOrder=0;
|
||||
int loopRow=0;
|
||||
int loopEnd=0;
|
||||
e->walkSong(loopOrder,loopRow,loopEnd);
|
||||
logAppendf("loop point: %d %d",loopOrder,loopRow);
|
||||
e->warnings="";
|
||||
|
||||
auto w = new SafeWriter;
|
||||
w->init();
|
||||
|
||||
// Reset the playback state.
|
||||
e->curOrder=0;
|
||||
e->freelance=false;
|
||||
e->playing=false;
|
||||
e->extValuePresent=false;
|
||||
e->remainingLoops=-1;
|
||||
|
||||
e->disCont[BEEPER].dispatch->toggleRegisterDump(true);
|
||||
|
||||
// Prepare to write song data.
|
||||
e->playSub(false);
|
||||
bool done=false;
|
||||
|
||||
logAppend("writing data...");
|
||||
progress[0].amount=0.15f;
|
||||
|
||||
int wait_tempo = 0;
|
||||
if (grubExportBin)
|
||||
w->writeI(tempo); // write tempo
|
||||
else
|
||||
w->writeText(fmt::sprintf("%d",tempo)); // write tempo
|
||||
|
||||
while (!done) {
|
||||
if (e->nextTick(false,true) || !e->playing) {
|
||||
done=true;
|
||||
}
|
||||
|
||||
// get register dumps
|
||||
uint8_t* regPool = e->disCont[BEEPER].dispatch->getRegisterPool();
|
||||
int chipClock = e->disCont[BEEPER].dispatch->chipClock;
|
||||
freq = (int)(regPool[0]|(regPool[1]<<8));
|
||||
if (freq > 0) freq = chipClock/freq;
|
||||
|
||||
// write wait
|
||||
tickCount++;
|
||||
int totalWait=e->cycles;
|
||||
if (totalWait>0 && !done) {
|
||||
while (totalWait) {
|
||||
wait_tempo++;
|
||||
if (freq != oldFreq || wait_tempo == 65535) {
|
||||
if (grubExportBin) {
|
||||
w->writeS(oldFreq); // pitch
|
||||
w->writeS(wait_tempo); // duration
|
||||
} else {
|
||||
w->writeText(fmt::sprintf(" %d %d", oldFreq, wait_tempo));
|
||||
}
|
||||
oldFreq = freq;
|
||||
wait_tempo = 0;
|
||||
}
|
||||
totalWait--;
|
||||
tickCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!grubExportBin) w->writeText(fmt::sprintf("\n")); // end song
|
||||
// end of song
|
||||
|
||||
// done - close out.
|
||||
e->got.rate=origRate;
|
||||
e->disCont[BEEPER].dispatch->getRegisterWrites().clear();
|
||||
e->disCont[BEEPER].dispatch->toggleRegisterDump(false);
|
||||
|
||||
e->remainingLoops=-1;
|
||||
e->playing=false;
|
||||
e->freelance=false;
|
||||
e->extValuePresent=false;
|
||||
|
||||
output.push_back(DivROMExportOutput(grubExportBin?"export.bin":"export.txt",w));
|
||||
});
|
||||
|
||||
|
||||
progress[0].amount=1.0f;
|
||||
|
||||
logAppend("finished!");
|
||||
|
||||
running=false;
|
||||
}
|
||||
|
||||
bool DivExportGRUB::go(DivEngine* eng) {
|
||||
progress[0].name="Progress";
|
||||
progress[0].amount=0.0f;
|
||||
|
||||
e=eng;
|
||||
running=true;
|
||||
failed=false;
|
||||
mustAbort=false;
|
||||
exportThread=new std::thread(&DivExportGRUB::run,this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivExportGRUB::wait() {
|
||||
if (exportThread!=NULL) {
|
||||
logV("waiting for export thread...");
|
||||
exportThread->join();
|
||||
delete exportThread;
|
||||
}
|
||||
}
|
||||
|
||||
void DivExportGRUB::abort() {
|
||||
mustAbort=true;
|
||||
wait();
|
||||
}
|
||||
|
||||
bool DivExportGRUB::isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
bool DivExportGRUB::hasFailed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
DivROMExportProgress DivExportGRUB::getProgress(int index) {
|
||||
if (index<0 || index>1) return progress[1];
|
||||
return progress[index];
|
||||
}
|
||||
38
src/engine/export/grub.h
Normal file
38
src/engine/export/grub.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 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 "../export.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
class DivExportGRUB: public DivROMExport {
|
||||
DivEngine* e;
|
||||
std::thread* exportThread;
|
||||
DivROMExportProgress progress[2];
|
||||
bool running, failed, mustAbort;
|
||||
void run();
|
||||
public:
|
||||
bool go(DivEngine* e);
|
||||
bool isRunning();
|
||||
bool hasFailed();
|
||||
void abort();
|
||||
void wait();
|
||||
DivROMExportProgress getProgress(int index=0);
|
||||
~DivExportGRUB() {}
|
||||
};
|
||||
194
src/engine/export/ipod.cpp
Normal file
194
src/engine/export/ipod.cpp
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 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.
|
||||
*/
|
||||
|
||||
// thanks asiekierka! (I used your SAP-R export code as a base for this)
|
||||
|
||||
#include "ipod.h"
|
||||
#include "../engine.h"
|
||||
#include "../ta-log.h"
|
||||
#include <fmt/printf.h>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
void DivExportiPod::run() {
|
||||
int BEEPER=-1;
|
||||
int IGNORED=0;
|
||||
|
||||
// Locate system index.
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (e->song.system[i] == DIV_SYSTEM_PCSPKR) {
|
||||
if (BEEPER>=0) {
|
||||
IGNORED++;
|
||||
logAppendf("Ignoring duplicate Beeper id %d",i);
|
||||
break;
|
||||
}
|
||||
BEEPER=i;
|
||||
logAppendf("PC Speaker detected as chip id %d",i);
|
||||
break;
|
||||
} else {
|
||||
IGNORED++;
|
||||
logAppendf("Ignoring chip id %d, system id %d",i,(int)e->song.system[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (BEEPER<0) {
|
||||
logAppendf("ERROR: Could not find PC Speaker/Beeper");
|
||||
failed=true;
|
||||
running=false;
|
||||
return;
|
||||
}
|
||||
if (IGNORED>0) {
|
||||
logAppendf("WARNING: tone export ignoring unsup sys count: %d",IGNORED);
|
||||
}
|
||||
|
||||
size_t tickCount=0;
|
||||
|
||||
double rate = 1000.0;
|
||||
|
||||
e->stop();
|
||||
e->repeatPattern=false;
|
||||
e->setOrder(0);
|
||||
|
||||
logAppend("playing and logging register writes...");
|
||||
|
||||
int oldFreq = 0;
|
||||
int freq = 0;
|
||||
|
||||
e->synchronizedSoft([&]() {
|
||||
double origRate = e->got.rate;
|
||||
e->got.rate=rate;
|
||||
|
||||
// Determine loop point.
|
||||
int loopOrder=0;
|
||||
int loopRow=0;
|
||||
int loopEnd=0;
|
||||
e->walkSong(loopOrder,loopRow,loopEnd);
|
||||
logAppendf("loop point: %d %d",loopOrder,loopRow);
|
||||
e->warnings="";
|
||||
|
||||
auto w = new SafeWriter;
|
||||
w->init();
|
||||
|
||||
w->writeText(fmt::sprintf("%s\n", e->song.name));
|
||||
|
||||
// Reset the playback state.
|
||||
e->curOrder=0;
|
||||
e->freelance=false;
|
||||
e->playing=false;
|
||||
e->extValuePresent=false;
|
||||
e->remainingLoops=-1;
|
||||
|
||||
e->disCont[BEEPER].dispatch->toggleRegisterDump(true);
|
||||
|
||||
// Prepare to write song data.
|
||||
e->playSub(false);
|
||||
bool done=false;
|
||||
|
||||
logAppend("writing data...");
|
||||
progress[0].amount=0.15f;
|
||||
|
||||
int wait_ms = 0;
|
||||
|
||||
while (!done) {
|
||||
if (e->nextTick(false,true) || !e->playing) {
|
||||
done=true;
|
||||
}
|
||||
|
||||
// get register dumps
|
||||
uint8_t* regPool = e->disCont[BEEPER].dispatch->getRegisterPool();
|
||||
int chipClock = e->disCont[BEEPER].dispatch->chipClock;
|
||||
freq = (int)(regPool[0]|(regPool[1]<<8));
|
||||
if (freq > 0) freq = chipClock/freq;
|
||||
|
||||
// write wait
|
||||
tickCount++;
|
||||
int totalWait=e->cycles;
|
||||
if (totalWait>0 && !done) {
|
||||
while (totalWait) {
|
||||
wait_ms++;
|
||||
if (freq != oldFreq) {
|
||||
w->writeText(fmt::sprintf("%d %d\n", oldFreq, wait_ms));
|
||||
oldFreq = freq;
|
||||
wait_ms = 0;
|
||||
}
|
||||
totalWait--;
|
||||
tickCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of song
|
||||
|
||||
// done - close out.
|
||||
e->got.rate=origRate;
|
||||
e->disCont[BEEPER].dispatch->getRegisterWrites().clear();
|
||||
e->disCont[BEEPER].dispatch->toggleRegisterDump(false);
|
||||
|
||||
e->remainingLoops=-1;
|
||||
e->playing=false;
|
||||
e->freelance=false;
|
||||
e->extValuePresent=false;
|
||||
|
||||
output.push_back(DivROMExportOutput("export.tone",w));
|
||||
});
|
||||
|
||||
|
||||
progress[0].amount=1.0f;
|
||||
|
||||
logAppend("finished!");
|
||||
|
||||
running=false;
|
||||
}
|
||||
|
||||
bool DivExportiPod::go(DivEngine* eng) {
|
||||
progress[0].name="Progress";
|
||||
progress[0].amount=0.0f;
|
||||
|
||||
e=eng;
|
||||
running=true;
|
||||
failed=false;
|
||||
mustAbort=false;
|
||||
exportThread=new std::thread(&DivExportiPod::run,this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivExportiPod::wait() {
|
||||
if (exportThread!=NULL) {
|
||||
logV("waiting for export thread...");
|
||||
exportThread->join();
|
||||
delete exportThread;
|
||||
}
|
||||
}
|
||||
|
||||
void DivExportiPod::abort() {
|
||||
mustAbort=true;
|
||||
wait();
|
||||
}
|
||||
|
||||
bool DivExportiPod::isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
bool DivExportiPod::hasFailed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
DivROMExportProgress DivExportiPod::getProgress(int index) {
|
||||
if (index<0 || index>1) return progress[1];
|
||||
return progress[index];
|
||||
}
|
||||
38
src/engine/export/ipod.h
Normal file
38
src/engine/export/ipod.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 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 "../export.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
class DivExportiPod: public DivROMExport {
|
||||
DivEngine* e;
|
||||
std::thread* exportThread;
|
||||
DivROMExportProgress progress[2];
|
||||
bool running, failed, mustAbort;
|
||||
void run();
|
||||
public:
|
||||
bool go(DivEngine* e);
|
||||
bool isRunning();
|
||||
bool hasFailed();
|
||||
void abort();
|
||||
void wait();
|
||||
DivROMExportProgress getProgress(int index=0);
|
||||
~DivExportiPod() {}
|
||||
};
|
||||
|
|
@ -119,4 +119,27 @@ void DivEngine::registerROMExports() {
|
|||
},
|
||||
false, DIV_REQPOL_EXACT
|
||||
);
|
||||
|
||||
romExportDefs[DIV_ROM_IPOD]=new DivROMExportDef(
|
||||
"iPod .tone alarm", "AArt1256",
|
||||
"iPod Beeper (.tone) Alarm export\n"
|
||||
"for playback, you can drag the resulting file\n"
|
||||
"into iPod_Control/Tones to your iPod IN DISK MODE",
|
||||
"alarm tone files", ".tone",
|
||||
{
|
||||
DIV_SYSTEM_PCSPKR
|
||||
},
|
||||
false, DIV_REQPOL_ANY
|
||||
);
|
||||
|
||||
romExportDefs[DIV_ROM_GRUB]=new DivROMExportDef(
|
||||
"GRUB_INIT_TUNE", "AArt1256",
|
||||
"GRUB_INIT_TUNE export\n"
|
||||
"for use with the GRUB bootloader using the \"play\" command",
|
||||
"Text/Binary files", NULL,
|
||||
{
|
||||
DIV_SYSTEM_PCSPKR
|
||||
},
|
||||
false, DIV_REQPOL_ANY
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,6 +436,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
unsigned int expansions = 0;
|
||||
unsigned int tchans = 0;
|
||||
unsigned int n163Chans = 0;
|
||||
int n163WaveOff[128];
|
||||
bool hasSequence[256][8];
|
||||
unsigned char sequenceIndex[256][8];
|
||||
unsigned char macro_types[256][8];
|
||||
|
|
@ -459,6 +460,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
|
||||
int total_chans = 0;
|
||||
|
||||
memset(n163WaveOff,0,128*sizeof(int));
|
||||
memset(hasSequence, 0, 256 * 8 * sizeof(bool));
|
||||
memset(sequenceIndex, 0, 256 * 8);
|
||||
memset(macro_types, 0, 256 * 8);
|
||||
|
|
@ -653,6 +655,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
int map_ch = 0;
|
||||
|
||||
ds.system[systemID++] = DIV_SYSTEM_NES;
|
||||
ds.systemFlags[0].set("resetSweep",true); // FamiTracker behavior
|
||||
|
||||
if (pal) {
|
||||
ds.systemFlags[0].set("clockSel", 1); // PAL clock
|
||||
|
|
@ -1086,7 +1089,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
ins->fds.modSpeed = reader.readI();
|
||||
ins->fds.modDepth = reader.readI();
|
||||
reader.readI(); // this is delay. currently ignored. TODO.
|
||||
if (ds.wave.size()>=256) {
|
||||
if (ds.wave.size()>=32768) {
|
||||
logW("too many waves! ignoring...");
|
||||
delete wave;
|
||||
} else {
|
||||
|
|
@ -1187,7 +1190,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
}
|
||||
|
||||
unsigned int wave_count = reader.readI();
|
||||
size_t waveOff = ds.wave.size();
|
||||
n163WaveOff[insIndex] = ds.wave.size();
|
||||
ins->n163.wave = n163WaveOff[insIndex];
|
||||
|
||||
if (wave_size>256) {
|
||||
logE("wave size %d out of range",wave_size);
|
||||
|
|
@ -1206,7 +1210,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
wave->data[jj] = val;
|
||||
}
|
||||
|
||||
if (ds.wave.size()<256) {
|
||||
if (ds.wave.size()<32768) {
|
||||
ds.wave.push_back(wave);
|
||||
} else {
|
||||
logW("too many waves...");
|
||||
|
|
@ -1214,17 +1218,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
}
|
||||
}
|
||||
|
||||
// offset wave macro
|
||||
if (ins->std.waveMacro.len == 0) // empty wave macro
|
||||
{
|
||||
ins->std.waveMacro.len = 1;
|
||||
ins->std.waveMacro.val[0] = waveOff;
|
||||
} else {
|
||||
for (int p=0; p<ins->std.waveMacro.len; p++) {
|
||||
ins->std.waveMacro.val[p] += waveOff;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1945,7 +1938,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
for (int v = 0; v < 8; v++) {
|
||||
if (map_channels[ch] == n163_chans[v]) {
|
||||
if (pat->data[row][4 + (j * 2)] == 0x12) {
|
||||
pat->data[row][4 + (j * 2)] = 0x10; // TODO: map wave
|
||||
pat->data[row][4 + (j * 2)] = 0x110; // N163 wave change (we'll map this later)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2773,6 +2766,46 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (i->virtualTempoD<1) i->virtualTempoD=1;
|
||||
}
|
||||
|
||||
// offset N163 wave macros (local -> global wave conversion)
|
||||
for (size_t i=0; i<ds.ins.size(); i++) {
|
||||
DivInstrument* ins=ds.ins[i];
|
||||
int waveOff=n163WaveOff[i];
|
||||
if (ins->type==DIV_INS_N163) {
|
||||
for (int j=0; j<ins->std.waveMacro.len; j++) {
|
||||
ins->std.waveMacro.val[j]+=waveOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// offset N163 wave change effects whether possible
|
||||
for (DivSubSong* i: ds.subsong) {
|
||||
for (int j=0; j<total_chans; j++) {
|
||||
int curWaveOff=0;
|
||||
for (int k=0; k<i->ordersLen; k++) {
|
||||
DivPattern* p=i->pat[j].getPattern(i->orders.ord[j][k],true);
|
||||
for (int l=0; l<i->patLen; l++) {
|
||||
// check for instrument change
|
||||
if (p->data[l][2]!=-1) {
|
||||
curWaveOff=n163WaveOff[p->data[l][2]&127];
|
||||
}
|
||||
|
||||
// check effect columns for 0x110 (dummy wave change)
|
||||
for (int m=0; m<i->pat[j].effectCols; m++) {
|
||||
if (p->data[l][4+(m<<1)]==0x110) {
|
||||
// map wave
|
||||
p->data[l][4+(m<<1)]=0x10;
|
||||
if (p->data[l][5+(m<<1)]==-1) {
|
||||
p->data[l][5+(m<<1)]=curWaveOff&0xff;
|
||||
} else {
|
||||
p->data[l][5+(m<<1)]=(p->data[l][5+(m<<1)]+curWaveOff)&0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active) quitDispatch();
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
|
|
|
|||
|
|
@ -692,9 +692,9 @@ void DivEngine::convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivS
|
|||
}
|
||||
|
||||
bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
||||
unsigned int insPtr[256];
|
||||
unsigned int wavePtr[256];
|
||||
unsigned int samplePtr[256];
|
||||
std::vector<unsigned int> insPtr;
|
||||
std::vector<unsigned int> wavePtr;
|
||||
std::vector<unsigned int> samplePtr;
|
||||
unsigned int subSongPtr[256];
|
||||
unsigned int sysFlagsPtr[DIV_MAX_CHIPS];
|
||||
unsigned int assetDirPtr[3];
|
||||
|
|
@ -934,13 +934,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
if (ds.waveLen<0 || ds.waveLen>256) {
|
||||
if (ds.waveLen<0 || ds.waveLen>32768) {
|
||||
logE("invalid wavetable count!");
|
||||
lastError="invalid wavetable count!";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
if (ds.sampleLen<0 || ds.sampleLen>256) {
|
||||
if (ds.sampleLen<0 || ds.sampleLen>32768) {
|
||||
logE("invalid sample count!");
|
||||
lastError="invalid sample count!";
|
||||
delete[] file;
|
||||
|
|
@ -1142,14 +1142,17 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
}
|
||||
|
||||
// pointers
|
||||
insPtr.reserve(ds.insLen);
|
||||
for (int i=0; i<ds.insLen; i++) {
|
||||
insPtr[i]=reader.readI();
|
||||
insPtr.push_back(reader.readI());
|
||||
}
|
||||
wavePtr.reserve(ds.waveLen);
|
||||
for (int i=0; i<ds.waveLen; i++) {
|
||||
wavePtr[i]=reader.readI();
|
||||
wavePtr.push_back(reader.readI());
|
||||
}
|
||||
samplePtr.reserve(ds.sampleLen);
|
||||
for (int i=0; i<ds.sampleLen; i++) {
|
||||
samplePtr[i]=reader.readI();
|
||||
samplePtr.push_back(reader.readI());
|
||||
}
|
||||
patPtr.reserve(numberOfPats);
|
||||
for (int i=0; i<numberOfPats; i++) patPtr.push_back(reader.readI());
|
||||
|
|
@ -2201,15 +2204,15 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
|
|||
saveLock.unlock();
|
||||
return NULL;
|
||||
}
|
||||
if (song.wave.size()>256) {
|
||||
logE("maximum number of wavetables is 256!");
|
||||
lastError="maximum number of wavetables is 256";
|
||||
if (song.wave.size()>32768) {
|
||||
logE("maximum number of wavetables is 32768!");
|
||||
lastError="maximum number of wavetables is 32768";
|
||||
saveLock.unlock();
|
||||
return NULL;
|
||||
}
|
||||
if (song.sample.size()>256) {
|
||||
logE("maximum number of samples is 256!");
|
||||
lastError="maximum number of samples is 256";
|
||||
if (song.sample.size()>32768) {
|
||||
logE("maximum number of samples is 32768!");
|
||||
lastError="maximum number of samples is 32768";
|
||||
saveLock.unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,23 +92,14 @@ void DivEngine::loadPPS(SafeReader& reader, std::vector<DivSample*>& ret, String
|
|||
|
||||
s->rate = PPS_SAMPLE_RATE;
|
||||
s->centerRate = PPS_SAMPLE_RATE;
|
||||
s->depth = DIV_SAMPLE_DEPTH_8BIT;
|
||||
s->init(headers[i].sample_length * 2); //byte per sample
|
||||
s->depth = DIV_SAMPLE_DEPTH_4BIT;
|
||||
s->init(headers[i].sample_length*2); // bytes->samples
|
||||
|
||||
reader.seek((int)headers[i].start_pointer, SEEK_SET);
|
||||
|
||||
int sample_pos = 0;
|
||||
|
||||
for(int j = 0; j < headers[i].sample_length; j++)
|
||||
{
|
||||
unsigned char curr_byte = (unsigned char)reader.readC();
|
||||
|
||||
s->data8[sample_pos] = (curr_byte >> 4) | (curr_byte & 0xf0);
|
||||
s->data8[sample_pos] += 0x80;
|
||||
sample_pos++;
|
||||
s->data8[sample_pos] = (curr_byte << 4) | (curr_byte & 0xf);
|
||||
s->data8[sample_pos] += 0x80;
|
||||
sample_pos++;
|
||||
s->data4[j] = reader.readC();
|
||||
}
|
||||
|
||||
ret.push_back(s);
|
||||
|
|
|
|||
|
|
@ -126,6 +126,13 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
w->writeText(fmt::sprintf("- type: %d\n",(int)ins->type));
|
||||
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPM || ins->type==DIV_INS_ESFM) {
|
||||
int opCount=4;
|
||||
if (ins->type==DIV_INS_OPLL) {
|
||||
opCount=2;
|
||||
} else if (ins->type==DIV_INS_OPL) {
|
||||
opCount=(ins->fm.ops==4)?4:2;
|
||||
}
|
||||
|
||||
w->writeText("- FM parameters:\n");
|
||||
w->writeText(fmt::sprintf(" - ALG: %d\n",ins->fm.alg));
|
||||
w->writeText(fmt::sprintf(" - FB: %d\n",ins->fm.fb));
|
||||
|
|
@ -133,14 +140,14 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
w->writeText(fmt::sprintf(" - AMS: %d\n",ins->fm.ams));
|
||||
w->writeText(fmt::sprintf(" - FMS2: %d\n",ins->fm.fms2));
|
||||
w->writeText(fmt::sprintf(" - AMS2: %d\n",ins->fm.ams2));
|
||||
w->writeText(fmt::sprintf(" - operators: %d\n",ins->fm.ops));
|
||||
w->writeText(fmt::sprintf(" - operators: %d\n",opCount));
|
||||
w->writeText(fmt::sprintf(" - OPLL patch: %d\n",ins->fm.opllPreset));
|
||||
w->writeText(fmt::sprintf(" - fixed drum freq: %s\n",trueFalse[ins->fm.fixedDrums?1:0]));
|
||||
w->writeText(fmt::sprintf(" - kick freq: %.4X\n",ins->fm.kickFreq));
|
||||
w->writeText(fmt::sprintf(" - snare/hat freq: %.4X\n",ins->fm.snareHatFreq));
|
||||
w->writeText(fmt::sprintf(" - tom/top freq: %.4X\n",ins->fm.tomTopFreq));
|
||||
|
||||
for (int j=0; j<ins->fm.ops; j++) {
|
||||
for (int j=0; j<opCount; j++) {
|
||||
DivInstrumentFM::Operator& op=ins->fm.op[j];
|
||||
|
||||
w->writeText(fmt::sprintf(" - operator %d:\n",j));
|
||||
|
|
@ -173,7 +180,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
w->writeText("- ESFM parameters:\n");
|
||||
w->writeText(fmt::sprintf(" - noise mode: %d\n",ins->esfm.noise));
|
||||
|
||||
for (int j=0; j<ins->fm.ops; j++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
DivInstrumentESFM::Operator& opE=ins->esfm.op[j];
|
||||
|
||||
w->writeText(fmt::sprintf(" - operator %d:\n",j));
|
||||
|
|
|
|||
|
|
@ -1334,7 +1334,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
ds.sampleLen=ds.sample.size();
|
||||
if (ds.sampleLen>256) {
|
||||
if (ds.sampleLen>32768) {
|
||||
logE("too many samples!");
|
||||
lastError="too many samples";
|
||||
ds.unload();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
std::vector<DivSample*> DivEngine::sampleFromFile(const char* path) {
|
||||
std::vector<DivSample*> ret;
|
||||
|
||||
if (song.sample.size()>=256) {
|
||||
if (song.sample.size()>=32768) {
|
||||
lastError="too many samples!";
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -313,12 +313,18 @@ std::vector<DivSample*> DivEngine::sampleFromFile(const char* path) {
|
|||
logD("sample is 32-bit float");
|
||||
buf=new float[si.channels*si.frames];
|
||||
sampleLen=sizeof(float);
|
||||
} else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_DOUBLE) {
|
||||
logD("sample is 64-bit float");
|
||||
buf=new float[si.channels*si.frames];
|
||||
sampleLen=sizeof(double);
|
||||
} else {
|
||||
logD("sample is 16-bit signed");
|
||||
buf=new short[si.channels*si.frames];
|
||||
sampleLen=sizeof(short);
|
||||
}
|
||||
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8 || (si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) {
|
||||
if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8 ||
|
||||
(si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT ||
|
||||
(si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_DOUBLE) {
|
||||
if (sf_read_raw(f,buf,si.frames*si.channels*sampleLen)!=(si.frames*si.channels*sampleLen)) {
|
||||
logW("sample read size mismatch!");
|
||||
}
|
||||
|
|
@ -361,6 +367,19 @@ std::vector<DivSample*> DivEngine::sampleFromFile(const char* path) {
|
|||
sample->data16[index++]=averaged;
|
||||
}
|
||||
delete[] (float*)buf;
|
||||
} else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_DOUBLE) {
|
||||
for (int i=0; i<si.frames*si.channels; i+=si.channels) {
|
||||
double averaged=0.0f;
|
||||
for (int j=0; j<si.channels; j++) {
|
||||
averaged+=((double*)buf)[i+j];
|
||||
}
|
||||
averaged/=si.channels;
|
||||
averaged*=32767.0;
|
||||
if (averaged<-32768.0) averaged=-32768.0;
|
||||
if (averaged>32767.0) averaged=32767.0;
|
||||
sample->data16[index++]=averaged;
|
||||
}
|
||||
delete[] (double*)buf;
|
||||
} else {
|
||||
for (int i=0; i<si.frames*si.channels; i+=si.channels) {
|
||||
int averaged=0;
|
||||
|
|
@ -413,7 +432,7 @@ std::vector<DivSample*> DivEngine::sampleFromFile(const char* path) {
|
|||
}
|
||||
|
||||
DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign, bool swapNibbles, int rate) {
|
||||
if (song.sample.size()>=256) {
|
||||
if (song.sample.size()>=32768) {
|
||||
lastError="too many samples!";
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -505,6 +524,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth,
|
|||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_K:
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
samples=lenDivided*2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_IMA_ADPCM:
|
||||
|
|
@ -617,6 +637,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth,
|
|||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||
case DIV_SAMPLE_DEPTH_ADPCM_K:
|
||||
case DIV_SAMPLE_DEPTH_VOX:
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
// swap nibbles
|
||||
for (unsigned int i=0; i<sample->getCurBufLen(); i++) {
|
||||
b[i]=(b[i]<<4)|(b[i]>>4);
|
||||
|
|
|
|||
|
|
@ -858,9 +858,11 @@ void DivInstrument::writeFeatureWS(SafeWriter* w) {
|
|||
FEATURE_END;
|
||||
}
|
||||
|
||||
size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector<int>& list, const DivSong* song) {
|
||||
bool sampleUsed[256];
|
||||
memset(sampleUsed,0,256*sizeof(bool));
|
||||
size_t DivInstrument::writeFeatureLS(SafeWriter* w, std::vector<int>& list, const DivSong* song) {
|
||||
if (song==NULL) return 0;
|
||||
|
||||
bool* sampleUsed=new bool[song->sample.size()];
|
||||
memset(sampleUsed,0,song->sample.size()*sizeof(bool));
|
||||
|
||||
if (amiga.initSample>=0 && amiga.initSample<(int)song->sample.size()) {
|
||||
sampleUsed[amiga.initSample]=true;
|
||||
|
|
@ -880,14 +882,16 @@ size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector<int>& list, cons
|
|||
}
|
||||
}
|
||||
|
||||
delete[] sampleUsed;
|
||||
|
||||
if (list.empty()) return 0;
|
||||
|
||||
FEATURE_BEGIN("SL");
|
||||
|
||||
w->writeC(list.size());
|
||||
w->writeS(list.size());
|
||||
|
||||
for (int i: list) {
|
||||
w->writeC(i);
|
||||
w->writeS(i);
|
||||
}
|
||||
|
||||
size_t ret=w->tell();
|
||||
|
|
@ -902,9 +906,11 @@ size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector<int>& list, cons
|
|||
return ret;
|
||||
}
|
||||
|
||||
size_t DivInstrument::writeFeatureWL(SafeWriter* w, std::vector<int>& list, const DivSong* song) {
|
||||
bool waveUsed[256];
|
||||
memset(waveUsed,0,256*sizeof(bool));
|
||||
size_t DivInstrument::writeFeatureLW(SafeWriter* w, std::vector<int>& list, const DivSong* song) {
|
||||
if (song==NULL) return 0;
|
||||
|
||||
bool* waveUsed=new bool[song->wave.size()];
|
||||
memset(waveUsed,0,song->wave.size()*sizeof(bool));
|
||||
|
||||
for (int i=0; i<std.waveMacro.len; i++) {
|
||||
if (std.waveMacro.val[i]>=0 && std.waveMacro.val[i]<(int)song->wave.size()) {
|
||||
|
|
@ -931,10 +937,10 @@ size_t DivInstrument::writeFeatureWL(SafeWriter* w, std::vector<int>& list, cons
|
|||
|
||||
FEATURE_BEGIN("WL");
|
||||
|
||||
w->writeC(list.size());
|
||||
w->writeS(list.size());
|
||||
|
||||
for (int i: list) {
|
||||
w->writeC(i);
|
||||
w->writeS(i);
|
||||
}
|
||||
|
||||
size_t ret=w->tell();
|
||||
|
|
@ -1621,10 +1627,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
writeFeatureWS(w);
|
||||
}
|
||||
if (featureSL) {
|
||||
slSeek=writeFeatureSL(w,sampleList,song);
|
||||
slSeek=writeFeatureLS(w,sampleList,song);
|
||||
}
|
||||
if (featureWL) {
|
||||
wlSeek=writeFeatureWL(w,waveList,song);
|
||||
wlSeek=writeFeatureLW(w,waveList,song);
|
||||
}
|
||||
if (featureMP) {
|
||||
writeFeatureMP(w);
|
||||
|
|
@ -2275,17 +2281,17 @@ void DivInstrument::readFeatureWS(SafeReader& reader, short version) {
|
|||
void DivInstrument::readFeatureSL(SafeReader& reader, DivSong* song, short version) {
|
||||
READ_FEAT_BEGIN;
|
||||
|
||||
unsigned int samplePtr[256];
|
||||
unsigned char sampleIndex[256];
|
||||
unsigned char sampleRemap[256];
|
||||
memset(samplePtr,0,256*sizeof(unsigned int));
|
||||
memset(sampleIndex,0,256);
|
||||
memset(sampleRemap,0,256);
|
||||
unsigned int* samplePtr=new unsigned int[32768];
|
||||
unsigned short* sampleIndex=new unsigned short[65536];
|
||||
unsigned short* sampleRemap=new unsigned short[65536];
|
||||
memset(samplePtr,0,32768*sizeof(unsigned int));
|
||||
memset(sampleIndex,0,65536*sizeof(unsigned short));
|
||||
memset(sampleRemap,0,65536*sizeof(unsigned short));
|
||||
|
||||
unsigned char sampleCount=reader.readC();
|
||||
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
sampleIndex[i]=reader.readC();
|
||||
sampleIndex[i]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
samplePtr[i]=reader.readI();
|
||||
|
|
@ -2296,7 +2302,7 @@ void DivInstrument::readFeatureSL(SafeReader& reader, DivSong* song, short versi
|
|||
// load samples
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
reader.seek(samplePtr[i],SEEK_SET);
|
||||
if (song->sample.size()>=256) {
|
||||
if (song->sample.size()>=32768) {
|
||||
break;
|
||||
}
|
||||
DivSample* sample=new DivSample;
|
||||
|
|
@ -2316,35 +2322,39 @@ void DivInstrument::readFeatureSL(SafeReader& reader, DivSong* song, short versi
|
|||
reader.seek(lastSeek,SEEK_SET);
|
||||
|
||||
// re-map samples
|
||||
if (amiga.initSample>=0 && amiga.initSample<256) {
|
||||
if (amiga.initSample>=0) {
|
||||
amiga.initSample=sampleRemap[amiga.initSample];
|
||||
}
|
||||
|
||||
if (amiga.useNoteMap) {
|
||||
for (int i=0; i<120; i++) {
|
||||
if (amiga.noteMap[i].map>=0 && amiga.noteMap[i].map<256) {
|
||||
if (amiga.noteMap[i].map>=0) {
|
||||
amiga.noteMap[i].map=sampleRemap[amiga.noteMap[i].map];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] samplePtr;
|
||||
delete[] sampleIndex;
|
||||
delete[] sampleRemap;
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
void DivInstrument::readFeatureWL(SafeReader& reader, DivSong* song, short version) {
|
||||
READ_FEAT_BEGIN;
|
||||
|
||||
unsigned int wavePtr[256];
|
||||
unsigned char waveIndex[256];
|
||||
unsigned char waveRemap[256];
|
||||
memset(wavePtr,0,256*sizeof(unsigned int));
|
||||
memset(waveIndex,0,256);
|
||||
memset(waveRemap,0,256);
|
||||
unsigned int* wavePtr=new unsigned int[32768];
|
||||
unsigned short* waveIndex=new unsigned short[65536];
|
||||
unsigned short* waveRemap=new unsigned short[65536];
|
||||
memset(wavePtr,0,32768*sizeof(unsigned int));
|
||||
memset(waveIndex,0,65536*sizeof(unsigned short));
|
||||
memset(waveRemap,0,65536*sizeof(unsigned short));
|
||||
|
||||
unsigned char waveCount=reader.readC();
|
||||
|
||||
for (int i=0; i<waveCount; i++) {
|
||||
waveIndex[i]=reader.readC();
|
||||
waveIndex[i]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (int i=0; i<waveCount; i++) {
|
||||
wavePtr[i]=reader.readI();
|
||||
|
|
@ -2355,7 +2365,7 @@ void DivInstrument::readFeatureWL(SafeReader& reader, DivSong* song, short versi
|
|||
// load wavetables
|
||||
for (int i=0; i<waveCount; i++) {
|
||||
reader.seek(wavePtr[i],SEEK_SET);
|
||||
if (song->wave.size()>=256) {
|
||||
if (song->wave.size()>=32768) {
|
||||
break;
|
||||
}
|
||||
DivWavetable* wave=new DivWavetable;
|
||||
|
|
@ -2376,16 +2386,164 @@ void DivInstrument::readFeatureWL(SafeReader& reader, DivSong* song, short versi
|
|||
|
||||
// re-map wavetables
|
||||
if (ws.enabled) {
|
||||
if (ws.wave1>=0 && ws.wave1<256) ws.wave1=waveRemap[ws.wave1];
|
||||
if (ws.wave1>=0 && ws.wave1<32768) ws.wave1=waveRemap[ws.wave1];
|
||||
if (ws.effect&0x80) {
|
||||
if (ws.wave2>=0 && ws.wave2<256) ws.wave2=waveRemap[ws.wave2];
|
||||
if (ws.wave2>=0 && ws.wave2<32768) ws.wave2=waveRemap[ws.wave2];
|
||||
}
|
||||
}
|
||||
if (n163.wave>=0 && n163.wave<256) n163.wave=waveRemap[n163.wave];
|
||||
if (n163.wave>=0 && n163.wave<32768) n163.wave=waveRemap[n163.wave];
|
||||
for (int i=0; i<std.waveMacro.len; i++) {
|
||||
if (std.waveMacro.val[i]>=0 && std.waveMacro.val[i]<256) std.waveMacro.val[i]=waveRemap[std.waveMacro.val[i]];
|
||||
if (std.waveMacro.val[i]>=0 && std.waveMacro.val[i]<32768) std.waveMacro.val[i]=waveRemap[std.waveMacro.val[i]];
|
||||
}
|
||||
|
||||
delete[] wavePtr;
|
||||
delete[] waveIndex;
|
||||
delete[] waveRemap;
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
// new versions
|
||||
void DivInstrument::readFeatureLS(SafeReader& reader, DivSong* song, short version) {
|
||||
READ_FEAT_BEGIN;
|
||||
|
||||
unsigned int* samplePtr=new unsigned int[32768];
|
||||
unsigned short* sampleIndex=new unsigned short[65536];
|
||||
unsigned short* sampleRemap=new unsigned short[65536];
|
||||
memset(samplePtr,0,32768*sizeof(unsigned int));
|
||||
memset(sampleIndex,0,65536*sizeof(unsigned short));
|
||||
memset(sampleRemap,0,65536*sizeof(unsigned short));
|
||||
|
||||
unsigned short sampleCount=reader.readS();
|
||||
|
||||
if (sampleCount>32768) {
|
||||
logW("invalid sample count!");
|
||||
delete[] samplePtr;
|
||||
delete[] sampleIndex;
|
||||
delete[] sampleRemap;
|
||||
READ_FEAT_END;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
sampleIndex[i]=(unsigned short)reader.readS();
|
||||
}
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
samplePtr[i]=reader.readI();
|
||||
}
|
||||
|
||||
size_t lastSeek=reader.tell();
|
||||
|
||||
// load samples
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
reader.seek(samplePtr[i],SEEK_SET);
|
||||
if (song->sample.size()>=32768) {
|
||||
break;
|
||||
}
|
||||
DivSample* sample=new DivSample;
|
||||
int sampleCount=(int)song->sample.size();
|
||||
|
||||
DivDataErrors result=sample->readSampleData(reader,version);
|
||||
if (result==DIV_DATA_SUCCESS) {
|
||||
song->sample.push_back(sample);
|
||||
song->sampleLen=sampleCount+1;
|
||||
sampleRemap[sampleIndex[i]]=sampleCount;
|
||||
} else {
|
||||
delete sample;
|
||||
sampleRemap[sampleIndex[i]]=0;
|
||||
}
|
||||
}
|
||||
|
||||
reader.seek(lastSeek,SEEK_SET);
|
||||
|
||||
// re-map samples
|
||||
if (amiga.initSample>=0) {
|
||||
amiga.initSample=sampleRemap[amiga.initSample];
|
||||
}
|
||||
|
||||
if (amiga.useNoteMap) {
|
||||
for (int i=0; i<120; i++) {
|
||||
if (amiga.noteMap[i].map>=0) {
|
||||
amiga.noteMap[i].map=sampleRemap[amiga.noteMap[i].map];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] samplePtr;
|
||||
delete[] sampleIndex;
|
||||
delete[] sampleRemap;
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
void DivInstrument::readFeatureLW(SafeReader& reader, DivSong* song, short version) {
|
||||
READ_FEAT_BEGIN;
|
||||
|
||||
unsigned int* wavePtr=new unsigned int[32768];
|
||||
unsigned short* waveIndex=new unsigned short[65536];
|
||||
unsigned short* waveRemap=new unsigned short[65536];
|
||||
memset(wavePtr,0,32768*sizeof(unsigned int));
|
||||
memset(waveIndex,0,65536*sizeof(unsigned short));
|
||||
memset(waveRemap,0,65536*sizeof(unsigned short));
|
||||
|
||||
unsigned short waveCount=reader.readS();
|
||||
|
||||
if (waveCount>32768) {
|
||||
logW("invalid wave count!");
|
||||
delete[] wavePtr;
|
||||
delete[] waveIndex;
|
||||
delete[] waveRemap;
|
||||
READ_FEAT_END;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; i<waveCount; i++) {
|
||||
waveIndex[i]=(unsigned short)reader.readS();
|
||||
}
|
||||
for (int i=0; i<waveCount; i++) {
|
||||
wavePtr[i]=reader.readI();
|
||||
}
|
||||
|
||||
size_t lastSeek=reader.tell();
|
||||
|
||||
// load wavetables
|
||||
for (int i=0; i<waveCount; i++) {
|
||||
reader.seek(wavePtr[i],SEEK_SET);
|
||||
if (song->wave.size()>=32768) {
|
||||
break;
|
||||
}
|
||||
DivWavetable* wave=new DivWavetable;
|
||||
int waveCount=(int)song->wave.size();
|
||||
|
||||
DivDataErrors result=wave->readWaveData(reader,version);
|
||||
if (result==DIV_DATA_SUCCESS) {
|
||||
song->wave.push_back(wave);
|
||||
song->waveLen=waveCount+1;
|
||||
waveRemap[waveIndex[i]]=waveCount;
|
||||
} else {
|
||||
delete wave;
|
||||
waveRemap[waveIndex[i]]=0;
|
||||
}
|
||||
}
|
||||
|
||||
reader.seek(lastSeek,SEEK_SET);
|
||||
|
||||
// re-map wavetables
|
||||
if (ws.enabled) {
|
||||
if (ws.wave1>=0 && ws.wave1<32768) ws.wave1=waveRemap[ws.wave1];
|
||||
if (ws.effect&0x80) {
|
||||
if (ws.wave2>=0 && ws.wave2<32768) ws.wave2=waveRemap[ws.wave2];
|
||||
}
|
||||
}
|
||||
if (n163.wave>=0 && n163.wave<32768) n163.wave=waveRemap[n163.wave];
|
||||
for (int i=0; i<std.waveMacro.len; i++) {
|
||||
if (std.waveMacro.val[i]>=0 && std.waveMacro.val[i]<32768) std.waveMacro.val[i]=waveRemap[std.waveMacro.val[i]];
|
||||
}
|
||||
|
||||
delete[] wavePtr;
|
||||
delete[] waveIndex;
|
||||
delete[] waveRemap;
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
|
|
@ -2647,10 +2805,14 @@ DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, b
|
|||
readFeatureFD(reader,version);
|
||||
} else if (memcmp(featCode,"WS",2)==0) { // WaveSynth
|
||||
readFeatureWS(reader,version);
|
||||
} else if (memcmp(featCode,"SL",2)==0 && fui && song!=NULL) { // sample list
|
||||
} else if (memcmp(featCode,"SL",2)==0 && fui && song!=NULL) { // sample list (old)
|
||||
readFeatureSL(reader,song,version);
|
||||
} else if (memcmp(featCode,"WL",2)==0 && fui && song!=NULL) { // wave list
|
||||
} else if (memcmp(featCode,"WL",2)==0 && fui && song!=NULL) { // wave list (old)
|
||||
readFeatureWL(reader,song,version);
|
||||
} else if (memcmp(featCode,"LS",2)==0 && fui && song!=NULL) { // sample list (new)
|
||||
readFeatureLS(reader,song,version);
|
||||
} else if (memcmp(featCode,"LW",2)==0 && fui && song!=NULL) { // wave list (new)
|
||||
readFeatureLW(reader,song,version);
|
||||
} else if (memcmp(featCode,"MP",2)==0) { // MultiPCM
|
||||
readFeatureMP(reader,version);
|
||||
} else if (memcmp(featCode,"SU",2)==0) { // Sound Unit
|
||||
|
|
|
|||
|
|
@ -1097,8 +1097,8 @@ struct DivInstrument : DivInstrumentPOD {
|
|||
void writeFeatureN1(SafeWriter* w);
|
||||
void writeFeatureFD(SafeWriter* w);
|
||||
void writeFeatureWS(SafeWriter* w);
|
||||
size_t writeFeatureSL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||
size_t writeFeatureWL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||
size_t writeFeatureLS(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||
size_t writeFeatureLW(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||
void writeFeatureMP(SafeWriter* w);
|
||||
void writeFeatureSU(SafeWriter* w);
|
||||
void writeFeatureES(SafeWriter* w);
|
||||
|
|
@ -1123,6 +1123,8 @@ struct DivInstrument : DivInstrumentPOD {
|
|||
void readFeatureWS(SafeReader& reader, short version);
|
||||
void readFeatureSL(SafeReader& reader, DivSong* song, short version);
|
||||
void readFeatureWL(SafeReader& reader, DivSong* song, short version);
|
||||
void readFeatureLS(SafeReader& reader, DivSong* song, short version);
|
||||
void readFeatureLW(SafeReader& reader, DivSong* song, short version);
|
||||
void readFeatureMP(SafeReader& reader, short version);
|
||||
void readFeatureSU(SafeReader& reader, short version);
|
||||
void readFeatureES(SafeReader& reader, short version);
|
||||
|
|
|
|||
|
|
@ -995,7 +995,7 @@ size_t DivPlatformAmiga::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformAmiga::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -1006,8 +1006,8 @@ const DivMemoryComposition* DivPlatformAmiga::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformAmiga::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,2097152);
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Chip Memory";
|
||||
|
|
@ -1082,3 +1082,14 @@ void DivPlatformAmiga::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformAmiga::DivPlatformAmiga() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformAmiga::~DivPlatformAmiga() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ class DivPlatformAmiga: public DivDispatch {
|
|||
|
||||
unsigned char volTable[64][64];
|
||||
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
|
||||
unsigned short regPool[256];
|
||||
|
||||
|
|
@ -171,6 +171,8 @@ class DivPlatformAmiga: public DivDispatch {
|
|||
const DivMemoryComposition* getMemCompo(int index);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformAmiga();
|
||||
~DivPlatformAmiga();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -602,7 +602,7 @@ size_t DivPlatformC140::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformC140::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -613,8 +613,8 @@ const DivMemoryComposition* DivPlatformC140::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformC140::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,is219?524288:16777216);
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -801,3 +801,14 @@ void DivPlatformC140::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformC140::DivPlatformC140() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformC140::~DivPlatformC140() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ class DivPlatformC140: public DivDispatch {
|
|||
Channel chan[24];
|
||||
DivDispatchOscBuffer* oscBuf[24];
|
||||
bool isMuted[24];
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
bool is219;
|
||||
int totalChans;
|
||||
unsigned char groupBank[4];
|
||||
|
|
@ -117,7 +117,8 @@ class DivPlatformC140: public DivDispatch {
|
|||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
private:
|
||||
DivPlatformC140();
|
||||
~DivPlatformC140();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -748,7 +748,7 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
if (amigaPitch && parent->song.linearPitch!=2) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch*16,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,2,chan[i].pitch2*16,16*COLOR_NTSC,chan[i].pcm.freqOffs);
|
||||
chan[i].freq=524288*(COLOR_NTSC/chan[i].freq)/(chipClock/32.0);
|
||||
chan[i].freq=PITCH_OFFSET*(COLOR_NTSC/chan[i].freq)/(chipClock/16.0);
|
||||
chan[i].freq=CLAMP(chan[i].freq,0,0x1ffff);
|
||||
} else {
|
||||
chan[i].freq=CLAMP(parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,chan[i].pcm.freqOffs),0,0x1ffff);
|
||||
|
|
@ -1439,7 +1439,7 @@ size_t DivPlatformES5506::getSampleMemOffset(int index) {
|
|||
|
||||
bool DivPlatformES5506::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -1450,8 +1450,8 @@ const DivMemoryComposition* DivPlatformES5506::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformES5506::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOffES5506,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffES5506,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample Memory";
|
||||
|
|
@ -1524,3 +1524,17 @@ void DivPlatformES5506::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformES5506::DivPlatformES5506():
|
||||
DivDispatch(),
|
||||
es550x_intf(),
|
||||
es5506(*this) {
|
||||
sampleOffES5506=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformES5506::~DivPlatformES5506() {
|
||||
delete[] sampleOffES5506;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,8 +232,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
bool isMuted[32];
|
||||
signed short* sampleMem; // ES5506 uses 16 bit data bus for samples
|
||||
size_t sampleMemLen;
|
||||
unsigned int sampleOffES5506[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffES5506;
|
||||
bool* sampleLoaded;
|
||||
struct QueuedHostIntf {
|
||||
unsigned char state;
|
||||
unsigned char step;
|
||||
|
|
@ -324,10 +324,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
virtual const char** getRegisterSheet() override;
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
DivPlatformES5506():
|
||||
DivDispatch(),
|
||||
es550x_intf(),
|
||||
es5506(*this) {}
|
||||
DivPlatformES5506();
|
||||
~DivPlatformES5506();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ class DivPlatformOPN: public DivPlatformFMBase {
|
|||
extSys(isExtSys),
|
||||
fbAllOps(false),
|
||||
useCombo(0) {}
|
||||
virtual ~DivPlatformOPN() {}
|
||||
public:
|
||||
void setCombo(unsigned char combo) {
|
||||
useCombo=combo;
|
||||
|
|
|
|||
|
|
@ -79,8 +79,10 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
unsigned int addr;
|
||||
unsigned short val;
|
||||
bool addrOrVal;
|
||||
QueuedWrite(): addr(0), val(0), addrOrVal(false) {}
|
||||
QueuedWrite(unsigned int a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||
bool urgent;
|
||||
QueuedWrite(): addr(0), val(0), addrOrVal(false), urgent(false) {}
|
||||
QueuedWrite(unsigned int a, unsigned char v): addr(a), val(v), addrOrVal(false), urgent(false) {}
|
||||
QueuedWrite(unsigned int a, unsigned char v, bool u): addr(a), val(v), addrOrVal(false), urgent(u) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,2048> writes;
|
||||
|
||||
|
|
@ -108,14 +110,7 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
// only used by OPN2 for DAC writes
|
||||
inline void urgentWrite(unsigned short a, unsigned char v) {
|
||||
if (!skipRegisterWrites && !flushFirst) {
|
||||
if (!writes.empty()) {
|
||||
// check for hard reset
|
||||
if (writes.front().addr==0xf0) {
|
||||
// replace hard reset with DAC write
|
||||
writes.pop_front();
|
||||
}
|
||||
}
|
||||
writes.push_front(QueuedWrite(a,v));
|
||||
writes.push_front(QueuedWrite(a,v,true));
|
||||
if (dumpWrites) {
|
||||
addWrite(a,v);
|
||||
}
|
||||
|
|
@ -152,6 +147,7 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
lastBusy(0),
|
||||
delay(0),
|
||||
flushFirst(false) {}
|
||||
virtual ~DivPlatformFMBase() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ size_t DivPlatformGA20::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformGA20::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -489,8 +489,8 @@ const DivMemoryComposition* DivPlatformGA20::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformGA20::renderSamples(int sysID) {
|
||||
memset(sampleMem,0x00,getSampleMemCapacity());
|
||||
memset(sampleOffGA20,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffGA20,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -558,3 +558,17 @@ void DivPlatformGA20::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformGA20::DivPlatformGA20():
|
||||
DivDispatch(),
|
||||
iremga20_intf(),
|
||||
ga20(*this) {
|
||||
sampleOffGA20=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformGA20::~DivPlatformGA20() {
|
||||
delete[] sampleOffGA20;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ class DivPlatformGA20: public DivDispatch, public iremga20_intf {
|
|||
val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,256> writes;
|
||||
unsigned int sampleOffGA20[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffGA20;
|
||||
bool* sampleLoaded;
|
||||
|
||||
int oldOut;
|
||||
|
||||
|
|
@ -104,10 +104,8 @@ class DivPlatformGA20: public DivDispatch, public iremga20_intf {
|
|||
virtual void renderSamples(int chipID) override;
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
DivPlatformGA20():
|
||||
DivDispatch(),
|
||||
iremga20_intf(),
|
||||
ga20(*this) {}
|
||||
DivPlatformGA20();
|
||||
~DivPlatformGA20();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ size_t DivPlatformGBADMA::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformGBADMA::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -463,6 +463,8 @@ const DivMemoryComposition* DivPlatformGBADMA::getMemCompo(int index) {
|
|||
void DivPlatformGBADMA::renderSamples(int sysID) {
|
||||
size_t maxPos=getSampleMemCapacity();
|
||||
memset(sampleMem,0,maxPos);
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
romMemCompo.entries.clear();
|
||||
romMemCompo.capacity=maxPos;
|
||||
|
||||
|
|
@ -533,3 +535,14 @@ void DivPlatformGBADMA::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformGBADMA::DivPlatformGBADMA() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformGBADMA::~DivPlatformGBADMA() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ class DivPlatformGBADMA: public DivDispatch {
|
|||
Channel chan[2];
|
||||
DivDispatchOscBuffer* oscBuf[2];
|
||||
bool isMuted[2];
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
int outDepth;
|
||||
|
||||
signed char* sampleMem;
|
||||
|
|
@ -93,6 +93,8 @@ class DivPlatformGBADMA: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformGBADMA();
|
||||
~DivPlatformGBADMA();
|
||||
|
||||
private:
|
||||
void updateWave(int ch);
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ size_t DivPlatformGBAMinMod::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformGBAMinMod::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -690,6 +690,8 @@ const DivMemoryComposition* DivPlatformGBAMinMod::getMemCompo(int index) {
|
|||
void DivPlatformGBAMinMod::renderSamples(int sysID) {
|
||||
size_t maxPos=getSampleMemCapacity();
|
||||
memset(sampleMem,0,maxPos);
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
romMemCompo.entries.clear();
|
||||
romMemCompo.capacity=maxPos;
|
||||
|
||||
|
|
@ -788,3 +790,14 @@ void DivPlatformGBAMinMod::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformGBAMinMod::DivPlatformGBAMinMod() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformGBAMinMod::~DivPlatformGBAMinMod() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ class DivPlatformGBAMinMod: public DivDispatch {
|
|||
Channel chan[16];
|
||||
DivDispatchOscBuffer* oscBuf[16];
|
||||
bool isMuted[16];
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
int volScale;
|
||||
unsigned char chanMax;
|
||||
|
||||
|
|
@ -121,6 +121,8 @@ class DivPlatformGBAMinMod: public DivDispatch {
|
|||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformGBAMinMod();
|
||||
~DivPlatformGBAMinMod();
|
||||
|
||||
float maxCPU;
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -150,17 +150,34 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
|
|||
|
||||
os[0]=0; os[1]=0;
|
||||
for (int i=0; i<6; i++) {
|
||||
if (delay<=0 && !writes.empty()) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addr==0xfffffffe) {
|
||||
delay=w.val*3;
|
||||
writes.pop_front();
|
||||
} else if (w.addrOrVal) {
|
||||
//logV("%.3x=%.2x",w.addr,w.val);
|
||||
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
if (delay<=0 || w.urgent) {
|
||||
if (w.addr==0xfffffffe) {
|
||||
delay=w.val*3;
|
||||
writes.pop_front();
|
||||
} else if (w.addrOrVal) {
|
||||
//logV("%.3x=%.2x",w.addr,w.val);
|
||||
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
} else {
|
||||
urgentWrite(0x2a,dacWrite);
|
||||
dacWrite=-1;
|
||||
canWriteDAC=writes.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fm.write_busy==0) {
|
||||
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
|
||||
w.addrOrVal=true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
|
|
@ -170,11 +187,6 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
|
|||
canWriteDAC=writes.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fm.write_busy==0) {
|
||||
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
|
||||
w.addrOrVal=true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
canWriteDAC=true;
|
||||
|
|
@ -244,24 +256,36 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
|
|||
if (delay>0) delay--;
|
||||
|
||||
os[0]=0; os[1]=0;
|
||||
if (delay<=0 && !writes.empty()) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addr==0xfffffffe) {
|
||||
delay=w.val;
|
||||
} else {
|
||||
fm_ymfm->write(0x0+((w.addr>>8)<<1),w.addr);
|
||||
fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val);
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
}
|
||||
writes.pop_front();
|
||||
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
if (delay<=0 || w.urgent) {
|
||||
if (w.addr==0xfffffffe) {
|
||||
delay=w.val;
|
||||
} else {
|
||||
urgentWrite(0x2a,dacWrite);
|
||||
dacWrite=-1;
|
||||
canWriteDAC=writes.empty();
|
||||
fm_ymfm->write(0x0+((w.addr>>8)<<1),w.addr);
|
||||
fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val);
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
}
|
||||
writes.pop_front();
|
||||
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
} else {
|
||||
urgentWrite(0x2a,dacWrite);
|
||||
dacWrite=-1;
|
||||
canWriteDAC=writes.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
} else {
|
||||
urgentWrite(0x2a,dacWrite);
|
||||
dacWrite=-1;
|
||||
canWriteDAC=writes.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -402,55 +426,89 @@ void DivPlatformGenesis::acquire_nuked276(short** buf, size_t len) {
|
|||
|
||||
if (delay>0) delay--;
|
||||
|
||||
if (delay<=0 && !writes.empty()) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addr==0xfffffffe) {
|
||||
delay=w.val;
|
||||
writes.pop_front();
|
||||
} else if (w.addrOrVal) {
|
||||
//logV("%.3x=%.2x",w.addr,w.val);
|
||||
//OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||
was_reg_write=true;
|
||||
if (delay<=0 || w.urgent) {
|
||||
if (w.addr==0xfffffffe) {
|
||||
delay=w.val;
|
||||
writes.pop_front();
|
||||
} else if (w.addrOrVal) {
|
||||
//logV("%.3x=%.2x",w.addr,w.val);
|
||||
//OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||
was_reg_write=true;
|
||||
|
||||
fm_276.input.address=w.addr<0x100?0:2;
|
||||
fm_276.input.data=w.addr&0xff;
|
||||
fm_276.input.wr=1;
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
fm_276.input.wr=0;
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
if (chipType==2) {
|
||||
if (!o_bco && fm_276.o_bco) {
|
||||
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||
|
||||
if (o_lro!=fm_276.o_lro) {
|
||||
if (o_lro)
|
||||
sample_l=dacShifter;
|
||||
else
|
||||
sample_r=dacShifter;
|
||||
}
|
||||
|
||||
o_lro=fm_276.o_lro;
|
||||
}
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
|
||||
for (int c=0; c<17; c++) {
|
||||
fm_276.input.address=w.addr<0x100?0:2;
|
||||
fm_276.input.data=w.addr&0xff;
|
||||
fm_276.input.wr=1;
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
fm_276.input.wr=0;
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
if (chipType==2) {
|
||||
if (!o_bco && fm_276.o_bco) {
|
||||
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||
|
||||
if (o_lro!=fm_276.o_lro) {
|
||||
if (o_lro)
|
||||
sample_l=dacShifter;
|
||||
else
|
||||
sample_r=dacShifter;
|
||||
}
|
||||
|
||||
o_lro=fm_276.o_lro;
|
||||
}
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
|
||||
for (int c=0; c<17; c++) {
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
if (chipType==2) {
|
||||
if (!o_bco && fm_276.o_bco) {
|
||||
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||
|
||||
if (o_lro!=fm_276.o_lro) {
|
||||
if (o_lro)
|
||||
sample_l=dacShifter;
|
||||
else
|
||||
sample_r=dacShifter;
|
||||
}
|
||||
|
||||
o_lro=fm_276.o_lro;
|
||||
}
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
}
|
||||
|
||||
fm_276.input.address=w.addr<0x100?1:3;
|
||||
fm_276.input.data=w.val;
|
||||
fm_276.input.wr=1;
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
fm_276.input.wr=0;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
|
@ -472,74 +530,54 @@ void DivPlatformGenesis::acquire_nuked276(short** buf, size_t len) {
|
|||
}
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
}
|
||||
|
||||
fm_276.input.address=w.addr<0x100?1:3;
|
||||
fm_276.input.data=w.val;
|
||||
fm_276.input.wr=1;
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
fm_276.input.wr=0;
|
||||
for (int c=0; c<83; c++) {
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
acquire276OscSub(h);
|
||||
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
acquire276OscSub(h);
|
||||
|
||||
if (chipType==2) {
|
||||
if (!o_bco && fm_276.o_bco) {
|
||||
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||
if (chipType==2) {
|
||||
if (!o_bco && fm_276.o_bco) {
|
||||
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||
|
||||
if (o_lro!=fm_276.o_lro) {
|
||||
if (o_lro)
|
||||
sample_l=dacShifter;
|
||||
else
|
||||
sample_r=dacShifter;
|
||||
}
|
||||
|
||||
o_lro=fm_276.o_lro;
|
||||
}
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
|
||||
for (int c=0; c<83; c++) {
|
||||
FMOPN2_Clock(&fm_276,0);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
FMOPN2_Clock(&fm_276,1);
|
||||
sum_l+=fm_276.out_l;
|
||||
sum_r+=fm_276.out_r;
|
||||
|
||||
acquire276OscSub(h);
|
||||
|
||||
if (chipType==2) {
|
||||
if (!o_bco && fm_276.o_bco) {
|
||||
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||
|
||||
if (o_lro!=fm_276.o_lro) {
|
||||
if (o_lro) {
|
||||
sample_l=dacShifter;
|
||||
} else {
|
||||
sample_r=dacShifter;
|
||||
if (o_lro!=fm_276.o_lro) {
|
||||
if (o_lro) {
|
||||
sample_l=dacShifter;
|
||||
} else {
|
||||
sample_r=dacShifter;
|
||||
}
|
||||
}
|
||||
|
||||
o_lro=fm_276.o_lro;
|
||||
}
|
||||
|
||||
o_lro=fm_276.o_lro;
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
o_bco=fm_276.o_bco;
|
||||
}
|
||||
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
} else {
|
||||
urgentWrite(0x2a,dacWrite);
|
||||
dacWrite=-1;
|
||||
canWriteDAC=writes.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.addrOrVal=true;
|
||||
}
|
||||
|
||||
regPool[w.addr&0x1ff]=w.val;
|
||||
writes.pop_front();
|
||||
|
||||
} else {
|
||||
if (dacWrite>=0) {
|
||||
if (!canWriteDAC) {
|
||||
canWriteDAC=true;
|
||||
|
|
@ -549,8 +587,6 @@ void DivPlatformGenesis::acquire_nuked276(short** buf, size_t len) {
|
|||
canWriteDAC=writes.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.addrOrVal=true;
|
||||
}
|
||||
} else {
|
||||
canWriteDAC=true;
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ size_t DivPlatformK007232::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformK007232::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -566,8 +566,8 @@ const DivMemoryComposition* DivPlatformK007232::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformK007232::renderSamples(int sysID) {
|
||||
memset(sampleMem,0xc0,getSampleMemCapacity());
|
||||
memset(sampleOffK007232,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffK007232,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -636,3 +636,17 @@ void DivPlatformK007232::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformK007232::DivPlatformK007232():
|
||||
DivDispatch(),
|
||||
k007232_intf(),
|
||||
k007232(*this) {
|
||||
sampleOffK007232=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformK007232::~DivPlatformK007232() {
|
||||
delete[] sampleOffK007232;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ class DivPlatformK007232: public DivDispatch, public k007232_intf {
|
|||
val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,256> writes;
|
||||
unsigned int sampleOffK007232[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffK007232;
|
||||
bool* sampleLoaded;
|
||||
|
||||
int delay;
|
||||
unsigned char lastLoop, lastVolume, oscDivider;
|
||||
|
|
@ -110,10 +110,8 @@ class DivPlatformK007232: public DivDispatch, public k007232_intf {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformK007232():
|
||||
DivDispatch(),
|
||||
k007232_intf(),
|
||||
k007232(*this) {}
|
||||
DivPlatformK007232();
|
||||
~DivPlatformK007232();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ void DivPlatformK053260::tick(bool sysTick) {
|
|||
unsigned int start=0;
|
||||
unsigned int length=0;
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
start=sampleOffK053260[sample];
|
||||
start=sampleOff[sample];
|
||||
length=(s->depth==DIV_SAMPLE_DEPTH_ADPCM_K)?s->lengthK:s->length8;
|
||||
if (chan[i].reverse) {
|
||||
start+=length;
|
||||
|
|
@ -474,7 +474,7 @@ size_t DivPlatformK053260::getSampleMemOffset(int index) {
|
|||
|
||||
bool DivPlatformK053260::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -485,8 +485,8 @@ const DivMemoryComposition* DivPlatformK053260::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformK053260::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOffK053260,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -495,7 +495,7 @@ void DivPlatformK053260::renderSamples(int sysID) {
|
|||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffK053260[i]=0;
|
||||
sampleOff[i]=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -505,7 +505,7 @@ void DivPlatformK053260::renderSamples(int sysID) {
|
|||
length=MIN(65535,s->getEndPosition(DIV_SAMPLE_DEPTH_ADPCM_K));
|
||||
actualLength=MIN((int)(getSampleMemCapacity()-memPos-getSampleMemOffset()),length);
|
||||
if (actualLength>0) {
|
||||
sampleOffK053260[i]=memPos-getSampleMemOffset();
|
||||
sampleOff[i]=memPos-getSampleMemOffset();
|
||||
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"Sample",i,memPos,memPos+actualLength+getSampleMemOffset()));
|
||||
for (int j=0; j<actualLength; j++) {
|
||||
sampleMem[memPos++]=s->dataK[j];
|
||||
|
|
@ -516,7 +516,7 @@ void DivPlatformK053260::renderSamples(int sysID) {
|
|||
length=MIN(65535,s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
actualLength=MIN((int)(getSampleMemCapacity()-memPos-getSampleMemOffset()),length);
|
||||
if (actualLength>0) {
|
||||
sampleOffK053260[i]=memPos-getSampleMemOffset();
|
||||
sampleOff[i]=memPos-getSampleMemOffset();
|
||||
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"Sample",i,memPos,memPos+actualLength+getSampleMemOffset()));
|
||||
for (int j=0; j<actualLength; j++) {
|
||||
sampleMem[memPos++]=s->data8[j];
|
||||
|
|
@ -559,3 +559,17 @@ void DivPlatformK053260::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformK053260::DivPlatformK053260():
|
||||
DivDispatch(),
|
||||
k053260_intf(),
|
||||
k053260(*this) {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformK053260::~DivPlatformK053260() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ class DivPlatformK053260: public DivDispatch, public k053260_intf {
|
|||
bool isMuted[4];
|
||||
int chipType;
|
||||
unsigned char curChan;
|
||||
unsigned int sampleOffK053260[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
@ -90,10 +90,8 @@ class DivPlatformK053260: public DivDispatch, public k053260_intf {
|
|||
virtual void renderSamples(int chipID) override;
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
DivPlatformK053260():
|
||||
DivDispatch(),
|
||||
k053260_intf(),
|
||||
k053260(*this) {}
|
||||
DivPlatformK053260();
|
||||
~DivPlatformK053260();
|
||||
private:
|
||||
void chWrite(unsigned char ch, unsigned int addr, unsigned char val);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ size_t DivPlatformMSM6295::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformMSM6295::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -395,12 +395,12 @@ const DivMemoryComposition* DivPlatformMSM6295::getMemCompo(int index) {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6295::renderSamples(int sysID) {
|
||||
unsigned int sampleOffVOX[256];
|
||||
unsigned int* sampleOffVOX=new unsigned int[32768];
|
||||
|
||||
memset(adpcmMem,0,16777216);
|
||||
memset(sampleOffVOX,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
for (int i=0; i<256; i++) {
|
||||
memset(sampleOffVOX,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
for (int i=0; i<32768; i++) {
|
||||
bankedPhrase[i].bank=0;
|
||||
bankedPhrase[i].phrase=0;
|
||||
}
|
||||
|
|
@ -412,10 +412,18 @@ void DivPlatformMSM6295::renderSamples(int sysID) {
|
|||
|
||||
// sample data
|
||||
size_t memPos=128*8;
|
||||
int sampleCount=parent->song.sampleLen;
|
||||
if (isBanked) {
|
||||
if (sampleCount>8191) {
|
||||
// mark the rest as unavailable
|
||||
for (int i=8191; i<sampleCount; i++) {
|
||||
sampleLoaded[i]=false;
|
||||
}
|
||||
sampleCount=8191;
|
||||
}
|
||||
int bankInd=0;
|
||||
int phraseInd=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
sampleOffVOX[i]=0;
|
||||
|
|
@ -455,7 +463,7 @@ void DivPlatformMSM6295::renderSamples(int sysID) {
|
|||
adpcmMemLen=memPos+256;
|
||||
|
||||
// phrase book
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
int endPos=sampleOffVOX[i]+bankedPhrase[i].length;
|
||||
for (int b=0; b<4; b++) {
|
||||
unsigned int bankedAddr=((unsigned int)bankedPhrase[i].bank<<16)+(b<<8)+(bankedPhrase[i].phrase*8);
|
||||
|
|
@ -468,8 +476,13 @@ void DivPlatformMSM6295::renderSamples(int sysID) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
int sampleCount=parent->song.sampleLen;
|
||||
if (sampleCount>127) sampleCount=127;
|
||||
if (sampleCount>127) {
|
||||
// mark the rest as unavailable
|
||||
for (int i=127; i<sampleCount; i++) {
|
||||
sampleLoaded[i]=false;
|
||||
}
|
||||
sampleCount=127;
|
||||
}
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
|
|
@ -510,6 +523,8 @@ void DivPlatformMSM6295::renderSamples(int sysID) {
|
|||
|
||||
memCompo.capacity=getSampleMemCapacity(0);
|
||||
memCompo.used=adpcmMemLen;
|
||||
|
||||
delete[] sampleOffVOX;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6295::setFlags(const DivConfig& flags) {
|
||||
|
|
@ -600,5 +615,16 @@ void DivPlatformMSM6295::quit() {
|
|||
delete[] adpcmMem;
|
||||
}
|
||||
|
||||
DivPlatformMSM6295::~DivPlatformMSM6295() {
|
||||
// initialization of important arrays
|
||||
DivPlatformMSM6295::DivPlatformMSM6295():
|
||||
DivDispatch(),
|
||||
vgsound_emu_mem_intf(),
|
||||
msm(*this) {
|
||||
bankedPhrase=new BankedPhrase[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformMSM6295::~DivPlatformMSM6295() {
|
||||
delete[] bankedPhrase;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
|
||||
unsigned char* adpcmMem;
|
||||
size_t adpcmMemLen;
|
||||
bool sampleLoaded[256];
|
||||
bool* sampleLoaded;
|
||||
unsigned char sampleBank;
|
||||
|
||||
int delay, updateOsc;
|
||||
|
|
@ -68,7 +68,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
bank(0),
|
||||
phrase(0),
|
||||
length(0) {}
|
||||
} bankedPhrase[256];
|
||||
}* bankedPhrase;
|
||||
|
||||
DivMemoryComposition memCompo;
|
||||
|
||||
|
|
@ -106,10 +106,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
DivPlatformMSM6295():
|
||||
DivDispatch(),
|
||||
vgsound_emu_mem_intf(),
|
||||
msm(*this) {}
|
||||
DivPlatformMSM6295();
|
||||
~DivPlatformMSM6295();
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ size_t DivPlatformNDS::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformNDS::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -542,8 +542,8 @@ const DivMemoryComposition* DivPlatformNDS::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformNDS::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,16777216);
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Main Memory";
|
||||
|
|
@ -629,3 +629,17 @@ void DivPlatformNDS::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformNDS::DivPlatformNDS():
|
||||
DivDispatch(),
|
||||
nds_sound_intf(),
|
||||
nds(*this) {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformNDS::~DivPlatformNDS() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf {
|
|||
bool isDSi;
|
||||
int globalVolume;
|
||||
int lastOut[2];
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char size;
|
||||
|
|
@ -104,10 +104,8 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf {
|
|||
virtual void setFlags(const DivConfig& flags) override;
|
||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||
virtual void quit() override;
|
||||
DivPlatformNDS():
|
||||
DivDispatch(),
|
||||
nds_sound_intf(),
|
||||
nds(*this) {}
|
||||
DivPlatformNDS();
|
||||
~DivPlatformNDS();
|
||||
private:
|
||||
void writeOutVol(int ch);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -352,9 +352,6 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].sweepChanged) {
|
||||
chan[i].sweepChanged=false;
|
||||
if (i==0) {
|
||||
// rWrite(16+i*5,chan[i].sweep);
|
||||
}
|
||||
}
|
||||
if (i<3) if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
|
|
@ -637,6 +634,13 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
} else if (!parent->song.brokenOutVol2) {
|
||||
rWrite(0x4000+c.chan*4,(chan[c.chan].envMode<<4)|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
|
||||
}
|
||||
if (resetSweep && c.chan<2) {
|
||||
if (chan[c.chan].sweep!=0x08 && !chan[c.chan].sweepChanged) {
|
||||
chan[c.chan].sweep=0x08;
|
||||
chan[c.chan].prevFreq=-1;
|
||||
rWrite(0x4001+(c.chan*4),chan[c.chan].sweep);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan==4) {
|
||||
|
|
@ -724,6 +728,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
}
|
||||
}
|
||||
rWrite(0x4001+(c.chan*4),chan[c.chan].sweep);
|
||||
chan[c.chan].sweepChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NES_ENV_MODE:
|
||||
chan[c.chan].envMode=c.value&3;
|
||||
|
|
@ -989,6 +994,7 @@ void DivPlatformNES::setFlags(const DivConfig& flags) {
|
|||
}
|
||||
|
||||
dpcmModeDefault=flags.getBool("dpcmMode",true);
|
||||
resetSweep=flags.getBool("resetSweep",false);
|
||||
}
|
||||
|
||||
void DivPlatformNES::notifyInsDeletion(void* ins) {
|
||||
|
|
@ -1033,7 +1039,7 @@ size_t DivPlatformNES::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformNES::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -1044,7 +1050,8 @@ const DivMemoryComposition* DivPlatformNES::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformNES::renderSamples(int sysID) {
|
||||
memset(dpcmMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffDPCM,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="DPCM";
|
||||
|
|
@ -1150,5 +1157,13 @@ void DivPlatformNES::quit() {
|
|||
}
|
||||
}
|
||||
|
||||
DivPlatformNES::~DivPlatformNES() {
|
||||
// initialization of important arrays
|
||||
DivPlatformNES::DivPlatformNES() {
|
||||
sampleOffDPCM=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformNES::~DivPlatformNES() {
|
||||
delete[] sampleOffDPCM;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
int dacSample;
|
||||
unsigned char* dpcmMem;
|
||||
size_t dpcmMemLen;
|
||||
bool sampleLoaded[256];
|
||||
bool* sampleLoaded;
|
||||
unsigned char dpcmBank;
|
||||
unsigned char sampleBank;
|
||||
unsigned char writeOscBuf;
|
||||
|
|
@ -68,6 +68,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
signed char lastDPCMFreq;
|
||||
bool dpcmMode;
|
||||
bool dpcmModeDefault;
|
||||
bool resetSweep;
|
||||
bool dacAntiClickOn;
|
||||
bool useNP;
|
||||
bool goingToLoop;
|
||||
|
|
@ -79,7 +80,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
xgm::I5E01_APU* e1_NP;
|
||||
xgm::I5E01_DMC* e2_NP;
|
||||
unsigned char regPool[128];
|
||||
unsigned int sampleOffDPCM[256];
|
||||
unsigned int* sampleOffDPCM;
|
||||
DivMemoryComposition memCompo;
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
|
|
@ -123,6 +124,7 @@ class DivPlatformNES: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformNES();
|
||||
~DivPlatformNES();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@
|
|||
#define PCM_CHECK(ch) ((chipType==4) && (ch>=pcmChanOffs))
|
||||
#define PCM_REG(ch) (ch-pcmChanOffs)
|
||||
|
||||
// check if PCM in RAM (and size is <= 2MB) - 4MB uses whole sample area
|
||||
#define PCM_IN_RAM (ramSize<=0x200000)
|
||||
|
||||
// N = invalid
|
||||
#define N 255
|
||||
|
||||
|
|
@ -1338,7 +1341,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
unsigned char slot=slots[j][i];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
if (baseAddr>0x100) {
|
||||
if (baseAddr>=0x100) {
|
||||
weWillWriteRRLater[(baseAddr&0xff)|32]=true;
|
||||
} else {
|
||||
weWillWriteRRLater[(baseAddr&0xff)]=true;
|
||||
|
|
@ -1464,38 +1467,43 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
chan[i].freqL=(chan[i].freq>>chan[i].freqH)&0x3ff;
|
||||
chan[i].freqH=8^chan[i].freqH;
|
||||
ctrl|=(chan[i].active?0x80:0)|(chan[i].damp?0x40:0)|(chan[i].lfoReset?0x20:0)|(chan[i].ch?0x10:0)|(isMuted[i]?8:(chan[i].pan&0xf));
|
||||
unsigned int waveNum=chan[i].sample;
|
||||
if (ramSize<=0x200000) {
|
||||
waveNum=CLAMP(waveNum,0,0x7f)|0x180;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
immWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl&~0x80); // force keyoff first
|
||||
immWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
immWrite(PCM_ADDR_WAVE_L+PCM_REG(i),waveNum&0xff);
|
||||
immWrite(PCM_ADDR_LFO_VIB+PCM_REG(i),(chan[i].lfo<<3)|(chan[i].vib));
|
||||
immWrite(PCM_ADDR_AR_D1R+PCM_REG(i),(chan[i].ar<<4)|(chan[i].d1r));
|
||||
immWrite(PCM_ADDR_DL_D2R+PCM_REG(i),(chan[i].dl<<4)|(chan[i].d2r));
|
||||
immWrite(PCM_ADDR_RC_RR+PCM_REG(i),(chan[i].rc<<4)|(chan[i].rr));
|
||||
immWrite(PCM_ADDR_AM+PCM_REG(i),chan[i].am);
|
||||
if (!chan[i].std.vol.had) {
|
||||
chan[i].outVol=chan[i].vol;
|
||||
immWrite(PCM_ADDR_TL+(PCM_REG(i)),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
|
||||
int waveNum=chan[i].sample;
|
||||
if (waveNum>=0) {
|
||||
if (PCM_IN_RAM) {
|
||||
waveNum=CLAMP(waveNum,0,0x7f)|0x180;
|
||||
}
|
||||
chan[i].writeCtrl=true;
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
chan[i].writeCtrl=true;
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].freqChanged) {
|
||||
immWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
immWrite(PCM_ADDR_FN_H_PR_OCT+PCM_REG(i),((chan[i].freqH&0xf)<<4)|(chan[i].pseudoReverb?0x08:0x00)|((chan[i].freqL>>7)&0x7));
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].writeCtrl) {
|
||||
immWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl);
|
||||
chan[i].writeCtrl=false;
|
||||
if (chan[i].keyOn) {
|
||||
immWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl&~0x80); // force keyoff first
|
||||
immWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
immWrite(PCM_ADDR_WAVE_L+PCM_REG(i),waveNum&0xff);
|
||||
immWrite(PCM_ADDR_LFO_VIB+PCM_REG(i),(chan[i].lfo<<3)|(chan[i].vib));
|
||||
immWrite(PCM_ADDR_AR_D1R+PCM_REG(i),(chan[i].ar<<4)|(chan[i].d1r));
|
||||
immWrite(PCM_ADDR_DL_D2R+PCM_REG(i),(chan[i].dl<<4)|(chan[i].d2r));
|
||||
immWrite(PCM_ADDR_RC_RR+PCM_REG(i),(chan[i].rc<<4)|(chan[i].rr));
|
||||
immWrite(PCM_ADDR_AM+PCM_REG(i),chan[i].am);
|
||||
if (!chan[i].std.vol.had) {
|
||||
chan[i].outVol=chan[i].vol;
|
||||
immWrite(PCM_ADDR_TL+(PCM_REG(i)),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
|
||||
}
|
||||
chan[i].writeCtrl=true;
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
chan[i].writeCtrl=true;
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].freqChanged) {
|
||||
immWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
immWrite(PCM_ADDR_FN_H_PR_OCT+PCM_REG(i),((chan[i].freqH&0xf)<<4)|(chan[i].pseudoReverb?0x08:0x00)|((chan[i].freqL>>7)&0x7));
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].writeCtrl) {
|
||||
immWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl);
|
||||
chan[i].writeCtrl=false;
|
||||
}
|
||||
} else {
|
||||
// cut if we don't have a sample
|
||||
immWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl&~0x80);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2936,7 +2944,7 @@ void DivPlatformOPL::reset() {
|
|||
if (chipType==4) {
|
||||
immWrite(0x105,3);
|
||||
// Reset wavetable header
|
||||
immWrite(0x202,(ramSize<=0x200000)?0x10:0x00);
|
||||
immWrite(0x202,PCM_IN_RAM?0x10:0x00);
|
||||
// initialize mixer volume
|
||||
fmMixL=7;
|
||||
fmMixR=7;
|
||||
|
|
@ -3204,7 +3212,7 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
|
|||
pcm.setClockFrequency(chipClock);
|
||||
rate=chipClock/768;
|
||||
chipRateBase=chipClock/684;
|
||||
immWrite(0x202,(ramSize<=0x200000)?0x10:0x00);
|
||||
immWrite(0x202,PCM_IN_RAM?0x10:0x00);
|
||||
break;
|
||||
case 759:
|
||||
rate=48000;
|
||||
|
|
@ -3227,7 +3235,7 @@ const void* DivPlatformOPL::getSampleMem(int index) {
|
|||
|
||||
size_t DivPlatformOPL::getSampleMemCapacity(int index) {
|
||||
return (index==0 && pcmChanOffs>=0)?
|
||||
((ramSize<=0x200000)?0x200000+ramSize:ramSize):
|
||||
(PCM_IN_RAM?0x200000+ramSize:ramSize):
|
||||
((index==0 && adpcmChan>=0)?262144:0);
|
||||
}
|
||||
|
||||
|
|
@ -3242,7 +3250,7 @@ size_t DivPlatformOPL::getSampleMemOffset(int index) {
|
|||
|
||||
bool DivPlatformOPL::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -3260,18 +3268,24 @@ void DivPlatformOPL::renderSamples(int sysID) {
|
|||
if (pcmChanOffs>=0 && pcmMem!=NULL) {
|
||||
memset(pcmMem,0,4194304);
|
||||
}
|
||||
memset(sampleOffPCM,0,256*sizeof(unsigned int));
|
||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffPCM,0,32768*sizeof(unsigned int));
|
||||
memset(sampleOffB,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample Memory";
|
||||
|
||||
if (pcmChanOffs>=0) { // OPL4 PCM
|
||||
size_t memPos=((ramSize<=0x200000)?0x200600:0x1800);
|
||||
const int maxSample=(ramSize<=0x200000)?127:511;
|
||||
size_t memPos=(PCM_IN_RAM?0x200600:0x1800);
|
||||
const int maxSample=PCM_IN_RAM?128:512;
|
||||
int sampleCount=parent->song.sampleLen;
|
||||
if (sampleCount>maxSample) sampleCount=maxSample;
|
||||
if (sampleCount>maxSample) {
|
||||
// mark the rest as unavailable
|
||||
for (int i=maxSample; i<sampleCount; i++) {
|
||||
sampleLoaded[i]=false;
|
||||
}
|
||||
sampleCount=maxSample;
|
||||
}
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
if (!s->renderOn[0][sysID]) {
|
||||
|
|
@ -3334,7 +3348,7 @@ void DivPlatformOPL::renderSamples(int sysID) {
|
|||
// instrument table
|
||||
for (int i=0; i<sampleCount; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
unsigned int insAddr=(i*12)+((ramSize<=0x200000)?0x200000:0);
|
||||
unsigned int insAddr=(i*12)+(PCM_IN_RAM?0x200000:0);
|
||||
unsigned char bitDepth;
|
||||
int endPos=CLAMP(s->isLoopable()?s->loopEnd:(s->samples+1),1,0x10000);
|
||||
int loop=s->isLoopable()?CLAMP(s->loopStart,0,endPos-2):(endPos-2);
|
||||
|
|
@ -3365,12 +3379,12 @@ void DivPlatformOPL::renderSamples(int sysID) {
|
|||
pcmMem[6+insAddr]=(~(endPos-1))&0xff;
|
||||
// on MultiPCM this consists of instrument params, but on OPL4 this is not used
|
||||
pcmMem[7+insAddr]=0; // LFO, VIB
|
||||
pcmMem[8+insAddr]=(0xf << 4) | (0xf << 0); // AR, D1R
|
||||
pcmMem[8+insAddr]=(0xf<<4)|(0xf<<0); // AR, D1R
|
||||
pcmMem[9+insAddr]=0; // DL, D2R
|
||||
pcmMem[10+insAddr]=(0xf << 4) | (0xf << 0); // RC, RR
|
||||
pcmMem[10+insAddr]=(0xf<<4)|(0xf<<0); // RC, RR
|
||||
pcmMem[11+insAddr]=0; // AM
|
||||
}
|
||||
if (ramSize<=0x200000) {
|
||||
if (PCM_IN_RAM) {
|
||||
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_RESERVED,"ROM data",0,0,0x200000));
|
||||
}
|
||||
|
||||
|
|
@ -3502,5 +3516,17 @@ void DivPlatformOPL::quit() {
|
|||
}
|
||||
}
|
||||
|
||||
DivPlatformOPL::~DivPlatformOPL() {
|
||||
// initialization of important arrays
|
||||
DivPlatformOPL::DivPlatformOPL():
|
||||
pcmMemory(0x400000),
|
||||
pcm(pcmMemory) {
|
||||
sampleOffPCM=new unsigned int[32768];
|
||||
sampleOffB=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformOPL::~DivPlatformOPL() {
|
||||
delete[] sampleOffPCM;
|
||||
delete[] sampleOffB;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,9 +123,9 @@ class DivPlatformOPL: public DivDispatch {
|
|||
size_t pcmMemLen;
|
||||
DivOPLAInterface iface;
|
||||
DivYMF278MemoryInterface pcmMemory;
|
||||
unsigned int sampleOffB[256];
|
||||
unsigned int sampleOffPCM[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffB;
|
||||
unsigned int* sampleOffPCM;
|
||||
bool* sampleLoaded;
|
||||
|
||||
ymfm::adpcm_b_engine* adpcmB;
|
||||
const unsigned char** slotsNonDrums;
|
||||
|
|
@ -224,9 +224,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformOPL():
|
||||
pcmMemory(0x400000),
|
||||
pcm(pcmMemory) {}
|
||||
DivPlatformOPL();
|
||||
~DivPlatformOPL();
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -202,81 +202,109 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
if (chan[i].std.alg.had) { // SUS
|
||||
chan[i].state.alg=chan[i].std.alg.val;
|
||||
if (chan[i].std.alg.had) { // SUS
|
||||
chan[i].state.alg=chan[i].std.alg.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.fb.had) {
|
||||
chan[i].state.fb=chan[i].std.fb.val;
|
||||
}
|
||||
if (chan[i].std.fb.had) {
|
||||
chan[i].state.fb=chan[i].std.fb.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
if (chan[i].std.fms.had) {
|
||||
chan[i].state.fms=chan[i].std.fms.val;
|
||||
}
|
||||
if (chan[i].std.fms.had) {
|
||||
chan[i].state.fms=chan[i].std.fms.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
if (chan[i].std.ams.had) {
|
||||
chan[i].state.ams=chan[i].std.ams.val;
|
||||
}
|
||||
if (chan[i].std.ams.had) {
|
||||
chan[i].state.ams=chan[i].std.ams.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j=0; j<2; j++) {
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
DivMacroInt::IntOp& m=chan[i].std.op[j];
|
||||
for (int j=0; j<2; j++) {
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
DivMacroInt::IntOp& m=chan[i].std.op[j];
|
||||
|
||||
if (m.am.had) {
|
||||
op.am=m.am.val;
|
||||
if (m.am.had) {
|
||||
op.am=m.am.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.ar.had) {
|
||||
op.ar=m.ar.val;
|
||||
}
|
||||
if (m.ar.had) {
|
||||
op.ar=m.ar.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x04+j,(op.ar<<4)|(op.dr));
|
||||
}
|
||||
if (m.dr.had) {
|
||||
op.dr=m.dr.val;
|
||||
}
|
||||
if (m.dr.had) {
|
||||
op.dr=m.dr.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x04+j,(op.ar<<4)|(op.dr));
|
||||
}
|
||||
if (m.mult.had) {
|
||||
op.mult=m.mult.val;
|
||||
}
|
||||
if (m.mult.had) {
|
||||
op.mult=m.mult.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.rr.had) {
|
||||
op.rr=m.rr.val;
|
||||
}
|
||||
if (m.rr.had) {
|
||||
op.rr=m.rr.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x06+j,(op.sl<<4)|(op.rr));
|
||||
}
|
||||
if (m.sl.had) {
|
||||
op.sl=m.sl.val;
|
||||
}
|
||||
if (m.sl.had) {
|
||||
op.sl=m.sl.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x06+j,(op.sl<<4)|(op.rr));
|
||||
}
|
||||
if (m.tl.had) {
|
||||
op.tl=m.tl.val&((j==1)?15:63);
|
||||
if (j==1) {
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (m.tl.had) {
|
||||
op.tl=m.tl.val&((j==1)?15:63);
|
||||
if (j==1) {
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
} else {
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(op.tl&63));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m.egt.had) {
|
||||
op.ssgEnv=(m.egt.val&1)?8:0;
|
||||
if (m.egt.had) {
|
||||
op.ssgEnv=(m.egt.val&1)?8:0;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.ksl.had) {
|
||||
op.ksl=m.ksl.val;
|
||||
}
|
||||
if (m.ksl.had) {
|
||||
op.ksl=m.ksl.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
if (j==1) {
|
||||
rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(chan[i].state.op[0].tl&63));
|
||||
} else {
|
||||
rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
}
|
||||
if (m.ksr.had) {
|
||||
op.ksr=m.ksr.val;
|
||||
}
|
||||
if (m.ksr.had) {
|
||||
op.ksr=m.ksr.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.vib.had) {
|
||||
op.vib=m.vib.val;
|
||||
}
|
||||
if (m.vib.had) {
|
||||
op.vib=m.vib.val;
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
}
|
||||
|
|
@ -390,6 +418,7 @@ int DivPlatformOPLL::toFreq(int freq, int fixedBlock) {
|
|||
block=freq/OPLL_C_NUM;
|
||||
if (block>0) block=bsr(block);
|
||||
}
|
||||
if (block>7) block=7;
|
||||
freq>>=block;
|
||||
if (freq>0x1ff) freq=0x1ff;
|
||||
return (block<<9)|freq;
|
||||
|
|
|
|||
|
|
@ -307,39 +307,44 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
uint16_t qsound_bank = 0;
|
||||
uint16_t qsound_addr = 0;
|
||||
uint16_t qsound_loop = 0;
|
||||
uint16_t qsound_end = 0;
|
||||
uint16_t qsoundBank=0;
|
||||
uint16_t qsoundAddr=0;
|
||||
uint16_t qsoundLoop=0;
|
||||
uint16_t qsoundEnd=0;
|
||||
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
if (i<16) {
|
||||
qsound_bank = 0x8000 | (offPCM[chan[i].sample] >> 16);
|
||||
qsound_addr = offPCM[chan[i].sample] & 0xffff;
|
||||
qsoundBank=0x8000|(offPCM[chan[i].sample]>>16);
|
||||
qsoundAddr=offPCM[chan[i].sample]&0xffff;
|
||||
} else {
|
||||
qsound_bank = 0x8000 | (offBS[chan[i].sample] >> 16);
|
||||
qsound_addr = offBS[chan[i].sample] & 0xffff;
|
||||
qsoundBank=0x8000|(offBS[chan[i].sample]>>16);
|
||||
qsoundAddr=offBS[chan[i].sample]&0xffff;
|
||||
}
|
||||
|
||||
int loopStart=s->loopStart;
|
||||
int length = s->loopEnd;
|
||||
if (length > 65536 - 16) {
|
||||
length = 65536 - 16;
|
||||
}
|
||||
if (!s->isLoopable()) {
|
||||
if (i<16) {
|
||||
qsound_end = offPCM[chan[i].sample] + length + 15;
|
||||
} else {
|
||||
qsound_end = offBS[chan[i].sample] + (length>>1) + 15;
|
||||
int length=s->loopEnd;
|
||||
if (i<16) {
|
||||
if (length>65536-16) {
|
||||
length=65536-16;
|
||||
}
|
||||
qsound_loop = 15;
|
||||
} else {
|
||||
if (i<16) {
|
||||
qsound_end = offPCM[chan[i].sample] + length;
|
||||
} else {
|
||||
qsound_end = offBS[chan[i].sample] + (length>>1);
|
||||
// ADPCM address is byte aligned
|
||||
length>>=1;
|
||||
if (length>65535) {
|
||||
length=65535;
|
||||
}
|
||||
qsound_loop = length - loopStart;
|
||||
}
|
||||
if (i<16) {
|
||||
if (!s->isLoopable()) {
|
||||
qsoundEnd=offPCM[chan[i].sample]+length+15;
|
||||
qsoundLoop=15;
|
||||
} else {
|
||||
qsoundEnd=offPCM[chan[i].sample]+length;
|
||||
qsoundLoop=length-loopStart;
|
||||
}
|
||||
} else {
|
||||
// ADPCM can't loop
|
||||
qsoundEnd=offBS[chan[i].sample]+length;
|
||||
}
|
||||
}
|
||||
if (NEW_ARP_STRAT) {
|
||||
|
|
@ -406,19 +411,19 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
if (i<16) {
|
||||
rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
|
||||
rWrite(q1_reg_map[Q1V_END][i], qsound_end);
|
||||
rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop);
|
||||
rWrite(q1_reg_map[Q1V_START][i], qsound_addr+chan[i].audPos);
|
||||
rWrite(q1_reg_map[Q1V_BANK][i], qsoundBank);
|
||||
rWrite(q1_reg_map[Q1V_END][i], qsoundEnd);
|
||||
rWrite(q1_reg_map[Q1V_LOOP][i], qsoundLoop);
|
||||
rWrite(q1_reg_map[Q1V_START][i], qsoundAddr+chan[i].audPos);
|
||||
rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000);
|
||||
} else {
|
||||
rWrite(Q1A_KEYON+(i-16),0);
|
||||
rWrite(q1a_bank_map[i-16], qsound_bank);
|
||||
rWrite(q1a_end_map[i-16], qsound_end);
|
||||
rWrite(q1a_start_map[i-16], qsound_addr+chan[i].audPos);
|
||||
rWrite(q1a_bank_map[i-16], qsoundBank);
|
||||
rWrite(q1a_end_map[i-16], qsoundEnd);
|
||||
rWrite(q1a_start_map[i-16], qsoundAddr+chan[i].audPos);
|
||||
rWrite(Q1A_KEYON+(i-16),1);
|
||||
}
|
||||
//logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop);
|
||||
//logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsoundBank,qsoundAddr,qsoundEnd,qsoundLoop);
|
||||
// Write sample address. Enable volume
|
||||
if (!chan[i].std.vol.had) {
|
||||
if (chan[i].isNewQSound) {
|
||||
|
|
@ -747,7 +752,7 @@ size_t DivPlatformQSound::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformQSound::isSampleLoaded(int index, int sample) {
|
||||
if (index<0 || index>1) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
if (index==1) return sampleLoadedBS[sample];
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
|
@ -763,8 +768,10 @@ const DivMemoryComposition* DivPlatformQSound::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformQSound::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleLoadedBS,0,256*sizeof(bool));
|
||||
memset(offPCM,0,32768*sizeof(unsigned int));
|
||||
memset(offBS,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
memset(sampleLoadedBS,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -839,7 +846,7 @@ void DivPlatformQSound::renderSamples(int sysID) {
|
|||
}
|
||||
offBS[i]=memPos;
|
||||
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE_ALT1,"ADPCM",i,memPos,memPos+length));
|
||||
memPos+=length+16;
|
||||
memPos+=length;
|
||||
}
|
||||
sampleMemLenBS=memPos+256;
|
||||
|
||||
|
|
@ -880,3 +887,18 @@ void DivPlatformQSound::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformQSound::DivPlatformQSound() {
|
||||
offPCM=new unsigned int[32768];
|
||||
offBS=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
sampleLoadedBS=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformQSound::~DivPlatformQSound() {
|
||||
delete[] offPCM;
|
||||
delete[] offBS;
|
||||
delete[] sampleLoaded;
|
||||
delete[] sampleLoadedBS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ class DivPlatformQSound: public DivDispatch {
|
|||
size_t sampleMemLen;
|
||||
size_t sampleMemLenBS;
|
||||
size_t sampleMemUsage;
|
||||
bool sampleLoaded[256];
|
||||
bool sampleLoadedBS[256];
|
||||
bool* sampleLoaded;
|
||||
bool* sampleLoadedBS;
|
||||
struct qsound_chip chip;
|
||||
unsigned short regPool[512];
|
||||
|
||||
unsigned int offPCM[256];
|
||||
unsigned int offBS[256];
|
||||
unsigned int* offPCM;
|
||||
unsigned int* offBS;
|
||||
|
||||
DivMemoryComposition memCompo;
|
||||
|
||||
|
|
@ -98,6 +98,8 @@ class DivPlatformQSound: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformQSound();
|
||||
~DivPlatformQSound();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ size_t DivPlatformRF5C68::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformRF5C68::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -431,8 +431,8 @@ const DivMemoryComposition* DivPlatformRF5C68::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformRF5C68::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOffRFC,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffRFC,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample Memory";
|
||||
|
|
@ -497,3 +497,14 @@ void DivPlatformRF5C68::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformRF5C68::DivPlatformRF5C68() {
|
||||
sampleOffRFC=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformRF5C68::~DivPlatformRF5C68() {
|
||||
delete[] sampleOffRFC;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
bool isMuted[8];
|
||||
int chipType;
|
||||
unsigned char curChan;
|
||||
unsigned int sampleOffRFC[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffRFC;
|
||||
bool* sampleLoaded;
|
||||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
@ -85,6 +85,8 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformRF5C68();
|
||||
~DivPlatformRF5C68();
|
||||
private:
|
||||
void chWrite(unsigned char ch, unsigned int addr, unsigned char val);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ size_t DivPlatformSegaPCM::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformSegaPCM::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -509,9 +509,9 @@ void DivPlatformSegaPCM::renderSamples(int sysID) {
|
|||
size_t memPos=0;
|
||||
|
||||
memset(sampleMem,0,2097152);
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
|
||||
memset(sampleEndSegaPCM,0,256);
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
memset(sampleOffSegaPCM,0,32768*sizeof(unsigned int));
|
||||
memset(sampleEndSegaPCM,0,32768);
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -595,5 +595,15 @@ void DivPlatformSegaPCM::quit() {
|
|||
delete sampleMem;
|
||||
}
|
||||
|
||||
DivPlatformSegaPCM::~DivPlatformSegaPCM() {
|
||||
// initialization of important arrays
|
||||
DivPlatformSegaPCM::DivPlatformSegaPCM() {
|
||||
sampleOffSegaPCM=new unsigned int[32768];
|
||||
sampleEndSegaPCM=new unsigned char[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformSegaPCM::~DivPlatformSegaPCM() {
|
||||
delete[] sampleOffSegaPCM;
|
||||
delete[] sampleEndSegaPCM;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,9 +78,9 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
short oldWrites[256];
|
||||
short pendingWrites[256];
|
||||
|
||||
unsigned int sampleOffSegaPCM[256];
|
||||
unsigned char sampleEndSegaPCM[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffSegaPCM;
|
||||
unsigned char* sampleEndSegaPCM;
|
||||
bool* sampleLoaded;
|
||||
|
||||
DivMemoryComposition memCompo;
|
||||
|
||||
|
|
@ -116,6 +116,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
const DivMemoryComposition* getMemCompo(int index);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformSegaPCM();
|
||||
~DivPlatformSegaPCM();
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -966,7 +966,7 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformSNES::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -977,8 +977,8 @@ const DivMemoryComposition* DivPlatformSNES::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformSNES::renderSamples(int sysID) {
|
||||
memset(copyOfSampleMem,0,65536);
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="SPC/DSP Memory";
|
||||
|
|
@ -1077,3 +1077,14 @@ void DivPlatformSNES::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformSNES::DivPlatformSNES() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformSNES::~DivPlatformSNES() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ class DivPlatformSNES: public DivDispatch {
|
|||
signed char sampleMem[65536];
|
||||
signed char copyOfSampleMem[65536];
|
||||
size_t sampleMemLen;
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
DivMemoryComposition memCompo;
|
||||
unsigned char regPool[0x80];
|
||||
SPC_DSP dsp;
|
||||
|
|
@ -132,6 +132,8 @@ class DivPlatformSNES: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformSNES();
|
||||
~DivPlatformSNES();
|
||||
private:
|
||||
void updateWave(int ch);
|
||||
void writeOutVol(int ch);
|
||||
|
|
|
|||
|
|
@ -72,11 +72,19 @@ void sm8521_noise_tick(struct sm8521_noise_t *noise, const int cycle)
|
|||
noise->base.counter += cycle;
|
||||
while (noise->base.counter >= (noise->base.t + 1))
|
||||
{
|
||||
// https://github.com/tildearrow/furnace/issues/2567
|
||||
// unknown algorithm, but don't use rand()
|
||||
//
|
||||
// some research suggests VIC-like noise, although
|
||||
// that remains to be confirmed
|
||||
noise->oldLFSR = noise->lfsr & 1;
|
||||
noise->lfsr = ( noise->lfsr>>1|(((noise->lfsr) ^ (noise->lfsr >> 5) ^ (noise->lfsr >> 8) ^ (noise->lfsr >> 13) ) & 1)<<31);
|
||||
noise->base.counter -= (noise->base.t + 1);
|
||||
if (noise->oldLFSR^(noise->lfsr&1)) {
|
||||
noise->out ^= 1;
|
||||
}
|
||||
}
|
||||
noise->base.out = (((noise->lfsr & 0x1) ? 7 : -8) * noise->base.level) >> 1; // scale out to 8bit
|
||||
noise->base.out = ((noise->out ? 7 : -8) * noise->base.level) >> 1; // scale out to 8bit
|
||||
}
|
||||
|
||||
void sm8521_sound_tick(struct sm8521_t *sm8521, const int cycle)
|
||||
|
|
@ -130,6 +138,8 @@ void sm8521_reset(struct sm8521_t *sm8521)
|
|||
sm8521->noise.base.out = 0;
|
||||
sm8521->noise.base.counter = 0;
|
||||
sm8521->noise.lfsr = 0x89abcdef;
|
||||
sm8521->noise.oldLFSR = 1;
|
||||
sm8521->noise.out = 0;
|
||||
sm8521->out = 0;
|
||||
sm8521->sgda = 0;
|
||||
sm8521->sgc = 0;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ struct sm8521_wave_t
|
|||
struct sm8521_noise_t
|
||||
{
|
||||
struct sm8521_sg_t base;
|
||||
unsigned int lfsr; // LFSR
|
||||
unsigned int lfsr, oldLFSR; // LFSR
|
||||
unsigned char out;
|
||||
};
|
||||
|
||||
struct sm8521_t
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ static const int noise_periods [3] = { 0x100, 0x200, 0x400 };
|
|||
void T6W28_Noise::reset()
|
||||
{
|
||||
period = &noise_periods [0];
|
||||
shifter = 0x4000;
|
||||
tap = 13;
|
||||
shifter = 0xfffe;
|
||||
tap = 12;
|
||||
period_extra = 0;
|
||||
T6W28_Osc::reset();
|
||||
}
|
||||
|
|
@ -201,9 +201,13 @@ void T6W28_Noise::run( sms_time_t time, sms_time_t end_time )
|
|||
|
||||
do
|
||||
{
|
||||
int changed = (l_shifter + 1) & 2; // set if prev and next bits differ
|
||||
l_shifter = (((l_shifter << 14) ^ (l_shifter << tap)) & 0x4000) | (l_shifter >> 1);
|
||||
if ( changed )
|
||||
int prev_l_shifter=l_shifter;
|
||||
if (tap==16) {
|
||||
l_shifter = ((l_shifter >> 14) & 1) | (l_shifter << 1);
|
||||
} else {
|
||||
l_shifter = ((((l_shifter >> 15)&1) ^ ((l_shifter >> 12)&1)) & 1) | (l_shifter << 1);
|
||||
}
|
||||
if ( (prev_l_shifter^l_shifter)&1 )
|
||||
{
|
||||
delta_left = -delta_left;
|
||||
blip_add_delta( output_left, time, delta_left );
|
||||
|
|
@ -370,8 +374,8 @@ void T6W28_Apu::write_data_right( sms_time_t time, int data )
|
|||
noise.period = &noise.period_extra;
|
||||
|
||||
int const tap_disabled = 16;
|
||||
noise.tap = (data & 0x04) ? 13 : tap_disabled;
|
||||
noise.shifter = 0x4000;
|
||||
noise.tap = (data & 0x04) ? 12 : tap_disabled;
|
||||
noise.shifter = 0xfffe;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
// Chip revisions
|
||||
// 0: V 0.3.0
|
||||
// 1: V 47.0.0 (9-bit volume, phase reset on mute)
|
||||
// 2: V 47.0.2 (Pulse Width XOR on Saw and Triangle)
|
||||
// 1: V 47.0.2 (9-bit volume, phase reset on mute)
|
||||
// 2: V 48.0.1 (Pulse Width XOR on Saw and Triangle)
|
||||
|
||||
#include "vera_psg.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ void VSU::Power(void)
|
|||
SweepControl = 0;
|
||||
SweepModCounter = 0;
|
||||
SweepModClockDivider = 1;
|
||||
ModState = 0;
|
||||
ModLock = 0;
|
||||
|
||||
for(int ch = 0; ch < 6; ch++)
|
||||
{
|
||||
|
|
@ -62,7 +64,9 @@ void VSU::Power(void)
|
|||
RAMAddress[ch] = 0;
|
||||
|
||||
EffFreq[ch] = 0;
|
||||
Envelope[ch] = 0;
|
||||
EnvelopeReload[ch] = 0;
|
||||
EnvelopeValue[ch] = 0;
|
||||
EnvelopeModMask[ch] = 0;
|
||||
WavePos[ch] = 0;
|
||||
FreqCounter[ch] = 1;
|
||||
IntervalCounter[ch] = 0;
|
||||
|
|
@ -100,6 +104,8 @@ void VSU::Write(int timestamp, unsigned int A, unsigned char V)
|
|||
|
||||
Update(timestamp);
|
||||
|
||||
ModLock = 0;
|
||||
|
||||
//printf("VSU Write: %d, %08x %02x\n", timestamp, A, V);
|
||||
|
||||
if(A < 0x280)
|
||||
|
|
@ -133,7 +139,6 @@ void VSU::Write(int timestamp, unsigned int A, unsigned char V)
|
|||
|
||||
if(V & 0x80)
|
||||
{
|
||||
EffFreq[ch] = Frequency[ch];
|
||||
if(ch == 5)
|
||||
FreqCounter[ch] = 10 * (2048 - EffFreq[ch]);
|
||||
else
|
||||
|
|
@ -146,15 +151,20 @@ void VSU::Write(int timestamp, unsigned int A, unsigned char V)
|
|||
SweepModCounter = (SweepControl >> 4) & 7;
|
||||
SweepModClockDivider = (SweepControl & 0x80) ? 8 : 1;
|
||||
ModWavePos = 0;
|
||||
ModState = 0;
|
||||
}
|
||||
|
||||
WavePos[ch] = 0;
|
||||
|
||||
if(ch == 5) // Not sure if this is correct.
|
||||
if(ch == 5) { // Not sure if this is correct.
|
||||
lfsr = 1;
|
||||
}
|
||||
|
||||
//if(!(IntlControl[ch] & 0x80))
|
||||
// Envelope[ch] = (EnvControl[ch] >> 4) & 0xF;
|
||||
EnvelopeModMask[ch] = 0;
|
||||
if(!(EnvControl[ch] & 0x200) && (
|
||||
(EnvelopeValue[ch] == 0 && !(EnvControl[ch] & 0x0008)) ||
|
||||
(EnvelopeValue[ch] == 0xF && (EnvControl[ch] & 0x0008))))
|
||||
EnvelopeModMask[ch] = 1;
|
||||
|
||||
EffectsClockDivider[ch] = 4800;
|
||||
IntervalClockDivider[ch] = 4;
|
||||
|
|
@ -167,21 +177,27 @@ void VSU::Write(int timestamp, unsigned int A, unsigned char V)
|
|||
break;
|
||||
|
||||
case 0x2: Frequency[ch] &= 0xFF00;
|
||||
Frequency[ch] |= V << 0;
|
||||
EffFreq[ch] &= 0xFF00;
|
||||
Frequency[ch] |= V << 0;
|
||||
EffFreq[ch] &= 0xFF00;
|
||||
EffFreq[ch] |= V << 0;
|
||||
ModLock = 1;
|
||||
break;
|
||||
|
||||
case 0x3: Frequency[ch] &= 0x00FF;
|
||||
Frequency[ch] |= (V & 0x7) << 8;
|
||||
EffFreq[ch] &= 0x00FF;
|
||||
Frequency[ch] |= (V & 0x7) << 8;
|
||||
EffFreq[ch] &= 0x00FF;
|
||||
EffFreq[ch] |= (V & 0x7) << 8;
|
||||
ModLock = 2;
|
||||
break;
|
||||
|
||||
case 0x4: EnvControl[ch] &= 0xFF00;
|
||||
EnvControl[ch] |= V << 0;
|
||||
|
||||
Envelope[ch] = (V >> 4) & 0xF;
|
||||
EnvelopeReload[ch] = (V >> 4) & 0xF;
|
||||
EnvelopeValue[ch] = (V >> 4) & 0xF;
|
||||
|
||||
if(EnvelopeModMask[ch] == 1)
|
||||
EnvelopeModMask[ch] = 2;
|
||||
break;
|
||||
|
||||
case 0x5: EnvControl[ch] &= 0x00FF;
|
||||
|
|
@ -194,6 +210,12 @@ void VSU::Write(int timestamp, unsigned int A, unsigned char V)
|
|||
}
|
||||
else
|
||||
EnvControl[ch] |= (V & 0x03) << 8;
|
||||
|
||||
if(EnvelopeModMask[ch] == 0 && !(EnvControl[ch] & 0x200) && (
|
||||
(EnvelopeValue[ch] == 0 && !(EnvControl[ch] & 0x0008)) ||
|
||||
(EnvelopeValue[ch] == 0xF && (EnvControl[ch] & 0x0008))))
|
||||
EnvelopeModMask[ch] = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x6: RAMAddress[ch] = V & 0xF;
|
||||
|
|
@ -228,14 +250,14 @@ inline void VSU::CalcCurrentOutput(int ch, int &left, int &right)
|
|||
else
|
||||
WD = WaveData[RAMAddress[ch]][WavePos[ch]]; // - 0x20;
|
||||
}
|
||||
l_ol = Envelope[ch] * LeftLevel[ch];
|
||||
l_ol = EnvelopeValue[ch] * LeftLevel[ch];
|
||||
if(l_ol)
|
||||
{
|
||||
l_ol >>= 3;
|
||||
l_ol += 1;
|
||||
}
|
||||
|
||||
r_ol = Envelope[ch] * RightLevel[ch];
|
||||
r_ol = EnvelopeValue[ch] * RightLevel[ch];
|
||||
if(r_ol)
|
||||
{
|
||||
r_ol >>= 3;
|
||||
|
|
@ -260,11 +282,11 @@ void VSU::Update(int timestamp)
|
|||
CalcCurrentOutput(ch, left, right);
|
||||
if (left!=last_output[ch][0]) {
|
||||
blip_add_delta(bb[0],running_timestamp,left - last_output[ch][0]);
|
||||
last_output[ch][0] = left;
|
||||
last_output[ch][0] = left;
|
||||
}
|
||||
if (right!=last_output[ch][1]) {
|
||||
blip_add_delta(bb[1],running_timestamp,right - last_output[ch][1]);
|
||||
last_output[ch][1] = right;
|
||||
last_output[ch][1] = right;
|
||||
}
|
||||
oscBuf[ch]->putSample(running_timestamp,(left+right)*8);
|
||||
|
||||
|
|
@ -355,23 +377,27 @@ void VSU::Update(int timestamp)
|
|||
{
|
||||
EnvelopeClockDivider[ch] += 4;
|
||||
|
||||
int new_envelope = EnvelopeValue[ch];
|
||||
if(EnvelopeValue[ch] < 0xF && (EnvControl[ch] & 0x0008))
|
||||
new_envelope++;
|
||||
else if(EnvelopeValue[ch] > 0 && !(EnvControl[ch] & 0x0008))
|
||||
new_envelope--;
|
||||
else if((EnvControl[ch] & 0x200) && EnvelopeModMask[ch] != 2)
|
||||
{
|
||||
new_envelope = EnvelopeReload[ch];
|
||||
EnvelopeModMask[ch] = 0;
|
||||
}
|
||||
else if(EnvelopeModMask[ch] == 0)
|
||||
EnvelopeModMask[ch] = 1;
|
||||
|
||||
if(EnvControl[ch] & 0x0100) // Enveloping enabled?
|
||||
{
|
||||
EnvelopeCounter[ch]--;
|
||||
if(!EnvelopeCounter[ch])
|
||||
{
|
||||
EnvelopeCounter[ch] = (EnvControl[ch] & 0x7) + 1;
|
||||
|
||||
if(EnvControl[ch] & 0x0008) // Grow
|
||||
{
|
||||
if(Envelope[ch] < 0xF || (EnvControl[ch] & 0x200))
|
||||
Envelope[ch] = (Envelope[ch] + 1) & 0xF;
|
||||
}
|
||||
else // Decay
|
||||
{
|
||||
if(Envelope[ch] > 0 || (EnvControl[ch] & 0x200))
|
||||
Envelope[ch] = (Envelope[ch] - 1) & 0xF;
|
||||
}
|
||||
EnvelopeCounter[ch] = (EnvControl[ch] & 0x7) + 1;
|
||||
if(EnvelopeModMask[ch] == 0)
|
||||
EnvelopeValue[ch] = new_envelope;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,6 +406,19 @@ void VSU::Update(int timestamp)
|
|||
|
||||
if(ch == 4)
|
||||
{
|
||||
|
||||
// Calculate sweep early
|
||||
int delta = EffFreq[ch] >> (SweepControl & 0x7);
|
||||
int NewSweepFreq = EffFreq[ch] + ((SweepControl & 0x8) ? delta : -delta);
|
||||
|
||||
if(!(EnvControl[ch] & 0x1000))
|
||||
{
|
||||
if(NewSweepFreq < 0)
|
||||
NewSweepFreq = 0;
|
||||
else if(NewSweepFreq > 0x7FF)
|
||||
IntlControl[ch] &= ~0x80;
|
||||
}
|
||||
|
||||
SweepModClockDivider--;
|
||||
while(SweepModClockDivider <= 0)
|
||||
{
|
||||
|
|
@ -394,33 +433,30 @@ void VSU::Update(int timestamp)
|
|||
{
|
||||
SweepModCounter = (SweepControl >> 4) & 0x7;
|
||||
|
||||
if(EnvControl[ch] & 0x1000) // Modulation
|
||||
if(EnvControl[ch] & 0x1000) // Modulation
|
||||
{
|
||||
if(ModWavePos < 32 || (EnvControl[ch] & 0x2000))
|
||||
{
|
||||
ModWavePos &= 0x1F;
|
||||
if(ModState == 0 || (EnvControl[ch] & 0x2000))
|
||||
EffFreq[ch] = (Frequency[ch] + (signed char)ModData[ModWavePos]) & 0x7FF;
|
||||
if(ModState == 1)
|
||||
ModState = 2;
|
||||
|
||||
EffFreq[ch] = (Frequency[ch] + (signed char)ModData[ModWavePos]) & 0x7FF;
|
||||
ModWavePos++;
|
||||
}
|
||||
// Hardware bug: writing to S5FQ* locks the relevant byte when modulating
|
||||
if(ModLock == 1)
|
||||
EffFreq[ch] = (EffFreq[ch] & 0x700) | (Frequency[ch] & 0xFF);
|
||||
else if(ModLock == 2)
|
||||
EffFreq[ch] = (EffFreq[ch] & 0xFF) | (Frequency[ch] & 0x700);
|
||||
}
|
||||
else // Sweep
|
||||
else if(ModState < 2) // Sweep
|
||||
{
|
||||
int delta = EffFreq[ch] >> (SweepControl & 0x7);
|
||||
int NewFreq = EffFreq[ch] + ((SweepControl & 0x8) ? delta : -delta);
|
||||
EffFreq[ch] = NewSweepFreq;
|
||||
}
|
||||
|
||||
//printf("Sweep(%d): Old: %d, New: %d\n", ch, EffFreq[ch], NewFreq);
|
||||
|
||||
if(NewFreq < 0)
|
||||
EffFreq[ch] = 0;
|
||||
else if(NewFreq > 0x7FF)
|
||||
if(++ModWavePos >= 32)
|
||||
{
|
||||
//EffFreq[ch] = 0x7FF;
|
||||
IntlControl[ch] &= ~0x80;
|
||||
if(ModState == 0)
|
||||
ModState = 1;
|
||||
ModWavePos = 0;
|
||||
}
|
||||
else
|
||||
EffFreq[ch] = NewFreq;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end while(SweepModClockDivider <= 0)
|
||||
|
|
@ -433,11 +469,11 @@ void VSU::Update(int timestamp)
|
|||
CalcCurrentOutput(ch, left, right);
|
||||
if (left!=last_output[ch][0]) {
|
||||
blip_add_delta(bb[0],running_timestamp,left - last_output[ch][0]);
|
||||
last_output[ch][0] = left;
|
||||
last_output[ch][0] = left;
|
||||
}
|
||||
if (right!=last_output[ch][1]) {
|
||||
blip_add_delta(bb[1],running_timestamp,right - last_output[ch][1]);
|
||||
last_output[ch][1] = right;
|
||||
last_output[ch][1] = right;
|
||||
}
|
||||
oscBuf[ch]->putSample(running_timestamp,(left+right)*8);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ class VSU
|
|||
//
|
||||
//
|
||||
int EffFreq[6];
|
||||
int Envelope[6];
|
||||
int EnvelopeValue[6];
|
||||
int EnvelopeReload[6];
|
||||
|
||||
int WavePos[6];
|
||||
int ModWavePos;
|
||||
|
|
@ -91,6 +92,12 @@ class VSU
|
|||
int EnvelopeClockDivider[6];
|
||||
int SweepModClockDivider;
|
||||
|
||||
public:
|
||||
int EnvelopeModMask[6];
|
||||
int ModState;
|
||||
int ModLock;
|
||||
|
||||
private:
|
||||
int NoiseLatcherClockDivider;
|
||||
unsigned int NoiseLatcher;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef YMF278_HH
|
||||
#define YMF278_HH
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
|
|
|||
|
|
@ -338,11 +338,13 @@ void pcm_channel::output(output_data &output) const
|
|||
|
||||
// fetch current sample and add
|
||||
int16_t sample = fetch_sample();
|
||||
int32_t outl = (lvol * sample) >> 15;
|
||||
int32_t outr = (rvol * sample) >> 15;
|
||||
uint32_t outnum = m_regs.ch_output_channel(m_choffs) * 2;
|
||||
output.data[outnum + 0] += (lvol * sample) >> 15;
|
||||
output.data[outnum + 1] += (rvol * sample) >> 15;
|
||||
m_output[outnum + 0] = output.data[outnum + 0];
|
||||
m_output[outnum + 1] = output.data[outnum + 1];
|
||||
output.data[outnum + 0] += outl;
|
||||
output.data[outnum + 1] += outr;
|
||||
m_output[outnum + 0] = outl;
|
||||
m_output[outnum + 1] = outr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ size_t DivPlatformSoundUnit::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformSoundUnit::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -701,8 +701,8 @@ const DivMemoryComposition* DivPlatformSoundUnit::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformSoundUnit::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,sampleMemSize?65536:8192);
|
||||
memset(sampleOffSU,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffSU,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample RAM";
|
||||
|
|
@ -770,5 +770,13 @@ void DivPlatformSoundUnit::quit() {
|
|||
delete[] sampleMem;
|
||||
}
|
||||
|
||||
DivPlatformSoundUnit::~DivPlatformSoundUnit() {
|
||||
// initialization of important arrays
|
||||
DivPlatformSoundUnit::DivPlatformSoundUnit() {
|
||||
sampleOffSU=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformSoundUnit::~DivPlatformSoundUnit() {
|
||||
delete[] sampleOffSU;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
unsigned char ilCtrl, ilSize, fil1;
|
||||
unsigned char initIlCtrl, initIlSize, initFil1;
|
||||
signed char echoVol, initEchoVol;
|
||||
unsigned int sampleOffSU[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffSU;
|
||||
bool* sampleLoaded;
|
||||
|
||||
int cycles, curChan, delay, sysIDCache;
|
||||
short tempL;
|
||||
|
|
@ -140,6 +140,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformSoundUnit();
|
||||
~DivPlatformSoundUnit();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ size_t DivPlatformSupervision::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformSupervision::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -524,7 +524,7 @@ const DivMemoryComposition* DivPlatformSupervision::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformSupervision::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample Memory";
|
||||
|
|
@ -603,5 +603,15 @@ void DivPlatformSupervision::quit() {
|
|||
}
|
||||
}
|
||||
|
||||
DivPlatformSupervision::~DivPlatformSupervision() {
|
||||
// initialization of important arrays
|
||||
DivPlatformSupervision::DivPlatformSupervision() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLen=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformSupervision::~DivPlatformSupervision() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLen;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ class DivPlatformSupervision: public DivDispatch {
|
|||
int tempR[32];
|
||||
int coreQuality;
|
||||
unsigned char regPool[64];
|
||||
unsigned int sampleOff[256];
|
||||
unsigned int sampleLen[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
unsigned int* sampleLen;
|
||||
bool* sampleLoaded;
|
||||
DivMemoryComposition memCompo;
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
@ -98,6 +98,7 @@ class DivPlatformSupervision: public DivDispatch {
|
|||
bool getDCOffRequired();
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformSupervision();
|
||||
~DivPlatformSupervision();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "vb.h"
|
||||
#include "../engine.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include "furIcons.h"
|
||||
#include <math.h>
|
||||
|
||||
//#define rWrite(a,v) pendingWrites[a]=v;
|
||||
|
|
@ -252,6 +254,27 @@ void DivPlatformVB::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
if ((chan[i].envHigh&3)==0) {
|
||||
chan[i].hasEnvWarning=0;
|
||||
} else {
|
||||
switch (vb->EnvelopeModMask[i]) {
|
||||
case 0: // envelope OK
|
||||
chan[i].hasEnvWarning=0;
|
||||
break;
|
||||
case 1: // envelope has finished
|
||||
chan[i].hasEnvWarning=21;
|
||||
break;
|
||||
case 2: // can't envelope
|
||||
chan[i].hasEnvWarning=22;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if (vb->ModLock) {
|
||||
chan[4].hasEnvWarning=4;
|
||||
}*/
|
||||
}
|
||||
|
||||
int DivPlatformVB::dispatch(DivCommand c) {
|
||||
|
|
@ -477,6 +500,16 @@ unsigned short DivPlatformVB::getPan(int ch) {
|
|||
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
|
||||
}
|
||||
|
||||
DivChannelModeHints DivPlatformVB::getModeHints(int ch) {
|
||||
DivChannelModeHints ret;
|
||||
//if (ch>4) return ret;
|
||||
ret.count=1;
|
||||
ret.hint[0]=ICON_FA_EXCLAMATION_TRIANGLE;
|
||||
ret.type[0]=chan[ch].hasEnvWarning;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformVB::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class DivPlatformVB: public DivDispatch {
|
|||
int antiClickPeriodCount, antiClickWavePos;
|
||||
unsigned char pan, envLow, envHigh;
|
||||
bool noise, deferredWaveUpdate, intWritten;
|
||||
unsigned char hasEnvWarning;
|
||||
signed short wave;
|
||||
DivWaveSynth ws;
|
||||
Channel():
|
||||
|
|
@ -42,6 +43,7 @@ class DivPlatformVB: public DivDispatch {
|
|||
noise(false),
|
||||
deferredWaveUpdate(false),
|
||||
intWritten(false),
|
||||
hasEnvWarning(0),
|
||||
wave(-1) {}
|
||||
};
|
||||
Channel chan[6];
|
||||
|
|
@ -78,6 +80,7 @@ class DivPlatformVB: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelModeHints getModeHints(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
|
|
@ -284,13 +284,13 @@ void DivPlatformVIC20::muteChannel(int ch, bool mute) {
|
|||
void DivPlatformVIC20::forceIns() {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].insChanged=true;
|
||||
// I give up!
|
||||
if (chan[i].onOff) {
|
||||
if (chan[i].onOff && chan[i].active) {
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
chan[i].freqChanged=false;
|
||||
chan[i].keyOff=true;
|
||||
chan[i].keyOn=false;
|
||||
chan[i].waveWriteCycle=-1;
|
||||
}
|
||||
writeOutVol(i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,6 +418,9 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
case DIV_CMD_STD_NOISE_MODE:
|
||||
if ((c.chan!=2) && (!chan[c.chan].pcm)) { // pulse
|
||||
chan[c.chan].duty=c.value;
|
||||
if (!isMuted[c.chan]) { // pulse
|
||||
chWrite(c.chan,0,(chan[c.chan].outVol&0xf)|((chan[c.chan].duty&7)<<4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_MODE:
|
||||
|
|
|
|||
|
|
@ -1001,7 +1001,7 @@ size_t DivPlatformX1_010::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformX1_010::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -1012,8 +1012,8 @@ const DivMemoryComposition* DivPlatformX1_010::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformX1_010::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,16777216);
|
||||
memset(sampleOffX1,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffX1,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -1081,5 +1081,16 @@ void DivPlatformX1_010::quit() {
|
|||
delete[] sampleMem;
|
||||
}
|
||||
|
||||
DivPlatformX1_010::~DivPlatformX1_010() {
|
||||
// initialization of important arrays
|
||||
DivPlatformX1_010::DivPlatformX1_010():
|
||||
DivDispatch(),
|
||||
vgsound_emu_mem_intf(),
|
||||
x1_010(*this) {
|
||||
sampleOffX1=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformX1_010::~DivPlatformX1_010() {
|
||||
delete[] sampleOffX1;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
|
||||
bool isBanked=false;
|
||||
unsigned int bankSlot[8];
|
||||
unsigned int sampleOffX1[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffX1;
|
||||
bool* sampleLoaded;
|
||||
|
||||
DivMemoryComposition memCompo;
|
||||
|
||||
|
|
@ -159,10 +159,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
const char** getRegisterSheet();
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformX1_010():
|
||||
DivDispatch(),
|
||||
vgsound_emu_mem_intf(),
|
||||
x1_010(*this) {}
|
||||
DivPlatformX1_010();
|
||||
~DivPlatformX1_010();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -531,6 +531,16 @@ void DivPlatformYM2608::acquire_lle(short** buf, size_t len) {
|
|||
signed char subCycle=0;
|
||||
unsigned char subSubCycle=0;
|
||||
|
||||
// AY -> OPN
|
||||
ay->runDAC();
|
||||
ay->runTFX(rate);
|
||||
ay->flushWrites();
|
||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||
if (i.addr>15) continue;
|
||||
immWrite(i.addr&15,i.val);
|
||||
}
|
||||
ay->getRegisterWrites().clear();
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
fmOut[i]=0;
|
||||
}
|
||||
|
|
@ -1991,7 +2001,7 @@ size_t DivPlatformYM2608::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformYM2608::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -2002,8 +2012,8 @@ const DivMemoryComposition* DivPlatformYM2608::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformYM2608::renderSamples(int sysID) {
|
||||
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOffB,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="ADPCM";
|
||||
|
|
@ -2148,5 +2158,16 @@ void DivPlatformYM2608::quit() {
|
|||
delete[] adpcmBMem;
|
||||
}
|
||||
|
||||
DivPlatformYM2608::~DivPlatformYM2608() {
|
||||
// initialization of important arrays
|
||||
DivPlatformYM2608::DivPlatformYM2608():
|
||||
DivPlatformOPN(2, 6, 9, 15, 16, 9440540.0, 72, 32, false, 16),
|
||||
prescale(0x2d),
|
||||
isCSM(0) {
|
||||
sampleOffB=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformYM2608::~DivPlatformYM2608() {
|
||||
delete[] sampleOffB;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
unsigned char* adpcmBMem;
|
||||
size_t adpcmBMemLen;
|
||||
DivYM2608Interface iface;
|
||||
unsigned int sampleOffB[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOffB;
|
||||
bool* sampleLoaded;
|
||||
|
||||
DivPlatformAY8910* ay;
|
||||
unsigned char sampleBank;
|
||||
|
|
@ -124,10 +124,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void setCSM(bool isCSM);
|
||||
void quit();
|
||||
DivPlatformYM2608():
|
||||
DivPlatformOPN(2, 6, 9, 15, 16, 9440540.0, 72, 32, false, 16),
|
||||
prescale(0x2d),
|
||||
isCSM(0) {}
|
||||
DivPlatformYM2608();
|
||||
~DivPlatformYM2608();
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -465,6 +465,16 @@ void DivPlatformYM2610::acquire_lle(short** buf, size_t len) {
|
|||
signed char subCycle=0;
|
||||
unsigned char subSubCycle=0;
|
||||
|
||||
// AY -> OPN
|
||||
ay->runDAC();
|
||||
ay->runTFX(rate);
|
||||
ay->flushWrites();
|
||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||
if (i.addr>15) continue;
|
||||
immWrite(i.addr&15,i.val);
|
||||
}
|
||||
ay->getRegisterWrites().clear();
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
fmOut[i]=0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -533,6 +533,16 @@ void DivPlatformYM2610B::acquire_lle(short** buf, size_t len) {
|
|||
signed char subCycle=0;
|
||||
unsigned char subSubCycle=0;
|
||||
|
||||
// AY -> OPN
|
||||
ay->runDAC();
|
||||
ay->runTFX(rate);
|
||||
ay->flushWrites();
|
||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||
if (i.addr>15) continue;
|
||||
immWrite(i.addr&15,i.val);
|
||||
}
|
||||
ay->getRegisterWrites().clear();
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
fmOut[i]=0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,14 +75,14 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
size_t adpcmBMemLen;
|
||||
DivYM2610Interface iface;
|
||||
|
||||
unsigned int sampleOffA[256];
|
||||
unsigned int sampleOffB[256];
|
||||
unsigned int* sampleOffA;
|
||||
unsigned int* sampleOffB;
|
||||
|
||||
unsigned char sampleBank;
|
||||
|
||||
bool extMode, noExtMacros;
|
||||
|
||||
bool sampleLoaded[2][256];
|
||||
bool* sampleLoaded[2];
|
||||
|
||||
unsigned char writeADPCMAOff, writeADPCMAOn;
|
||||
int globalADPCMAVolume;
|
||||
|
|
@ -214,7 +214,7 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
|
||||
bool isSampleLoaded(int index, int sample) {
|
||||
if (index<0 || index>1) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[index][sample];
|
||||
}
|
||||
|
||||
|
|
@ -226,9 +226,10 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
|
||||
void renderSamples(int sysID) {
|
||||
memset(adpcmAMem,0,getSampleMemCapacity(0));
|
||||
memset(sampleOffA,0,256*sizeof(unsigned int));
|
||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*2*sizeof(bool));
|
||||
memset(sampleOffA,0,32768*sizeof(unsigned int));
|
||||
memset(sampleOffB,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded[0],0,32768*sizeof(bool));
|
||||
memset(sampleLoaded[1],0,32768*sizeof(bool));
|
||||
|
||||
memCompoA=DivMemoryComposition();
|
||||
memCompoA.name="ADPCM-A";
|
||||
|
|
@ -365,7 +366,18 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
}
|
||||
|
||||
DivPlatformYM2610Base(int ext, int psg, int adpcmA, int adpcmB, int chanCount):
|
||||
DivPlatformOPN(ext,psg,adpcmA,adpcmB,chanCount,9440540.0, 72, 32, false, 16) {}
|
||||
DivPlatformOPN(ext,psg,adpcmA,adpcmB,chanCount,9440540.0, 72, 32, false, 16) {
|
||||
sampleOffA=new unsigned int[32768];
|
||||
sampleOffB=new unsigned int[32768];
|
||||
sampleLoaded[0]=new bool[32768];
|
||||
sampleLoaded[1]=new bool[32768];
|
||||
}
|
||||
~DivPlatformYM2610Base() {
|
||||
delete[] sampleOffA;
|
||||
delete[] sampleOffB;
|
||||
delete[] sampleLoaded[0];
|
||||
delete[] sampleLoaded[1];
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ size_t DivPlatformYMZ280B::getSampleMemUsage(int index) {
|
|||
|
||||
bool DivPlatformYMZ280B::isSampleLoaded(int index, int sample) {
|
||||
if (index!=0) return false;
|
||||
if (sample<0 || sample>255) return false;
|
||||
if (sample<0 || sample>32767) return false;
|
||||
return sampleLoaded[sample];
|
||||
}
|
||||
|
||||
|
|
@ -460,8 +460,8 @@ const DivMemoryComposition* DivPlatformYMZ280B::getMemCompo(int index) {
|
|||
|
||||
void DivPlatformYMZ280B::renderSamples(int sysID) {
|
||||
memset(sampleMem,0,getSampleMemCapacity());
|
||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,256*sizeof(bool));
|
||||
memset(sampleOff,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLoaded,0,32768*sizeof(bool));
|
||||
|
||||
memCompo=DivMemoryComposition();
|
||||
memCompo.name="Sample ROM";
|
||||
|
|
@ -570,3 +570,14 @@ void DivPlatformYMZ280B::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
// initialization of important arrays
|
||||
DivPlatformYMZ280B::DivPlatformYMZ280B() {
|
||||
sampleOff=new unsigned int[32768];
|
||||
sampleLoaded=new bool[32768];
|
||||
}
|
||||
|
||||
DivPlatformYMZ280B::~DivPlatformYMZ280B() {
|
||||
delete[] sampleOff;
|
||||
delete[] sampleLoaded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
DivDispatchOscBuffer* oscBuf[8];
|
||||
bool isMuted[8];
|
||||
int chipType;
|
||||
unsigned int sampleOff[256];
|
||||
bool sampleLoaded[256];
|
||||
unsigned int* sampleOff;
|
||||
bool* sampleLoaded;
|
||||
|
||||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
|
|
@ -86,6 +86,8 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
void setFlags(const DivConfig& flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
DivPlatformYMZ280B();
|
||||
~DivPlatformYMZ280B();
|
||||
private:
|
||||
void writeOutVol(int ch);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1577,6 +1577,9 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
cycles++;
|
||||
}
|
||||
|
||||
// don't let user play anything during export
|
||||
if (exporting) pendingNotes.clear();
|
||||
|
||||
if (!pendingNotes.empty()) {
|
||||
bool isOn[DIV_MAX_CHANS];
|
||||
memset(isOn,0,DIV_MAX_CHANS*sizeof(bool));
|
||||
|
|
@ -1616,6 +1619,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note));
|
||||
keyHit[note.channel]=true;
|
||||
chan[note.channel].note = note.note;
|
||||
chan[note.channel].releasing=false;
|
||||
chan[note.channel].noteOnInhibit=true;
|
||||
chan[note.channel].lastIns=note.ins;
|
||||
|
|
@ -2248,7 +2252,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
}
|
||||
}
|
||||
int ins=-1;
|
||||
if ((ins=midiCallback(msg))!=-2) {
|
||||
if ((ins=midiCallback(msg))!=-3) {
|
||||
int chan=msg.type&15;
|
||||
switch (msg.type&0xf0) {
|
||||
case TA_MIDI_NOTE_OFF: {
|
||||
|
|
@ -2298,7 +2302,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
}
|
||||
|
||||
// process sample/wave preview
|
||||
if ((sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) || (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size())) {
|
||||
if (((sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) || (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size())) && !exporting) {
|
||||
unsigned int samp_bbOff=0;
|
||||
unsigned int prevAvail=blip_samples_avail(samp_bb);
|
||||
if (prevAvail>size) prevAvail=size;
|
||||
|
|
|
|||
|
|
@ -291,6 +291,9 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
|
|||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
off=offset*2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
off=(offset+1)/2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -355,6 +358,10 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
|
|||
off=((offset*3)+1)/2;
|
||||
len=((length*3)+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
off=(offset+1)/2;
|
||||
len=(length+1)/2;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
off=offset*2;
|
||||
len=length*2;
|
||||
|
|
@ -419,6 +426,9 @@ int DivSample::getEndPosition(DivSampleDepth depth) {
|
|||
case DIV_SAMPLE_DEPTH_12BIT:
|
||||
off=length12;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
off=length4;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
off=length16;
|
||||
break;
|
||||
|
|
@ -622,6 +632,12 @@ bool DivSample::initInternal(DivSampleDepth d, int count) {
|
|||
data12=new unsigned char[length12+8];
|
||||
memset(data12,0,length12+8);
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
if (data4!=NULL) delete[] data4;
|
||||
length4=(count+1)/2;
|
||||
data4=new unsigned char[length4];
|
||||
memset(data4,0,length4);
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT: // 16-bit
|
||||
if (data16!=NULL) delete[] data16;
|
||||
length16=count*2;
|
||||
|
|
@ -860,6 +876,9 @@ void DivSample::convert(DivSampleDepth newDepth, unsigned int formatMask) {
|
|||
case DIV_SAMPLE_DEPTH_VOX: // VOX
|
||||
setSampleCount((samples+1)&(~1));
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
setSampleCount((samples+1)&(~1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1170,6 +1189,7 @@ bool DivSample::resampleSinc(double sRate, double tRate) {
|
|||
|
||||
bool DivSample::resample(double sRate, double tRate, int filter) {
|
||||
if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) return false;
|
||||
if (tRate<100) return false;
|
||||
switch (filter) {
|
||||
case DIV_RESAMPLE_NONE:
|
||||
return resampleNone(sRate,tRate);
|
||||
|
|
@ -1317,6 +1337,18 @@ void DivSample::render(unsigned int formatMask) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_4BIT: {
|
||||
unsigned short nibble=0;
|
||||
for (unsigned int i=0; i<samples; i++) {
|
||||
if (i&1) {
|
||||
nibble=data4[i>>1]&0xf;
|
||||
} else {
|
||||
nibble=data4[i>>1]>>4;
|
||||
}
|
||||
data16[i]=((nibble<<12)|(nibble<<8)|(nibble<<4)|nibble)^0x8000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
|
@ -1518,6 +1550,20 @@ void DivSample::render(unsigned int formatMask) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_4BIT)) {
|
||||
if (!initInternal(DIV_SAMPLE_DEPTH_4BIT,samples)) return;
|
||||
unsigned char _sample=0, sample4=0;
|
||||
unsigned short* samplePtr = (unsigned short*)data16;
|
||||
for (unsigned int i=0; i<samples; i+=2) {
|
||||
_sample=(*samplePtr++^0x8000)>>12;
|
||||
sample4=_sample<<4;
|
||||
if (i+1<samples) {
|
||||
_sample=(*samplePtr++^0x8000)>>12;
|
||||
sample4|=_sample;
|
||||
}
|
||||
data4[i>>1]=sample4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* DivSample::getCurBuf() {
|
||||
|
|
@ -1550,6 +1596,8 @@ void* DivSample::getCurBuf() {
|
|||
return dataIMA;
|
||||
case DIV_SAMPLE_DEPTH_12BIT:
|
||||
return data12;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
return data4;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
return data16;
|
||||
default:
|
||||
|
|
@ -1588,6 +1636,8 @@ unsigned int DivSample::getCurBufLen() {
|
|||
return lengthIMA;
|
||||
case DIV_SAMPLE_DEPTH_12BIT:
|
||||
return length12;
|
||||
case DIV_SAMPLE_DEPTH_4BIT:
|
||||
return length4;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
return length16;
|
||||
default:
|
||||
|
|
@ -1703,4 +1753,5 @@ DivSample::~DivSample() {
|
|||
if (dataC219) delete[] dataC219;
|
||||
if (dataIMA) delete[] dataIMA;
|
||||
if (data12) delete[] data12;
|
||||
if (data4) delete[] data4;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ enum DivSampleDepth: unsigned char {
|
|||
DIV_SAMPLE_DEPTH_C219=12,
|
||||
DIV_SAMPLE_DEPTH_IMA_ADPCM=13,
|
||||
DIV_SAMPLE_DEPTH_12BIT=14,
|
||||
DIV_SAMPLE_DEPTH_4BIT=15,
|
||||
DIV_SAMPLE_DEPTH_16BIT=16,
|
||||
DIV_SAMPLE_DEPTH_MAX // boundary for sample depth
|
||||
};
|
||||
|
|
@ -147,8 +148,9 @@ struct DivSample {
|
|||
unsigned char* dataC219; // 12
|
||||
unsigned char* dataIMA; // 13
|
||||
unsigned char* data12; // 14
|
||||
unsigned char* data4; // 15
|
||||
|
||||
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthK, lengthBRR, lengthVOX, lengthMuLaw, lengthC219, lengthIMA, length12;
|
||||
unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthK, lengthBRR, lengthVOX, lengthMuLaw, lengthC219, lengthIMA, length12, length4;
|
||||
|
||||
unsigned int samples;
|
||||
|
||||
|
|
@ -360,6 +362,7 @@ struct DivSample {
|
|||
dataC219(NULL),
|
||||
dataIMA(NULL),
|
||||
data12(NULL),
|
||||
data4(NULL),
|
||||
length8(0),
|
||||
length16(0),
|
||||
length1(0),
|
||||
|
|
@ -375,6 +378,7 @@ struct DivSample {
|
|||
lengthC219(0),
|
||||
lengthIMA(0),
|
||||
length12(0),
|
||||
length4(0),
|
||||
samples(0) {
|
||||
for (int i=0; i<DIV_MAX_CHIPS; i++) {
|
||||
for (int j=0; j<DIV_MAX_SAMPLE_TYPE; j++) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
// this function is so long
|
||||
// may as well make it something else
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES) {
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection) {
|
||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||
unsigned char baseAddr2=isSecond?0x80:0;
|
||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||
|
|
@ -188,6 +188,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
case DIV_SYSTEM_YM2610_CSM:
|
||||
case DIV_SYSTEM_YM2610B_CSM:
|
||||
// TODO: YM2610B channels 1 and 4 and ADPCM-B
|
||||
for (int i=0; i<2; i++) { // set SL and RR to highest
|
||||
w->writeC(8|baseAddr1);
|
||||
|
|
@ -264,6 +266,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
case DIV_SYSTEM_YM2203:
|
||||
case DIV_SYSTEM_YM2203_EXT:
|
||||
case DIV_SYSTEM_YM2203_CSM:
|
||||
for (int i=0; i<3; i++) { // set SL and RR to highest
|
||||
w->writeC(5|baseAddr1);
|
||||
w->writeC(0x80+i);
|
||||
|
|
@ -761,8 +764,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
pendingFreq[streamID]=write.val;
|
||||
} else {
|
||||
DivSample* sample=song.sample[write.val];
|
||||
int pos=sampleOff8[write.val&0xff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[write.val&0xff]-setPos[streamID];
|
||||
int pos=sampleOff8[write.val&0x7fff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[write.val&0x7fff]-setPos[streamID];
|
||||
|
||||
if (len<0) len=0;
|
||||
|
||||
|
|
@ -795,7 +798,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
case 1: { // set sample freq
|
||||
sampleStoppable[streamID]=true;
|
||||
int realFreq=write.val;
|
||||
int realFreq=(write.val*44100)/rateCorrection;
|
||||
if (realFreq<0) realFreq=0;
|
||||
if (realFreq>44100) realFreq=44100;
|
||||
w->writeC(0x92);
|
||||
|
|
@ -804,8 +807,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
loopFreq[streamID]=realFreq;
|
||||
if (pendingFreq[streamID]!=-1) {
|
||||
DivSample* sample=song.sample[pendingFreq[streamID]];
|
||||
int pos=sampleOff8[pendingFreq[streamID]&0xff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[pendingFreq[streamID]&0xff]-setPos[streamID];
|
||||
int pos=sampleOff8[pendingFreq[streamID]&0x7fff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[pendingFreq[streamID]&0x7fff]-setPos[streamID];
|
||||
|
||||
if (len<0) len=0;
|
||||
|
||||
|
|
@ -856,8 +859,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
if (playingSample[streamID]!=-1 && pendingFreq[streamID]==-1) {
|
||||
// play the sample again
|
||||
DivSample* sample=song.sample[playingSample[streamID]];
|
||||
int pos=sampleOff8[playingSample[streamID]&0xff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[playingSample[streamID]&0xff]-setPos[streamID];
|
||||
int pos=sampleOff8[playingSample[streamID]&0x7fff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[playingSample[streamID]&0x7fff]-setPos[streamID];
|
||||
|
||||
if (len<0) len=0;
|
||||
|
||||
|
|
@ -977,6 +980,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
case DIV_SYSTEM_YM2610_CSM:
|
||||
case DIV_SYSTEM_YM2610B_CSM:
|
||||
switch (write.addr>>8) {
|
||||
case 0: // port 0
|
||||
w->writeC(8|baseAddr1);
|
||||
|
|
@ -992,12 +997,14 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
case DIV_SYSTEM_YM2203:
|
||||
case DIV_SYSTEM_YM2203_EXT:
|
||||
case DIV_SYSTEM_YM2203_CSM:
|
||||
w->writeC(5|baseAddr1);
|
||||
w->writeC(write.addr&0xff);
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
case DIV_SYSTEM_YM2608:
|
||||
case DIV_SYSTEM_YM2608_EXT:
|
||||
case DIV_SYSTEM_YM2608_CSM:
|
||||
switch (write.addr>>8) {
|
||||
case 0: // port 0
|
||||
w->writeC(6|baseAddr1);
|
||||
|
|
@ -1233,7 +1240,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
chipVol.push_back((_id)|(0x80000100)|(((unsigned int)_vol)<<16)); \
|
||||
}
|
||||
|
||||
SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool patternHints, bool directStream, int trailingTicks, bool dpcm07) {
|
||||
SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool patternHints, bool directStream, int trailingTicks, bool dpcm07, int correctedRate) {
|
||||
if (version<0x150) {
|
||||
lastError="VGM version is too low";
|
||||
return NULL;
|
||||
|
|
@ -1243,7 +1250,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
setOrder(0);
|
||||
BUSY_BEGIN_SOFT;
|
||||
double origRate=got.rate;
|
||||
got.rate=44100;
|
||||
got.rate=correctedRate;
|
||||
// determine loop point
|
||||
int loopOrder=0;
|
||||
int loopRow=0;
|
||||
|
|
@ -1322,9 +1329,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
int loopTickSong=-1;
|
||||
int songTick=0;
|
||||
|
||||
unsigned int sampleOff8[256];
|
||||
unsigned int sampleLen8[256];
|
||||
unsigned int sampleOffSegaPCM[256];
|
||||
unsigned int* sampleOff8=new unsigned int[32768];
|
||||
unsigned int* sampleLen8=new unsigned int[32768];
|
||||
unsigned int* sampleOffSegaPCM=new unsigned int[32768];
|
||||
|
||||
SafeWriter* w=new SafeWriter;
|
||||
w->init();
|
||||
|
|
@ -1516,6 +1523,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
case DIV_SYSTEM_YM2610_CSM:
|
||||
case DIV_SYSTEM_YM2610B_CSM:
|
||||
if (!hasOPNB) {
|
||||
hasOPNB=disCont[i].dispatch->chipClock;
|
||||
CHIP_VOL(8,1.0);
|
||||
|
|
@ -1531,7 +1540,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
hasOPNB|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
if (((song.system[i]==DIV_SYSTEM_YM2610B) || (song.system[i]==DIV_SYSTEM_YM2610B_EXT)) && (!(hasOPNB&0x80000000))) { // YM2610B flag
|
||||
if (((song.system[i]==DIV_SYSTEM_YM2610B) || (song.system[i]==DIV_SYSTEM_YM2610B_EXT) || (song.system[i]==DIV_SYSTEM_YM2610B_CSM)) && (!(hasOPNB&0x80000000))) { // YM2610B flag
|
||||
hasOPNB|=0x80000000;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1627,6 +1636,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
break;
|
||||
case DIV_SYSTEM_YM2203:
|
||||
case DIV_SYSTEM_YM2203_EXT:
|
||||
case DIV_SYSTEM_YM2203_CSM:
|
||||
if (!hasOPN) {
|
||||
hasOPN=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
|
|
@ -1643,6 +1653,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
break;
|
||||
case DIV_SYSTEM_YM2608:
|
||||
case DIV_SYSTEM_YM2608_EXT:
|
||||
case DIV_SYSTEM_YM2608_CSM:
|
||||
if (!hasOPNA) {
|
||||
hasOPNA=disCont[i].dispatch->chipClock;
|
||||
CHIP_VOL(7,1.0);
|
||||
|
|
@ -2191,9 +2202,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
unsigned int songOff=w->tell();
|
||||
|
||||
// initialize sample offsets
|
||||
memset(sampleOff8,0,256*sizeof(unsigned int));
|
||||
memset(sampleLen8,0,256*sizeof(unsigned int));
|
||||
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
|
||||
memset(sampleOff8,0,32768*sizeof(unsigned int));
|
||||
memset(sampleLen8,0,32768*sizeof(unsigned int));
|
||||
memset(sampleOffSegaPCM,0,32768*sizeof(unsigned int));
|
||||
|
||||
// write samples
|
||||
unsigned int sampleSeek=0;
|
||||
|
|
@ -2362,7 +2373,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
unsigned char* mem=((unsigned char*)writePCM_OPL4[i]->getSampleMem(0))+writePCM_OPL4[i]->getSampleMemOffset(0);
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC((writePCM_OPL4[i]->getSampleMemOffset(0)==0x200000)?0x87:0x84);
|
||||
w->writeC(0x84);
|
||||
w->writeI((usage+8)|(i*0x80000000));
|
||||
w->writeI(writePCM_OPL4[i]->getSampleMemCapacity(0));
|
||||
w->writeI(writePCM_OPL4[i]->getSampleMemOffset(0));
|
||||
|
|
@ -2849,7 +2860,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
lastOne=i.second.time;
|
||||
}
|
||||
// write write
|
||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable,dpcm07,writeNES);
|
||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable,dpcm07,writeNES,correctedRate);
|
||||
writeCount++;
|
||||
}
|
||||
sortedWrites.clear();
|
||||
|
|
@ -2966,6 +2977,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
|
||||
logI("%d register writes total.",writeCount);
|
||||
|
||||
delete[] sampleOff8;
|
||||
delete[] sampleLen8;
|
||||
delete[] sampleOffSegaPCM;
|
||||
|
||||
BUSY_END;
|
||||
return w;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,9 @@ void DivEngine::runExportThread() {
|
|||
|
||||
// take control of audio output
|
||||
deinitAudioBackend();
|
||||
freelance=false;
|
||||
playSub(false);
|
||||
freelance=false;
|
||||
|
||||
logI("rendering to file...");
|
||||
|
||||
|
|
@ -244,7 +246,9 @@ void DivEngine::runExportThread() {
|
|||
|
||||
// take control of audio output
|
||||
deinitAudioBackend();
|
||||
freelance=false;
|
||||
playSub(false);
|
||||
freelance=false;
|
||||
|
||||
logI("rendering to files...");
|
||||
|
||||
|
|
@ -380,7 +384,9 @@ void DivEngine::runExportThread() {
|
|||
totalLoops=0;
|
||||
isFadingOut=false;
|
||||
remainingLoops=-1;
|
||||
freelance=false;
|
||||
playSub(false);
|
||||
freelance=false;
|
||||
|
||||
while (playing) {
|
||||
size_t total=0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue