mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 22:43:01 +00:00
Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
66f7ab688b
23 changed files with 1760 additions and 50 deletions
|
@ -435,6 +435,7 @@ src/engine/platform/sound/ymz280b.cpp
|
|||
|
||||
src/engine/platform/sound/rf5c68.cpp
|
||||
|
||||
src/engine/platform/sound/oki/msm5232.cpp
|
||||
src/engine/platform/sound/oki/okim6258.cpp
|
||||
|
||||
src/engine/platform/sound/snes/SPC_DSP.cpp
|
||||
|
@ -493,6 +494,7 @@ src/engine/platform/fds.cpp
|
|||
src/engine/platform/tia.cpp
|
||||
src/engine/platform/saa.cpp
|
||||
src/engine/platform/amiga.cpp
|
||||
src/engine/platform/msm5232.cpp
|
||||
src/engine/platform/msm6258.cpp
|
||||
src/engine/platform/msm6295.cpp
|
||||
src/engine/platform/pcspkr.cpp
|
||||
|
|
|
@ -452,8 +452,8 @@ size | description
|
|||
4 | size of this block
|
||||
2 | format version (see header)
|
||||
1 | instrument type
|
||||
| - 0: standard
|
||||
| - 1: FM (OPM/OPN)
|
||||
| - 0: SN76489/standard
|
||||
| - 1: FM (OPN)
|
||||
| - 2: Game Boy
|
||||
| - 3: C64
|
||||
| - 4: Amiga/sample
|
||||
|
@ -485,6 +485,17 @@ size | description
|
|||
| - 30: Sound Unit
|
||||
| - 31: Namco WSG
|
||||
| - 32: OPL (drums)
|
||||
| - 33: FM (OPM)
|
||||
| - 34: NES
|
||||
| - 35: MSM6258
|
||||
| - 36: MSM6295
|
||||
| - 37: ADPCM-A
|
||||
| - 38: ADPCM-B
|
||||
| - 39: SegaPCM
|
||||
| - 40: QSound
|
||||
| - 41: YMZ280B
|
||||
| - 42: RF5C68
|
||||
| - 43: MSM5232
|
||||
1 | reserved
|
||||
STR | instrument name
|
||||
--- | **FM instrument data**
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "engine.h"
|
||||
#include "platform/genesis.h"
|
||||
#include "platform/genesisext.h"
|
||||
#include "platform/msm5232.h"
|
||||
#include "platform/msm6258.h"
|
||||
#include "platform/msm6295.h"
|
||||
#include "platform/namcowsg.h"
|
||||
|
@ -390,6 +391,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_MSM6295:
|
||||
dispatch=new DivPlatformMSM6295;
|
||||
break;
|
||||
case DIV_SYSTEM_MSM5232:
|
||||
dispatch=new DivPlatformMSM5232;
|
||||
break;
|
||||
case DIV_SYSTEM_NAMCO:
|
||||
dispatch=new DivPlatformNamcoWSG;
|
||||
// Pac-Man (TODO: support Pole Position?)
|
||||
|
|
|
@ -2127,12 +2127,13 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
|||
blip_clear(samp_bb);
|
||||
double rate=song.sample[sample]->rate;
|
||||
if (note>=0) {
|
||||
rate=(song.tuning*pow(2.0,(double)(note+3)/12.0)*((double)song.sample[sample]->centerRate/8363.0));
|
||||
rate=(pow(2.0,(double)(note)/12.0)*((double)song.sample[sample]->centerRate)*0.0625);
|
||||
if (rate<=0) rate=song.sample[sample]->rate;
|
||||
}
|
||||
if (rate<100) rate=100;
|
||||
blip_set_rates(samp_bb,rate,got.rate);
|
||||
samp_prevSample=0;
|
||||
sPreview.rate=rate;
|
||||
sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0;
|
||||
sPreview.sample=sample;
|
||||
sPreview.wave=-1;
|
||||
|
@ -2166,6 +2167,7 @@ void DivEngine::previewWave(int wave, int note) {
|
|||
if (rate<100) rate=100;
|
||||
blip_set_rates(samp_bb,rate,got.rate);
|
||||
samp_prevSample=0;
|
||||
sPreview.rate=rate;
|
||||
sPreview.pos=0;
|
||||
sPreview.sample=-1;
|
||||
sPreview.wave=wave;
|
||||
|
@ -2181,6 +2183,18 @@ void DivEngine::stopWavePreview() {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
bool DivEngine::isPreviewingSample() {
|
||||
return (sPreview.sample>=0 && sPreview.sample<(int)song.sample.size());
|
||||
}
|
||||
|
||||
int DivEngine::getSamplePreviewPos() {
|
||||
return sPreview.pos;
|
||||
}
|
||||
|
||||
double DivEngine::getSamplePreviewRate() {
|
||||
return sPreview.rate;
|
||||
}
|
||||
|
||||
String DivEngine::getConfigPath() {
|
||||
return configPath;
|
||||
}
|
||||
|
|
|
@ -387,12 +387,14 @@ class DivEngine {
|
|||
DivSystem sysFileMapDMF[256];
|
||||
|
||||
struct SamplePreview {
|
||||
double rate;
|
||||
int sample;
|
||||
int wave;
|
||||
int pos;
|
||||
int pBegin, pEnd;
|
||||
bool dir;
|
||||
SamplePreview():
|
||||
rate(0.0),
|
||||
sample(-1),
|
||||
wave(-1),
|
||||
pos(0),
|
||||
|
@ -601,6 +603,11 @@ class DivEngine {
|
|||
// reset playback state
|
||||
void syncReset();
|
||||
|
||||
// sample preview query
|
||||
bool isPreviewingSample();
|
||||
int getSamplePreviewPos();
|
||||
double getSamplePreviewRate();
|
||||
|
||||
// trigger sample preview
|
||||
void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1);
|
||||
void stopSamplePreview();
|
||||
|
|
|
@ -1502,11 +1502,36 @@ bool DivInstrument::saveDMP(const char* path) {
|
|||
}
|
||||
|
||||
w->writeC(std.arpMacro.len);
|
||||
bool arpMacroMode=false;
|
||||
int arpMacroHowManyFixed=0;
|
||||
int realArpMacroLen=std.arpMacro.len;
|
||||
for (int i=0; i<std.arpMacro.len; i++) {
|
||||
w->writeI(std.arpMacro.val[i]+12);
|
||||
if ((std.arpMacro.val[i]&0xc0000000)==0x40000000 || (std.arpMacro.val[i]&0xc0000000)==0x80000000) {
|
||||
arpMacroHowManyFixed++;
|
||||
}
|
||||
}
|
||||
if (std.arpMacro.len>0) w->writeC(std.arpMacro.loop);
|
||||
w->writeC(std.arpMacro.mode);
|
||||
if (arpMacroHowManyFixed>=std.arpMacro.len-1) {
|
||||
arpMacroMode=true;
|
||||
}
|
||||
if (std.arpMacro.len>0) {
|
||||
if (arpMacroMode && std.arpMacro.val[std.arpMacro.len-1]==0 && std.arpMacro.loop>=std.arpMacro.len) {
|
||||
realArpMacroLen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (arpMacroMode) {
|
||||
for (int i=0; i<realArpMacroLen; i++) {
|
||||
w->writeI(std.arpMacro.val[i]);
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<realArpMacroLen; i++) {
|
||||
w->writeI(std.arpMacro.val[i]+12);
|
||||
}
|
||||
}
|
||||
if (realArpMacroLen>0) {
|
||||
w->writeC(std.arpMacro.loop);
|
||||
}
|
||||
w->writeC(arpMacroMode);
|
||||
|
||||
w->writeC(std.dutyMacro.len);
|
||||
for (int i=0; i<std.dutyMacro.len; i++) {
|
||||
|
|
|
@ -72,6 +72,7 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_QSOUND=40,
|
||||
DIV_INS_YMZ280B=41,
|
||||
DIV_INS_RF5C68=42,
|
||||
DIV_INS_MSM5232=43,
|
||||
DIV_INS_MAX,
|
||||
DIV_INS_NULL
|
||||
};
|
||||
|
|
421
src/engine/platform/msm5232.cpp
Normal file
421
src/engine/platform/msm5232.cpp
Normal file
|
@ -0,0 +1,421 @@
|
|||
/**
|
||||
* 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 "msm5232.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 NOTE_LINEAR(x) ((x)<<7)
|
||||
|
||||
const char* regCheatSheetMSM5232[]={
|
||||
"Select", "0",
|
||||
"MasterVol", "1",
|
||||
"FreqL", "2",
|
||||
"FreqH", "3",
|
||||
"DataCtl", "4",
|
||||
"ChanVol", "5",
|
||||
"WaveCtl", "6",
|
||||
"NoiseCtl", "7",
|
||||
"LFOFreq", "8",
|
||||
"LFOCtl", "9",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformMSM5232::getRegisterSheet() {
|
||||
return regCheatSheetMSM5232;
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::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();
|
||||
msm->write(w.addr,w.val);
|
||||
regPool[w.addr&0x0f]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
memset(temp,0,16*sizeof(short));
|
||||
|
||||
/*for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP((pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1])<<1,-32768,32767);
|
||||
}*/
|
||||
|
||||
msm->sound_stream_update(temp);
|
||||
|
||||
//printf("tempL: %d tempR: %d\n",tempL,tempR);
|
||||
bufL[h]=0;
|
||||
for (int i=0; i<8; i++) {
|
||||
bufL[h]+=(temp[i]*partVolume[i])>>8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int attackMap[8]={
|
||||
0, 1, 2, 3, 4, 5, 5, 5
|
||||
};
|
||||
|
||||
const int decayMap[16]={
|
||||
0, 1, 2, 3, 8, 9, 4, 10, 5, 11, 12, 13, 13, 13, 13, 13
|
||||
};
|
||||
|
||||
void DivPlatformMSM5232::tick(bool sysTick) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&127,MIN(127,chan[i].std.vol.val),127);
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=NOTE_LINEAR(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
groupControl[i>>2]=(chan[i].std.duty.val&0x1f)|(groupEnv[i>>2]?0x20:0);
|
||||
updateGroup[i>>2]=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) { // attack
|
||||
groupAR[i>>2]=attackMap[chan[i].std.ex1.val&7];
|
||||
updateGroupAR[i>>2]=true;
|
||||
}
|
||||
if (chan[i].std.ex2.had) { // decay
|
||||
groupDR[i>>2]=decayMap[chan[i].std.ex2.val&15];
|
||||
updateGroupDR[i>>2]=true;
|
||||
}
|
||||
if (chan[i].std.ex3.had) { // noise
|
||||
chan[i].noise=chan[i].std.ex3.val;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<2; i++) {
|
||||
if (updateGroup[i]) {
|
||||
rWrite(12+i,groupControl[i]);
|
||||
updateGroup[i]=false;
|
||||
}
|
||||
if (updateGroupAR[i]) {
|
||||
rWrite(8+i,groupAR[i]);
|
||||
updateGroupAR[i]=false;
|
||||
}
|
||||
if (updateGroupDR[i]) {
|
||||
rWrite(10+i,groupDR[i]);
|
||||
updateGroupDR[i]=false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
|
||||
chan[i].freq=chan[i].baseFreq+chan[i].pitch+chan[i].pitch2-(12<<7);
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>0x2aff) chan[i].freq=0x2aff;
|
||||
if (chan[i].keyOn) {
|
||||
//rWrite(16+i*5,0x80);
|
||||
//chWrite(i,0x04,0x80|chan[i].vol);
|
||||
}
|
||||
if (chan[i].active) {
|
||||
rWrite(i,chan[i].noise?0xd8:(0x80|(chan[i].freq>>7)));
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(i,0);
|
||||
}
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
}
|
||||
|
||||
msm->set_vol_input(
|
||||
chan[0].active?((double)chan[0].outVol/127.0):0.0,
|
||||
chan[1].active?((double)chan[1].outVol/127.0):0.0,
|
||||
chan[2].active?((double)chan[2].outVol/127.0):0.0,
|
||||
chan[3].active?((double)chan[3].outVol/127.0):0.0,
|
||||
chan[4].active?((double)chan[4].outVol/127.0):0.0,
|
||||
chan[5].active?((double)chan[5].outVol/127.0):0.0,
|
||||
chan[6].active?((double)chan[6].outVol/127.0):0.0,
|
||||
chan[7].active?((double)chan[7].outVol/127.0):0.0
|
||||
);
|
||||
}
|
||||
|
||||
int DivPlatformMSM5232::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_LINEAR(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].macroInit(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;
|
||||
}
|
||||
}
|
||||
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_NOTE_PORTA: {
|
||||
int destFreq=NOTE_LINEAR(c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value*parent->song.pitchSlideSpeed;
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value*parent->song.pitchSlideSpeed;
|
||||
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_STD_NOISE_MODE:
|
||||
chan[c.chan].noise=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_LINEAR(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].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
|
||||
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 DivPlatformMSM5232::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
msm->mute(ch,mute);
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::forceIns() {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
for (int i=0; i<2; i++) {
|
||||
updateGroup[i]=true;
|
||||
updateGroupAR[i]=true;
|
||||
updateGroupDR[i]=true;
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformMSM5232::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformMSM5232::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformMSM5232::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformMSM5232::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformMSM5232::getRegisterPoolSize() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
memset(regPool,0,128);
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i]=DivPlatformMSM5232::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
msm->device_start();
|
||||
msm->device_reset();
|
||||
memset(temp,0,16*sizeof(short));
|
||||
cycles=0;
|
||||
curChan=-1;
|
||||
delay=500;
|
||||
|
||||
for (int i=0; i<2; i++) {
|
||||
groupControl[i]=15|(groupEnv[i]?0x20:0);
|
||||
groupAR[i]=0;
|
||||
groupDR[i]=5;
|
||||
|
||||
updateGroup[i]=true;
|
||||
updateGroupAR[i]=true;
|
||||
updateGroupDR[i]=true;
|
||||
}
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
rWrite(i,0);
|
||||
partVolume[i]=initPartVolume[i];
|
||||
msm->mute(i,isMuted[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool DivPlatformMSM5232::isStereo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DivPlatformMSM5232::keyOffAffectsArp(int ch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::setFlags(const DivConfig& flags) {
|
||||
chipClock=2119040;
|
||||
detune=flags.getInt("detune",0);
|
||||
msm->set_clock(chipClock+detune*1024);
|
||||
rate=msm->get_rate();
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
initPartVolume[0]=flags.getInt("partVolume0",255);
|
||||
initPartVolume[1]=flags.getInt("partVolume1",255);
|
||||
initPartVolume[2]=flags.getInt("partVolume2",255);
|
||||
initPartVolume[3]=flags.getInt("partVolume3",255);
|
||||
initPartVolume[4]=flags.getInt("partVolume4",255);
|
||||
initPartVolume[5]=flags.getInt("partVolume5",255);
|
||||
initPartVolume[6]=flags.getInt("partVolume6",255);
|
||||
initPartVolume[7]=flags.getInt("partVolume7",255);
|
||||
|
||||
capacitance[0]=flags.getFloat("capValue0",390.0f);
|
||||
capacitance[1]=flags.getFloat("capValue1",390.0f);
|
||||
capacitance[2]=flags.getFloat("capValue2",390.0f);
|
||||
capacitance[3]=flags.getFloat("capValue3",390.0f);
|
||||
capacitance[4]=flags.getFloat("capValue4",390.0f);
|
||||
capacitance[5]=flags.getFloat("capValue5",390.0f);
|
||||
capacitance[6]=flags.getFloat("capValue6",390.0f);
|
||||
capacitance[7]=flags.getFloat("capValue7",390.0f);
|
||||
|
||||
groupEnv[0]=flags.getBool("groupEnv0",true);
|
||||
groupEnv[1]=flags.getBool("groupEnv1",true);
|
||||
|
||||
msm->set_capacitors(
|
||||
capacitance[0]*0.000000001,
|
||||
capacitance[1]*0.000000001,
|
||||
capacitance[2]*0.000000001,
|
||||
capacitance[3]*0.000000001,
|
||||
capacitance[4]*0.000000001,
|
||||
capacitance[5]*0.000000001,
|
||||
capacitance[6]*0.000000001,
|
||||
capacitance[7]*0.000000001
|
||||
);
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::poke(unsigned int addr, unsigned short val) {
|
||||
rWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformMSM5232::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<8; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
msm=new msm5232_device(2119040);
|
||||
msm->device_start();
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 8;
|
||||
}
|
||||
|
||||
void DivPlatformMSM5232::quit() {
|
||||
for (int i=0; i<8; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
if (msm!=NULL) {
|
||||
msm->device_stop();
|
||||
delete msm;
|
||||
msm=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformMSM5232::~DivPlatformMSM5232() {
|
||||
}
|
106
src/engine/platform/msm5232.h
Normal file
106
src/engine/platform/msm5232.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* 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 _MSM5232_H
|
||||
#define _MSM5232_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include <queue>
|
||||
#include "../macroInt.h"
|
||||
#include "sound/oki/msm5232.h"
|
||||
|
||||
class DivPlatformMSM5232: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, pitch2, note;
|
||||
int ins;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise;
|
||||
signed char vol, outVol;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel():
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
noise(false),
|
||||
vol(127),
|
||||
outVol(127) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
DivDispatchOscBuffer* oscBuf[8];
|
||||
int partVolume[8];
|
||||
int initPartVolume[8];
|
||||
double capacitance[8];
|
||||
bool isMuted[8];
|
||||
bool updateGroup[2];
|
||||
bool updateGroupAR[2];
|
||||
bool updateGroupDR[2];
|
||||
bool groupEnv[2];
|
||||
unsigned char groupControl[2];
|
||||
unsigned char groupAR[2];
|
||||
unsigned char groupDR[2];
|
||||
struct QueuedWrite {
|
||||
unsigned char addr;
|
||||
unsigned char val;
|
||||
QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
std::queue<QueuedWrite> writes;
|
||||
|
||||
int cycles, curChan, delay, detune;
|
||||
short temp[16];
|
||||
msm5232_device* msm;
|
||||
unsigned char regPool[128];
|
||||
friend void putDispatchChip(void*,int);
|
||||
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);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(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(const DivConfig& flags);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformMSM5232();
|
||||
};
|
||||
|
||||
#endif
|
735
src/engine/platform/sound/oki/msm5232.cpp
Normal file
735
src/engine/platform/sound/oki/msm5232.cpp
Normal file
|
@ -0,0 +1,735 @@
|
|||
// license:GPL-2.0+
|
||||
// copyright-holders:Jarek Burczynski, Hiromitsu Shioya
|
||||
// additional modifications for Furnace by tildearrow
|
||||
#include "msm5232.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CLOCK_RATE_DIVIDER 16
|
||||
|
||||
/*
|
||||
OKI MSM5232RS
|
||||
8 channel tone generator
|
||||
*/
|
||||
|
||||
msm5232_device::msm5232_device(uint32_t clock)
|
||||
: m_noise_cnt(0), m_noise_step(0), m_noise_rng(0), m_noise_clocks(0), m_UpdateStep(0), m_control1(0), m_control2(0), m_gate(0), m_chip_clock(0), m_rate(0), m_clock(clock)
|
||||
, m_gate_handler_cb(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void msm5232_device::device_start()
|
||||
{
|
||||
int rate = m_clock/CLOCK_RATE_DIVIDER;
|
||||
|
||||
init(m_clock, rate);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void msm5232_device::device_reset()
|
||||
{
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
write(i, 0x80);
|
||||
write(i, 0x00);
|
||||
}
|
||||
m_noise_cnt = 0;
|
||||
m_noise_rng = 1;
|
||||
m_noise_clocks = 0;
|
||||
|
||||
m_control1 = 0;
|
||||
m_EN_out16[0] = 0;
|
||||
m_EN_out8[0] = 0;
|
||||
m_EN_out4[0] = 0;
|
||||
m_EN_out2[0] = 0;
|
||||
|
||||
m_control2 = 0;
|
||||
m_EN_out16[1] = 0;
|
||||
m_EN_out8[1] = 0;
|
||||
m_EN_out4[1] = 0;
|
||||
m_EN_out2[1] = 0;
|
||||
|
||||
gate_update();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_stop - device-specific stop
|
||||
//-------------------------------------------------
|
||||
|
||||
void msm5232_device::device_stop()
|
||||
{
|
||||
}
|
||||
|
||||
void msm5232_device::set_capacitors(double cap1, double cap2, double cap3, double cap4, double cap5, double cap6, double cap7, double cap8)
|
||||
{
|
||||
m_external_capacity[0] = cap1;
|
||||
m_external_capacity[1] = cap2;
|
||||
m_external_capacity[2] = cap3;
|
||||
m_external_capacity[3] = cap4;
|
||||
m_external_capacity[4] = cap5;
|
||||
m_external_capacity[5] = cap6;
|
||||
m_external_capacity[6] = cap7;
|
||||
m_external_capacity[7] = cap8;
|
||||
}
|
||||
|
||||
void msm5232_device::set_vol_input(double v1, double v2, double v3, double v4, double v5, double v6, double v7, double v8)
|
||||
{
|
||||
m_external_input[0] = v1;
|
||||
m_external_input[1] = v2;
|
||||
m_external_input[2] = v3;
|
||||
m_external_input[3] = v4;
|
||||
m_external_input[4] = v5;
|
||||
m_external_input[5] = v6;
|
||||
m_external_input[6] = v7;
|
||||
m_external_input[7] = v8;
|
||||
}
|
||||
|
||||
/* Default chip clock is 2119040 Hz */
|
||||
/* At this clock chip generates exactly 440.0 Hz signal on 8' output when pitch data=0x21 */
|
||||
|
||||
|
||||
/* ROM table to convert from pitch data into data for programmable counter and binary counter */
|
||||
/* Chip has 88x12bits ROM (addressing (in hex) from 0x00 to 0x57) */
|
||||
#define ROM(counter,bindiv) (counter|(bindiv<<9))
|
||||
|
||||
static const uint16_t MSM5232_ROM[88]={
|
||||
/* higher values are Programmable Counter data (9 bits) */
|
||||
/* lesser values are Binary Counter shift data (3 bits) */
|
||||
|
||||
/* 0 */ ROM (506, 7),
|
||||
|
||||
/* 1 */ ROM (478, 7),/* 2 */ ROM (451, 7),/* 3 */ ROM (426, 7),/* 4 */ ROM (402, 7),
|
||||
/* 5 */ ROM (379, 7),/* 6 */ ROM (358, 7),/* 7 */ ROM (338, 7),/* 8 */ ROM (319, 7),
|
||||
/* 9 */ ROM (301, 7),/* A */ ROM (284, 7),/* B */ ROM (268, 7),/* C */ ROM (253, 7),
|
||||
|
||||
/* D */ ROM (478, 6),/* E */ ROM (451, 6),/* F */ ROM (426, 6),/*10 */ ROM (402, 6),
|
||||
/*11 */ ROM (379, 6),/*12 */ ROM (358, 6),/*13 */ ROM (338, 6),/*14 */ ROM (319, 6),
|
||||
/*15 */ ROM (301, 6),/*16 */ ROM (284, 6),/*17 */ ROM (268, 6),/*18 */ ROM (253, 6),
|
||||
|
||||
/*19 */ ROM (478, 5),/*1A */ ROM (451, 5),/*1B */ ROM (426, 5),/*1C */ ROM (402, 5),
|
||||
/*1D */ ROM (379, 5),/*1E */ ROM (358, 5),/*1F */ ROM (338, 5),/*20 */ ROM (319, 5),
|
||||
/*21 */ ROM (301, 5),/*22 */ ROM (284, 5),/*23 */ ROM (268, 5),/*24 */ ROM (253, 5),
|
||||
|
||||
/*25 */ ROM (478, 4),/*26 */ ROM (451, 4),/*27 */ ROM (426, 4),/*28 */ ROM (402, 4),
|
||||
/*29 */ ROM (379, 4),/*2A */ ROM (358, 4),/*2B */ ROM (338, 4),/*2C */ ROM (319, 4),
|
||||
/*2D */ ROM (301, 4),/*2E */ ROM (284, 4),/*2F */ ROM (268, 4),/*30 */ ROM (253, 4),
|
||||
|
||||
/*31 */ ROM (478, 3),/*32 */ ROM (451, 3),/*33 */ ROM (426, 3),/*34 */ ROM (402, 3),
|
||||
/*35 */ ROM (379, 3),/*36 */ ROM (358, 3),/*37 */ ROM (338, 3),/*38 */ ROM (319, 3),
|
||||
/*39 */ ROM (301, 3),/*3A */ ROM (284, 3),/*3B */ ROM (268, 3),/*3C */ ROM (253, 3),
|
||||
|
||||
/*3D */ ROM (478, 2),/*3E */ ROM (451, 2),/*3F */ ROM (426, 2),/*40 */ ROM (402, 2),
|
||||
/*41 */ ROM (379, 2),/*42 */ ROM (358, 2),/*43 */ ROM (338, 2),/*44 */ ROM (319, 2),
|
||||
/*45 */ ROM (301, 2),/*46 */ ROM (284, 2),/*47 */ ROM (268, 2),/*48 */ ROM (253, 2),
|
||||
|
||||
/*49 */ ROM (478, 1),/*4A */ ROM (451, 1),/*4B */ ROM (426, 1),/*4C */ ROM (402, 1),
|
||||
/*4D */ ROM (379, 1),/*4E */ ROM (358, 1),/*4F */ ROM (338, 1),/*50 */ ROM (319, 1),
|
||||
/*51 */ ROM (301, 1),/*52 */ ROM (284, 1),/*53 */ ROM (268, 1),/*54 */ ROM (253, 1),
|
||||
|
||||
/*55 */ ROM (253, 1),/*56 */ ROM (253, 1),
|
||||
|
||||
/*57 */ ROM (13, 7)
|
||||
};
|
||||
#undef ROM
|
||||
|
||||
|
||||
#define STEP_SH (16) /* step calculations accuracy */
|
||||
|
||||
/*
|
||||
* resistance values are guesswork, default capacity is mentioned in the datasheets
|
||||
*
|
||||
* charges external capacitor (default is 0.39uF) via R51
|
||||
* in approx. 5*1400 * 0.39e-6
|
||||
*
|
||||
* external capacitor is discharged through R52
|
||||
* in approx. 5*28750 * 0.39e-6
|
||||
*/
|
||||
|
||||
|
||||
#define R51 1400 /* charge resistance */
|
||||
#define R52 28750 /* discharge resistance */
|
||||
|
||||
#if 0
|
||||
/*
|
||||
C24 = external capacity
|
||||
|
||||
osd_printf_debug("Time constant T=R*C =%f sec.\n",R51*C24);
|
||||
osd_printf_debug("Cap fully charged after 5T=%f sec (sample=%f). Level=%f\n",(R51*C24)*5,(R51*C24)*5*sample_rate , VMAX*0.99326 );
|
||||
osd_printf_debug("Cap charged after 5T=%f sec (sample=%f). Level=%20.16f\n",(R51*C24)*5,(R51*C24)*5*sample_rate ,
|
||||
VMAX*(1.0-pow(2.718,-0.0748/(R51*C24))) );
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
void msm5232_device::init_tables()
|
||||
{
|
||||
int i;
|
||||
double scale;
|
||||
|
||||
/* sample rate = chip clock !!! But : */
|
||||
/* highest possible frequency is chipclock/13/16 (pitch data=0x57) */
|
||||
/* at 2MHz : 2000000/13/16 = 9615 Hz */
|
||||
|
||||
i = ((double)(1<<STEP_SH) * (double)m_rate) / (double)m_chip_clock;
|
||||
m_UpdateStep = i;
|
||||
/* printf("clock=%d Hz rate=%d Hz, UpdateStep=%d\n",
|
||||
m_chip_clock, m_rate, m_UpdateStep); */
|
||||
|
||||
scale = ((double)m_chip_clock) / (double)m_rate;
|
||||
m_noise_step = ((1<<STEP_SH)/128.0) * scale; /* step of the rng reg in 16.16 format */
|
||||
/* logerror("noise step=%8x\n", m_noise_step); */
|
||||
|
||||
#if 0
|
||||
{
|
||||
/* rate tables (in milliseconds) */
|
||||
static const int ATBL[8] = { 2,4,8,16, 32,64, 32,64};
|
||||
static const int DTBL[16]= { 40,80,160,320, 640,1280, 640,1280,
|
||||
333,500,1000,2000, 4000,8000, 4000,8000};
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
double clockscale = (double)m_chip_clock / 2119040.0;
|
||||
double time = (ATBL[i] / 1000.0) / clockscale; /* attack time in seconds */
|
||||
m_ar_tbl[i] = 0.50 * ( (1.0/time) / (double)m_rate );
|
||||
/* printf("ATBL[%d] = %20.16f time = %f s\n",i, m_ar_tbl[i], time); */
|
||||
}
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
double clockscale = (double)m_chip_clock / 2119040.0;
|
||||
double time = (DTBL[i] / 1000.0) / clockscale; /* decay time in seconds */
|
||||
m_dr_tbl[i] = 0.50 * ( (1.0/time) / (double)m_rate );
|
||||
/* printf("DTBL[%d] = %20.16f time = %f s\n",i, m_dr_tbl[i], time); */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
double clockscale = (double)m_chip_clock / 2119040.0;
|
||||
m_ar_tbl[i] = ((1<<i) / clockscale) * (double)R51;
|
||||
}
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
double clockscale = (double)m_chip_clock / 2119040.0;
|
||||
m_dr_tbl[i] = ( (1<<i) / clockscale) * (double)R52;
|
||||
m_dr_tbl[i+8] = (6.25*(1<<i) / clockscale) * (double)R52;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void msm5232_device::init_voice(int i)
|
||||
{
|
||||
m_voi[i].ar_rate= m_ar_tbl[0] * m_external_capacity[i];
|
||||
m_voi[i].dr_rate= m_dr_tbl[0] * m_external_capacity[i];
|
||||
m_voi[i].rr_rate= m_dr_tbl[0] * m_external_capacity[i]; /* this is constant value */
|
||||
m_voi[i].eg_sect= -1;
|
||||
m_voi[i].eg = 0.0;
|
||||
m_voi[i].eg_arm = 0;
|
||||
m_voi[i].eg_ext = 0;
|
||||
m_voi[i].pitch = -1.0;
|
||||
m_voi[i].mute = false;
|
||||
}
|
||||
|
||||
void msm5232_device::mute(int voice, bool mute)
|
||||
{
|
||||
m_voi[voice].mute = mute;
|
||||
}
|
||||
|
||||
void msm5232_device::gate_update()
|
||||
{
|
||||
int new_state = (m_control2 & 0x20) ? m_voi[7].GF : 0;
|
||||
|
||||
if (m_gate != new_state && m_gate_handler_cb!=NULL)
|
||||
{
|
||||
m_gate = new_state;
|
||||
m_gate_handler_cb(new_state);
|
||||
}
|
||||
}
|
||||
|
||||
int msm5232_device::get_rate() {
|
||||
return m_rate;
|
||||
}
|
||||
|
||||
void msm5232_device::init(int clock, int rate)
|
||||
{
|
||||
int j;
|
||||
|
||||
m_chip_clock = clock;
|
||||
m_rate = rate ? rate : 44100; /* avoid division by 0 */
|
||||
|
||||
init_tables();
|
||||
|
||||
for (j=0; j<8; j++)
|
||||
{
|
||||
memset(&m_voi[j],0,sizeof(VOICE));
|
||||
init_voice(j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void msm5232_device::write(unsigned int offset, uint8_t data)
|
||||
{
|
||||
if (offset > 0x0d)
|
||||
return;
|
||||
|
||||
if (offset < 0x08) /* pitch */
|
||||
{
|
||||
int ch = offset&7;
|
||||
|
||||
m_voi[ch].GF = ((data&0x80)>>7);
|
||||
if (ch == 7)
|
||||
gate_update();
|
||||
|
||||
if(data&0x80)
|
||||
{
|
||||
if(data >= 0xd8)
|
||||
{
|
||||
/*if ((data&0x7f) != 0x5f) logerror("MSM5232: WRONG PITCH CODE = %2x\n",data&0x7f);*/
|
||||
m_voi[ch].mode = 1; /* noise mode */
|
||||
m_voi[ch].eg_sect = 0; /* Key On */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_voi[ch].pitch != (data&0x7f) )
|
||||
{
|
||||
int n;
|
||||
uint16_t pg;
|
||||
|
||||
m_voi[ch].pitch = data&0x7f;
|
||||
|
||||
pg = MSM5232_ROM[ data&0x7f ];
|
||||
|
||||
m_voi[ch].TG_count_period = (pg & 0x1ff) * m_UpdateStep / 2;
|
||||
|
||||
n = (pg>>9) & 7; /* n = bit number for 16' output */
|
||||
m_voi[ch].TG_out16 = 1<<n;
|
||||
/* for 8' it is bit n-1 (bit 0 if n-1<0) */
|
||||
/* for 4' it is bit n-2 (bit 0 if n-2<0) */
|
||||
/* for 2' it is bit n-3 (bit 0 if n-3<0) */
|
||||
n = (n>0)? n-1: 0;
|
||||
m_voi[ch].TG_out8 = 1<<n;
|
||||
|
||||
n = (n>0)? n-1: 0;
|
||||
m_voi[ch].TG_out4 = 1<<n;
|
||||
|
||||
n = (n>0)? n-1: 0;
|
||||
m_voi[ch].TG_out2 = 1<<n;
|
||||
}
|
||||
m_voi[ch].mode = 0; /* tone mode */
|
||||
m_voi[ch].eg_sect = 0; /* Key On */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !m_voi[ch].eg_arm ) /* arm = 0 */
|
||||
m_voi[ch].eg_sect = 2; /* Key Off -> go to release */
|
||||
else /* arm = 1 */
|
||||
m_voi[ch].eg_sect = 1; /* Key Off -> go to decay */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
switch(offset)
|
||||
{
|
||||
case 0x08: /* group1 attack */
|
||||
for (i=0; i<4; i++)
|
||||
m_voi[i].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i];
|
||||
break;
|
||||
|
||||
case 0x09: /* group2 attack */
|
||||
for (i=0; i<4; i++)
|
||||
m_voi[i+4].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i+4];
|
||||
break;
|
||||
|
||||
case 0x0a: /* group1 decay */
|
||||
for (i=0; i<4; i++) {
|
||||
m_voi[i].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0b: /* group2 decay */
|
||||
for (i=0; i<4; i++)
|
||||
m_voi[i+4].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i+4];
|
||||
break;
|
||||
|
||||
case 0x0c: /* group1 control */
|
||||
|
||||
/*if (m_control1 != data)
|
||||
logerror("msm5232: control1 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/
|
||||
|
||||
/*if (data & 0x10)
|
||||
popmessage("msm5232: control1 ctrl=%2x\n", data);*/
|
||||
|
||||
m_control1 = data;
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ( (data&0x10) && (m_voi[i].eg_sect == 1) )
|
||||
m_voi[i].eg_sect = 0;
|
||||
m_voi[i].eg_arm = data&0x10;
|
||||
m_voi[i].eg_ext = !(data&0x20);
|
||||
}
|
||||
|
||||
m_EN_out16[0] = (data&1) ? ~0:0;
|
||||
m_EN_out8[0] = (data&2) ? ~0:0;
|
||||
m_EN_out4[0] = (data&4) ? ~0:0;
|
||||
m_EN_out2[0] = (data&8) ? ~0:0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x0d: /* group2 control */
|
||||
|
||||
/*if (m_control2 != data)
|
||||
logerror("msm5232: control2 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/
|
||||
|
||||
/*if (data & 0x10)
|
||||
popmessage("msm5232: control2 ctrl=%2x\n", data);*/
|
||||
|
||||
m_control2 = data;
|
||||
gate_update();
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ( (data&0x10) && (m_voi[i+4].eg_sect == 1) )
|
||||
m_voi[i+4].eg_sect = 0;
|
||||
m_voi[i+4].eg_arm = data&0x10;
|
||||
m_voi[i+4].eg_ext = !(data&0x20);
|
||||
}
|
||||
|
||||
m_EN_out16[1] = (data&1) ? ~0:0;
|
||||
m_EN_out8[1] = (data&2) ? ~0:0;
|
||||
m_EN_out4[1] = (data&4) ? ~0:0;
|
||||
m_EN_out2[1] = (data&8) ? ~0:0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define VMIN 0
|
||||
#define VMAX 32768
|
||||
|
||||
|
||||
void msm5232_device::EG_voices_advance()
|
||||
{
|
||||
VOICE *voi = &m_voi[0];
|
||||
int samplerate = m_rate;
|
||||
int i;
|
||||
|
||||
i = 8;
|
||||
do
|
||||
{
|
||||
if (voi->eg_ext) {
|
||||
voi->egvol=m_external_input[8-i]*2048.0;
|
||||
} else {
|
||||
switch(voi->eg_sect)
|
||||
{
|
||||
case 0: /* attack */
|
||||
|
||||
/* capacitor charge */
|
||||
if (voi->eg < VMAX)
|
||||
{
|
||||
voi->counter -= (int)((VMAX - voi->eg) / voi->ar_rate);
|
||||
if ( voi->counter <= 0 )
|
||||
{
|
||||
int n = -voi->counter / samplerate + 1;
|
||||
voi->counter += n * samplerate;
|
||||
if ( (voi->eg += n) > VMAX )
|
||||
voi->eg = VMAX;
|
||||
}
|
||||
}
|
||||
|
||||
/* when ARM=0, EG switches to decay as soon as cap is charged to VT (EG inversion voltage; about 80% of MAX) */
|
||||
if (!voi->eg_arm)
|
||||
{
|
||||
if(voi->eg >= VMAX * 80/100 )
|
||||
{
|
||||
voi->eg_sect = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* ARM=1 */
|
||||
{
|
||||
/* when ARM=1, EG stays at maximum until key off */
|
||||
}
|
||||
|
||||
voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/
|
||||
|
||||
break;
|
||||
|
||||
case 1: /* decay */
|
||||
|
||||
/* capacitor discharge */
|
||||
if (voi->eg > VMIN)
|
||||
{
|
||||
voi->counter -= (int)((voi->eg - VMIN) / voi->dr_rate);
|
||||
if ( voi->counter <= 0 )
|
||||
{
|
||||
int n = -voi->counter / samplerate + 1;
|
||||
voi->counter += n * samplerate;
|
||||
if ( (voi->eg -= n) < VMIN )
|
||||
voi->eg = VMIN;
|
||||
}
|
||||
}
|
||||
else /* voi->eg <= VMIN */
|
||||
{
|
||||
voi->eg_sect =-1;
|
||||
}
|
||||
|
||||
voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/
|
||||
|
||||
break;
|
||||
|
||||
case 2: /* release */
|
||||
|
||||
/* capacitor discharge */
|
||||
if (voi->eg > VMIN)
|
||||
{
|
||||
voi->counter -= (int)((voi->eg - VMIN) / voi->rr_rate);
|
||||
if ( voi->counter <= 0 )
|
||||
{
|
||||
int n = -voi->counter / samplerate + 1;
|
||||
voi->counter += n * samplerate;
|
||||
if ( (voi->eg -= n) < VMIN )
|
||||
voi->eg = VMIN;
|
||||
}
|
||||
}
|
||||
else /* voi->eg <= VMIN */
|
||||
{
|
||||
voi->eg_sect =-1;
|
||||
}
|
||||
|
||||
voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
voi++;
|
||||
i--;
|
||||
} while (i>0);
|
||||
|
||||
}
|
||||
|
||||
static int o2,o4,o8,o16,solo8,solo16;
|
||||
|
||||
void msm5232_device::TG_group_advance(int groupidx)
|
||||
{
|
||||
VOICE *voi = &m_voi[groupidx*4];
|
||||
int i;
|
||||
|
||||
o2 = o4 = o8 = o16 = solo8 = solo16 = 0;
|
||||
|
||||
i=4;
|
||||
do
|
||||
{
|
||||
int out2, out4, out8, out16;
|
||||
|
||||
out2 = out4 = out8 = out16 = 0;
|
||||
|
||||
if (voi->mode==0) /* generate square tone */
|
||||
{
|
||||
int left = 1<<STEP_SH;
|
||||
do
|
||||
{
|
||||
int nextevent = left;
|
||||
|
||||
if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count;
|
||||
if (voi->TG_cnt&voi->TG_out8) out8 +=voi->TG_count;
|
||||
if (voi->TG_cnt&voi->TG_out4) out4 +=voi->TG_count;
|
||||
if (voi->TG_cnt&voi->TG_out2) out2 +=voi->TG_count;
|
||||
|
||||
voi->TG_count -= nextevent;
|
||||
|
||||
while (voi->TG_count <= 0)
|
||||
{
|
||||
voi->TG_count += voi->TG_count_period;
|
||||
voi->TG_cnt++;
|
||||
if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count_period;
|
||||
if (voi->TG_cnt&voi->TG_out8 ) out8 +=voi->TG_count_period;
|
||||
if (voi->TG_cnt&voi->TG_out4 ) out4 +=voi->TG_count_period;
|
||||
if (voi->TG_cnt&voi->TG_out2 ) out2 +=voi->TG_count_period;
|
||||
|
||||
if (voi->TG_count > 0)
|
||||
break;
|
||||
|
||||
voi->TG_count += voi->TG_count_period;
|
||||
voi->TG_cnt++;
|
||||
if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count_period;
|
||||
if (voi->TG_cnt&voi->TG_out8 ) out8 +=voi->TG_count_period;
|
||||
if (voi->TG_cnt&voi->TG_out4 ) out4 +=voi->TG_count_period;
|
||||
if (voi->TG_cnt&voi->TG_out2 ) out2 +=voi->TG_count_period;
|
||||
}
|
||||
if (voi->TG_cnt&voi->TG_out16) out16-=voi->TG_count;
|
||||
if (voi->TG_cnt&voi->TG_out8 ) out8 -=voi->TG_count;
|
||||
if (voi->TG_cnt&voi->TG_out4 ) out4 -=voi->TG_count;
|
||||
if (voi->TG_cnt&voi->TG_out2 ) out2 -=voi->TG_count;
|
||||
|
||||
left -=nextevent;
|
||||
|
||||
}while (left>0);
|
||||
}
|
||||
else /* generate noise */
|
||||
{
|
||||
if (m_noise_clocks&8) out16+=(1<<STEP_SH);
|
||||
if (m_noise_clocks&4) out8 +=(1<<STEP_SH);
|
||||
if (m_noise_clocks&2) out4 +=(1<<STEP_SH);
|
||||
if (m_noise_clocks&1) out2 +=(1<<STEP_SH);
|
||||
}
|
||||
|
||||
/* calculate signed output */
|
||||
if (!voi->mute) {
|
||||
o16 += ( (out16-(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
|
||||
o8 += ( (out8 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
|
||||
o4 += ( (out4 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
|
||||
o2 += ( (out2 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH;
|
||||
|
||||
if (i == 1 && groupidx == 1)
|
||||
{
|
||||
solo16 += ( (out16-(1<<(STEP_SH-1))) << 11) >> STEP_SH;
|
||||
solo8 += ( (out8 -(1<<(STEP_SH-1))) << 11) >> STEP_SH;
|
||||
}
|
||||
}
|
||||
|
||||
voi++;
|
||||
i--;
|
||||
}while (i>0);
|
||||
|
||||
/* cut off disabled output lines */
|
||||
o16 &= m_EN_out16[groupidx];
|
||||
o8 &= m_EN_out8 [groupidx];
|
||||
o4 &= m_EN_out4 [groupidx];
|
||||
o2 &= m_EN_out2 [groupidx];
|
||||
}
|
||||
|
||||
|
||||
/* macro saves feet data to mono file */
|
||||
#ifdef SAVE_SEPARATE_CHANNELS
|
||||
#define SAVE_SINGLE_CHANNEL(j,val) \
|
||||
{ signed int pom= val; \
|
||||
if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \
|
||||
fputc((unsigned short)pom&0xff,sample[j]); \
|
||||
fputc(((unsigned short)pom>>8)&0xff,sample[j]); }
|
||||
#else
|
||||
#define SAVE_SINGLE_CHANNEL(j,val)
|
||||
#endif
|
||||
|
||||
/* first macro saves all 8 feet outputs to mixed (mono) file */
|
||||
/* second macro saves one group into left and the other in right channel */
|
||||
#if 1 /*MONO*/
|
||||
#ifdef SAVE_SAMPLE
|
||||
#define SAVE_ALL_CHANNELS \
|
||||
{ signed int pom = buf1[i] + buf2[i]; \
|
||||
fputc((unsigned short)pom&0xff,sample[8]); \
|
||||
fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
|
||||
}
|
||||
#else
|
||||
#define SAVE_ALL_CHANNELS
|
||||
#endif
|
||||
#else /*STEREO*/
|
||||
#ifdef SAVE_SAMPLE
|
||||
#define SAVE_ALL_CHANNELS \
|
||||
{ signed int pom = buf1[i]; \
|
||||
fputc((unsigned short)pom&0xff,sample[8]); \
|
||||
fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
|
||||
pom = buf2[i]; \
|
||||
fputc((unsigned short)pom&0xff,sample[8]); \
|
||||
fputc(((unsigned short)pom>>8)&0xff,sample[8]); \
|
||||
}
|
||||
#else
|
||||
#define SAVE_ALL_CHANNELS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* MAME Interface */
|
||||
void msm5232_device::device_post_load()
|
||||
{
|
||||
init_tables();
|
||||
}
|
||||
|
||||
void msm5232_device::set_clock(int clock)
|
||||
{
|
||||
if (m_chip_clock != clock)
|
||||
{
|
||||
m_chip_clock = clock;
|
||||
m_rate = clock/CLOCK_RATE_DIVIDER;
|
||||
init_tables();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sound_stream_update - handle a stream update
|
||||
//-------------------------------------------------
|
||||
|
||||
void msm5232_device::sound_stream_update(short* outputs)
|
||||
{
|
||||
auto &buf1 = outputs[0];
|
||||
auto &buf2 = outputs[1];
|
||||
auto &buf3 = outputs[2];
|
||||
auto &buf4 = outputs[3];
|
||||
auto &buf5 = outputs[4];
|
||||
auto &buf6 = outputs[5];
|
||||
auto &buf7 = outputs[6];
|
||||
auto &buf8 = outputs[7];
|
||||
auto &bufsolo1 = outputs[8];
|
||||
auto &bufsolo2 = outputs[9];
|
||||
auto &bufnoise = outputs[10];
|
||||
|
||||
/* calculate all voices' envelopes */
|
||||
EG_voices_advance();
|
||||
|
||||
TG_group_advance(0); /* calculate tones group 1 */
|
||||
buf1=o2;
|
||||
buf2=o4;
|
||||
buf3=o8;
|
||||
buf4=o16;
|
||||
|
||||
TG_group_advance(1); /* calculate tones group 2 */
|
||||
buf5=o2;
|
||||
buf6=o4;
|
||||
buf7=o8;
|
||||
buf8=o16;
|
||||
|
||||
bufsolo1=solo8;
|
||||
bufsolo2=solo16;
|
||||
|
||||
/* update noise generator */
|
||||
{
|
||||
int cnt = (m_noise_cnt+=m_noise_step) >> STEP_SH;
|
||||
m_noise_cnt &= ((1<<STEP_SH)-1);
|
||||
while (cnt > 0)
|
||||
{
|
||||
int tmp = m_noise_rng & (1<<16); /* store current level */
|
||||
|
||||
if (m_noise_rng&1)
|
||||
m_noise_rng ^= 0x24000;
|
||||
m_noise_rng>>=1;
|
||||
|
||||
if ( (m_noise_rng & (1<<16)) != tmp ) /* level change detect */
|
||||
m_noise_clocks++;
|
||||
|
||||
cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
bufnoise=(m_noise_rng & (1<<16)) ? 32767 : 0;
|
||||
}
|
106
src/engine/platform/sound/oki/msm5232.h
Normal file
106
src/engine/platform/sound/oki/msm5232.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
// license:GPL-2.0+
|
||||
// copyright-holders:Jarek Burczynski, Hiromitsu Shioya
|
||||
// additional modifications for Furnace by tildearrow
|
||||
#ifndef MAME_SOUND_MSM5232_H
|
||||
#define MAME_SOUND_MSM5232_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <functional>
|
||||
|
||||
class msm5232_device
|
||||
{
|
||||
public:
|
||||
msm5232_device(uint32_t clock);
|
||||
|
||||
void set_capacitors(double cap1, double cap2, double cap3, double cap4, double cap5, double cap6, double cap7, double cap8);
|
||||
void set_vol_input(double v1, double v2, double v3, double v4, double v5, double v6, double v7, double v8);
|
||||
//auto gate() { return m_gate_handler_cb.bind(); }
|
||||
|
||||
void write(unsigned int offset, uint8_t data);
|
||||
void set_clock(int clock);
|
||||
void mute(int voice, bool mute);
|
||||
|
||||
// device-level overrides
|
||||
void device_start();
|
||||
void device_stop();
|
||||
void device_reset();
|
||||
void device_post_load();
|
||||
|
||||
// sound stream update overrides
|
||||
void sound_stream_update(short* outputs);
|
||||
|
||||
int get_rate();
|
||||
|
||||
private:
|
||||
struct VOICE {
|
||||
uint8_t mode;
|
||||
bool mute;
|
||||
|
||||
int TG_count_period;
|
||||
int TG_count;
|
||||
|
||||
uint8_t TG_cnt; /* 7 bits binary counter (frequency output) */
|
||||
uint8_t TG_out16; /* bit number (of TG_cnt) for 16' output */
|
||||
uint8_t TG_out8; /* bit number (of TG_cnt) for 8' output */
|
||||
uint8_t TG_out4; /* bit number (of TG_cnt) for 4' output */
|
||||
uint8_t TG_out2; /* bit number (of TG_cnt) for 2' output */
|
||||
|
||||
int egvol;
|
||||
int eg_sect;
|
||||
int counter;
|
||||
int eg;
|
||||
|
||||
uint8_t eg_arm; /* attack/release mode */
|
||||
uint8_t eg_ext; /* inhibit envelope generator */
|
||||
|
||||
double ar_rate;
|
||||
double dr_rate;
|
||||
double rr_rate;
|
||||
|
||||
int pitch; /* current pitch data */
|
||||
|
||||
int GF;
|
||||
};
|
||||
|
||||
VOICE m_voi[8];
|
||||
|
||||
uint32_t m_EN_out16[2]; /* enable 16' output masks for both groups (0-disabled ; ~0 -enabled) */
|
||||
uint32_t m_EN_out8[2]; /* enable 8' output masks */
|
||||
uint32_t m_EN_out4[2]; /* enable 4' output masks */
|
||||
uint32_t m_EN_out2[2]; /* enable 2' output masks */
|
||||
|
||||
int m_noise_cnt;
|
||||
int m_noise_step;
|
||||
int m_noise_rng;
|
||||
int m_noise_clocks; /* number of the noise_rng (output) level changes */
|
||||
|
||||
unsigned int m_UpdateStep;
|
||||
|
||||
/* rate tables */
|
||||
double m_ar_tbl[8];
|
||||
double m_dr_tbl[16];
|
||||
|
||||
uint8_t m_control1;
|
||||
uint8_t m_control2;
|
||||
|
||||
int m_gate; /* current state of the GATE output */
|
||||
|
||||
int m_chip_clock; /* chip clock in Hz */
|
||||
int m_rate; /* sample rate in Hz */
|
||||
uint32_t m_clock;
|
||||
|
||||
double m_external_capacity[8]; /* in Farads, eg 0.39e-6 = 0.36 uF (microFarads) */
|
||||
double m_external_input[8];
|
||||
std::function<void(int)> m_gate_handler_cb;/* callback called when the GATE output pin changes state */
|
||||
|
||||
void init_tables();
|
||||
void init_voice(int i);
|
||||
void gate_update();
|
||||
void init(int clock, int rate);
|
||||
void EG_voices_advance();
|
||||
void TG_group_advance(int groupidx);
|
||||
};
|
||||
|
||||
#endif // MAME_SOUND_MSM5232_H
|
|
@ -114,7 +114,7 @@ enum DivSystem {
|
|||
DIV_SYSTEM_NAMCO_CUS30,
|
||||
DIV_SYSTEM_YM2612_FRAC,
|
||||
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||
DIV_SYSTEM_RESERVED_8,
|
||||
DIV_SYSTEM_MSM5232,
|
||||
DIV_SYSTEM_T6W28,
|
||||
DIV_SYSTEM_PCM_DAC,
|
||||
DIV_SYSTEM_DUMMY,
|
||||
|
|
|
@ -1646,14 +1646,13 @@ void DivEngine::registerSystems() {
|
|||
namcoEffectHandlerMap
|
||||
);
|
||||
|
||||
// replace with an 8-channel chip in a future
|
||||
sysDefs[DIV_SYSTEM_RESERVED_8]=new DivSysDef(
|
||||
"Reserved", NULL, 0xbc, 0, 8, false, true, 0, false, 0,
|
||||
"this was YM2612_FRAC, but due to changes this ID is reserved.",
|
||||
sysDefs[DIV_SYSTEM_MSM5232]=new DivSysDef(
|
||||
"OKI MSM5232", NULL, 0xbc, 0, 8, false, true, 0, false, 0,
|
||||
"a square wave additive synthesis chip made by OKI. used in some arcade machines and instruments.",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
||||
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
|
||||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}
|
||||
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
|
||||
{DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_YM2612_FRAC]=new DivSysDef(
|
||||
|
|
|
@ -378,6 +378,10 @@ void FurnaceGUI::drawInsList(bool asChild) {
|
|||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_RF5C68]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_MSM5232:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM5232]);
|
||||
name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
default:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]);
|
||||
name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
|
|
|
@ -822,6 +822,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_CUT: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
if (end-start<1) break;
|
||||
|
@ -866,6 +867,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
if (sampleClipboard==NULL || sampleClipboardLen<1) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?sample->samples:sampleSelStart;
|
||||
if (pos>=(int)sample->samples) pos=sample->samples-1;
|
||||
|
@ -896,6 +898,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
if (sampleClipboard==NULL || sampleClipboardLen<1) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?0:sampleSelStart;
|
||||
if (pos>=(int)sample->samples) pos=sample->samples-1;
|
||||
|
@ -926,6 +929,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
if (sampleClipboard==NULL || sampleClipboardLen<1) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?0:sampleSelStart;
|
||||
if (pos>=(int)sample->samples) pos=sample->samples-1;
|
||||
|
@ -981,6 +985,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_NORMALIZE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1028,6 +1033,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_FADE_IN: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1058,6 +1064,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_FADE_OUT: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1092,6 +1099,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_SILENCE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1116,6 +1124,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_DELETE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1133,6 +1142,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_TRIM: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1150,6 +1160,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_REVERSE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1182,6 +1193,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_INVERT: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
@ -1208,6 +1220,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_SIGN: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) break;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
|
|
@ -2134,18 +2134,20 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
|
|||
if (x1>=(int)sampleDragLen) x1=sampleDragLen-1;
|
||||
double y=0.5-double(dragY-sampleDragStart.y)/sampleDragAreaSize.y;
|
||||
if (sampleDragMode) { // draw
|
||||
if (sampleDrag16) {
|
||||
int val=y*65536;
|
||||
if (val<-32768) val=-32768;
|
||||
if (val>32767) val=32767;
|
||||
for (int i=x; i<=x1; i++) ((short*)sampleDragTarget)[i]=val;
|
||||
} else {
|
||||
int val=y*256;
|
||||
if (val<-128) val=-128;
|
||||
if (val>127) val=127;
|
||||
for (int i=x; i<=x1; i++) ((signed char*)sampleDragTarget)[i]=val;
|
||||
if (sampleDragTarget) {
|
||||
if (sampleDrag16) {
|
||||
int val=y*65536;
|
||||
if (val<-32768) val=-32768;
|
||||
if (val>32767) val=32767;
|
||||
for (int i=x; i<=x1; i++) ((short*)sampleDragTarget)[i]=val;
|
||||
} else {
|
||||
int val=y*256;
|
||||
if (val<-128) val=-128;
|
||||
if (val>127) val=127;
|
||||
for (int i=x; i<=x1; i++) ((signed char*)sampleDragTarget)[i]=val;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
updateSampleTex=true;
|
||||
} else { // select
|
||||
if (sampleSelStart<0) {
|
||||
sampleSelStart=x;
|
||||
|
@ -2836,7 +2838,7 @@ void FurnaceGUI::pointDown(int x, int y, int button) {
|
|||
}
|
||||
|
||||
void FurnaceGUI::pointUp(int x, int y, int button) {
|
||||
if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode)) {
|
||||
if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode && sampleDragTarget)) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (macroDragActive && macroDragLineMode && !macroDragMouseMoved) {
|
||||
|
@ -5395,6 +5397,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
editOptsVisible(false),
|
||||
latchNibble(false),
|
||||
nonLatchNibble(false),
|
||||
keepLoopAlive(false),
|
||||
curWindow(GUI_WINDOW_NOTHING),
|
||||
nextWindow(GUI_WINDOW_NOTHING),
|
||||
curWindowLast(GUI_WINDOW_NOTHING),
|
||||
|
|
|
@ -170,6 +170,7 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_INSTR_QSOUND,
|
||||
GUI_COLOR_INSTR_YMZ280B,
|
||||
GUI_COLOR_INSTR_RF5C68,
|
||||
GUI_COLOR_INSTR_MSM5232,
|
||||
GUI_COLOR_INSTR_UNKNOWN,
|
||||
|
||||
GUI_COLOR_CHANNEL_BG,
|
||||
|
@ -217,6 +218,15 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC,
|
||||
|
||||
GUI_COLOR_SAMPLE_BG,
|
||||
GUI_COLOR_SAMPLE_FG,
|
||||
GUI_COLOR_SAMPLE_LOOP,
|
||||
GUI_COLOR_SAMPLE_CENTER,
|
||||
GUI_COLOR_SAMPLE_GRID,
|
||||
GUI_COLOR_SAMPLE_SEL,
|
||||
GUI_COLOR_SAMPLE_SEL_POINT,
|
||||
GUI_COLOR_SAMPLE_NEEDLE,
|
||||
|
||||
GUI_COLOR_PAT_MANAGER_NULL,
|
||||
GUI_COLOR_PAT_MANAGER_USED,
|
||||
GUI_COLOR_PAT_MANAGER_OVERUSED,
|
||||
|
@ -1357,6 +1367,7 @@ class FurnaceGUI {
|
|||
SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd;
|
||||
bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI;
|
||||
bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, waveSigned, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble;
|
||||
bool keepLoopAlive;
|
||||
FurnaceGUIWindows curWindow, nextWindow, curWindowLast;
|
||||
float peak[2];
|
||||
float patChanX[DIV_MAX_CHANS+1];
|
||||
|
|
|
@ -113,8 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={
|
|||
"Sound Unit",
|
||||
"Namco WSG",
|
||||
"OPL (drums)",
|
||||
"FM (OPM)", // 33
|
||||
"NES", // 34
|
||||
"FM (OPM)",
|
||||
"NES",
|
||||
"MSM6258",
|
||||
"MSM6295",
|
||||
"ADPCM-A",
|
||||
|
@ -123,6 +123,7 @@ const char* insTypes[DIV_INS_MAX+1]={
|
|||
"QSound",
|
||||
"YMZ280B",
|
||||
"RF5C68",
|
||||
"MSM5232",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -799,6 +800,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.8f,0.3f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(0.4f,0.5f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.3f,0.3f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_MSM5232,"",ImVec4(0.5f,0.9f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
|
||||
|
@ -846,6 +848,15 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"",ImVec4(0.0f,1.0f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_PATTERN_EFFECT_MISC,"",ImVec4(0.3f,0.3f,1.0f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_SAMPLE_BG,"",ImVec4(0.04f,0.13f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_SAMPLE_FG,"",ImVec4(0.7f,0.7f,0.7f,1.0f)),
|
||||
D(GUI_COLOR_SAMPLE_LOOP,"",ImVec4(0.1f,0.22f,0.35f,1.0f)),
|
||||
D(GUI_COLOR_SAMPLE_CENTER,"",ImVec4(0.2f,0.2f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_SAMPLE_GRID,"",ImVec4(0.1f,0.1f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_SAMPLE_SEL,"",ImVec4(0.26f,0.59f,0.98f,0.25f)),
|
||||
D(GUI_COLOR_SAMPLE_SEL_POINT,"",ImVec4(0.06f,0.53f,0.98f,0.5f)),
|
||||
D(GUI_COLOR_SAMPLE_NEEDLE,"",ImVec4(1.0f,0.8f,0.0f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_PAT_MANAGER_NULL,"",ImVec4(0.15f,0.15f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_USED,"",ImVec4(0.15f,1.0f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_OVERUSED,"",ImVec4(1.0f,1.0f,0.15f,1.0f)),
|
||||
|
@ -944,6 +955,7 @@ const int availableSystems[]={
|
|||
DIV_SYSTEM_MSM6295,
|
||||
DIV_SYSTEM_RF5C68,
|
||||
DIV_SYSTEM_SNES,
|
||||
DIV_SYSTEM_MSM5232,
|
||||
DIV_SYSTEM_PCM_DAC,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
@ -988,6 +1000,7 @@ const int chipsSquare[]={
|
|||
DIV_SYSTEM_PCSPKR,
|
||||
DIV_SYSTEM_SAA1099,
|
||||
DIV_SYSTEM_VIC20,
|
||||
DIV_SYSTEM_MSM5232,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
|
|
@ -243,6 +243,10 @@ const char* mikeyFeedbackBits[11] = {
|
|||
"0", "1", "2", "3", "4", "5", "7", "10", "11", "int", NULL
|
||||
};
|
||||
|
||||
const char* msm5232ControlBits[7]={
|
||||
"2'", "4'", "8'", "16'", "sustain", NULL
|
||||
};
|
||||
|
||||
const char* x1_010EnvBits[8]={
|
||||
"enable", "oneshot", "split L/R", "HinvR", "VinvR", "HinvL", "VinvL", NULL
|
||||
};
|
||||
|
@ -4513,7 +4517,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY ||
|
||||
ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ ||
|
||||
ins->type==DIV_INS_OPM || ins->type==DIV_INS_SNES) {
|
||||
ins->type==DIV_INS_OPM || ins->type==DIV_INS_SNES || ins->type==DIV_INS_MSM5232) {
|
||||
volMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_GB) {
|
||||
|
@ -4576,6 +4580,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
dutyLabel="Duty/Int";
|
||||
dutyMax=ins->amiga.useSample?0:10;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM5232) {
|
||||
dutyLabel="Group Ctrl";
|
||||
dutyMax=5;
|
||||
}
|
||||
if (ins->type==DIV_INS_BEEPER) {
|
||||
dutyLabel="Pulse Width";
|
||||
dutyMax=255;
|
||||
|
@ -4684,6 +4692,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_ADPCMB) waveMax=0;
|
||||
if (ins->type==DIV_INS_QSOUND) waveMax=0;
|
||||
if (ins->type==DIV_INS_YMZ280B) waveMax=0;
|
||||
if (ins->type==DIV_INS_MSM5232) waveMax=0;
|
||||
if (ins->type==DIV_INS_MSM6258) waveMax=0;
|
||||
if (ins->type==DIV_INS_MSM6295) waveMax=0;
|
||||
if (ins->type==DIV_INS_SEGAPCM) waveMax=0;
|
||||
|
@ -4751,6 +4760,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ex1Max=5;
|
||||
ex2Max=5;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM5232) {
|
||||
ex1Max=5;
|
||||
ex2Max=11;
|
||||
}
|
||||
|
||||
int panMin=0;
|
||||
int panMax=0;
|
||||
|
@ -4815,6 +4828,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (dutyMax>0) {
|
||||
if (ins->type==DIV_INS_MIKEY) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,0,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,mikeyFeedbackBits));
|
||||
} else if (ins->type==DIV_INS_MSM5232) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,0,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,msm5232ControlBits));
|
||||
} else if (ins->type==DIV_INS_ES5506) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,¯oHoverES5506FilterMode));
|
||||
} else {
|
||||
|
@ -4845,7 +4860,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
}
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
||||
if (ins->type!=DIV_INS_MSM5232) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
||||
}
|
||||
if (ins->type==DIV_INS_FM ||
|
||||
ins->type==DIV_INS_OPM ||
|
||||
ins->type==DIV_INS_STD ||
|
||||
|
@ -4897,6 +4914,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_SNES) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex1Macro,0,ex1Max,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,snesModeBits));
|
||||
} else if (ins->type==DIV_INS_MSM5232) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Group Attack",&ins->std.ex1Macro,0,ex1Max,96,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
}
|
||||
|
@ -4916,6 +4935,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Echo Length",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_SNES) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Gain Mode",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,snesGainModes));
|
||||
} else if (ins->type==DIV_INS_MSM5232) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Group Decay",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits));
|
||||
}
|
||||
|
@ -4958,6 +4979,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_SNES) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM5232) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Noise",&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
}
|
||||
|
||||
drawMacros(macroList);
|
||||
ImGui::EndTabItem();
|
||||
|
|
|
@ -306,6 +306,12 @@ void FurnaceGUI::initSystemPresets() {
|
|||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"OKI MSM5232", {
|
||||
DIV_SYSTEM_MSM5232, 64, 0, 0,
|
||||
0
|
||||
}
|
||||
));
|
||||
sysCategories.push_back(cat);
|
||||
|
||||
cat=FurnaceGUISysCategory("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis.");
|
||||
|
|
|
@ -121,10 +121,14 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("changing the loop in a BRR sample may result in glitches!");
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Length: %d",sample->samples);
|
||||
if (doLoop) {
|
||||
if (doLoop || keepLoopAlive) {
|
||||
keepLoopAlive=false;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Mode");
|
||||
|
@ -156,6 +160,12 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
keepLoopAlive=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("changing the loop in a BRR sample may result in glitches!");
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop End");
|
||||
ImGui::SameLine();
|
||||
|
@ -169,6 +179,12 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
keepLoopAlive=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("changing the loop in a BRR sample may result in glitches!");
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -181,8 +197,6 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
*/
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
|
||||
pushToggleColors(!sampleDragMode);
|
||||
if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) {
|
||||
sampleDragMode=false;
|
||||
|
@ -200,6 +214,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Edit mode: Draw");
|
||||
}
|
||||
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
|
||||
ImGui::SameLine();
|
||||
|
@ -567,6 +582,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale));
|
||||
ImGui::SameLine();
|
||||
|
@ -681,10 +697,14 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("changing the loop in a BRR sample may result in glitches!");
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Length: %d",sample->samples);
|
||||
if (doLoop) {
|
||||
if (doLoop || keepLoopAlive) {
|
||||
keepLoopAlive=false;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop Mode");
|
||||
|
@ -717,6 +737,12 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
keepLoopAlive=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("changing the loop in a BRR sample may result in glitches!");
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Loop End");
|
||||
ImGui::SameLine();
|
||||
|
@ -730,6 +756,12 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
updateSampleTex=true;
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
keepLoopAlive=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && sample->depth==DIV_SAMPLE_DEPTH_BRR) {
|
||||
ImGui::SetTooltip("changing the loop in a BRR sample may result in glitches!");
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -742,8 +774,6 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
*/
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
|
||||
pushToggleColors(!sampleDragMode);
|
||||
if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) {
|
||||
sampleDragMode=false;
|
||||
|
@ -761,6 +791,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Edit mode: Draw");
|
||||
}
|
||||
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(7.0*dpiScale,dpiScale));
|
||||
ImGui::SameLine();
|
||||
|
@ -1135,6 +1166,8 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::SetTooltip("Trim");
|
||||
}
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (ImGui::Button(ICON_FA_PLAY "##PreviewSample")) {
|
||||
e->previewSample(curSample);
|
||||
}
|
||||
|
@ -1236,10 +1269,10 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (SDL_LockTexture(sampleTex,NULL,(void**)&data,&pitch)!=0) {
|
||||
logE("error while locking sample texture! %s",SDL_GetError());
|
||||
} else {
|
||||
ImU32 bgColor=ImGui::GetColorU32(ImGuiCol_FrameBg);
|
||||
ImU32 bgColorLoop=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_FrameBgHovered,0.5));
|
||||
ImU32 lineColor=ImGui::GetColorU32(ImGuiCol_PlotLines);
|
||||
ImU32 centerLineColor=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_PlotLines,0.25));
|
||||
ImU32 bgColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_BG]);
|
||||
ImU32 bgColorLoop=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_LOOP]);
|
||||
ImU32 lineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_FG]);
|
||||
ImU32 centerLineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_CENTER]);
|
||||
for (int i=0; i<availY; i++) {
|
||||
for (int j=0; j<availX; j++) {
|
||||
int scaledPos=samplePos+(j*sampleZoom);
|
||||
|
@ -1314,11 +1347,23 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sampleSelStart=0;
|
||||
sampleSelEnd=sample->samples;
|
||||
} else {
|
||||
if (sample->samples>0 && (sample->depth==DIV_SAMPLE_DEPTH_16BIT || sample->depth==DIV_SAMPLE_DEPTH_8BIT)) {
|
||||
if (sample->samples>0) {
|
||||
sampleDragStart=rectMin;
|
||||
sampleDragAreaSize=rectSize;
|
||||
sampleDrag16=(sample->depth==DIV_SAMPLE_DEPTH_16BIT);
|
||||
sampleDragTarget=(sample->depth==DIV_SAMPLE_DEPTH_16BIT)?((void*)sample->data16):((void*)sample->data8);
|
||||
switch (sample->depth) {
|
||||
case DIV_SAMPLE_DEPTH_8BIT:
|
||||
sampleDrag16=false;
|
||||
sampleDragTarget=(void*)sample->data8;
|
||||
break;
|
||||
case DIV_SAMPLE_DEPTH_16BIT:
|
||||
sampleDrag16=true;
|
||||
sampleDragTarget=(void*)sample->data16;
|
||||
break;
|
||||
default:
|
||||
sampleDrag16=true;
|
||||
sampleDragTarget=NULL;
|
||||
break;
|
||||
}
|
||||
sampleDragLen=sample->samples;
|
||||
sampleDragActive=true;
|
||||
sampleSelStart=-1;
|
||||
|
@ -1334,12 +1379,15 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
if (ImGui::BeginPopup("SRightClick",ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
if (ImGui::MenuItem("cut",BIND_FOR(GUI_ACTION_SAMPLE_CUT))) {
|
||||
doAction(GUI_ACTION_SAMPLE_CUT);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if (ImGui::MenuItem("copy",BIND_FOR(GUI_ACTION_SAMPLE_COPY))) {
|
||||
doAction(GUI_ACTION_SAMPLE_COPY);
|
||||
}
|
||||
ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
if (ImGui::MenuItem("paste",BIND_FOR(GUI_ACTION_SAMPLE_PASTE))) {
|
||||
doAction(GUI_ACTION_SAMPLE_PASTE);
|
||||
}
|
||||
|
@ -1349,6 +1397,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (ImGui::MenuItem("paste (mix)",BIND_FOR(GUI_ACTION_SAMPLE_PASTE_MIX))) {
|
||||
doAction(GUI_ACTION_SAMPLE_PASTE_MIX);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if (ImGui::MenuItem("select all",BIND_FOR(GUI_ACTION_SAMPLE_SELECT_ALL))) {
|
||||
doAction(GUI_ACTION_SAMPLE_SELECT_ALL);
|
||||
}
|
||||
|
@ -1374,7 +1423,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
end^=start;
|
||||
start^=end;
|
||||
}
|
||||
statusBar+=fmt::sprintf(" (%d-%d)",start,end);
|
||||
if (start==end) {
|
||||
statusBar+=fmt::sprintf(" (%d)",start);
|
||||
} else {
|
||||
statusBar+=fmt::sprintf(" (%d-%d: %d samples)",start,end,end-start);
|
||||
}
|
||||
drawSelection=true;
|
||||
}
|
||||
}
|
||||
|
@ -1426,6 +1479,43 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
}
|
||||
|
||||
if (e->isPreviewingSample()) {
|
||||
statusBar+=fmt::sprintf(" | %.2fHz",e->getSamplePreviewRate());
|
||||
|
||||
int start=sampleSelStart;
|
||||
int end=sampleSelEnd;
|
||||
if (start>end) {
|
||||
start^=end;
|
||||
end^=start;
|
||||
start^=end;
|
||||
}
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImVec2 p1=rectMin;
|
||||
p1.x+=(e->getSamplePreviewPos()-samplePos)/sampleZoom;
|
||||
ImVec4 posColor=uiColors[GUI_COLOR_SAMPLE_NEEDLE];
|
||||
ImVec4 posTrail1=posColor;
|
||||
ImVec4 posTrail2=posColor;
|
||||
posTrail1.w*=0.5f;
|
||||
posTrail2.w=0.0f;
|
||||
float trailDistance=(e->getSamplePreviewRate()/100.0f)/sampleZoom;
|
||||
|
||||
if (p1.x<rectMin.x) p1.x=rectMin.x;
|
||||
if (p1.x>rectMax.x) p1.x=rectMax.x;
|
||||
|
||||
ImVec2 p2=p1;
|
||||
p2.y=rectMax.y;
|
||||
|
||||
dl->AddRectFilledMultiColor(
|
||||
ImVec2(p1.x-trailDistance,p1.y),
|
||||
p2,
|
||||
ImGui::GetColorU32(posTrail2),
|
||||
ImGui::GetColorU32(posTrail1),
|
||||
ImGui::GetColorU32(posTrail1),
|
||||
ImGui::GetColorU32(posTrail2)
|
||||
);
|
||||
dl->AddLine(p1,p2,ImGui::GetColorU32(posColor));
|
||||
}
|
||||
|
||||
if (drawSelection) {
|
||||
int start=sampleSelStart;
|
||||
int end=sampleSelEnd;
|
||||
|
@ -1439,10 +1529,8 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
p1.x+=(start-samplePos)/sampleZoom;
|
||||
|
||||
ImVec2 p2=ImVec2(rectMin.x+(end-samplePos)/sampleZoom,rectMax.y);
|
||||
ImVec4 boundColor=uiColors[GUI_COLOR_ACCENT_PRIMARY];
|
||||
ImVec4 selColor=uiColors[GUI_COLOR_ACCENT_SECONDARY];
|
||||
boundColor.w*=0.5;
|
||||
selColor.w*=0.25;
|
||||
ImVec4 boundColor=uiColors[GUI_COLOR_SAMPLE_SEL_POINT];
|
||||
ImVec4 selColor=uiColors[GUI_COLOR_SAMPLE_SEL];
|
||||
|
||||
if (p1.x<rectMin.x) p1.x=rectMin.x;
|
||||
if (p1.x>rectMax.x) p1.x=rectMax.x;
|
||||
|
@ -1470,11 +1558,9 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
}
|
||||
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT && sampleDragMode) {
|
||||
statusBar="Non-8/16-bit samples cannot be edited without prior conversion.";
|
||||
}
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY()+ImGui::GetStyle().ScrollbarSize);
|
||||
ImGui::Text("%s",statusBar.c_str());
|
||||
|
|
|
@ -1773,6 +1773,17 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Sample Editor")) {
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_BG,"Background");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_FG,"Waveform");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_LOOP,"Loop region");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_CENTER,"Center guide");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_GRID,"Grid");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_SEL,"Selection");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_SEL_POINT,"Selection points");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_NEEDLE,"Preview needle");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Pattern Manager")) {
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_NULL,"Unallocated");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_UNUSED,"Unused");
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "gui.h"
|
||||
#include <imgui.h>
|
||||
|
||||
bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool modifyOnChange) {
|
||||
bool altered=false;
|
||||
|
@ -1306,6 +1307,113 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_MSM5232: {
|
||||
int detune=flags.getInt("detune",0);
|
||||
bool groupEnv[2];
|
||||
int groupVol[8];
|
||||
float capValue[8];
|
||||
char temp[64];
|
||||
groupEnv[0]=flags.getBool("groupEnv0",true);
|
||||
groupEnv[1]=flags.getBool("groupEnv1",true);
|
||||
groupVol[0]=flags.getInt("partVolume0",255);
|
||||
groupVol[1]=flags.getInt("partVolume1",255);
|
||||
groupVol[2]=flags.getInt("partVolume2",255);
|
||||
groupVol[3]=flags.getInt("partVolume3",255);
|
||||
groupVol[4]=flags.getInt("partVolume4",255);
|
||||
groupVol[5]=flags.getInt("partVolume5",255);
|
||||
groupVol[6]=flags.getInt("partVolume6",255);
|
||||
groupVol[7]=flags.getInt("partVolume7",255);
|
||||
capValue[0]=flags.getFloat("capValue0",390.0f);
|
||||
capValue[1]=flags.getFloat("capValue1",390.0f);
|
||||
capValue[2]=flags.getFloat("capValue2",390.0f);
|
||||
capValue[3]=flags.getFloat("capValue3",390.0f);
|
||||
capValue[4]=flags.getFloat("capValue4",390.0f);
|
||||
capValue[5]=flags.getFloat("capValue5",390.0f);
|
||||
capValue[6]=flags.getFloat("capValue6",390.0f);
|
||||
capValue[7]=flags.getFloat("capValue7",390.0f);
|
||||
|
||||
if (CWSliderInt("Detune",&detune,-127,127)) {
|
||||
if (detune<-127) detune=-127;
|
||||
if (detune>127) detune=127;
|
||||
altered=true;
|
||||
} rightClickable
|
||||
|
||||
ImGui::Text("Capacitor values (nF):");
|
||||
for (int i=0; i<8; i++) {
|
||||
snprintf(temp,63,"%d##CAPV%d",i+1,i);
|
||||
if (CWSliderFloat(temp,&capValue[i],1.0f,1000.0f)) {
|
||||
if (capValue[i]<0) capValue[i]=0;
|
||||
if (capValue[i]>1000) capValue[i]=1000;
|
||||
altered=true;
|
||||
} rightClickable
|
||||
}
|
||||
|
||||
ImGui::Text("Initial part volume (channel 1-4):");
|
||||
for (int i=0; i<4; i++) {
|
||||
snprintf(temp,63,"%d'##GRPV%d",16>>i,i);
|
||||
if (CWSliderInt(temp,&groupVol[i],0,255)) {
|
||||
if (groupVol[i]<0) groupVol[i]=0;
|
||||
if (groupVol[i]>255) groupVol[i]=255;
|
||||
altered=true;
|
||||
} rightClickable
|
||||
}
|
||||
|
||||
ImGui::Text("Initial part volume (channel 5-8):");
|
||||
for (int i=4; i<8; i++) {
|
||||
snprintf(temp,63,"%d'##GRPV%d",16>>(i-4),i);
|
||||
if (CWSliderInt(temp,&groupVol[i],0,255)) {
|
||||
if (groupVol[i]<0) groupVol[i]=0;
|
||||
if (groupVol[i]>255) groupVol[i]=255;
|
||||
altered=true;
|
||||
} rightClickable
|
||||
}
|
||||
|
||||
ImGui::Text("Envelope mode (channel 1-4):");
|
||||
if (ImGui::RadioButton("Capacitor (attack/decay)##EM00",groupEnv[0])) {
|
||||
groupEnv[0]=true;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton("External (volume macro)##EM01",!groupEnv[0])) {
|
||||
groupEnv[0]=false;
|
||||
altered=true;
|
||||
}
|
||||
|
||||
ImGui::Text("Envelope mode (channel 5-8):");
|
||||
if (ImGui::RadioButton("Capacitor (attack/decay)##EM10",groupEnv[1])) {
|
||||
groupEnv[1]=true;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton("External (volume macro)##EM11",!groupEnv[1])) {
|
||||
groupEnv[1]=false;
|
||||
altered=true;
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
flags.set("detune",detune);
|
||||
|
||||
flags.set("capValue0",capValue[0]);
|
||||
flags.set("capValue1",capValue[1]);
|
||||
flags.set("capValue2",capValue[2]);
|
||||
flags.set("capValue3",capValue[3]);
|
||||
flags.set("capValue4",capValue[4]);
|
||||
flags.set("capValue5",capValue[5]);
|
||||
flags.set("capValue6",capValue[6]);
|
||||
flags.set("capValue7",capValue[7]);
|
||||
|
||||
flags.set("partVolume0",groupVol[0]);
|
||||
flags.set("partVolume1",groupVol[1]);
|
||||
flags.set("partVolume2",groupVol[2]);
|
||||
flags.set("partVolume3",groupVol[3]);
|
||||
flags.set("partVolume4",groupVol[4]);
|
||||
flags.set("partVolume5",groupVol[5]);
|
||||
flags.set("partVolume6",groupVol[6]);
|
||||
flags.set("partVolume7",groupVol[7]);
|
||||
|
||||
flags.set("groupEnv0",groupEnv[0]);
|
||||
flags.set("groupEnv1",groupEnv[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_SWAN:
|
||||
case DIV_SYSTEM_VERA:
|
||||
case DIV_SYSTEM_BUBSYS_WSG:
|
||||
|
|
Loading…
Reference in a new issue