mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 13:05:11 +00:00
Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: fix MSVC oh my improvements to sysDef and UX changes # Conflicts: # src/engine/dispatchContainer.cpp # src/gui/insEdit.cpp
This commit is contained in:
commit
37216e323f
11 changed files with 519 additions and 4 deletions
|
@ -284,6 +284,8 @@ src/engine/platform/sound/x1_010/x1_010.cpp
|
|||
|
||||
src/engine/platform/sound/swan.cpp
|
||||
|
||||
src/engine/platform/sound/su.cpp
|
||||
|
||||
src/engine/platform/sound/k005289/k005289.cpp
|
||||
|
||||
src/engine/platform/sound/n163/n163.cpp
|
||||
|
@ -348,6 +350,7 @@ src/engine/platform/segapcm.cpp
|
|||
src/engine/platform/qsound.cpp
|
||||
src/engine/platform/x1_010.cpp
|
||||
src/engine/platform/lynx.cpp
|
||||
src/engine/platform/su.cpp
|
||||
src/engine/platform/swan.cpp
|
||||
src/engine/platform/vera.cpp
|
||||
src/engine/platform/bubsyswsg.cpp
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "platform/qsound.h"
|
||||
#include "platform/vera.h"
|
||||
#include "platform/x1_010.h"
|
||||
#include "platform/su.h"
|
||||
#include "platform/swan.h"
|
||||
#include "platform/lynx.h"
|
||||
#include "platform/bubsyswsg.h"
|
||||
|
@ -315,6 +316,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_ES5506:
|
||||
dispatch=new DivPlatformES5506;
|
||||
break;
|
||||
case DIV_SYSTEM_SOUND_UNIT:
|
||||
dispatch=new DivPlatformSoundUnit;
|
||||
break;
|
||||
case DIV_SYSTEM_DUMMY:
|
||||
dispatch=new DivPlatformDummy;
|
||||
break;
|
||||
|
|
|
@ -1070,8 +1070,10 @@ const char** DivEngine::getRegisterSheet(int sys) {
|
|||
}
|
||||
|
||||
void DivEngine::recalcChans() {
|
||||
bool isInsTypePossible[DIV_INS_MAX];
|
||||
chans=0;
|
||||
int chanIndex=0;
|
||||
memset(isInsTypePossible,0,DIV_INS_MAX*sizeof(bool));
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
int chanCount=getChannelCount(song.system[i]);
|
||||
chans+=chanCount;
|
||||
|
@ -1080,8 +1082,24 @@ void DivEngine::recalcChans() {
|
|||
dispatchOfChan[chanIndex]=i;
|
||||
dispatchChanOfChan[chanIndex]=j;
|
||||
chanIndex++;
|
||||
|
||||
if (sysDefs[song.system[i]]!=NULL) {
|
||||
if (sysDefs[song.system[i]]->chanInsType[j][0]!=DIV_INS_NULL) {
|
||||
isInsTypePossible[sysDefs[song.system[i]]->chanInsType[j][0]]=true;
|
||||
logV("Marking");
|
||||
}
|
||||
|
||||
if (sysDefs[song.system[i]]->chanInsType[j][1]!=DIV_INS_NULL) {
|
||||
isInsTypePossible[sysDefs[song.system[i]]->chanInsType[j][1]]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
possibleInsTypes.clear();
|
||||
for (int i=0; i<DIV_INS_MAX; i++) {
|
||||
if (isInsTypePossible[i]) possibleInsTypes.push_back((DivInstrumentType)i);
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::reset() {
|
||||
|
|
|
@ -220,7 +220,10 @@ struct DivSysDef {
|
|||
memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*));
|
||||
memset(chanShortNames,0,DIV_MAX_CHANS*sizeof(void*));
|
||||
memset(chanTypes,0,DIV_MAX_CHANS*sizeof(int));
|
||||
memset(chanInsType,0,DIV_MAX_CHANS*2*sizeof(DivInstrumentType));
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
chanInsType[i][0]=DIV_INS_NULL;
|
||||
chanInsType[i][1]=DIV_INS_NULL;
|
||||
}
|
||||
|
||||
int index=0;
|
||||
for (const char* i: chNames) {
|
||||
|
@ -317,6 +320,7 @@ class DivEngine {
|
|||
std::vector<String> midiIns;
|
||||
std::vector<String> midiOuts;
|
||||
std::vector<DivCommand> cmdStream;
|
||||
std::vector<DivInstrumentType> possibleInsTypes;
|
||||
DivSysDef* sysDefs[256];
|
||||
DivSystem sysFileMapFur[256];
|
||||
DivSystem sysFileMapDMF[256];
|
||||
|
@ -503,6 +507,9 @@ class DivEngine {
|
|||
// get channel count
|
||||
int getTotalChannelCount();
|
||||
|
||||
// get instrument types available for use
|
||||
std::vector<DivInstrumentType>& getPossibleInsTypes();
|
||||
|
||||
// get effect description
|
||||
const char* getEffectDesc(unsigned char effect, int chan, bool notNull=false);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#define _USE_MATH_DEFINES
|
||||
#include "su.h"
|
||||
#include <string.h>
|
||||
|
||||
|
@ -211,6 +212,10 @@ void SoundUnit::NextSample(short* l, short* r) {
|
|||
ocycle[i]=0;
|
||||
chan[i].flags.resosc=0;
|
||||
}
|
||||
if (muted[i]) {
|
||||
nsL[i]=0;
|
||||
nsR[i]=0;
|
||||
}
|
||||
}
|
||||
tnsL=(nsL[0]+nsL[1]+nsL[2]+nsL[3]+nsL[4]+nsL[5]+nsL[6]+nsL[7])>>2;
|
||||
tnsR=(nsR[0]+nsR[1]+nsR[2]+nsR[3]+nsR[4]+nsR[5]+nsR[6]+nsR[7])>>2;
|
||||
|
@ -233,22 +238,38 @@ void SoundUnit::Init() {
|
|||
SCpantabR[128+i]=i-1;
|
||||
}
|
||||
SCpantabR[128]=0;
|
||||
for (int i=0; i<8; i++) {
|
||||
muted[i]=false;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundUnit::Reset() {
|
||||
for (int i=0; i<8; i++) {
|
||||
ocycle[i]=0;
|
||||
cycle[i]=0;
|
||||
rcycle[i]=0;
|
||||
resetfreq[i]=0;
|
||||
voldcycles[i]=0;
|
||||
volicycles[i]=0;
|
||||
fscycles[i]=0;
|
||||
sweep[i]=0;
|
||||
ns[i]=0;
|
||||
fns[i]=0;
|
||||
nsL[i]=0;
|
||||
nsR[i]=0;
|
||||
nslow[i]=0;
|
||||
nshigh[i]=0;
|
||||
nsband[i]=0;
|
||||
swvolt[i]=1;
|
||||
swfreqt[i]=1;
|
||||
swcutt[i]=1;
|
||||
lfsr[i]=0xaaaa;
|
||||
oldfreq[i]=0;
|
||||
oldflags[i]=0;
|
||||
pcmdec[i]=0;
|
||||
}
|
||||
tnsL=0;
|
||||
tnsR=0;
|
||||
memset(chan,0,sizeof(SUChannel)*8);
|
||||
}
|
||||
|
||||
|
@ -258,4 +279,5 @@ void SoundUnit::Write(unsigned char addr, unsigned char data) {
|
|||
|
||||
SoundUnit::SoundUnit() {
|
||||
Init();
|
||||
memset(pcm,0,SOUNDCHIP_PCM_SIZE);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ class SoundUnit {
|
|||
unsigned short restimer;
|
||||
} chan[8];
|
||||
signed char pcm[SOUNDCHIP_PCM_SIZE];
|
||||
bool muted[8];
|
||||
void Write(unsigned char addr, unsigned char data);
|
||||
void NextSample(short* l, short* r);
|
||||
void Init();
|
||||
|
|
325
src/engine/platform/su.cpp
Normal file
325
src/engine/platform/su.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "su.h"
|
||||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
//#define rWrite(a,v) pendingWrites[a]=v;
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
#define chWrite(c,a,v) rWrite(((c)<<5)|(a),v);
|
||||
|
||||
#define CHIP_FREQBASE 524288
|
||||
|
||||
const char** DivPlatformSoundUnit::getRegisterSheet() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* DivPlatformSoundUnit::getEffectName(unsigned char effect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
su->Write(w.addr,w.val);
|
||||
writes.pop();
|
||||
}
|
||||
su->NextSample(&bufL[h],&bufR[h]);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::writeControl(int ch) {
|
||||
chWrite(ch,0x04,(chan[ch].wave&7)|(chan[ch].pcm<<3)|(chan[ch].control<<4));
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::tick(bool sysTick) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
||||
chWrite(i,0x02,chan[i].outVol);
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
chWrite(i,0x08,chan[i].duty);
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
chan[i].wave=chan[i].std.wave.val&7;
|
||||
writeControl(i);
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val;
|
||||
chWrite(i,0x03,chan[i].pan);
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
chan[i].cutoff=chan[i].std.ex1.val;
|
||||
chWrite(i,0x06,chan[i].cutoff&0xff);
|
||||
chWrite(i,0x07,chan[i].cutoff>>8);
|
||||
}
|
||||
if (chan[i].std.ex2.had) {
|
||||
chan[i].res=chan[i].std.ex2.val;
|
||||
chWrite(i,0x09,chan[i].res);
|
||||
}
|
||||
if (chan[i].std.ex3.had) {
|
||||
chan[i].control=chan[i].std.ex3.val&15;
|
||||
writeControl(i);
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
|
||||
chWrite(i,0x00,chan[i].freq&0xff);
|
||||
chWrite(i,0x01,chan[i].freq>>8);
|
||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
if (chan[i].keyOn) {
|
||||
//rWrite(16+i*5,0x80);
|
||||
//chWrite(i,0x04,0x80|chan[i].vol);
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
chWrite(i,0x02,0);
|
||||
}
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chWrite(c.chan,0x02,chan[c.chan].vol);
|
||||
chan[c.chan].std.init(ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].std.init(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
chan[c.chan].ins=c.value;
|
||||
chan[c.chan].insChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan[c.chan].vol!=c.value) {
|
||||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
if (chan[c.chan].active) chWrite(c.chan,0x02,chan[c.chan].outVol);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
if (chan[c.chan].std.vol.has) {
|
||||
return chan[c.chan].vol;
|
||||
}
|
||||
return chan[c.chan].outVol;
|
||||
break;
|
||||
case DIV_CMD_PITCH:
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_WAVE:
|
||||
chan[c.chan].wave=c.value;
|
||||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value*(1+(chan[c.chan].baseFreq>>9));
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value*(1+(chan[c.chan].baseFreq>>9));
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].pan=c.value;
|
||||
chWrite(c.chan,0x03,chan[c.chan].pan);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
su->muted[ch]=mute;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::forceIns() {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformSoundUnit::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformSoundUnit::getRegisterPool() {
|
||||
return (unsigned char*)su->chan;
|
||||
}
|
||||
|
||||
int DivPlatformSoundUnit::getRegisterPoolSize() {
|
||||
return 256;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
memset(regPool,0,128);
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i]=DivPlatformSoundUnit::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
su->Reset();
|
||||
for (int i=0; i<8; i++) {
|
||||
chWrite(i,0x08,0x3f);
|
||||
}
|
||||
lastPan=0xff;
|
||||
cycles=0;
|
||||
curChan=-1;
|
||||
sampleBank=0;
|
||||
lfoMode=0;
|
||||
lfoSpeed=255;
|
||||
delay=500;
|
||||
}
|
||||
|
||||
bool DivPlatformSoundUnit::isStereo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivPlatformSoundUnit::keyOffAffectsArp(int ch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::setFlags(unsigned int flags) {
|
||||
if (flags&1) {
|
||||
chipClock=1190000;
|
||||
} else {
|
||||
chipClock=1236000;
|
||||
}
|
||||
rate=chipClock/4;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::poke(unsigned int addr, unsigned short val) {
|
||||
rWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<8; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
setFlags(flags);
|
||||
su=new SoundUnit();
|
||||
su->Init();
|
||||
reset();
|
||||
return 6;
|
||||
}
|
||||
|
||||
void DivPlatformSoundUnit::quit() {
|
||||
delete su;
|
||||
}
|
||||
|
||||
DivPlatformSoundUnit::~DivPlatformSoundUnit() {
|
||||
}
|
102
src/engine/platform/su.h
Normal file
102
src/engine/platform/su.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _SU_H
|
||||
#define _SU_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include <queue>
|
||||
#include "../macroInt.h"
|
||||
#include "sound/su.h"
|
||||
|
||||
class DivPlatformSoundUnit: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, note;
|
||||
int ins, cutoff, res, control;
|
||||
signed char pan;
|
||||
unsigned char duty;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm;
|
||||
signed char vol, outVol, wave;
|
||||
DivMacroInt std;
|
||||
Channel():
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
cutoff(65535),
|
||||
res(0),
|
||||
control(0),
|
||||
pan(0),
|
||||
duty(63),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
noise(false),
|
||||
pcm(false),
|
||||
vol(127),
|
||||
outVol(127),
|
||||
wave(-1) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
bool isMuted[8];
|
||||
struct QueuedWrite {
|
||||
unsigned char addr;
|
||||
unsigned char val;
|
||||
QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
std::queue<QueuedWrite> writes;
|
||||
unsigned char lastPan;
|
||||
|
||||
int cycles, curChan, delay;
|
||||
short tempL;
|
||||
short tempR;
|
||||
unsigned char sampleBank, lfoMode, lfoSpeed;
|
||||
SoundUnit* su;
|
||||
unsigned char regPool[128];
|
||||
void writeControl(int ch);
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(unsigned int flags);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformSoundUnit();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -48,6 +48,10 @@ int DivEngine::getTotalChannelCount() {
|
|||
return chans;
|
||||
}
|
||||
|
||||
std::vector<DivInstrumentType>& DivEngine::getPossibleInsTypes() {
|
||||
return possibleInsTypes;
|
||||
}
|
||||
|
||||
// TODO: rewrite this function (again). it's an unreliable mess.
|
||||
const char* DivEngine::getSongSystemName() {
|
||||
switch (song.systemLen) {
|
||||
|
@ -358,7 +362,7 @@ int DivEngine::minVGMVersion(DivSystem which) {
|
|||
|
||||
void DivEngine::registerSystems() {
|
||||
logD("registering systems...");
|
||||
|
||||
|
||||
sysDefs[DIV_SYSTEM_YMU759]=new DivSysDef(
|
||||
"Yamaha YMU759", NULL, 0x01, 0x01, 17, true, false, 0, false,
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "PCM" }, // name
|
||||
|
|
|
@ -2729,7 +2729,7 @@ bool FurnaceGUI::loop() {
|
|||
editOptions(true);
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("clear...")) {
|
||||
showWarning("Are you sure you want to clear...",GUI_WARN_CLEAR);
|
||||
showWarning("Are you sure you want to clear... (cannot be undone!)",GUI_WARN_CLEAR);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
|
|
@ -179,6 +179,10 @@ const char* es5506FilterModes[4]={
|
|||
"HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1",
|
||||
};
|
||||
|
||||
const char* suControlBits[5]={
|
||||
"ring mod", "low pass", "band pass", "high pass", NULL
|
||||
};
|
||||
|
||||
const char* panBits[3]={
|
||||
"right", "left", NULL
|
||||
};
|
||||
|
@ -1418,9 +1422,19 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM;
|
||||
int insType=ins->type;
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
/*
|
||||
if (ImGui::Combo("##Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) {
|
||||
ins->type=(DivInstrumentType)insType;
|
||||
}
|
||||
*/
|
||||
if (ImGui::BeginCombo("##Type",insTypes[insType])) {
|
||||
for (DivInstrumentType i: e->getPossibleInsTypes()) {
|
||||
if (ImGui::Selectable(insTypes[i],insType==i)) {
|
||||
ins->type=i;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -2776,7 +2790,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_AMIGA) {
|
||||
volMax=64;
|
||||
}
|
||||
if (ins->type==DIV_INS_FM || ins->type == DIV_INS_MIKEY) {
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SU) {
|
||||
volMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_GB) {
|
||||
|
@ -2851,6 +2865,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
dutyLabel="Filter Mode";
|
||||
dutyMax=3;
|
||||
}
|
||||
if (ins->type==DIV_INS_SU) {
|
||||
dutyMax=127;
|
||||
}
|
||||
bool dutyIsRel=(ins->type==DIV_INS_C64 && !ins->c64.dutyIsAbs);
|
||||
|
||||
const char* waveLabel="Waveform";
|
||||
|
@ -2866,6 +2883,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) waveMax=0;
|
||||
if (ins->type==DIV_INS_MIKEY) waveMax=0;
|
||||
if (ins->type==DIV_INS_ES5506) waveMax=255;
|
||||
if (ins->type==DIV_INS_SU) waveMax=7;
|
||||
if (ins->type==DIV_INS_PET) {
|
||||
waveMax=8;
|
||||
bitMode=true;
|
||||
|
@ -2901,6 +2919,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ex1Max=63;
|
||||
ex2Max=4095;
|
||||
}
|
||||
if (ins->type==DIV_INS_SU) {
|
||||
ex1Max=65535;
|
||||
ex2Max=255;
|
||||
}
|
||||
if (ins->type==DIV_INS_SAA1099) ex1Max=8;
|
||||
if (ins->type==DIV_INS_ES5506) {
|
||||
ex1Max=65535;
|
||||
|
@ -2979,6 +3001,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
|
||||
} else if (ins->type==DIV_INS_ES5506) {
|
||||
NORMAL_MACRO(ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,"ex1","Filter K1",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,true,2,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,NULL,false);
|
||||
} else if (ins->type==DIV_INS_SU) {
|
||||
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Cutoff",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
|
||||
} else {
|
||||
NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
|
||||
}
|
||||
|
@ -2992,6 +3016,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
|
||||
} else if (ins->type==DIV_INS_ES5506) {
|
||||
NORMAL_MACRO(ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,"ex2","Filter K2",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,true,2,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,NULL,false);
|
||||
} else if (ins->type==DIV_INS_SU) {
|
||||
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
|
||||
} else {
|
||||
NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
|
||||
}
|
||||
|
@ -3025,6 +3051,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
NORMAL_MACRO(ins->std.ex7Macro,-128,127,"ex7","Envelope K2 ramp",160,ins->std.ex7Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],-128,127,NULL,false);
|
||||
NORMAL_MACRO(ins->std.ex8Macro,0,2,"ex8","Envelope mode",64,ins->std.ex8Macro.open,true,es5506EnvelopeModes,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[11],0,2,NULL,false);
|
||||
}
|
||||
if (ins->type==DIV_INS_SU) {
|
||||
NORMAL_MACRO(ins->std.ex3Macro,0,4,"ex3","Control",64,ins->std.ex3Macro.open,true,suControlBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,4,NULL,false);
|
||||
}
|
||||
|
||||
MACRO_END;
|
||||
} else { // classic view (TODO: possibly remove)
|
||||
|
|
Loading…
Reference in a new issue