From b034e3c5da634dbbb8bd84297c3e0c1b3e871c0d Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Thu, 26 May 2022 00:24:21 -0500 Subject: [PATCH 001/515] Commander X16 file export: ZSM format --- CMakeLists.txt | 2 + papers/zsm-format.md | 142 +++++++++++++++++++++++ src/engine/engine.h | 2 + src/engine/platform/vera.cpp | 4 +- src/engine/zsm.cpp | 218 +++++++++++++++++++++++++++++++++++ src/engine/zsm.h | 67 +++++++++++ src/engine/zsmOps.cpp | 175 ++++++++++++++++++++++++++++ src/gui/gui.cpp | 114 ++++++++++++++++-- src/gui/gui.h | 13 ++- src/gui/guiConst.cpp | 1 + src/gui/settings.cpp | 2 + src/main.cpp | 9 ++ 12 files changed, 733 insertions(+), 16 deletions(-) create mode 100644 papers/zsm-format.md create mode 100644 src/engine/zsm.cpp create mode 100644 src/engine/zsm.h create mode 100644 src/engine/zsmOps.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 59f88820c..a3056e962 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -375,6 +375,8 @@ src/engine/sysDef.cpp src/engine/wavetable.cpp src/engine/waveSynth.cpp src/engine/vgmOps.cpp +src/engine/zsmOps.cpp +src/engine/zsm.cpp src/engine/platform/abstract.cpp src/engine/platform/genesis.cpp src/engine/platform/genesisext.cpp diff --git a/papers/zsm-format.md b/papers/zsm-format.md new file mode 100644 index 000000000..739281254 --- /dev/null +++ b/papers/zsm-format.md @@ -0,0 +1,142 @@ +# ZSM format specification + +#### Zsound Repo + +ZSM is part of the Zsound suite of Commander X16 audio tools found at:
+https://github.com/ZeroByteOrg/zsound/ + + +#### Current ZSM Revision: 1 + +ZSM is a standard specifying both a data stream format and a file structure for containing the data stream. This document provides the standard for both the ZSM stream format and for the ZSM container file format. + +Whenever it becomes necessary to modify the ZSM standard in such a way that existing software will not be compatible with files using the newer standard, this version number will be incremented, up to a maximum value of 254. + +Version 255 (-1) is reserved for internal use by the player + +#### Headerless Data File Format: + + Since Kernal version r39, it is possible to load data files that do not have the CBM 2-byte load-to-address header. As of version r41, this functionality is equally accessible in the standard interactive BASIC interface. As the "PRG" header is no longer necessary, ZSM files will NOT contain this header in order to appear as any other common data file such as ``.wav``, ``.png``, etc. As such, users and programs must use the "headerless mode" when loading a ZSM into memory on the Commander X16. The previously-suggested dummy PRG header has been incorporated to the ZSM header as a magic header for file identity verification purposes. + + +## ZSM file composition + + Offset|Length|Field + --|--|-- + 0x00|16|ZSM HEADER + 0x10|variable|ZSM STREAM + ?|?|(optional) PCM HEADER + ?|variable|(optional) PCM DATA + +### ZSM Header + +The ZSM header is 16 bytes long. + +- All multi-byte values are little endian unless specified otherwise +- All offsets are relative to the beginning of the ZSM header + +Offset|Length|Field|Description +---|---|---|--- +0x00|2|Magic Header| The string 'zm' (binary 0x7a 0x6d) +0x02|1|Version| ZSM Version. 0-0xFE (0xFF is reserved) +0x03|3|Loop Point|Offset to the starting point of song loop. 0 = no loop. +0x06|3|PCM offset|Offset to the beginning of the PCM index table (if present). 0 = no PCM header or data is present. +0x09|1|FM channel mask|Bit 0-7 are set if the corresponding OPM channel is used by the music. +0x0a|2|PSG channel mask|Bits 0-15 are set if the corresponding PSG channel is used by the music. +0x0c|2|Tick Rate|The rate (in Hz) for song delay ticks. *60Hz (one tick per frame) is recommended.* +0x0e|2|reserved| Reserved for future use. Set to zero. + + +### ZSM Music Data Stream Format + +Byte 0|Byte 1 (variable)|Byte n|Byte n+1 (variable)|...|End of stream +---|---|---|---|---|--- +CMD|DATA|CMD|DATA|...|0x80 + +#### CMD (command) byte values +CMD bytes are bit-packed to hold a command Type ID and a value (n) as follows: + +CMD|Bit Pattern|Type|Arg. Bytes|Action +---|--|--|--|----- +0x00-0x3F|`00nnnnnn`|PSG write|1 | Write the following byte into PSG register offset *n*. (from 0x1F9C0 in VRAM) + 0x40 |`01000000`|EXTCMD |1+?| The following byte is an extension command. (see below for EXTCMD syntax) + 0x41-0x7F|`01nnnnnn`|FM write |2*n* | Write the following *n* reg/val pairs into the YM2151. +0x80|`10000000`|EOF |0 |This byte MUST be present at the end of the data stream. Player may loop or halt as necessary. +0x81-0xFF|`1nnnnnnn`|Delay |0 |Delay *n* ticks. + +#### EXTCMD: +The EXTCMD byte is formatted as `ccnnnnnn` where `c`=channel and `n`=number of bytes that follow. If the player wishes to ignore a channel, it can simply advance `n` bytes and continue processing. See EXTCMD Channel Specifications below for more details. + +### PCM Header + +The size and contents of the PCM header table is not yet decided. This will depend largely on the strucure of EXTCMD channel 0, and be covered in detail in that specification. + +Any offset values contained in the PCM data header block will be relative to the beginning of the PCM header, not the ZSM header. The intention is to present the digital audio portion as a set of digi clips ("samples" in tracker terminology) whose playback can be triggered by EXTCMD channel zero. + +### PCM Sample Data + +This will be a blob of PCM data with no internal formatting. Indeces / format information / loop points / etc regarding this blob will be provided via the PCM header. The end of this blob will be the end of the ZSM file. + + +## EXTCMD Channel Scifications + +Extension commands provide optional functionality within a ZSM music file. EXTCMD may be ignored by any player. EXTCMD defines 4 "channels" of message streams. Players may implement support for any, all, or none of the channels as desired. An EXTCMD may specify up to 63 bytes of data. If more data than this is required, then it must be broken up into multiple EXTCMDs. + +##### EXTCMD in ZSM stream context: + +...|CMD 0x40|EXTCMD|N bytes|CMD|... +---|---|---|---|---|--- + +##### EXTCMD byte format: + +Bit Pattern|C|N +--|--|-- +`ccnnnnnn`|Extension Channel ID|Number of bytes that follow + + + +##### EXTCMD Channels: +0. PCM instrument channel +1. Expansion Sound Devices +2. Synchronization events +3. Custom + +The formatting of the data within these 4 channels is presently a work in progress. Definitions for channels 0-3 will be part of the official ZSM specifications and implemented in the Zsound library. Significant changes within one of these three channels' structure may result in a new ZSM version number being issued. The formatting and content of the 3 official EXTCMD channels will be covered here. + +The Custom channel data may take whatever format is desired for any particular purpose with the understanding that the general ecosystem of ZSM-aware applications will most likely ignore them. + +### EXTCMD Channel: +#### 0: PCM audio + +The structure of data within this channel is not yet defined. + +#### 1: Expansion Sound Devices + +This channel is for data intended for "well-known" expansion hardware used with the Commander X16. As the community adopts various expansion hardware, such devices will be given a standard "ID" number so that all ZSM files will agree on which device is being referenced by expansion HW data. + +The specification of new chip IDs should not affect the format of ZSM itself, and thus will not result in a ZSM version update. Players will simply need to update their list of known hardware. + +Players implementing this channel should implement detection routines during init to determine which (if any) expansion hardware is present. Any messages intended for a chip that is not present in the system should be skipped. + +An expansion HW write will contain the following data: + +Chip ID|Nuber of writes (`N`)| `N` tuples of data +--|--|-- +one byte|one byte|N * tuple_size bytes + +- The total number of bytes MUST equal exactly the number of bytes specified in the preceding EXTCMD. +- The tuple_size is determined by the needs of the device, and thus will be specified per-device along with its chip ID assignment. This is likely to be 1-3 bytes for most devices. + +There are currently no supported expansion HW IDs assigned. + +#### 2: Synchronization Events + +The purpose of this channel is to provide for music synchronization cues that applications may use to perform operations in sync with the music (such as when the Goombas jump in New Super Mario Bros in time with the BOP! BOP! notes in the music). It is intended for the reference player to provide a sync channel callback, passing the data bytes to the callback function, and then to proceed with playback. + +The data structure within this channel is not yet defined. It is our intention to work with the community in order to collaborate on a useful structure. + +#### 3: Custom + +The purpose for this channel is that any project with an idea that does not fit neatly into the above categories may pack data into the project's music files in whatever form is required. It should be understood that these ZSMs will not be expected to use the extended behaviors outside of the project they were designed for. The music itself, however, should play properly. The only constraint is that the data must conform to the EXTCMD byte - supplying exactly the specified number of bytes per EXTCMD. + +The reference playback library in Zsound will implement this channel as a simple callback passing the memory location and data size to the referenced function, and take no further action internally. diff --git a/src/engine/engine.h b/src/engine/engine.h index 94c122195..a2210a66c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -458,6 +458,8 @@ class DivEngine { SafeWriter* buildROM(int sys); // dump to VGM. SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171); + // dump to ZSM. + SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true); // export to an audio file bool saveAudio(const char* path, int loops, DivAudioExportModes mode); // wait for audio export to finish diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 2ad06c6ef..c562698a6 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -27,7 +27,9 @@ extern "C" { #include "sound/vera_pcm.h" } -#define rWrite(c,a,d) {regPool[(c)*4+(a)]=(d); psg_writereg(psg,((c)*4+(a)),(d));} +//if (dumpWrites) {addWrite(((c)*4+(a)),(d));} +//#define rWrite(c,a,d) {regPool[(c)*4+(a)]=(d); psg_writereg(psg,((c)*4+(a)),(d));} +#define rWrite(c,a,d) {regPool[(c)*4+(a)]=(d); psg_writereg(psg,((c)*4+(a)),(d));if (dumpWrites) {addWrite(((c)*4+(a)),(d));}} #define rWriteLo(c,a,d) rWrite(c,a,(regPool[(c)*4+(a)]&(~0x3f))|((d)&0x3f)) #define rWriteHi(c,a,d) rWrite(c,a,(regPool[(c)*4+(a)]&(~0xc0))|(((d)<<6)&0xc0)) #define rWritePCMCtrl(d) {regPool[64]=(d); pcm_write_ctrl(pcm,d);} diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp new file mode 100644 index 000000000..6f1e02df1 --- /dev/null +++ b/src/engine/zsm.cpp @@ -0,0 +1,218 @@ +/** + * 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 "zsm.h" +#include "../ta-log.h" +#include "../utfutils.h" +#include "song.h" + +ZSM::ZSM() { + w = NULL; + init(); +} + +ZSM::~ZSM() { +} + +void ZSM::init(unsigned int rate) { + if (w != NULL) delete w; + w = new SafeWriter; + w->init(); + // write default ZSM data header + w->write("zm",2); // magic header + w->writeC(ZSM_VERSION); + // no loop offset + w->writeS(0); + w->writeC(0); + // no PCM + w->writeS(0x00); + w->writeC(0x00); + // FM channel mask + w->writeC(0x00); + // PSG channel mask + w->writeS(0x00); + w->writeS((unsigned short)rate); + // 2 reserved bytes (set to zero) + w->writeS(0x00); + tickRate = rate; + loopOffset=-1; + numWrites=0; + memset(&ymState,-1,sizeof(ymState)); + memset(&psgState,-1,sizeof(psgState)); + ticks=0; +} + +int ZSM::getoffset() { + return w->tell(); +} + +void ZSM::writeYM(unsigned char a, unsigned char v) { + int lastMask = ymMask; + if (a==0x19 && v>=0x80) a=0x1a; // AMD/PSD use same reg addr. store PMD as 0x1a + if (a==0x08 && (v&0xf8)) ymMask |= (1 << (v & 0x07)); // mark chan as in-use if keyDN + if (a!=0x08) ymState[ym_NEW][a] = v; // cache the newly-written value + bool writeit=false; // used to suppress spurious writes to unused channels + if (a < 0x20) { + if (a == 0x08) { + // write keyUPDN messages if channel is active. + writeit = (ymMask & (1 << (v & 0x07))) > 0; + } + else { + // do not suppress global registers + writeit = true; + } + } else { + writeit = (ymMask & (1 << (a & 0x07))) > 0; // a&0x07 = chan ID for regs >=0x20 + } + if (lastMask != ymMask) { + // if the ymMask just changed, then the channel has become active. + // This can only happen on a KeyDN event, so voice = v & 0x07 + // insert a keyUP just to be safe. + ymwrites.push_back(DivRegWrite(0x08,v&0x07)); + numWrites++; + // flush the ym_NEW cached states for this channel into the ZSM.... + for ( int i=0x20 + (v&0x07); i <= 0xff ; i+=8) { + if (ymState[ym_NEW][i] != ymState[ym_PREV][i]) { + ymwrites.push_back(DivRegWrite(i,ymState[ym_NEW][i])); + numWrites++; + // ...and update the shadow + ymState[ym_PREV][i] = ymState[ym_NEW][i]; + } + } + } + // Handle the current write if channel is active + if (writeit && ((ymState[ym_NEW][a] != ymState[ym_PREV][a])||a==0x08) ) { + // update YM shadow if not the KeyUPDN register. + if (a!=0x008) ymState[ym_PREV][a] = ymState[ym_NEW][a]; + // if reg = PMD, then change back to real register 0x19 + if (a==0x1a) a=0x19; + ymwrites.push_back(DivRegWrite(a,v)); + numWrites++; + } +} + +void ZSM::writePSG(unsigned char a, unsigned char v) { + // TODO: suppress writes to PSG voice that is not audible (volume=0) + if (a >= 64) { + logD ("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); + return; + } + if(psgState[psg_PREV][a] == v) { + if (psgState[psg_NEW][a] != v) + // NEW value is being reset to the same as PREV value + // so it is no longer a new write. + numWrites--; + } else { + if (psgState[psg_PREV][a] == psgState[psg_NEW][a]) + // if this write changes the NEW cached value to something other + // than the PREV value, then this is a new write. + numWrites++; + } + psgState[psg_NEW][a] = v; + // mark channel as used in the psgMask if volume is set > 0. + if ((a % 4 == 2) && (v & 0x3f)) psgMask |= (1 << (a>>2)); +} + +void ZSM::writePCM(unsigned char a, unsigned char v) { + // ZSM standard for PCM playback has not been established yet. +} + +void ZSM::tick(int numticks) { + flushWrites(); + ticks += numticks; +} + +void ZSM::setLoopPoint() { + tick(0); // flush any ticks+writes + flushTicks(); // flush ticks incase no writes were pending + logI("ZSM: loop at file offset %d bytes",w->tell()); + loopOffset=w->tell(); + //update the ZSM header's loop offset value + w->seek(0x03,SEEK_SET); + w->writeS((short)(loopOffset&0xffff)); + w->writeC((short)((loopOffset>>16)&0xff)); + w->seek(loopOffset,SEEK_SET); + // reset the PSG shadow and write cache + memset(&psgState,-1,sizeof(psgState)); + // reset the YM shadow.... + memset(&ymState[ym_PREV],-1,sizeof(ymState[ym_PREV])); + // ... and cache (except for unused channels) + memset(&ymState[ym_NEW],-1,0x20); + for (int chan=0; chan<8 ; chan++) { + //do not clear state for as-yet-unused channels + if (!(ymMask & (1<writeC(ZSM_EOF); + // update channel use masks. + w->seek(0x09,SEEK_SET); + w->writeC((short)(ymMask & 0xff)); + w->writeS((short)(psgMask & 0xffff)); + // todo: put PCM offset/data writes here once defined in ZSM standard. + return w; +} + +void ZSM::flushWrites() { + logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d",numWrites,ticks,ymwrites.size()); + if (numWrites==0) return; + flushTicks(); // only flush ticks if there are writes pending. + for (int i=0;i<64;i++) { + if (psgState[psg_NEW][i] == psgState[psg_PREV][i]) continue; + psgState[psg_PREV][i]=psgState[psg_NEW][i]; + w->writeC(i); + w->writeC(psgState[psg_NEW][i]); + } + int n=0; // n = completed YM writes. used to determine when to write the CMD byte... + for (DivRegWrite& write: ymwrites) { + if (n%ZSM_YM_MAX_WRITES == 0) { + if(ymwrites.size()-n > ZSM_YM_MAX_WRITES) { + w->writeC(ZSM_YM_CMD+ZSM_YM_MAX_WRITES); + logD("ZSM: YM-write: %d (%02x) [max]",ZSM_YM_MAX_WRITES,ZSM_YM_MAX_WRITES+ZSM_YM_CMD); + } else { + w->writeC(ZSM_YM_CMD+ymwrites.size()-n); + logD("ZSM: YM-write: %d (%02x)",ymwrites.size()-n,ZSM_YM_CMD+ymwrites.size()-n); + } + } + n++; + w->writeC(write.addr); + w->writeC(write.val); + } + ymwrites.clear(); + numWrites=0; +} + +void ZSM::flushTicks() { + while (ticks > ZSM_DELAY_MAX) { + logD("ZSM: write delay %d (max)",ZSM_DELAY_MAX); + w->writeC(ZSM_DELAY_CMD+ZSM_DELAY_MAX); + ticks -= ZSM_DELAY_MAX; + } + if (ticks>0) { + logD("ZSM: write delay %d",ticks); + w->writeC(ZSM_DELAY_CMD+ticks); + } + ticks=0; +} diff --git a/src/engine/zsm.h b/src/engine/zsm.h new file mode 100644 index 000000000..281e19bb4 --- /dev/null +++ b/src/engine/zsm.h @@ -0,0 +1,67 @@ +/** + * 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 _ZSM_H +#define _ZSM_H + +//#include "engine.h" +#include "safeWriter.h" +#include "dispatch.h" +#include + +#define ZSM_HEADER_SIZE 16 +#define ZSM_VERSION 1 +#define ZSM_YM_CMD 0x40 +#define ZSM_DELAY_CMD 0x80 +#define ZSM_YM_MAX_WRITES 63 +#define ZSM_DELAY_MAX 127 +#define ZSM_EOF ZSM_DELAY_CMD + +enum YM_STATE { ym_PREV, ym_NEW, ym_STATES }; +enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; + +class ZSM { + private: + SafeWriter* w; + int ymState[ym_STATES][256]; + int psgState[psg_STATES][64]; + std::vector ymwrites; + int loopOffset; + int numWrites; + int ticks; + int tickRate; + int ymMask = 0; + int psgMask = 0; + public: + ZSM(); + ~ZSM(); + void init(unsigned int rate = 60); + int getoffset(); + void writeYM(unsigned char a, unsigned char v); + void writePSG(unsigned char a, unsigned char v); + void writePCM(unsigned char a, unsigned char v); + void tick(int numticks = 1); + void setLoopPoint(); + SafeWriter* finish(); + private: + void flushWrites(); + void flushTicks(); +}; + +#endif diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp new file mode 100644 index 000000000..b115876a6 --- /dev/null +++ b/src/engine/zsmOps.cpp @@ -0,0 +1,175 @@ +/** + * 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 "engine.h" +#include "../ta-log.h" +#include "../utfutils.h" +#include "song.h" +#include "zsm.h" + +constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; +constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; + +SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { + + int VERA = -1; + int YM = -1; + int IGNORED = 0; + + //loop = false; + // find indexes for YM and VERA. Ignore other systems. + for (int i=0; i= 0) { IGNORED++;break; } + VERA = i; + logD("VERA detected as chip id %d",i); + break; + case DIV_SYSTEM_YM2151: + if (YM >= 0) { IGNORED++;break; } + YM = i; + logD("YM detected as chip id %d",i); + break; + default: + IGNORED++; + logD("Ignoring chip %d systemID %d",i,song.system[i]); + } + } + if (VERA < 0 && YM < 0) { + logE("No supported systems for ZSM"); + return NULL; + } + if (IGNORED > 0) + logW("ZSM export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); + + stop(); + repeatPattern=false; + setOrder(0); + BUSY_BEGIN_SOFT; + + double origRate=got.rate; + got.rate=zsmrate & 0xffff; + + // determine loop point + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + walkSong(loopOrder,loopRow,loopEnd); + logI("loop point: %d %d",loopOrder,loopRow); + warnings=""; + + ZSM zsm; + zsm.init(zsmrate); + + // reset the playback state + curOrder=0; + freelance=false; + playing=false; + extValuePresent=false; + remainingLoops=-1; + + // Prepare to write song data + playSub(false); + size_t tickCount=0; + bool done=false; + int loopPos=-1; + int writeCount=0; + int fracWait=0; // accumulates fractional ticks + if (VERA >= 0) disCont[VERA].dispatch->toggleRegisterDump(true); + if (YM >= 0) { + disCont[YM].dispatch->toggleRegisterDump(true); + zsm.writeYM(0x18,0); // initialize the LFO freq to 0 + // note - I think there's a bug where Furnace writes AMD/PMD=max + // that shouldn't be there, requiring this initialization that shouldn't + // be there for ZSM. + } + + while (!done) { + if (loopPos==-1) { + if (loopOrder==curOrder && loopRow==curRow && ticks==1 && loop) { + loopPos=zsm.getoffset(); + zsm.setLoopPoint(); + } + } + if (nextTick() || !playing) { + done=true; + if (!loop) { + for (int i=0; igetRegisterWrites().clear(); + } + break; + } + if (!playing) { + loopPos=-1; + } + } + // get register dumps + for (int j=0; j<2; j++) { + int i=0; + // dump YM writes first + if (j==0) { + if (YM < 0) + continue; + else + i=YM; + } + // dump VERA writes second + if (j==1) { + if (VERA < 0) + continue; + else { + i=VERA; + } + } + std::vector& writes=disCont[i].dispatch->getRegisterWrites(); + if (writes.size() > 0) + logD("zsmOps: Writing %d messages to chip %d",writes.size(), i); + for (DivRegWrite& write: writes) { + if (i==YM) zsm.writeYM(write.addr&0xff, write.val); + if (i==VERA) zsm.writePSG(write.addr&0xff, write.val); + writeCount++; + } + writes.clear(); + } + + // write wait + int totalWait=cycles>>MASTER_CLOCK_PREC; + fracWait += cycles & MASTER_CLOCK_MASK; + totalWait += fracWait>>MASTER_CLOCK_PREC; + fracWait &= MASTER_CLOCK_MASK; + if (totalWait>0) { + zsm.tick(totalWait); + tickCount+=totalWait; + } + } + // end of song + + // done - close out. + got.rate = origRate; + if (VERA >= 0) disCont[VERA].dispatch->toggleRegisterDump(false); + if (YM >= 0) disCont[YM].dispatch->toggleRegisterDump(false); + + remainingLoops=-1; + playing=false; + freelance=false; + extValuePresent=false; + + BUSY_END; + return zsm.finish(); +} diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0441a3aff..4196123c7 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -860,7 +860,7 @@ void FurnaceGUI::stopPreviewNote(SDL_Scancode scancode, bool autoNote) { void FurnaceGUI::noteInput(int num, int key, int vol) { DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],true); - + prepareUndo(GUI_UNDO_PATTERN_EDIT); if (key==100) { // note off @@ -1399,6 +1399,16 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { dpiScale ); break; + case GUI_FILE_EXPORT_ZSM: + if (!dirExists(workingDirZSMExport)) workingDirZSMExport=getHomeDir(); + hasOpened=fileDialog->openSave( + "Export ZSM", + {"ZSM file", "*.zsm"}, + "ZSM file{.zsm}", + workingDirZSMExport, + dpiScale + ); + break; case GUI_FILE_EXPORT_ROM: showError("Coming soon!"); break; @@ -2023,7 +2033,7 @@ void FurnaceGUI::editOptions(bool topMenu) { snprintf(id,63,"%.2x##LatchFX",data); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]); } - + if (ImGui::Selectable(id,latchTarget==3,ImGuiSelectableFlags_DontClosePopups)) { latchTarget=3; latchNibble=false; @@ -2096,7 +2106,7 @@ void FurnaceGUI::editOptions(bool topMenu) { doTranspose(transposeAmount,opMaskTransposeValue); ImGui::CloseCurrentPopup(); } - + ImGui::Separator(); if (ImGui::MenuItem("interpolate",BIND_FOR(GUI_ACTION_PAT_INTERPOLATE))) doInterpolate(); if (ImGui::BeginMenu("change instrument...")) { @@ -2212,7 +2222,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) { if (mobileUI!=enable || force) { if (!mobileUI && enable) { ImGui::SaveIniSettingsToDisk(finalLayoutPath); - } + } mobileUI=enable; if (mobileUI) { ImGui::GetIO().IniFilename=NULL; @@ -2220,7 +2230,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) { ImGui::GetIO().IniFilename=finalLayoutPath; ImGui::LoadIniSettingsFromDisk(finalLayoutPath); } - } + } } int _processEvent(void* instance, SDL_Event* event) { @@ -2569,7 +2579,7 @@ bool FurnaceGUI::loop() { if (ImGui::GetIO().MouseDown[0] || ImGui::GetIO().MouseDown[1] || ImGui::GetIO().MouseDown[2] || ImGui::GetIO().MouseDown[3] || ImGui::GetIO().MouseDown[4]) { WAKE_UP; } - + while (true) { midiLock.lock(); if (midiQueue.empty()) { @@ -2722,10 +2732,13 @@ bool FurnaceGUI::loop() { midiLock.unlock(); } +<<<<<<< HEAD eventTimeEnd=SDL_GetPerformanceCounter(); layoutTimeBegin=SDL_GetPerformanceCounter(); +======= +>>>>>>> Commander X16 file export: ZSM format ImGui_ImplSDLRenderer_NewFrame(); ImGui_ImplSDL2_NewFrame(sdlWin); ImGui::NewFrame(); @@ -2824,6 +2837,26 @@ bool FurnaceGUI::loop() { } ImGui::EndMenu(); } + int numZSMCompat=0; + for (int i=0; isong.systemLen; i++) { + if ((e->song.system[i] == DIV_SYSTEM_VERA) || (e->song.system[i] == DIV_SYSTEM_YM2151)) numZSMCompat++; + } + if (numZSMCompat > 0) { + if (ImGui::BeginMenu("export ZSM...")) { + ImGui::Text("Commander X16 Zsound Music File"); + if (ImGui::InputInt("Tick Rate (Hz)",&zsmExportTickRate,1,2)) { + if (zsmExportTickRate<1) zsmExportTickRate=1; + if (zsmExportTickRate>44100) zsmExportTickRate=44100; + } + ImGui::Checkbox("loop",&zsmExportLoop); + ImGui::SameLine(); + if (ImGui::Button(" Go ")) { + openFileDialog(GUI_FILE_EXPORT_ZSM); + ImGui::CloseCurrentPopup(); + } + ImGui::EndMenu(); + } + } ImGui::Separator(); if (ImGui::BeginMenu("add system...")) { for (int j=0; availableSystems[j]; j++) { @@ -2939,7 +2972,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; - + ImGui::EndMenu(); } if (ImGui::BeginMenu("help")) { @@ -3022,8 +3055,39 @@ bool FurnaceGUI::loop() { } if (mobileUI) { - globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; - drawMobileControls(); + ImGuiViewport* mainView=ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(mainView->Pos); + ImGui::SetNextWindowSize(mainView->Size); + ImGui::SetNextWindowViewport(mainView->ID); + ImGuiID dockID=ImGui::GetID("MobileUISpace"); + ImGuiWindowFlags muiFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoDocking|ImGuiWindowFlags_NoBringToFrontOnFocus|ImGuiWindowFlags_NoNavFocus; + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("MobileUI",NULL,muiFlags); + ImGui::PopStyleVar(3); + if (ImGui::DockBuilderGetNode(dockID)==NULL) { + ImGui::DockBuilderRemoveNode(dockID); + ImGuiID dn=ImGui::DockBuilderAddNode(dockID); + ImGuiID upper, lower, left, right; + ImGui::DockBuilderSplitNode(dn,ImGuiDir_Left,0.1f,&left,&right); + ImGui::DockBuilderSplitNode(right,ImGuiDir_Down,0.2f,&lower,&upper); + ImGui::DockBuilderDockWindow("Mobile Controls",left); + ImGui::DockBuilderDockWindow("Pattern",upper); + ImGui::DockBuilderDockWindow("Piano",lower); + ImGui::DockBuilderFinish(dn); + } + ImGui::DockSpace(dockID); + ImGui::End(); + + if (ImGui::Begin("Mobile Controls")) { + ImGui::Text("Hi!"); + if (ImGui::Button("Get me out of here")) { + toggleMobileUI(false); + } + } + ImGui::End(); + drawPattern(); drawPiano(); } else { @@ -3127,6 +3191,9 @@ bool FurnaceGUI::loop() { case GUI_FILE_EXPORT_ROM: workingDirVGMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; break; + case GUI_FILE_EXPORT_ZSM: + workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; + break; case GUI_FILE_LOAD_MAIN_FONT: case GUI_FILE_LOAD_PAT_FONT: workingDirFont=fileDialog->getPath()+DIR_SEPARATOR_STR; @@ -3175,6 +3242,9 @@ bool FurnaceGUI::loop() { if (curFileDialog==GUI_FILE_EXPORT_VGM) { checkExtension(".vgm"); } + if (curFileDialog==GUI_FILE_EXPORT_ZSM) { + checkExtension(".zsm"); + } if (curFileDialog==GUI_FILE_EXPORT_COLORS) { checkExtension(".cfgc"); } @@ -3337,6 +3407,26 @@ bool FurnaceGUI::loop() { } break; } + case GUI_FILE_EXPORT_ZSM: { + SafeWriter* w=e->saveZSM(zsmExportTickRate,zsmExportLoop); + if (w!=NULL) { + FILE* f=ps_fopen(copyOfName.c_str(),"wb"); + if (f!=NULL) { + fwrite(w->getFinalBuf(),1,w->size(),f); + fclose(f); + } else { + showError("could not open file!"); + } + w->finish(); + delete w; + if (!e->getWarnings().empty()) { + showWarning(e->getWarnings(),GUI_WARN_GENERIC); + } + } else { + showError(fmt::sprintf("Could not write ZSM! (%s)",e->getLastError())); + } + break; + } case GUI_FILE_EXPORT_ROM: showError("Coming soon!"); break; @@ -3759,7 +3849,7 @@ bool FurnaceGUI::loop() { } logD("saving backup..."); SafeWriter* w=e->saveFur(true); - + if (w!=NULL) { FILE* outFile=ps_fopen(backupPath.c_str(),"wb"); if (outFile!=NULL) { @@ -3834,6 +3924,7 @@ bool FurnaceGUI::init() { workingDirSample=e->getConfString("lastDirSample",workingDir); workingDirAudioExport=e->getConfString("lastDirAudioExport",workingDir); workingDirVGMExport=e->getConfString("lastDirVGMExport",workingDir); + workingDirZSMExport=e->getConfString("lastDirZSMExport",workingDir); workingDirFont=e->getConfString("lastDirFont",workingDir); workingDirColors=e->getConfString("lastDirColors",workingDir); workingDirKeybinds=e->getConfString("lastDirKeybinds",workingDir); @@ -4042,6 +4133,7 @@ bool FurnaceGUI::finish() { e->setConf("lastDirSample",workingDirSample); e->setConf("lastDirAudioExport",workingDirAudioExport); e->setConf("lastDirVGMExport",workingDirVGMExport); + e->setConf("lastDirZSMExport",workingDirZSMExport); e->setConf("lastDirFont",workingDirFont); e->setConf("lastDirColors",workingDirColors); e->setConf("lastDirKeybinds",workingDirKeybinds); @@ -4125,6 +4217,7 @@ FurnaceGUI::FurnaceGUI(): displayError(false), displayExporting(false), vgmExportLoop(true), + zsmExportLoop(true), wantCaptureKeyboard(false), oldWantCaptureKeyboard(false), displayMacroMenu(false), @@ -4134,6 +4227,7 @@ FurnaceGUI::FurnaceGUI(): wantScrollList(false), vgmExportVersion(0x171), drawHalt(10), + zsmExportTickRate(60), macroPointSize(16), globalWinFlags(0), curFileDialog(GUI_FILE_OPEN), diff --git a/src/gui/gui.h b/src/gui/gui.h index 93f4835fe..cb8ed690c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -73,6 +73,7 @@ enum FurnaceGUIColors { GUI_COLOR_FILE_AUDIO, GUI_COLOR_FILE_WAVE, GUI_COLOR_FILE_VGM, + GUI_COLOR_FILE_ZSM, GUI_COLOR_FILE_FONT, GUI_COLOR_FILE_OTHER, @@ -260,6 +261,7 @@ enum FurnaceGUIFileDialogs { GUI_FILE_EXPORT_AUDIO_PER_SYS, GUI_FILE_EXPORT_AUDIO_PER_CHANNEL, GUI_FILE_EXPORT_VGM, + GUI_FILE_EXPORT_ZSM, GUI_FILE_EXPORT_ROM, GUI_FILE_LOAD_MAIN_FONT, GUI_FILE_LOAD_PAT_FONT, @@ -807,15 +809,16 @@ class FurnaceGUI { bool updateSampleTex; String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; - String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM; - String mmlString[32]; + String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirZSMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM; + String mmlString[17]; String mmlStringW; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList; bool willExport[32]; int vgmExportVersion; int drawHalt; + int zsmExportTickRate; int macroPointSize; ImGuiWindowFlags globalWinFlags; @@ -1196,7 +1199,7 @@ class FurnaceGUI { int chanToMove; ImVec2 patWindowPos, patWindowSize; - + // pattern view specific ImVec2 fourChars, threeChars, twoChars; ImVec2 noteCellSize, insCellSize, volCellSize, effectCellSize, effectValCellSize; @@ -1250,7 +1253,7 @@ class FurnaceGUI { // visualizer float keyHit[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; - + // log window bool followLog; diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index ffb60c434..2a321a809 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -679,6 +679,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_FILE_AUDIO,"",ImVec4(1.0f,1.0f,0.5f,1.0f)), D(GUI_COLOR_FILE_WAVE,"",ImVec4(1.0f,0.75f,0.5f,1.0f)), D(GUI_COLOR_FILE_VGM,"",ImVec4(1.0f,1.0f,0.5f,1.0f)), + D(GUI_COLOR_FILE_ZSM,"",ImVec4(1.0f,1.0f,0.5f,1.0f)), D(GUI_COLOR_FILE_FONT,"",ImVec4(0.3f,1.0f,0.6f,1.0f)), D(GUI_COLOR_FILE_OTHER,"",ImVec4(0.7f,0.7f,0.7f,1.0f)), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 3c71d157e..b22c1a07d 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1320,6 +1320,7 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_FILE_AUDIO,"Audio"); UI_COLOR_CONFIG(GUI_COLOR_FILE_WAVE,"Wavetable"); UI_COLOR_CONFIG(GUI_COLOR_FILE_VGM,"VGM"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_ZSM,"ZSM"); UI_COLOR_CONFIG(GUI_COLOR_FILE_FONT,"Font"); UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other"); ImGui::TreePop(); @@ -2917,6 +2918,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmc",uiColors[GUI_COLOR_FILE_AUDIO],ICON_FA_FILE_AUDIO_O); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgm",uiColors[GUI_COLOR_FILE_VGM],ICON_FA_FILE_AUDIO_O); + ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".zsm",uiColors[GUI_COLOR_FILE_ZSM],ICON_FA_FILE_AUDIO_O); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".otf",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttc",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT); diff --git a/src/main.cpp b/src/main.cpp index 079058528..f2274562e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,7 @@ FurnaceGUI g; String outName; String vgmOutName; +String zsmOutName; int loops=1; DivAudioExportModes outMode=DIV_EXPORT_MODE_ONE; @@ -213,6 +214,12 @@ TAParamResult pVGMOut(String val) { return TA_PARAM_SUCCESS; } +TAParamResult pZSMOut(String val) { + zsmOutName=val; + e.setAudio(DIV_AUDIO_DUMMY); + return TA_PARAM_SUCCESS; +} + bool needsValue(String param) { for (size_t i=0; i","output audio to file")); params.push_back(TAParam("O","vgmout",true,pVGMOut,"","output .vgm data")); + params.push_back(TAParam("Z","zsmout",true,pZSMOut,"","output .zsm data for Commander X16 Zsound")); params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)")); params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (pattern by default)")); params.push_back(TAParam("c","console",false,pConsole,"","enable console mode")); @@ -251,6 +259,7 @@ int main(int argc, char** argv) { #endif outName=""; vgmOutName=""; + zsmOutName=""; initParams(); From dcba41c6e9ce7288831de79da69fd4faa3b19117 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Thu, 26 May 2022 00:38:44 -0500 Subject: [PATCH 002/515] Fixed mmlString[32] in gui.h --- src/gui/gui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index cb8ed690c..380537e95 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -810,7 +810,7 @@ class FurnaceGUI { String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirZSMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM; - String mmlString[17]; + String mmlString[32]; String mmlStringW; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; From 8af85096ff29f3815f1bee57cc5f4c25bb62611d Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Thu, 26 May 2022 13:28:18 -0500 Subject: [PATCH 003/515] Fixed incorrect conflict-resolution in gui.cpp line 3049 --- src/gui/gui.cpp | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4196123c7..dd622d2a0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3055,39 +3055,8 @@ bool FurnaceGUI::loop() { } if (mobileUI) { - ImGuiViewport* mainView=ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(mainView->Pos); - ImGui::SetNextWindowSize(mainView->Size); - ImGui::SetNextWindowViewport(mainView->ID); - ImGuiID dockID=ImGui::GetID("MobileUISpace"); - ImGuiWindowFlags muiFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoDocking|ImGuiWindowFlags_NoBringToFrontOnFocus|ImGuiWindowFlags_NoNavFocus; - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::Begin("MobileUI",NULL,muiFlags); - ImGui::PopStyleVar(3); - if (ImGui::DockBuilderGetNode(dockID)==NULL) { - ImGui::DockBuilderRemoveNode(dockID); - ImGuiID dn=ImGui::DockBuilderAddNode(dockID); - ImGuiID upper, lower, left, right; - ImGui::DockBuilderSplitNode(dn,ImGuiDir_Left,0.1f,&left,&right); - ImGui::DockBuilderSplitNode(right,ImGuiDir_Down,0.2f,&lower,&upper); - ImGui::DockBuilderDockWindow("Mobile Controls",left); - ImGui::DockBuilderDockWindow("Pattern",upper); - ImGui::DockBuilderDockWindow("Piano",lower); - ImGui::DockBuilderFinish(dn); - } - ImGui::DockSpace(dockID); - ImGui::End(); - - if (ImGui::Begin("Mobile Controls")) { - ImGui::Text("Hi!"); - if (ImGui::Button("Get me out of here")) { - toggleMobileUI(false); - } - } - ImGui::End(); - + globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; + drawMobileControls(); drawPattern(); drawPiano(); } else { From 0846f66a7eebf245367190dd25e7ee88523cc011 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Fri, 27 May 2022 13:00:23 -0500 Subject: [PATCH 004/515] Removed merge conflict tag from gui.cpp --- src/gui/gui.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dd622d2a0..0de71fe3c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2732,13 +2732,10 @@ bool FurnaceGUI::loop() { midiLock.unlock(); } -<<<<<<< HEAD eventTimeEnd=SDL_GetPerformanceCounter(); layoutTimeBegin=SDL_GetPerformanceCounter(); - -======= ->>>>>>> Commander X16 file export: ZSM format + ImGui_ImplSDLRenderer_NewFrame(); ImGui_ImplSDL2_NewFrame(sdlWin); ImGui::NewFrame(); From 7ad4a8f5a78adb7e8af89cb901e9cef085776e4c Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Tue, 7 Jun 2022 20:24:50 -0500 Subject: [PATCH 005/515] Fixed compile error in MacOS --- src/engine/zsm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index 6f1e02df1..7768e6590 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -207,7 +207,7 @@ void ZSM::flushWrites() { void ZSM::flushTicks() { while (ticks > ZSM_DELAY_MAX) { logD("ZSM: write delay %d (max)",ZSM_DELAY_MAX); - w->writeC(ZSM_DELAY_CMD+ZSM_DELAY_MAX); + w->writeC((signed char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); ticks -= ZSM_DELAY_MAX; } if (ticks>0) { From 8ed02530f648f48e577cd3e06251e8fdd00532a4 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Tue, 7 Jun 2022 22:08:04 -0500 Subject: [PATCH 006/515] Added WriteUC wrapper to safewrite for unsigned char. --- src/engine/safeWriter.cpp | 6 +++++- src/engine/safeWriter.h | 1 + src/engine/zsm.cpp | 26 +++++++++++++------------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index f29800a4a..48d7d1227 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -77,6 +77,10 @@ int SafeWriter::writeC(signed char val) { return write(&val,1); } +int SafeWriter::writeUC(unsigned char val) { + return write(&val,1); +} + int SafeWriter::writeS(short val) { return write(&val,2); } @@ -139,4 +143,4 @@ void SafeWriter::finish() { delete[] buf; buf=NULL; operative=false; -} \ No newline at end of file +} diff --git a/src/engine/safeWriter.h b/src/engine/safeWriter.h index 9072c61d7..3e36f3df7 100644 --- a/src/engine/safeWriter.h +++ b/src/engine/safeWriter.h @@ -45,6 +45,7 @@ class SafeWriter { int write(const void* what, size_t count); int writeC(signed char val); + int writeUC(unsigned char val); int writeS(short val); int writeS_BE(short val); int writeI(int val); diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index 7768e6590..fc8b471e7 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -36,7 +36,7 @@ void ZSM::init(unsigned int rate) { w->init(); // write default ZSM data header w->write("zm",2); // magic header - w->writeC(ZSM_VERSION); + w->writeUC(ZSM_VERSION); // no loop offset w->writeS(0); w->writeC(0); @@ -146,7 +146,7 @@ void ZSM::setLoopPoint() { //update the ZSM header's loop offset value w->seek(0x03,SEEK_SET); w->writeS((short)(loopOffset&0xffff)); - w->writeC((short)((loopOffset>>16)&0xff)); + w->writeUC((short)((loopOffset>>16)&0xff)); w->seek(loopOffset,SEEK_SET); // reset the PSG shadow and write cache memset(&psgState,-1,sizeof(psgState)); @@ -166,10 +166,10 @@ void ZSM::setLoopPoint() { SafeWriter* ZSM::finish() { tick(0); // flush any pending writes / ticks flushTicks(); // flush ticks in case there were no writes pending - w->writeC(ZSM_EOF); + w->writeUC(ZSM_EOF); // update channel use masks. w->seek(0x09,SEEK_SET); - w->writeC((short)(ymMask & 0xff)); + w->writeUC((unsigned char)(ymMask & 0xff)); w->writeS((short)(psgMask & 0xffff)); // todo: put PCM offset/data writes here once defined in ZSM standard. return w; @@ -179,26 +179,26 @@ void ZSM::flushWrites() { logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d",numWrites,ticks,ymwrites.size()); if (numWrites==0) return; flushTicks(); // only flush ticks if there are writes pending. - for (int i=0;i<64;i++) { + for (unsigned char i=0;i<64;i++) { if (psgState[psg_NEW][i] == psgState[psg_PREV][i]) continue; psgState[psg_PREV][i]=psgState[psg_NEW][i]; - w->writeC(i); - w->writeC(psgState[psg_NEW][i]); + w->writeUC(i); + w->writeUC(psgState[psg_NEW][i]); } int n=0; // n = completed YM writes. used to determine when to write the CMD byte... for (DivRegWrite& write: ymwrites) { if (n%ZSM_YM_MAX_WRITES == 0) { if(ymwrites.size()-n > ZSM_YM_MAX_WRITES) { - w->writeC(ZSM_YM_CMD+ZSM_YM_MAX_WRITES); + w->writeUC((unsigned char)(ZSM_YM_CMD+ZSM_YM_MAX_WRITES)); logD("ZSM: YM-write: %d (%02x) [max]",ZSM_YM_MAX_WRITES,ZSM_YM_MAX_WRITES+ZSM_YM_CMD); } else { - w->writeC(ZSM_YM_CMD+ymwrites.size()-n); + w->writeUC((unsigned char)(ZSM_YM_CMD+ymwrites.size()-n)); logD("ZSM: YM-write: %d (%02x)",ymwrites.size()-n,ZSM_YM_CMD+ymwrites.size()-n); } } n++; - w->writeC(write.addr); - w->writeC(write.val); + w->writeUC(write.addr); + w->writeUC(write.val); } ymwrites.clear(); numWrites=0; @@ -207,12 +207,12 @@ void ZSM::flushWrites() { void ZSM::flushTicks() { while (ticks > ZSM_DELAY_MAX) { logD("ZSM: write delay %d (max)",ZSM_DELAY_MAX); - w->writeC((signed char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); + w->writeUC((unsigned char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); ticks -= ZSM_DELAY_MAX; } if (ticks>0) { logD("ZSM: write delay %d",ticks); - w->writeC(ZSM_DELAY_CMD+ticks); + w->writeUC(ZSM_DELAY_CMD+ticks); } ticks=0; } From f3a90d554c28013ab2b14b66939079dfbc745ded Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Mon, 21 Mar 2022 14:38:12 +0700 Subject: [PATCH 007/515] WIP SNES support, part 1 --- CMakeLists.txt | 3 + papers/doc/7-systems/README.md | 1 + papers/doc/7-systems/snes.md | 18 + src/engine/dispatchContainer.cpp | 4 + src/engine/instrument.h | 1 + src/engine/platform/snes.cpp | 351 ++++++ src/engine/platform/snes.h | 98 ++ src/engine/platform/sound/snes/SPC_DSP.cpp | 1027 +++++++++++++++++ src/engine/platform/sound/snes/SPC_DSP.h | 307 +++++ .../platform/sound/snes/blargg_common.h | 186 +++ .../platform/sound/snes/blargg_config.h | 26 + .../platform/sound/snes/blargg_endian.h | 185 +++ .../platform/sound/snes/blargg_source.h | 100 ++ src/gui/gui.h | 1 + src/gui/guiConst.cpp | 3 +- 15 files changed, 2310 insertions(+), 1 deletion(-) create mode 100644 papers/doc/7-systems/snes.md create mode 100644 src/engine/platform/snes.cpp create mode 100644 src/engine/platform/snes.h create mode 100644 src/engine/platform/sound/snes/SPC_DSP.cpp create mode 100644 src/engine/platform/sound/snes/SPC_DSP.h create mode 100644 src/engine/platform/sound/snes/blargg_common.h create mode 100644 src/engine/platform/sound/snes/blargg_config.h create mode 100644 src/engine/platform/sound/snes/blargg_endian.h create mode 100644 src/engine/platform/sound/snes/blargg_source.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d8491b455..bc720fc24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,6 +377,8 @@ src/engine/platform/sound/rf5c68.cpp src/engine/platform/sound/oki/okim6258.cpp src/engine/platform/sound/oki/msm6295.cpp +src/engine/platform/sound/snes/SPC_DSP.cpp + src/engine/platform/oplAInterface.cpp src/engine/platform/ym2608Interface.cpp src/engine/platform/ym2610Interface.cpp @@ -447,6 +449,7 @@ src/engine/platform/scc.cpp src/engine/platform/ymz280b.cpp src/engine/platform/namcowsg.cpp src/engine/platform/rf5c68.cpp +src/engine/platform/snes.cpp src/engine/platform/dummy.cpp ) diff --git a/papers/doc/7-systems/README.md b/papers/doc/7-systems/README.md index fcf2e8860..d8551e1c3 100644 --- a/papers/doc/7-systems/README.md +++ b/papers/doc/7-systems/README.md @@ -34,5 +34,6 @@ this is a list of systems that Furnace supports, including each system's effects - [Konami VRC6](vrc6.md) - [Famicom Disk System](fds.md) - [Nintendo MMC5](mmc5.md) +- [SNES](snes.md) Furnace also reads .dmf files with the [Yamaha YMU759](ymu759.md) system, but... diff --git a/papers/doc/7-systems/snes.md b/papers/doc/7-systems/snes.md new file mode 100644 index 000000000..5bb1ae5f1 --- /dev/null +++ b/papers/doc/7-systems/snes.md @@ -0,0 +1,18 @@ +# Super NES + +The successor to NES to compete with Genesis. Now packing with superior graphics and sample-based audio. Also known as Super Famicom. + +Its audio subsystem, developed by Sony, features the DSP chip, SPC700 microcontroller and 64KB of dedicated SRAM used by both. This whole system itself is pretty much a separate computer that the main CPU needs to upload its program and samples to. + +The DSP chip can + +Furnace communicates with the DSP directly and provide a full 64KB memory. This memory might be reduced excessively on ROM export to make up for playback engine and pattern data. + +# effects + +Note: this chip has a signed left/right level. Which can be used for inverted (surround) stereo. A signed 8-bit value means 80 - FF = -128 - -1. Other values work normally. A value of -128 is not recommended as it could cause overflows. + +- `10xx`: Set echo feedback level. This effect will apply to all channels. +- `11xx`: Set echo left level (signed 8-bit). This effect will apply to all channels. +- `12xx`: Set echo right level (signed 8-bit). This effect will apply to all channels. +- `13xx`: Set the length of the echo delay buffer. This will also affect the size of the sample RAM! diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 227f60679..5437d6fc8 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -64,6 +64,7 @@ #include "platform/scc.h" #include "platform/ymz280b.h" #include "platform/rf5c68.h" +#include "platform/snes.h" #include "platform/dummy.h" #include "../ta-log.h" #include "platform/zxbeeper.h" @@ -395,6 +396,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do dispatch=new DivPlatformNamcoWSG; ((DivPlatformNamcoWSG*)dispatch)->setDeviceType(30); break; + case DIV_SYSTEM_SNES: + dispatch=new DivPlatformSNES; + break; case DIV_SYSTEM_DUMMY: dispatch=new DivPlatformDummy; break; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c4af6f042..66197a0fe 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,6 +60,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, + DIV_INS_SNES=33, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp new file mode 100644 index 000000000..de96ee968 --- /dev/null +++ b/src/engine/platform/snes.cpp @@ -0,0 +1,351 @@ +/** + * 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 "snes.h" +#include "../engine.h" +#include + +#define CHIP_DIVIDER 16 + +#define rWrite(a,v) {dsp->write(a,v); regPool[(a)&0x7f]=v; } + +const char* regCheatSheetSNESDSP[]={ + "VxVOLL", "x0", + "VxVOLR", "x1", + "VxPITCHL", "x2", + "VxPITCHH", "x3", + "VxSRCN", "x4", + "VxADSR1", "x5", + "VxADSR2", "x6", + "VxGAIN", "x7", + "VxENVX", "x8", + "VxOUTX", "x9", + "FIRx", "xF", + + "MVOLL", "0C", + "MVOLR", "1C", + "EVOLL", "2C", + "EVOLR", "3C", + "KON", "4C", + "KOFF", "5C", + "FLG", "6C", + "ENDX", "7C", + + "EFB", "0D", + "PMON", "2D", + "NON", "3D", + "EON", "4D", + "DIR", "5D", + "ESA", "6D", + "EDL", "7D", + NULL +}; + +const char** DivPlatformSNES::getRegisterSheet() { + return regCheatSheetSNESDSP; +} + +void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { + for (size_t h=start; hset_output(out,1); + dsp->run(32); + bufL[h]=out[0]; + bufR[h]=out[1]; + } +} + +void DivPlatformSNES::tick() { + for (int i=0; i<8; i++) { + chan[i].std.next(); + if (chan[i].std.hadVol) { + chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol))>>6; + } + double off=1.0; + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + if (chan[i].std.hadArp) { + if (!chan[i].inPorta) { + if (chan[i].std.arpMode) { + chan[i].baseFreq=off*NOTE_PERIODIC(chan[i].std.arp); + } else { + chan[i].baseFreq=off*NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + } + } + chan[i].freqChanged=true; + } else { + if (chan[i].std.arpMode && chan[i].std.finishedArp) { + chan[i].baseFreq=off*NOTE_PERIODIC(chan[i].note); + chan[i].freqChanged=true; + } + } + if (chan[i].std.hadWave) { + if (chan[i].wave!=chan[i].std.wave) { + chan[i].wave=chan[i].std.wave; + if (!chan[i].keyOff) chan[i].keyOn=true; + } + } + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { + //DivInstrument* ins=parent->getIns(chan[i].ins); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); + if (chan[i].freq>4095) chan[i].freq=4095; + if (chan[i].note>0x5d) chan[i].freq=0x01; + if (chan[i].keyOn) { + if (chan[i].wave<0) { + chan[i].wave=0; + } + } + if (chan[i].keyOff) { + } + if (chan[i].keyOn) chan[i].keyOn=false; + if (chan[i].keyOff) chan[i].keyOff=false; + chan[i].freqChanged=false; + } + } +} + +int DivPlatformSNES::dispatch(DivCommand c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins); + chan[c.chan].sample=ins->amiga.initSample; + double off=1.0; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=off*NOTE_PERIODIC(c.value); + } + if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { + chan[c.chan].sample=-1; + } + if (chan[c.chan].setPos) { + chan[c.chan].setPos=false; + } else { + chan[c.chan].audPos=0; + } + chan[c.chan].audSub=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + chan[c.chan].std.init(ins); + break; + } + case DIV_CMD_NOTE_OFF: + chan[c.chan].sample=-1; + 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; + } + break; + case DIV_CMD_VOLUME: + if (chan[c.chan].vol!=c.value) { + chan[c.chan].vol=c.value; + if (!chan[c.chan].std.hasVol) { + chan[c.chan].outVol=c.value; + } + } + break; + case DIV_CMD_GET_VOLUME: + if (chan[c.chan].std.hasVol) { + 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_PERIODIC(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + 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_LEGATO: { + double off=1.0; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + chan[c.chan].baseFreq=off*NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(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)); + } + chan[c.chan].inPorta=c.value; + break; + case DIV_CMD_SAMPLE_POS: + chan[c.chan].audPos=c.value; + chan[c.chan].setPos=true; + break; + case DIV_CMD_GET_VOLMAX: + return 127; + break; + case DIV_ALWAYS_SET_VOLUME: + return 1; + break; + default: + break; + } + return 1; +} + +void DivPlatformSNES::muteChannel(int ch, bool mute) { + isMuted[ch]=mute; +} + +void DivPlatformSNES::forceIns() { + for (int i=0; i<8; i++) { + chan[i].insChanged=true; + chan[i].freqChanged=true; + chan[i].audPos=131072; + chan[i].audDat=0; + chan[i].sample=-1; + } +} + +void* DivPlatformSNES::getChanState(int ch) { + return &chan[ch]; +} + +unsigned char* DivPlatformSNES::getRegisterPool() { + // get states from emulator + for (int i=0; i<0x80; i+=0x10) { + regPool[i+8]=dsp->read(i+8); + regPool[i+9]=dsp->read(i+9); + } + return regPool; +} + +int DivPlatformSNES::getRegisterPoolSize() { + return 128; +} + +void DivPlatformSNES::reset() { + for (int i=0; i<8; i++) { + chan[i]=Channel(); + } + dsp->init(&aram); + dsp->set_output(NULL, 0); + memset(regPool,0,128); +} + +bool DivPlatformSNES::isStereo() { + return true; +} + +bool DivPlatformSNES::keyOffAffectsArp(int ch) { + return true; +} + +void DivPlatformSNES::notifyInsChange(int ins) { + for (int i=0; i<8; i++) { + if (chan[i].ins==ins) { + chan[i].insChanged=true; + } + } +} + +void DivPlatformSNES::notifyWaveChange(int wave) { + // TODO when wavetables are added +} + +void DivPlatformSNES::notifyInsDeletion(void* ins) { + for (int i=0; i<8; i++) { + chan[i].std.notifyInsDeletion((DivInstrument*)ins); + } +} + +void DivPlatformSNES::poke(unsigned int addr, unsigned short val) { + rWrite(addr,val); +} + +void DivPlatformSNES::poke(std::vector& wlist) { + for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); +} + +int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { + parent=p; + dsp=new SPC_DSP; + dumpWrites=false; + skipRegisterWrites=false; + for (int i=0; i<8; i++) { + isMuted[i]=false; + } + chipClock=1024000; + rate=chipClock/32; + reset(); + return 8; +} + +void DivPlatformSNES::quit() { + delete dsp; +} diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h new file mode 100644 index 000000000..93564ee58 --- /dev/null +++ b/src/engine/platform/snes.h @@ -0,0 +1,98 @@ +/** + * 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 _SNES_H +#define _SNES_H + +#include "../dispatch.h" +#include "../macroInt.h" +#include +#include "sound/snes/SPC_DSP.h" + +class DivPlatformSNES: public DivDispatch { + struct Channel { + int freq, baseFreq, pitch; + unsigned int audLoc; + unsigned short audLen; + unsigned int audPos; + int audSub; + signed char audDat; + int sample, wave; + unsigned char ins; + int busClock; + int note; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos; + signed char vol, outVol; + DivMacroInt std; + Channel(): + freq(0), + baseFreq(0), + pitch(0), + audLoc(0), + audLen(0), + audPos(0), + audSub(0), + audDat(0), + sample(-1), + wave(0), + ins(-1), + busClock(0), + note(0), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + useWave(false), + setPos(false), + vol(64), + outVol(64) {} + }; + Channel chan[8]; + bool isMuted[8]; + + unsigned char regPool[0x80]; + unsigned char aram[0x10000]; + SPC_DSP* dsp; + friend void putDispatchChan(void*,int,int); + + public: + void acquire(short* bufL, short* bufR, size_t start, size_t len); + int dispatch(DivCommand c); + void* getChanState(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); + void reset(); + void forceIns(); + void tick(); + void muteChannel(int ch, bool mute); + bool isStereo(); + bool keyOffAffectsArp(int ch); + void notifyInsChange(int ins); + void notifyWaveChange(int wave); + void notifyInsDeletion(void* ins); + void poke(unsigned int addr, unsigned short val); + void poke(std::vector& wlist); + const char** getRegisterSheet(); + int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); + void quit(); +}; + +#endif diff --git a/src/engine/platform/sound/snes/SPC_DSP.cpp b/src/engine/platform/sound/snes/SPC_DSP.cpp new file mode 100644 index 000000000..abbf827db --- /dev/null +++ b/src/engine/platform/sound/snes/SPC_DSP.cpp @@ -0,0 +1,1027 @@ +// snes_spc 0.9.0. http://www.slack.net/~ant/ + +#include "SPC_DSP.h" + +#include "blargg_endian.h" +#include + +/* Copyright (C) 2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#ifdef BLARGG_ENABLE_OPTIMIZER + #include BLARGG_ENABLE_OPTIMIZER +#endif + +#if INT_MAX < 0x7FFFFFFF + #error "Requires that int type have at least 32 bits" +#endif + +// TODO: add to blargg_endian.h +#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) +#define GET_LE16A( addr ) GET_LE16( addr ) +#define SET_LE16A( addr, data ) SET_LE16( addr, data ) + +static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + +// 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, +// 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, +// 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, +// 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, +// 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, +// 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, +// 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, +// 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF +}; + +// if ( io < -32768 ) io = -32768; +// if ( io > 32767 ) io = 32767; +#define CLAMP16( io )\ +{\ + if ( (int16_t) io != io )\ + io = (io >> 31) ^ 0x7FFF;\ +} + +// Access global DSP register +#define REG(n) m.regs [r_##n] + +// Access voice DSP register +#define VREG(r,n) r [v_##n] + +#define WRITE_SAMPLES( l, r, out ) \ +{\ + out [0] = l;\ + out [1] = r;\ + out += 2;\ + if ( out >= m.out_end )\ + {\ + check( out == m.out_end );\ + check( m.out_end != &m.extra [extra_size] || \ + (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ + out = m.extra;\ + m.out_end = &m.extra [extra_size];\ + }\ +}\ + +void SPC_DSP::set_output( sample_t* out, int size ) +{ + require( (size & 1) == 0 ); // must be even + if ( !out ) + { + out = m.extra; + size = extra_size; + } + m.out_begin = out; + m.out = out; + m.out_end = out + size; +} + +// Volume registers and efb are signed! Easy to forget int8_t cast. +// Prefixes are to avoid accidental use of locals with same names. + +// Gaussian interpolation + +static short const gauss [512] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, +}; + +inline int SPC_DSP::interpolate( voice_t const* v ) +{ + // Make pointers into gaussian based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = gauss + 255 - offset; + short const* rev = gauss + offset; // mirror left half of gaussian + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = (fwd [ 0] * in [0]) >> 11; + out += (fwd [256] * in [1]) >> 11; + out += (rev [256] * in [2]) >> 11; + out = (int16_t) out; + out += (rev [ 0] * in [3]) >> 11; + + CLAMP16( out ); + out &= ~1; + return out; +} + + +//// Counters + +int const simple_counter_range = 2048 * 5 * 3; // 30720 + +static unsigned const counter_rates [32] = +{ + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 +}; + +static unsigned const counter_offsets [32] = +{ + 1, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 0, + 0 +}; + +inline void SPC_DSP::init_counter() +{ + m.counter = 0; +} + +inline void SPC_DSP::run_counters() +{ + if ( --m.counter < 0 ) + m.counter = simple_counter_range - 1; +} + +inline unsigned SPC_DSP::read_counter( int rate ) +{ + return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; +} + + +//// Envelope + +inline void SPC_DSP::run_envelope( voice_t* const v ) +{ + int env = v->env; + if ( v->env_mode == env_release ) // 60% + { + if ( (env -= 0x8) < 0 ) + env = 0; + v->env = env; + } + else + { + int rate; + int env_data = VREG(v->regs,adsr1); + if ( m.t_adsr0 & 0x80 ) // 99% ADSR + { + if ( v->env_mode >= env_decay ) // 99% + { + env--; + env -= env >> 8; + rate = env_data & 0x1F; + if ( v->env_mode == env_decay ) // 1% + rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; + } + else // env_attack + { + rate = (m.t_adsr0 & 0x0F) * 2 + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } + else // GAIN + { + int mode; + env_data = VREG(v->regs,gain); + mode = env_data >> 5; + if ( mode < 4 ) // direct + { + env = env_data * 0x10; + rate = 31; + } + else + { + rate = env_data & 0x1F; + if ( mode == 4 ) // 4: linear decrease + { + env -= 0x20; + } + else if ( mode < 6 ) // 5: exponential decrease + { + env--; + env -= env >> 8; + } + else // 6,7: linear increase + { + env += 0x20; + if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + env += 0x8 - 0x20; // 7: two-slope linear increase + } + } + } + + // Sustain level + if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + v->env_mode = env_sustain; + + v->hidden_env = env; + + // unsigned cast because linear decrease going negative also triggers this + if ( (unsigned) env > 0x7FF ) + { + env = (env < 0 ? 0 : 0x7FF); + if ( v->env_mode == env_attack ) + v->env_mode = env_decay; + } + + if ( !read_counter( rate ) ) + v->env = env; // nothing else is controlled by the counter + } +} + + +//// BRR Decoding + +inline void SPC_DSP::decode_brr( voice_t* v ) +{ + // Arrange the four input nybbles in 0xABCD order for easy decoding + int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; + + int const header = m.t_brr_header; + + // Write to next four samples in circular buffer + int* pos = &v->buf [v->buf_pos]; + int* end; + if ( (v->buf_pos += 4) >= brr_buf_size ) + v->buf_pos = 0; + + // Decode four samples + for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) + { + // Extract nybble and sign-extend + int s = (int16_t) nybbles >> 12; + + // Shift sample based on header + int const shift = header >> 4; + s = (s << shift) >> 1; + if ( shift >= 0xD ) // handle invalid range + s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) + + // Apply IIR filter (8 is the most commonly used) + int const filter = header & 0x0C; + int const p1 = pos [brr_buf_size - 1]; + int const p2 = pos [brr_buf_size - 2] >> 1; + if ( filter >= 8 ) + { + s += p1; + s -= p2; + if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 + { + s += p2 >> 4; + s += (p1 * -3) >> 6; + } + else // s += p1 * 0.8984375 - p2 * 0.40625 + { + s += (p1 * -13) >> 7; + s += (p2 * 3) >> 4; + } + } + else if ( filter ) // s += p1 * 0.46875 + { + s += p1 >> 1; + s += (-p1) >> 5; + } + + // Adjust and write sample + CLAMP16( s ); + s = (int16_t) (s * 2); + pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + } +} + + +//// Misc + +#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() + +MISC_CLOCK( 27 ) +{ + m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON +} +MISC_CLOCK( 28 ) +{ + m.t_non = REG(non); + m.t_eon = REG(eon); + m.t_dir = REG(dir); +} +MISC_CLOCK( 29 ) +{ + if ( (m.every_other_sample ^= 1) != 0 ) + m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read +} +MISC_CLOCK( 30 ) +{ + if ( m.every_other_sample ) + { + m.kon = m.new_kon; + m.t_koff = REG(koff) | m.mute_mask; + } + + run_counters(); + + // Noise + if ( !read_counter( REG(flg) & 0x1F ) ) + { + int feedback = (m.noise << 13) ^ (m.noise << 14); + m.noise = (feedback & 0x4000) ^ (m.noise >> 1); + } +} + + +//// Voices + +#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) + +inline VOICE_CLOCK( V1 ) +{ + m.t_dir_addr = (m.t_dir * 0x100 + m.t_srcn * 4) & 0xffff; + m.t_srcn = VREG(v->regs,srcn); +} +inline VOICE_CLOCK( V2 ) +{ + // Read sample pointer (ignored if not needed) + uint8_t const* entry = &m.ram [m.t_dir_addr]; + if ( !v->kon_delay ) + entry += 2; + m.t_brr_next_addr = GET_LE16A( entry ); + + m.t_adsr0 = VREG(v->regs,adsr0); + + // Read pitch, spread over two clocks + m.t_pitch = VREG(v->regs,pitchl); +} +inline VOICE_CLOCK( V3a ) +{ + m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; +} +inline VOICE_CLOCK( V3b ) +{ + // Read BRR header and byte + m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; + m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking +} +VOICE_CLOCK( V3c ) +{ + // Pitch modulation using previous voice's output + if ( m.t_pmon & v->vbit ) + m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; + + if ( v->kon_delay ) + { + // Get ready to start BRR decoding on next sample + if ( v->kon_delay == 5 ) + { + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; + m.t_brr_header = 0; // header is ignored on this sample + m.kon_check = true; + } + + // Envelope is never run during KON + v->env = 0; + v->hidden_env = 0; + + // Disable BRR decoding until last three samples + v->interp_pos = 0; + if ( --v->kon_delay & 3 ) + v->interp_pos = 0x4000; + + // Pitch is never added during KON + m.t_pitch = 0; + } + + // Gaussian interpolation + { + int output = interpolate( v ); + + // Noise + if ( m.t_non & v->vbit ) + output = (int16_t) (m.noise * 2); + + // Apply envelope + m.t_output = (output * v->env) >> 11 & ~1; + v->t_envx_out = (uint8_t) (v->env >> 4); + } + + // Immediate silence due to end of sample or soft reset + if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + { + v->env_mode = env_release; + v->env = 0; + } + + if ( m.every_other_sample ) + { + // KOFF + if ( m.t_koff & v->vbit ) + v->env_mode = env_release; + + // KON + if ( m.kon & v->vbit ) + { + v->kon_delay = 5; + v->env_mode = env_attack; + } + } + + // Run envelope for next sample + if ( !v->kon_delay ) + run_envelope( v ); +} +inline void SPC_DSP::voice_output( voice_t const* v, int ch ) +{ + // Apply left/right volume + int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; + + // Add to output total + m.t_main_out [ch] += amp; + CLAMP16( m.t_main_out [ch] ); + + // Optionally add to echo total + if ( m.t_eon & v->vbit ) + { + m.t_echo_out [ch] += amp; + CLAMP16( m.t_echo_out [ch] ); + } +} +VOICE_CLOCK( V4 ) +{ + // Decode BRR + m.t_looped = 0; + if ( v->interp_pos >= 0x4000 ) + { + decode_brr( v ); + + if ( (v->brr_offset += 2) >= brr_block_size ) + { + // Start decoding next BRR block + assert( v->brr_offset == brr_block_size ); + v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; + if ( m.t_brr_header & 1 ) + { + v->brr_addr = m.t_brr_next_addr; + m.t_looped = v->vbit; + } + v->brr_offset = 1; + } + } + + // Apply pitch + v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; + + // Keep from getting too far ahead (when using pitch modulation) + if ( v->interp_pos > 0x7FFF ) + v->interp_pos = 0x7FFF; + + // Output left + voice_output( v, 0 ); +} +inline VOICE_CLOCK( V5 ) +{ + // Output right + voice_output( v, 1 ); + + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier + int endx_buf = REG(endx) | m.t_looped; + + // Clear bit in ENDX if KON just began + if ( v->kon_delay == 5 ) + endx_buf &= ~v->vbit; + m.endx_buf = (uint8_t) endx_buf; +} +inline VOICE_CLOCK( V6 ) +{ + (void) v; // avoid compiler warning about unused v + m.outx_buf = (uint8_t) (m.t_output >> 8); +} +inline VOICE_CLOCK( V7 ) +{ + // Update ENDX + REG(endx) = m.endx_buf; + + m.envx_buf = v->t_envx_out; +} +inline VOICE_CLOCK( V8 ) +{ + // Update OUTX + VREG(v->regs,outx) = m.outx_buf; +} +inline VOICE_CLOCK( V9 ) +{ + // Update ENVX + VREG(v->regs,envx) = m.envx_buf; +} + +// Most voices do all these in one clock, so make a handy composite +inline VOICE_CLOCK( V3 ) +{ + voice_V3a( v ); + voice_V3b( v ); + voice_V3c( v ); +} + +// Common combinations of voice steps on different voices. This greatly reduces +// code size and allows everything to be inlined in these functions. +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } + + +//// Echo + +// Current echo buffer pointer for left/right channel +#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) + +// Sample in echo history buffer, where 0 is the oldest +#define ECHO_FIR( i ) (m.echo_hist_pos [i]) + +// Calculate FIR point for left/right channel +#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) + +#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() + +inline void SPC_DSP::echo_read( int ch ) +{ + int s = GET_LE16SA( ECHO_PTR( ch ) ); + // second copy simplifies wrap-around handling + ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; +} + +ECHO_CLOCK( 22 ) +{ + // History + if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) + m.echo_hist_pos = m.echo_hist; + + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; + echo_read( 0 ); + + // FIR (using l and r temporaries below helps compiler optimize) + int l = CALC_FIR( 0, 0 ); + int r = CALC_FIR( 0, 1 ); + + m.t_echo_in [0] = l; + m.t_echo_in [1] = r; +} +ECHO_CLOCK( 23 ) +{ + int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); + int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; + + echo_read( 1 ); +} +ECHO_CLOCK( 24 ) +{ + int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); + int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; +} +ECHO_CLOCK( 25 ) +{ + int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); + int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); + + l = (int16_t) l; + r = (int16_t) r; + + l += (int16_t) CALC_FIR( 7, 0 ); + r += (int16_t) CALC_FIR( 7, 1 ); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_in [0] = l & ~1; + m.t_echo_in [1] = r & ~1; +} +inline int SPC_DSP::echo_output( int ch ) +{ + int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + + (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); + CLAMP16( out ); + return out; +} +ECHO_CLOCK( 26 ) +{ + // Left output volumes + // (save sample for next clock so we can output both together) + m.t_main_out [0] = echo_output( 0 ); + + // Echo feedback + int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); + int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_out [0] = l & ~1; + m.t_echo_out [1] = r & ~1; +} +ECHO_CLOCK( 27 ) +{ + // Output + int l = m.t_main_out [0]; + int r = echo_output( 1 ); + m.t_main_out [0] = 0; + m.t_main_out [1] = 0; + + // TODO: global muting isn't this simple (turns DAC on and off + // or something, causing small ~37-sample pulse when first muted) + if ( REG(flg) & 0x40 ) + { + l = 0; + r = 0; + } + + // Output sample to DAC + #ifdef SPC_DSP_OUT_HOOK + SPC_DSP_OUT_HOOK( l, r ); + #else + sample_t* out = m.out; + WRITE_SAMPLES( l, r, out ); + m.out = out; + #endif +} +ECHO_CLOCK( 28 ) +{ + m.t_echo_enabled = REG(flg); +} +inline void SPC_DSP::echo_write( int ch ) +{ + if ( !(m.t_echo_enabled & 0x20) ) + SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); + m.t_echo_out [ch] = 0; +} +ECHO_CLOCK( 29 ) +{ + m.t_esa = REG(esa); + + if ( !m.echo_offset ) + m.echo_length = (REG(edl) & 0x0F) * 0x800; + + m.echo_offset += 4; + if ( m.echo_offset >= m.echo_length ) + m.echo_offset = 0; + + // Write left echo + echo_write( 0 ); + + m.t_echo_enabled = REG(flg); +} +ECHO_CLOCK( 30 ) +{ + // Write right echo + echo_write( 1 ); +} + + +//// Timing + +// Execute clock for a particular voice +#define V( clock, voice ) voice_##clock( &m.voices [voice] ); + +/* The most common sequence of clocks uses composite operations +for efficiency. For example, the following are equivalent to the +individual steps on the right: + +V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) +V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) +V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ + +// Voice 0 1 2 3 4 5 6 7 +#define GEN_DSP_TIMING \ +PHASE( 0) V(V5,0)V(V2,1)\ +PHASE( 1) V(V6,0)V(V3,1)\ +PHASE( 2) V(V7_V4_V1,0)\ +PHASE( 3) V(V8_V5_V2,0)\ +PHASE( 4) V(V9_V6_V3,0)\ +PHASE( 5) V(V7_V4_V1,1)\ +PHASE( 6) V(V8_V5_V2,1)\ +PHASE( 7) V(V9_V6_V3,1)\ +PHASE( 8) V(V7_V4_V1,2)\ +PHASE( 9) V(V8_V5_V2,2)\ +PHASE(10) V(V9_V6_V3,2)\ +PHASE(11) V(V7_V4_V1,3)\ +PHASE(12) V(V8_V5_V2,3)\ +PHASE(13) V(V9_V6_V3,3)\ +PHASE(14) V(V7_V4_V1,4)\ +PHASE(15) V(V8_V5_V2,4)\ +PHASE(16) V(V9_V6_V3,4)\ +PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ +PHASE(18) V(V8_V5_V2,5)\ +PHASE(19) V(V9_V6_V3,5)\ +PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ +PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ +PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ +PHASE(23) V(V7,7) echo_23();\ +PHASE(24) V(V8,7) echo_24();\ +PHASE(25) V(V3b,0) V(V9,7) echo_25();\ +PHASE(26) echo_26();\ +PHASE(27) misc_27(); echo_27();\ +PHASE(28) misc_28(); echo_28();\ +PHASE(29) misc_29(); echo_29();\ +PHASE(30) misc_30();V(V3c,0) echo_30();\ +PHASE(31) V(V4,0) V(V1,2)\ + +#if !SPC_DSP_CUSTOM_RUN + +void SPC_DSP::run( int clocks_remain ) +{ + require( clocks_remain > 0 ); + + int const phase = m.phase; + m.phase = (phase + clocks_remain) & 31; + switch ( phase ) + { + loop: + + #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: + GEN_DSP_TIMING + #undef PHASE + + if ( --clocks_remain ) + goto loop; + } +} + +#endif + + +//// Setup + +void SPC_DSP::init( void* ram_64k ) +{ + m.ram = (uint8_t*) ram_64k; + mute_voices( 0 ); + disable_surround( false ); + set_output( 0, 0 ); + reset(); + + #ifndef NDEBUG + // be sure this sign-extends + assert( (int16_t) 0x8000 == -0x8000 ); + + // be sure right shift preserves sign + assert( (-1 >> 1) == -1 ); + + // check clamp macro + int i; + i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); + i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); + + blargg_verify_byte_order(); + #endif +} + +void SPC_DSP::soft_reset_common() +{ + require( m.ram ); // init() must have been called already + + m.noise = 0x4000; + m.echo_hist_pos = m.echo_hist; + m.every_other_sample = 1; + m.echo_offset = 0; + m.phase = 0; + + init_counter(); +} + +void SPC_DSP::soft_reset() +{ + REG(flg) = 0xE0; + soft_reset_common(); +} + +void SPC_DSP::load( uint8_t const regs [register_count] ) +{ + memcpy( m.regs, regs, sizeof m.regs ); + memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); + + // Internal state + for ( int i = voice_count; --i >= 0; ) + { + voice_t* v = &m.voices [i]; + v->brr_offset = 1; + v->vbit = 1 << i; + v->regs = &m.regs [i * 0x10]; + } + m.new_kon = REG(kon); + m.t_dir = REG(dir); + m.t_esa = REG(esa); + + soft_reset_common(); +} + +void SPC_DSP::reset() { load( initial_regs ); } + + +//// State save/load + +#if !SPC_NO_COPY_STATE_FUNCS + +void SPC_State_Copier::copy( void* state, size_t size ) +{ + func( buf, state, size ); +} + +int SPC_State_Copier::copy_int( int state, int size ) +{ + BOOST::uint8_t s [2]; + SET_LE16( s, state ); + func( buf, &s, size ); + return GET_LE16( s ); +} + +void SPC_State_Copier::skip( int count ) +{ + if ( count > 0 ) + { + char temp [64]; + memset( temp, 0, sizeof temp ); + do + { + int n = sizeof temp; + if ( n > count ) + n = count; + count -= n; + func( buf, temp, n ); + } + while ( count ); + } +} + +void SPC_State_Copier::extra() +{ + int n = 0; + SPC_State_Copier& copier = *this; + SPC_COPY( uint8_t, n ); + skip( n ); +} + +void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) +{ + SPC_State_Copier copier( io, copy ); + + // DSP registers + copier.copy( m.regs, register_count ); + + // Internal state + + // Voices + int i; + for ( i = 0; i < voice_count; i++ ) + { + voice_t* v = &m.voices [i]; + + // BRR buffer + int i; + for ( i = 0; i < brr_buf_size; i++ ) + { + int s = v->buf [i]; + SPC_COPY( int16_t, s ); + v->buf [i] = v->buf [i + brr_buf_size] = s; + } + + SPC_COPY( uint16_t, v->interp_pos ); + SPC_COPY( uint16_t, v->brr_addr ); + SPC_COPY( uint16_t, v->env ); + SPC_COPY( int16_t, v->hidden_env ); + SPC_COPY( uint8_t, v->buf_pos ); + SPC_COPY( uint8_t, v->brr_offset ); + SPC_COPY( uint8_t, v->kon_delay ); + { + int m = v->env_mode; + SPC_COPY( uint8_t, m ); + v->env_mode = (enum env_mode_t) m; + } + SPC_COPY( uint8_t, v->t_envx_out ); + + copier.extra(); + } + + // Echo history + for ( i = 0; i < echo_hist_size; i++ ) + { + int j; + for ( j = 0; j < 2; j++ ) + { + int s = m.echo_hist_pos [i] [j]; + SPC_COPY( int16_t, s ); + m.echo_hist [i] [j] = s; // write back at offset 0 + } + } + m.echo_hist_pos = m.echo_hist; + memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); + + // Misc + SPC_COPY( uint8_t, m.every_other_sample ); + SPC_COPY( uint8_t, m.kon ); + + SPC_COPY( uint16_t, m.noise ); + SPC_COPY( uint16_t, m.counter ); + SPC_COPY( uint16_t, m.echo_offset ); + SPC_COPY( uint16_t, m.echo_length ); + SPC_COPY( uint8_t, m.phase ); + + SPC_COPY( uint8_t, m.new_kon ); + SPC_COPY( uint8_t, m.endx_buf ); + SPC_COPY( uint8_t, m.envx_buf ); + SPC_COPY( uint8_t, m.outx_buf ); + + SPC_COPY( uint8_t, m.t_pmon ); + SPC_COPY( uint8_t, m.t_non ); + SPC_COPY( uint8_t, m.t_eon ); + SPC_COPY( uint8_t, m.t_dir ); + SPC_COPY( uint8_t, m.t_koff ); + + SPC_COPY( uint16_t, m.t_brr_next_addr ); + SPC_COPY( uint8_t, m.t_adsr0 ); + SPC_COPY( uint8_t, m.t_brr_header ); + SPC_COPY( uint8_t, m.t_brr_byte ); + SPC_COPY( uint8_t, m.t_srcn ); + SPC_COPY( uint8_t, m.t_esa ); + SPC_COPY( uint8_t, m.t_echo_enabled ); + + SPC_COPY( int16_t, m.t_main_out [0] ); + SPC_COPY( int16_t, m.t_main_out [1] ); + SPC_COPY( int16_t, m.t_echo_out [0] ); + SPC_COPY( int16_t, m.t_echo_out [1] ); + SPC_COPY( int16_t, m.t_echo_in [0] ); + SPC_COPY( int16_t, m.t_echo_in [1] ); + + SPC_COPY( uint16_t, m.t_dir_addr ); + SPC_COPY( uint16_t, m.t_pitch ); + SPC_COPY( int16_t, m.t_output ); + SPC_COPY( uint16_t, m.t_echo_ptr ); + SPC_COPY( uint8_t, m.t_looped ); + + copier.extra(); +} +#endif diff --git a/src/engine/platform/sound/snes/SPC_DSP.h b/src/engine/platform/sound/snes/SPC_DSP.h new file mode 100644 index 000000000..d59284797 --- /dev/null +++ b/src/engine/platform/sound/snes/SPC_DSP.h @@ -0,0 +1,307 @@ +// Highly accurate SNES SPC-700 DSP emulator + +// snes_spc 0.9.0 +#ifndef SPC_DSP_H +#define SPC_DSP_H + +#include "blargg_common.h" + +extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } + +class SPC_DSP { +public: + typedef BOOST::uint8_t uint8_t; + +// Setup + + // Initializes DSP and has it use the 64K RAM provided + void init( void* ram_64k ); + + // Sets destination for output samples. If out is NULL or out_size is 0, + // doesn't generate any. + typedef short sample_t; + void set_output( sample_t* out, int out_size ); + + // Number of samples written to output since it was last set, always + // a multiple of 2. Undefined if more samples were generated than + // output buffer could hold. + int sample_count() const; + +// Emulation + + // Resets DSP to power-on state + void reset(); + + // Emulates pressing reset switch on SNES + void soft_reset(); + + // Reads/writes DSP registers. For accuracy, you must first call run() + // to catch the DSP up to present. + int read ( int addr ) const; + void write( int addr, int data ); + + // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks + // a pair of samples is be generated. + void run( int clock_count ); + +// Sound control + + // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). + // Reduces emulation accuracy. + enum { voice_count = 8 }; + void mute_voices( int mask ); + +// State + + // Resets DSP and uses supplied values to initialize registers + enum { register_count = 128 }; + void load( uint8_t const regs [register_count] ); + + // Saves/loads exact emulator state + enum { state_size = 640 }; // maximum space needed when saving + typedef dsp_copy_func_t copy_func_t; + void copy_state( unsigned char** io, copy_func_t ); + + // Returns non-zero if new key-on events occurred since last call + bool check_kon(); + +// DSP register addresses + + // Global registers + enum { + r_mvoll = 0x0C, r_mvolr = 0x1C, + r_evoll = 0x2C, r_evolr = 0x3C, + r_kon = 0x4C, r_koff = 0x5C, + r_flg = 0x6C, r_endx = 0x7C, + r_efb = 0x0D, r_pmon = 0x2D, + r_non = 0x3D, r_eon = 0x4D, + r_dir = 0x5D, r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F + }; + + // Voice registers + enum { + v_voll = 0x00, v_volr = 0x01, + v_pitchl = 0x02, v_pitchh = 0x03, + v_srcn = 0x04, v_adsr0 = 0x05, + v_adsr1 = 0x06, v_gain = 0x07, + v_envx = 0x08, v_outx = 0x09 + }; + +public: + enum { extra_size = 16 }; + sample_t* extra() { return m.extra; } + sample_t const* out_pos() const { return m.out; } + void disable_surround( bool ) { } // not supported +public: + BLARGG_DISABLE_NOTHROW + + typedef BOOST::int8_t int8_t; + typedef BOOST::int16_t int16_t; + + enum { echo_hist_size = 8 }; + + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + enum { brr_buf_size = 12 }; + struct voice_t + { + int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8_t* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase + env_mode_t env_mode; + int env; // current envelope level + int hidden_env; // used by GAIN mode 7, very obscure quirk + uint8_t t_envx_out; + }; +private: + enum { brr_block_size = 9 }; + + struct state_t + { + uint8_t regs [register_count]; + + // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) + int echo_hist [echo_hist_size * 2] [2]; + int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] + + int every_other_sample; // toggles every sample + int kon; // KON value when last checked + int noise; + int counter; + int echo_offset; // offset from ESA in echo buffer + int echo_length; // number of bytes that echo_offset will stop at + int phase; // next clock cycle to run (0-31) + bool kon_check; // set when a new KON occurs + + // Hidden registers also written to when main register is written to + int new_kon; + uint8_t endx_buf; + uint8_t envx_buf; + uint8_t outx_buf; + + // Temporary state between clocks + + // read once per sample + int t_pmon; + int t_non; + int t_eon; + int t_dir; + int t_koff; + + // read a few clocks ahead then used + int t_brr_next_addr; + int t_adsr0; + int t_brr_header; + int t_brr_byte; + int t_srcn; + int t_esa; + int t_echo_enabled; + + // internal state that is recalculated every sample + int t_dir_addr; + int t_pitch; + int t_output; + int t_looped; + int t_echo_ptr; + + // left/right sums + int t_main_out [2]; + int t_echo_out [2]; + int t_echo_in [2]; + + voice_t voices [voice_count]; + + // non-emulation state + uint8_t* ram; // 64K shared RAM between DSP and SMP + int mute_mask; + sample_t* out; + sample_t* out_end; + sample_t* out_begin; + sample_t extra [extra_size]; + }; + state_t m; + + void init_counter(); + void run_counters(); + unsigned read_counter( int rate ); + + int interpolate( voice_t const* v ); + void run_envelope( voice_t* const v ); + void decode_brr( voice_t* v ); + + void misc_27(); + void misc_28(); + void misc_29(); + void misc_30(); + + void voice_output( voice_t const* v, int ch ); + void voice_V1( voice_t* const ); + void voice_V2( voice_t* const ); + void voice_V3( voice_t* const ); + void voice_V3a( voice_t* const ); + void voice_V3b( voice_t* const ); + void voice_V3c( voice_t* const ); + void voice_V4( voice_t* const ); + void voice_V5( voice_t* const ); + void voice_V6( voice_t* const ); + void voice_V7( voice_t* const ); + void voice_V8( voice_t* const ); + void voice_V9( voice_t* const ); + void voice_V7_V4_V1( voice_t* const ); + void voice_V8_V5_V2( voice_t* const ); + void voice_V9_V6_V3( voice_t* const ); + + void echo_read( int ch ); + int echo_output( int ch ); + void echo_write( int ch ); + void echo_22(); + void echo_23(); + void echo_24(); + void echo_25(); + void echo_26(); + void echo_27(); + void echo_28(); + void echo_29(); + void echo_30(); + + void soft_reset_common(); + +public: + bool mute() { return m.regs[r_flg] & 0x40; } +}; + +#include + +inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } + +inline int SPC_DSP::read( int addr ) const +{ + assert( (unsigned) addr < register_count ); + return m.regs [addr]; +} + +inline void SPC_DSP::write( int addr, int data ) +{ + assert( (unsigned) addr < register_count ); + + m.regs [addr] = (uint8_t) data; + switch ( addr & 0x0F ) + { + case v_envx: + m.envx_buf = (uint8_t) data; + break; + + case v_outx: + m.outx_buf = (uint8_t) data; + break; + + case 0x0C: + if ( addr == r_kon ) + m.new_kon = (uint8_t) data; + + if ( addr == r_endx ) // always cleared, regardless of data written + { + m.endx_buf = 0; + m.regs [r_endx] = 0; + } + break; + } +} + +inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } + +inline bool SPC_DSP::check_kon() +{ + bool old = m.kon_check; + m.kon_check = 0; + return old; +} + +#if !SPC_NO_COPY_STATE_FUNCS + +class SPC_State_Copier { + SPC_DSP::copy_func_t func; + unsigned char** buf; +public: + SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } + void copy( void* state, size_t size ); + int copy_int( int state, int size ); + void skip( int count ); + void extra(); +}; + +#define SPC_COPY( type, state )\ +{\ + state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ + assert( (BOOST::type) state == state );\ +} + +#endif + +#endif diff --git a/src/engine/platform/sound/snes/blargg_common.h b/src/engine/platform/sound/snes/blargg_common.h new file mode 100644 index 000000000..75edff391 --- /dev/null +++ b/src/engine/platform/sound/snes/blargg_common.h @@ -0,0 +1,186 @@ +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// snes_spc 0.9.0 +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include +#include + +#undef BLARGG_COMMON_H +// allow blargg_config.h to #include blargg_common.h +#include "blargg_config.h" +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +// BLARGG_RESTRICT: equivalent to restrict, where supported +#if defined (__GNUC__) || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +// STATIC_CAST(T,expr): Used in place of static_cast (expr) +#ifndef STATIC_CAST + #define STATIC_CAST(T,expr) ((T) (expr)) +#endif + +// blargg_err_t (0 on success, otherwise error string) +#ifndef blargg_err_t + typedef const char* blargg_err_t; +#endif + +// blargg_vector - very lightweight vector of POD types (no constructor/destructor) +template +class blargg_vector { + T* begin_; + size_t size_; +public: + blargg_vector() : begin_( 0 ), size_( 0 ) { } + ~blargg_vector() { free( begin_ ); } + size_t size() const { return size_; } + T* begin() const { return begin_; } + T* end() const { return begin_ + size_; } + blargg_err_t resize( size_t n ) + { + // TODO: blargg_common.cpp to hold this as an outline function, ugh + void* p = realloc( begin_, n * sizeof (T) ); + if ( p ) + begin_ = (T*) p; + else if ( n > size_ ) // realloc failure only a problem if expanding + return "Out of memory"; + size_ = n; + return 0; + } + void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } + T& operator [] ( size_t n ) const + { + assert( n <= size_ ); // <= to allow past-the-end value + return begin_ [n]; + } +}; + +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if operator new can return NULL + #if __cplusplus >= 199711 || defined (__GNUC__) + #define BLARGG_THROWS( spec ) throw spec + #else + #define BLARGG_THROWS( spec ) + #endif + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ + void operator delete ( void* p ) { free( p ); } + #define BLARGG_NEW new +#else + #include + #define BLARGG_NEW new (std::nothrow) +#endif + +// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) + +// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +#ifndef BOOST_STATIC_ASSERT + #ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) + #else + // Some other compilers fail when declaring same function multiple times in class, + // so differentiate them by line + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) + #endif +#endif + +// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, +// compiler is assumed to support bool. If undefined, availability is determined. +#ifndef BLARGG_COMPILER_HAS_BOOL + #if defined (__MWERKS__) + #if !__option(bool) + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (_MSC_VER) + #if _MSC_VER < 1100 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (__GNUC__) + // supports bool + #elif __cplusplus < 199711 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif +#endif +#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL + // If you get errors here, modify your blargg_config.h file + typedef int bool; + const bool true = 1; + const bool false = 0; +#endif + +// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough + +#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF + typedef long blargg_long; +#else + typedef int blargg_long; +#endif + +#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF + typedef unsigned long blargg_ulong; +#else + typedef unsigned blargg_ulong; +#endif + +// BOOST::int8_t etc. + +// HAVE_STDINT_H: If defined, use for int8_t etc. +#if defined (HAVE_STDINT_H) + #include + #define BOOST + +// HAVE_INTTYPES_H: If defined, use for int8_t etc. +#elif defined (HAVE_INTTYPES_H) + #include + #define BOOST + +#else + struct BOOST + { + #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; + #else + // No suitable 8-bit type available + typedef struct see_blargg_common_h int8_t; + typedef struct see_blargg_common_h uint8_t; + #endif + + #if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; + #else + // No suitable 16-bit type available + typedef struct see_blargg_common_h int16_t; + typedef struct see_blargg_common_h uint16_t; + #endif + + #if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; + #elif UINT_MAX == 0xFFFFFFFF + typedef int int32_t; + typedef unsigned int uint32_t; + #else + // No suitable 32-bit type available + typedef struct see_blargg_common_h int32_t; + typedef struct see_blargg_common_h uint32_t; + #endif + }; +#endif + +#endif +#endif diff --git a/src/engine/platform/sound/snes/blargg_config.h b/src/engine/platform/sound/snes/blargg_config.h new file mode 100644 index 000000000..94570ca0b --- /dev/null +++ b/src/engine/platform/sound/snes/blargg_config.h @@ -0,0 +1,26 @@ +// snes_spc 0.9.0 user configuration file. Don't replace when updating library. + +// snes_spc 0.9.0 +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment to disable debugging checks +#ifndef NDEBUG + #define NDEBUG 1 +#endif + +// Uncomment to enable platform-specific (and possibly non-portable) optimizations +//#define BLARGG_NONPORTABLE 1 + +// Uncomment if automatic byte-order determination doesn't work +//#define BLARGG_BIG_ENDIAN 1 + +// Uncomment if you get errors in the bool section of blargg_common.h +//#define BLARGG_COMPILER_HAS_BOOL 1 + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/src/engine/platform/sound/snes/blargg_endian.h b/src/engine/platform/sound/snes/blargg_endian.h new file mode 100644 index 000000000..f2daca641 --- /dev/null +++ b/src/engine/platform/sound/snes/blargg_endian.h @@ -0,0 +1,185 @@ +// CPU Byte Order Utilities + +// snes_spc 0.9.0 +#ifndef BLARGG_ENDIAN +#define BLARGG_ENDIAN + +#include "blargg_common.h" + +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + #define BLARGG_CPU_X86 1 + #define BLARGG_CPU_CISC 1 +#endif + +#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) + #define BLARGG_CPU_POWERPC 1 + #define BLARGG_CPU_RISC 1 +#endif + +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only +// one may be #defined to 1. Only needed if something actually depends on byte order. +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) +#ifdef __GLIBC__ + // GCC handles this for us + #include + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define BLARGG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER == __BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 + #endif +#else + +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ + (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) + #define BLARGG_LITTLE_ENDIAN 1 +#endif + +#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ + defined (__sparc__) || BLARGG_CPU_POWERPC || \ + (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) + #define BLARGG_BIG_ENDIAN 1 +#elif !defined (__mips__) + // No endian specified; assume little-endian, since it's most common + #define BLARGG_LITTLE_ENDIAN 1 +#endif +#endif +#endif + +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN + #undef BLARGG_LITTLE_ENDIAN + #undef BLARGG_BIG_ENDIAN +#endif + +inline void blargg_verify_byte_order() +{ + #ifndef NDEBUG + #if BLARGG_BIG_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i == 0 ); + #elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i != 0 ); + #endif + #endif +} + +inline unsigned get_le16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 8 | + (unsigned) ((unsigned char const*) p) [1]; +} + +inline blargg_ulong get_le32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | + (blargg_ulong) ((unsigned char const*) p) [2] << 16 | + (blargg_ulong) ((unsigned char const*) p) [1] << 8 | + (blargg_ulong) ((unsigned char const*) p) [0]; +} + +inline blargg_ulong get_be32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | + (blargg_ulong) ((unsigned char const*) p) [1] << 16 | + (blargg_ulong) ((unsigned char const*) p) [2] << 8 | + (blargg_ulong) ((unsigned char const*) p) [3]; +} + +inline void set_le16( void* p, unsigned n ) +{ + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [0] = (unsigned char) n; +} + +inline void set_be16( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) n; +} + +inline void set_le32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24); +} + +inline void set_be32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [3] = (unsigned char) n; + ((unsigned char*) p) [2] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) (n >> 16); + ((unsigned char*) p) [0] = (unsigned char) (n >> 24); +} + +#if BLARGG_NONPORTABLE + // Optimized implementation if byte order is known + #if BLARGG_LITTLE_ENDIAN + #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + #elif BLARGG_BIG_ENDIAN + #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + + #if BLARGG_CPU_POWERPC + // PowerPC has special byte-reversed instructions + #if defined (__MWERKS__) + #define GET_LE16( addr ) (__lhbrx( addr, 0 )) + #define GET_LE32( addr ) (__lwbrx( addr, 0 )) + #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) + #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) + #elif defined (__GNUC__) + #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) + #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) + #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #endif + #endif + #endif +#endif + +#ifndef GET_LE16 + #define GET_LE16( addr ) get_le16( addr ) + #define SET_LE16( addr, data ) set_le16( addr, data ) +#endif + +#ifndef GET_LE32 + #define GET_LE32( addr ) get_le32( addr ) + #define SET_LE32( addr, data ) set_le32( addr, data ) +#endif + +#ifndef GET_BE16 + #define GET_BE16( addr ) get_be16( addr ) + #define SET_BE16( addr, data ) set_be16( addr, data ) +#endif + +#ifndef GET_BE32 + #define GET_BE32( addr ) get_be32( addr ) + #define SET_BE32( addr, data ) set_be32( addr, data ) +#endif + +// auto-selecting versions + +inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } +inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } +inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } +inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } +inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } +inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } +inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } +inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } + +#endif diff --git a/src/engine/platform/sound/snes/blargg_source.h b/src/engine/platform/sound/snes/blargg_source.h new file mode 100644 index 000000000..5e45c4fb4 --- /dev/null +++ b/src/engine/platform/sound/snes/blargg_source.h @@ -0,0 +1,100 @@ +/* Included at the beginning of library source files, after all other #include lines. +Sets up helpful macros and services used in my source code. They don't need +module an annoying module prefix on their names since they are defined after +all other #include lines. */ + +// snes_spc 0.9.0 +#ifndef BLARGG_SOURCE_H +#define BLARGG_SOURCE_H + +// If debugging is enabled, abort program if expr is false. Meant for checking +// internal state and consistency. A failed assertion indicates a bug in the module. +// void assert( bool expr ); +#include + +// If debugging is enabled and expr is false, abort program. Meant for checking +// caller-supplied parameters and operations that are outside the control of the +// module. A failed requirement indicates a bug outside the module. +// void require( bool expr ); +#undef require +#define require( expr ) assert( expr ) + +// Like printf() except output goes to debug log file. Might be defined to do +// nothing (not even evaluate its arguments). +// void dprintf( const char* format, ... ); +static inline void blargg_dprintf_( const char*, ... ) { } +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ + +// If enabled, evaluate expr and if false, make debug log entry with source file +// and line. Meant for finding situations that should be examined further, but that +// don't indicate a problem. In all cases, execution continues normally. +#undef check +#define check( expr ) ((void) 0) + +// If expr yields error string, return it from current function, otherwise continue. +#undef RETURN_ERR +#define RETURN_ERR( expr ) do { \ + blargg_err_t blargg_return_err_ = (expr); \ + if ( blargg_return_err_ ) return blargg_return_err_; \ + } while ( 0 ) + +// If ptr is 0, return out of memory error string. +#undef CHECK_ALLOC +#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) + +// Avoid any macros which evaluate their arguments multiple times +#undef min +#undef max + +#define DEF_MIN_MAX( type ) \ + static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ + static inline type max( type x, type y ) { if ( y < x ) return x; return y; } + +DEF_MIN_MAX( int ) +DEF_MIN_MAX( unsigned ) +DEF_MIN_MAX( long ) +DEF_MIN_MAX( unsigned long ) +DEF_MIN_MAX( float ) +DEF_MIN_MAX( double ) + +#undef DEF_MIN_MAX + +/* +// using const references generates crappy code, and I am currenly only using these +// for built-in types, so they take arguments by value + +// TODO: remove +inline int min( int x, int y ) +template +inline T min( T x, T y ) +{ + if ( x < y ) + return x; + return y; +} + +template +inline T max( T x, T y ) +{ + if ( x < y ) + return y; + return x; +} +*/ + +// TODO: good idea? bad idea? +#undef byte +#define byte byte_ +typedef unsigned char byte; + +// deprecated +#define BLARGG_CHECK_ALLOC CHECK_ALLOC +#define BLARGG_RETURN_ERR RETURN_ERR + +// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check +#ifdef BLARGG_SOURCE_BEGIN + #include BLARGG_SOURCE_BEGIN +#endif + +#endif diff --git a/src/gui/gui.h b/src/gui/gui.h index 2ee6170aa..005b2f26e 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -154,6 +154,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, GUI_COLOR_INSTR_OPL_DRUMS, + GUI_COLOR_INSTR_SNES, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_FM, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 80f9b5d85..9eb1e6d09 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -113,6 +113,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", + "SNES", NULL }; @@ -126,7 +127,7 @@ const char* sampleDepths[17]={ "ADPCM-B", NULL, "8-bit PCM", - NULL, // "BRR", + "BRR", "VOX", NULL, NULL, From b49b596fbe99fef1d92c099a4f67feee595c4339 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Fri, 10 Jun 2022 22:59:44 +0700 Subject: [PATCH 008/515] WIP SNES support, part 2 Make the code build again, still no sound though --- src/engine/instrument.h | 1 - src/engine/platform/snes.cpp | 282 +++++++++++++-------- src/engine/platform/snes.h | 48 ++-- src/engine/platform/sound/snes/SPC_DSP.cpp | 9 +- src/engine/platform/sound/snes/SPC_DSP.h | 17 +- src/engine/sample.h | 3 +- src/gui/gui.h | 1 - src/gui/guiConst.cpp | 2 +- src/gui/presets.cpp | 14 +- src/gui/sysConf.cpp | 1 + 10 files changed, 249 insertions(+), 129 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 66197a0fe..c4af6f042 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,7 +60,6 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, - DIV_INS_SNES=33, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index de96ee968..8f930342a 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -19,11 +19,12 @@ #include "snes.h" #include "../engine.h" +#include "../../ta-log.h" #include -#define CHIP_DIVIDER 16 +#define CHIP_FREQBASE 4096 -#define rWrite(a,v) {dsp->write(a,v); regPool[(a)&0x7f]=v; } +#define rWrite(a,v) {dsp.write(a,v); regPool[(a)&0x7f]=v; } const char* regCheatSheetSNESDSP[]={ "VxVOLL", "x0", @@ -61,111 +62,134 @@ const char** DivPlatformSNES::getRegisterSheet() { return regCheatSheetSNESDSP; } +const char* DivPlatformSNES::getEffectName(unsigned char effect) { + switch (effect) { + case 0x10: + return "10xx: Set echo feedback level (signed 8-bit)"; + break; + // TODO + } + return NULL; +} + void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { + short out[2]; + short chOut[16]; for (size_t h=start; hset_output(out,1); - dsp->run(32); + dsp.set_output(out,1); + dsp.run(32); + dsp.get_voice_outputs(chOut); bufL[h]=out[0]; bufR[h]=out[1]; + for (int i=0; i<8; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=chOut[i*2]+chOut[i*2+1]; + } } } void DivPlatformSNES::tick() { + // KON/KOFF can't be written several times per one sample + // so they have to be accumulated + unsigned char kon=0; + unsigned char koff=0; for (int i=0; i<8; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol))>>6; + if (chan[i].std.vol.had) { + // TODO handle gain writes } - double off=1.0; - if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[i].sample); - if (s->centerRate<1) { - off=1.0; - } else { - off=8363.0/(double)s->centerRate; - } - } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=off*NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=off*NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { - chan[i].baseFreq=off*NOTE_PERIODIC(chan[i].note); + 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.hadWave) { - if (chan[i].wave!=chan[i].std.wave) { - chan[i].wave=chan[i].std.wave; - if (!chan[i].keyOff) chan[i].keyOn=true; + if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-32768,32767); + } else { + chan[i].pitch2=chan[i].std.pitch.val; } + chan[i].freqChanged=true; + } + if (chan[i].std.panL.had) { + int val=chan[i].std.panL.val&0x7f; + chan[i].panL=(val<<1)|(val>>6); + } + if (chan[i].std.panR.had) { + int val=chan[i].std.panR.val&0x7f; + chan[i].panR=(val<<1)|(val>>6); + } + if (chan[i].std.panL.had || chan[i].std.panR.had) { + writeOutVol(i); + } + if (chan[i].setPos) { + // force keyon + chan[i].keyOn=true; + chan[i].setPos=false; + } else { + chan[i].audPos=0; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins); - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); - if (chan[i].freq>4095) chan[i].freq=4095; - if (chan[i].note>0x5d) chan[i].freq=0x01; + DivSample* s=parent->getSample(chan[i].sample); + double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; + chan[i].freq=(unsigned int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE)); + if (chan[i].freq>16383) chan[i].freq=16383; if (chan[i].keyOn) { - if (chan[i].wave<0) { - chan[i].wave=0; - } + // TODO handle sample offsets + kon|=(1<>8); + chan[i].freqChanged=false; } - if (chan[i].keyOn) chan[i].keyOn=false; - if (chan[i].keyOff) chan[i].keyOff=false; - chan[i].freqChanged=false; } } + rWrite(0x4c,kon); + rWrite(0x5c,koff); } int DivPlatformSNES::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); - chan[c.chan].sample=ins->amiga.initSample; - double off=1.0; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - if (s->centerRate<1) { - off=1.0; - } else { - off=8363.0/(double)s->centerRate; - } - } + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=off*NOTE_PERIODIC(c.value); + chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value)); } - if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { + if (chan[c.chan].useWave || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { chan[c.chan].sample=-1; } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - chan[c.chan].audPos=0; - } - chan[c.chan].audSub=0; if (c.value!=DIV_NOTE_NULL) { chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); + chan[c.chan].insChanged=false; break; } case DIV_CMD_NOTE_OFF: chan[c.chan].sample=-1; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -174,32 +198,35 @@ int DivPlatformSNES::dispatch(DivCommand c) { 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.hasVol) { - chan[c.chan].outVol=c.value; - } + writeOutVol(c.chan); } break; + // case DIV_CMD_GLOBAL_VOLUME: + // gblVolL=MIN(c.value,127); + // gblVolR=MIN(c.value,127); + // rWrite(0x0c,gblVolL); + // rWrite(0x1c,gblVolR); + // break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { - return chan[c.chan].vol; - } - return chan[c.chan].outVol; + return chan[c.chan].vol; + break; + case DIV_CMD_PANNING: + chan[c.chan].panL=c.value; + chan[c.chan].panR=c.value2; + writeOutVol(c.chan); 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_PERIODIC(c.value2); + int destFreq=round(NOTE_FREQUENCY(c.value2)); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -222,23 +249,14 @@ int DivPlatformSNES::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - double off=1.0; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - if (s->centerRate<1) { - off=1.0; - } else { - off=8363.0/(double)s->centerRate; - } - } - chan[c.chan].baseFreq=off*NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0))); + chan[c.chan].baseFreq=round(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)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } chan[c.chan].inPorta=c.value; break; @@ -246,28 +264,37 @@ int DivPlatformSNES::dispatch(DivCommand c) { chan[c.chan].audPos=c.value; chan[c.chan].setPos=true; break; + // TODO SNES-specific commands case DIV_CMD_GET_VOLMAX: return 127; break; - case DIV_ALWAYS_SET_VOLUME: - return 1; - break; default: break; } return 1; } +void DivPlatformSNES::writeOutVol(int ch) { + // TODO negative (inverted) panning support + int outL=0; + int outR=0; + if (!isMuted[ch]) { + outL=chan[ch].vol*chan[ch].panL/255; + outR=chan[ch].vol*chan[ch].panR/255; + } + rWrite(0+ch*16,outL); + rWrite(1+ch*16,outR); +} + void DivPlatformSNES::muteChannel(int ch, bool mute) { isMuted[ch]=mute; + writeOutVol(ch); } void DivPlatformSNES::forceIns() { for (int i=0; i<8; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; - chan[i].audPos=131072; - chan[i].audDat=0; chan[i].sample=-1; } } @@ -276,12 +303,21 @@ void* DivPlatformSNES::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSNES::getChanMacroInt(int ch) { + return &chan[ch].std; +} + +DivDispatchOscBuffer* DivPlatformSNES::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformSNES::getRegisterPool() { // get states from emulator for (int i=0; i<0x80; i+=0x10) { - regPool[i+8]=dsp->read(i+8); - regPool[i+9]=dsp->read(i+9); + regPool[i+8]=dsp.read(i+8); + regPool[i+9]=dsp.read(i+9); } + regPool[0x7c]=dsp.read(0x7c); // ENDX return regPool; } @@ -290,22 +326,25 @@ int DivPlatformSNES::getRegisterPoolSize() { } void DivPlatformSNES::reset() { + dsp.init(sampleMem); + dsp.set_output(NULL,0); + memset(regPool,0,128); + // TODO more initial values + sampleTableBase=0; + rWrite(0x5d,sampleTableBase>>8); + rWrite(0x0c,127); // global volume left + rWrite(0x1c,127); // global volume right for (int i=0; i<8; i++) { chan[i]=Channel(); + chan[i].std.setEngine(parent); + writeOutVol(i); } - dsp->init(&aram); - dsp->set_output(NULL, 0); - memset(regPool,0,128); } bool DivPlatformSNES::isStereo() { return true; } -bool DivPlatformSNES::keyOffAffectsArp(int ch) { - return true; -} - void DivPlatformSNES::notifyInsChange(int ins) { for (int i=0; i<8; i++) { if (chan[i].ins==ins) { @@ -314,10 +353,6 @@ void DivPlatformSNES::notifyInsChange(int ins) { } } -void DivPlatformSNES::notifyWaveChange(int wave) { - // TODO when wavetables are added -} - void DivPlatformSNES::notifyInsDeletion(void* ins) { for (int i=0; i<8; i++) { chan[i].std.notifyInsDeletion((DivInstrument*)ins); @@ -332,14 +367,59 @@ void DivPlatformSNES::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); } +const void* DivPlatformSNES::getSampleMem(int index) { + return index == 0 ? sampleMem : NULL; +} + +size_t DivPlatformSNES::getSampleMemCapacity(int index) { + // TODO change it based on current echo buffer size + return index == 0 ? 65536 : 0; +} + +size_t DivPlatformSNES::getSampleMemUsage(int index) { + return index == 0 ? sampleMemLen : 0; +} + +void DivPlatformSNES::renderSamples() { + memset(sampleMem,0,getSampleMemCapacity()); + + // skip past sample table + size_t memPos=sampleTableBase+0x400; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + int length=s->lengthBRR; + int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length); + if (actualLength>0) { + size_t tabAddr=sampleTableBase+i*4; + size_t loopPos=memPos; + if (s->loopStart>=0) loopPos+=s->loopStart; + s->offSNES=memPos; + sampleMem[tabAddr+0]=memPos&0xff; + sampleMem[tabAddr+1]=memPos>>8; + sampleMem[tabAddr+2]=loopPos&0xff; + sampleMem[tabAddr+3]=loopPos>>8; + memcpy(&sampleMem[memPos],s->data8,actualLength); + memPos+=actualLength; + } + if (actualLength& wlist); const char** getRegisterSheet(); + const char* getEffectName(unsigned char effect); + const void* getSampleMem(int index = 0); + size_t getSampleMemCapacity(int index = 0); + size_t getSampleMemUsage(int index = 0); + void renderSamples(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + private: + void writeOutVol(int ch); }; #endif diff --git a/src/engine/platform/sound/snes/SPC_DSP.cpp b/src/engine/platform/sound/snes/SPC_DSP.cpp index abbf827db..6510f460a 100644 --- a/src/engine/platform/sound/snes/SPC_DSP.cpp +++ b/src/engine/platform/sound/snes/SPC_DSP.cpp @@ -491,10 +491,11 @@ VOICE_CLOCK( V3c ) if ( !v->kon_delay ) run_envelope( v ); } -inline void SPC_DSP::voice_output( voice_t const* v, int ch ) +inline void SPC_DSP::voice_output( voice_t* const v, int ch ) { // Apply left/right volume int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; + v->out [ch] = (sample_t) amp; // Furnace addition // Add to output total m.t_main_out [ch] += amp; @@ -801,8 +802,12 @@ void SPC_DSP::run( int clocks_remain ) switch ( phase ) { loop: - + // GCC, why +#ifdef __GNUC__ + #define PHASE( n ) if ( n && !--clocks_remain ) break; __attribute__ ((fallthrough)); case n: +#else #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: +#endif GEN_DSP_TIMING #undef PHASE diff --git a/src/engine/platform/sound/snes/SPC_DSP.h b/src/engine/platform/sound/snes/SPC_DSP.h index d59284797..879ee703d 100644 --- a/src/engine/platform/sound/snes/SPC_DSP.h +++ b/src/engine/platform/sound/snes/SPC_DSP.h @@ -64,6 +64,9 @@ public: // Returns non-zero if new key-on events occurred since last call bool check_kon(); + + // Furnace addition, gets all current voice outputs to an array of samples + void get_voice_outputs( sample_t* outs ); // DSP register addresses @@ -118,6 +121,7 @@ public: int env; // current envelope level int hidden_env; // used by GAIN mode 7, very obscure quirk uint8_t t_envx_out; + sample_t out[2]; // Furnace addition, for per-channel oscilloscope }; private: enum { brr_block_size = 9 }; @@ -200,7 +204,7 @@ private: void misc_29(); void misc_30(); - void voice_output( voice_t const* v, int ch ); + void voice_output( voice_t* const v, int ch ); void voice_V1( voice_t* const ); void voice_V2( voice_t* const ); void voice_V3( voice_t* const ); @@ -283,6 +287,17 @@ inline bool SPC_DSP::check_kon() return old; } +inline void SPC_DSP::get_voice_outputs( sample_t* outs ) +{ + int i; + for ( i = 0; i < voice_count; i++ ) + { + voice_t* v = &m.voices [i]; + outs [i * 2] = v->out [0]; + outs [i * 2 + 1] = v->out [1]; + } +} + #if !SPC_NO_COPY_STATE_FUNCS class SPC_State_Copier { diff --git a/src/engine/sample.h b/src/engine/sample.h index d9ad633c9..5195da1be 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -86,7 +86,7 @@ struct DivSample { unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthBRR, lengthVOX; unsigned int off8, off16, off1, offDPCM, offZ, offQSoundA, offA, offB, offBRR, offVOX; - unsigned int offSegaPCM, offQSound, offX1_010, offSU, offYMZ280B, offRF5C68; + unsigned int offSegaPCM, offQSound, offX1_010, offSU, offYMZ280B, offRF5C68, offSNES; unsigned int samples; @@ -249,6 +249,7 @@ struct DivSample { offX1_010(0), offSU(0), offRF5C68(0), + offSNES(0), samples(0) {} ~DivSample(); }; diff --git a/src/gui/gui.h b/src/gui/gui.h index 005b2f26e..2ee6170aa 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -154,7 +154,6 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, GUI_COLOR_INSTR_OPL_DRUMS, - GUI_COLOR_INSTR_SNES, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_FM, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 9eb1e6d09..532df4e17 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -113,7 +113,6 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", - "SNES", NULL }; @@ -895,6 +894,7 @@ const int availableSystems[]={ DIV_SYSTEM_MSM6258, DIV_SYSTEM_MSM6295, DIV_SYSTEM_RF5C68, + DIV_SYSTEM_SNES, 0 // don't remove this last one! }; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 994902e8e..b2c86440b 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -307,7 +307,13 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_MSM6295, 64, 0, 0, 0 } - )); + )); + cat.systems.push_back(FurnaceGUISysDef( + "SNES", { + DIV_SYSTEM_SNES, 64, 0, 0, + 0 + } + )); sysCategories.push_back(cat); cat=FurnaceGUISysCategory("Wavetable","chips which use user-specified waveforms to generate sound."); @@ -589,6 +595,12 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "SNES", { + DIV_SYSTEM_SNES, 64, 0, 0, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Mattel Intellivision", { DIV_SYSTEM_AY8910, 64, 0, 48, diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 89d35b0b2..9ab85da2a 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -489,6 +489,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_SCC: case DIV_SYSTEM_SCC_PLUS: case DIV_SYSTEM_YMZ280B: + case DIV_SYSTEM_SNES: ImGui::Text("nothing to configure"); break; default: From 807848cfee501f2d50cdd386c199b6c4b1e4f181 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Wed, 29 Jun 2022 16:59:47 -0500 Subject: [PATCH 009/515] Fix LFO disable/enable behavior for YM2151. --- src/engine/platform/arcade.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 1be61fa23..47cc1b600 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -172,7 +172,7 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si w.addrOrVal=true; } } - + OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,NULL,NULL,NULL,NULL); @@ -182,13 +182,13 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si for (int i=0; i<8; i++) { oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]; } - + if (o[0]<-32768) o[0]=-32768; if (o[0]>32767) o[0]=32767; if (o[1]<-32768) o[1]=-32768; if (o[1]>32767) o[1]=32767; - + bufL[h]=o[0]; bufR[h]=o[1]; } @@ -211,7 +211,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz delay=1; } } - + fm_ymfm->generate(&out_ymfm); for (int i=0; i<8; i++) { @@ -225,7 +225,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz os[1]=out_ymfm.data[1]; if (os[1]<-32768) os[1]=-32768; if (os[1]>32767) os[1]=32767; - + bufL[h]=os[0]; bufR[h]=os[1]; } @@ -616,6 +616,12 @@ int DivPlatformArcade::dispatch(DivCommand c) { break; } case DIV_CMD_FM_LFO: { + if(c.value==0) { + rWrite(0x01,0x02); + } + else { + rWrite(0x01,0x00); + } rWrite(0x18,c.value); break; } @@ -938,6 +944,8 @@ void DivPlatformArcade::reset() { pmDepth=0x7f; //rWrite(0x18,0x10); + immWrite(0x01,0x02); // LFO Off + immWrite(0x18,0x00); // LFO Freq Off immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); //rWrite(0x1b,0x00); From 97832c6c9a13d425d1d2a260d87f84c6ec4ac2f1 Mon Sep 17 00:00:00 2001 From: Eris Lund <38136789+0x5066@users.noreply.github.com> Date: Sat, 2 Jul 2022 17:25:22 +0200 Subject: [PATCH 010/515] Add The Cheetahmen --- demos/The Cheetahmen.fur | Bin 0 -> 2454 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/The Cheetahmen.fur diff --git a/demos/The Cheetahmen.fur b/demos/The Cheetahmen.fur new file mode 100644 index 0000000000000000000000000000000000000000..105b64b11e6327f741bad1f658de1185735367e4 GIT binary patch literal 2454 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 UaoF3vLfBg-OOHJLKZtB$k0fXS2mk;8 literal 0 HcmV?d00001 From d3cd7bbb8151bb63007f061a79ca069eaea290fa Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Sun, 3 Jul 2022 01:42:47 +0700 Subject: [PATCH 011/515] Add generic PCM DAC system For use with NGP DAC and some arcade system combos --- CMakeLists.txt | 1 + src/engine/dispatchContainer.cpp | 6 +- src/engine/platform/pcmdac.cpp | 370 +++++++++++++++++++++++++++++++ src/engine/platform/pcmdac.h | 99 +++++++++ src/gui/guiConst.cpp | 1 + src/gui/sysConf.cpp | 8 +- 6 files changed, 481 insertions(+), 4 deletions(-) create mode 100644 src/engine/platform/pcmdac.cpp create mode 100644 src/engine/platform/pcmdac.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5312692a6..dbf3ada7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -448,6 +448,7 @@ src/engine/platform/scc.cpp src/engine/platform/ymz280b.cpp src/engine/platform/namcowsg.cpp src/engine/platform/rf5c68.cpp +src/engine/platform/pcmdac.cpp src/engine/platform/dummy.cpp ) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 227f60679..8d8db5c5a 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -54,6 +54,7 @@ #include "platform/su.h" #include "platform/swan.h" #include "platform/lynx.h" +#include "platform/zxbeeper.h" #include "platform/bubsyswsg.h" #include "platform/n163.h" #include "platform/pet.h" @@ -64,9 +65,9 @@ #include "platform/scc.h" #include "platform/ymz280b.h" #include "platform/rf5c68.h" +#include "platform/pcmdac.h" #include "platform/dummy.h" #include "../ta-log.h" -#include "platform/zxbeeper.h" #include "song.h" void DivDispatchContainer::setRates(double gotRate) { @@ -395,6 +396,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do dispatch=new DivPlatformNamcoWSG; ((DivPlatformNamcoWSG*)dispatch)->setDeviceType(30); break; + case DIV_SYSTEM_PCM_DAC: + dispatch=new DivPlatformPCMDAC; + break; case DIV_SYSTEM_DUMMY: dispatch=new DivPlatformDummy; break; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp new file mode 100644 index 000000000..314ba7dd1 --- /dev/null +++ b/src/engine/platform/pcmdac.cpp @@ -0,0 +1,370 @@ +/** + * 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. + */ + +#define _USE_MATH_DEFINES +#include "pcmdac.h" +#include "../engine.h" +#include + +// to ease the driver, freqency register is a 8.16 counter relative to output sample rate +#define CHIP_FREQBASE 65536 + +void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t len) { + const int depthScale=(15-outDepth); + int output=0; + for (size_t h=start; hdata[oscBuf->needle++]=0; + continue; + } + if (chan.useWave || (chan.sample>=0 && chan.samplesong.sampleLen)) { + chan.audPos+=chan.freq>>16; + chan.audSub+=(chan.freq&0xffff); + if (chan.audSub>=0x10000) { + chan.audSub-=0x10000; + chan.audPos+=1; + } + if (chan.useWave) { + if (chan.audPos>=(unsigned int)(chan.audLen<<1)) { + chan.audPos=0; + } + output=(chan.ws.output[chan.audPos]^0x80)<<8; + } else { + DivSample* s=parent->getSample(chan.sample); + if (s->samples>0) { + if (chan.audPos>=s->samples) { + if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + chan.audPos=s->loopStart; + } else { + chan.sample=-1; + } + } + if (chan.audPossamples) { + output=s->data16[chan.audPos]; + } + } else { + chan.sample=-1; + } + } + } + output=output*chan.vol*chan.envVol/16384; + oscBuf->data[oscBuf->needle++]=output; + if (outStereo) { + bufL[h]=((output*chan.panL)>>(depthScale+8))<>(depthScale+8))<>depthScale)<getIns(chan.ins,DIV_INS_AMIGA); + double off=1.0; + if (!chan.useWave && chan.sample>=0 && chan.samplesong.sampleLen) { + DivSample* s=parent->getSample(chan.sample); + off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; + } + chan.freq=off*parent->calcFreq(chan.baseFreq,chan.pitch,false,2,chan.pitch2,chipClock,CHIP_FREQBASE); + if (chan.freq>16777215) chan.freq=16777215; + if (chan.keyOn) { + if (!chan.std.vol.had) { + chan.envVol=64; + } + chan.keyOn=false; + } + if (chan.keyOff) { + chan.keyOff=false; + } + chan.freqChanged=false; + } +} + +int DivPlatformPCMDAC::dispatch(DivCommand c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA); + if (ins->amiga.useWave) { + chan.useWave=true; + chan.audLen=(ins->amiga.waveLen+1)>>1; + if (chan.insChanged) { + if (chan.wave<0) { + chan.wave=0; + chan.ws.setWidth(chan.audLen<<1); + chan.ws.changeWave1(chan.wave); + } + } + } else { + chan.sample=ins->amiga.getSample(c.value); + chan.useWave=false; + } + if (c.value!=DIV_NOTE_NULL) { + chan.baseFreq=round(NOTE_FREQUENCY(c.value)); + } + if (chan.useWave || chan.sample<0 || chan.sample>=parent->song.sampleLen) { + chan.sample=-1; + } + if (chan.setPos) { + chan.setPos=false; + } else { + chan.audPos=0; + } + chan.audSub=0; + if (c.value!=DIV_NOTE_NULL) { + chan.freqChanged=true; + chan.note=c.value; + } + chan.active=true; + chan.keyOn=true; + chan.macroInit(ins); + if (!parent->song.brokenOutVol && !chan.std.vol.will) { + chan.envVol=64; + } + if (chan.useWave) { + chan.ws.init(ins,chan.audLen<<1,255,chan.insChanged); + } + chan.insChanged=false; + break; + } + case DIV_CMD_NOTE_OFF: + chan.sample=-1; + chan.active=false; + chan.keyOff=true; + chan.macroInit(NULL); + break; + case DIV_CMD_NOTE_OFF_ENV: + case DIV_CMD_ENV_RELEASE: + chan.std.release(); + break; + case DIV_CMD_INSTRUMENT: + if (chan.ins!=c.value || c.value2==1) { + chan.ins=c.value; + chan.insChanged=true; + } + break; + case DIV_CMD_VOLUME: + if (chan.vol!=c.value) { + chan.vol=c.value; + if (!chan.std.vol.has) { + chan.envVol=64; + } + } + break; + case DIV_CMD_GET_VOLUME: + return chan.vol; + break; + case DIV_CMD_PANNING: + chan.panL=c.value; + chan.panR=c.value2; + break; + case DIV_CMD_PITCH: + chan.pitch=c.value; + chan.freqChanged=true; + break; + case DIV_CMD_WAVE: + if (!chan.useWave) break; + chan.wave=c.value; + chan.keyOn=true; + chan.ws.changeWave1(chan.wave); + break; + case DIV_CMD_NOTE_PORTA: { + DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA); + chan.sample=ins->amiga.getSample(c.value2); + int destFreq=round(NOTE_FREQUENCY(c.value2)); + bool return2=false; + if (destFreq>chan.baseFreq) { + chan.baseFreq+=c.value; + if (chan.baseFreq>=destFreq) { + chan.baseFreq=destFreq; + return2=true; + } + } else { + chan.baseFreq-=c.value; + if (chan.baseFreq<=destFreq) { + chan.baseFreq=destFreq; + return2=true; + } + } + chan.freqChanged=true; + if (return2) { + chan.inPorta=false; + return 2; + } + break; + } + case DIV_CMD_LEGATO: { + chan.baseFreq=round(NOTE_FREQUENCY(c.value+((chan.std.arp.will && !chan.std.arp.mode)?(chan.std.arp.val):(0)))); + chan.freqChanged=true; + chan.note=c.value; + break; + } + case DIV_CMD_PRE_PORTA: + if (chan.active && c.value2) { + if (parent->song.resetMacroOnPorta) chan.macroInit(parent->getIns(chan.ins,DIV_INS_AMIGA)); + } + chan.inPorta=c.value; + break; + case DIV_CMD_SAMPLE_POS: + if (chan.useWave) break; + chan.audPos=c.value; + chan.setPos=true; + break; + case DIV_CMD_GET_VOLMAX: + return 255; + break; + case DIV_ALWAYS_SET_VOLUME: + return 1; + break; + default: + break; + } + return 1; +} + +void DivPlatformPCMDAC::muteChannel(int ch, bool mute) { + isMuted=mute; +} + +void DivPlatformPCMDAC::forceIns() { + chan.insChanged=true; + chan.freqChanged=true; + chan.audPos=0; + chan.sample=-1; +} + +void* DivPlatformPCMDAC::getChanState(int ch) { + return &chan; +} + +DivDispatchOscBuffer* DivPlatformPCMDAC::getOscBuffer(int ch) { + return oscBuf; +} + +void DivPlatformPCMDAC::reset() { + chan=DivPlatformPCMDAC::Channel(); + chan.std.setEngine(parent); + chan.ws.setEngine(parent); + chan.ws.init(NULL,32,255); +} + +bool DivPlatformPCMDAC::isStereo() { + return true; +} + +DivMacroInt* DivPlatformPCMDAC::getChanMacroInt(int ch) { + return &chan.std; +} + +void DivPlatformPCMDAC::notifyInsChange(int ins) { + if (chan.ins==ins) { + chan.insChanged=true; + } +} + +void DivPlatformPCMDAC::notifyWaveChange(int wave) { + if (chan.useWave && chan.wave==wave) { + chan.ws.changeWave1(wave); + } +} + +void DivPlatformPCMDAC::notifyInsDeletion(void* ins) { + chan.std.notifyInsDeletion((DivInstrument*)ins); +} + +void DivPlatformPCMDAC::setFlags(unsigned int flags) { + // default to 44100Hz 16-bit stereo + if (!flags) flags=0x1f0000|44099; + rate=(flags&0xffff)+1; + // rate can't be too low or the resampler will break + if (rate<1000) rate=1000; + chipClock=rate; + outDepth=(flags>>16)&0xf; + outStereo=(flags>>20)&1; +} + +int DivPlatformPCMDAC::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { + parent=p; + dumpWrites=false; + skipRegisterWrites=false; + oscBuf=new DivDispatchOscBuffer; + isMuted=false; + setFlags(flags); + reset(); + return 1; +} + +void DivPlatformPCMDAC::quit() { + delete oscBuf; +} diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h new file mode 100644 index 000000000..c372219c2 --- /dev/null +++ b/src/engine/platform/pcmdac.h @@ -0,0 +1,99 @@ +/** + * 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 _PCM_DAC_H +#define _PCM_DAC_H + +#include "../dispatch.h" +#include +#include "../macroInt.h" +#include "../waveSynth.h" + +class DivPlatformPCMDAC: public DivDispatch { + struct Channel { + int freq, baseFreq, pitch, pitch2; + unsigned int audLoc; + unsigned short audLen; + unsigned int audPos; + int audSub; + int sample, wave, ins; + int note; + int panL, panR; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos; + int vol, envVol; + DivMacroInt std; + DivWaveSynth ws; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + audLoc(0), + audLen(0), + audPos(0), + audSub(0), + sample(-1), + wave(-1), + ins(-1), + panL(255), + panR(255), + note(0), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + useWave(false), + setPos(false), + vol(255), + envVol(64) {} + }; + Channel chan; + DivDispatchOscBuffer* oscBuf; + bool isMuted; + int outDepth; + bool outStereo; + + 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); + DivDispatchOscBuffer* getOscBuffer(int chan); + void reset(); + void forceIns(); + void tick(bool sysTick=true); + void muteChannel(int ch, bool mute); + bool isStereo(); + DivMacroInt* getChanMacroInt(int ch); + void setFlags(unsigned int flags); + void notifyInsChange(int ins); + void notifyWaveChange(int wave); + void notifyInsDeletion(void* ins); + int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); + void quit(); +}; + +#endif diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 80f9b5d85..566a12e12 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -894,6 +894,7 @@ const int availableSystems[]={ DIV_SYSTEM_MSM6258, DIV_SYSTEM_MSM6295, DIV_SYSTEM_RF5C68, + DIV_SYSTEM_PCM_DAC, 0 // don't remove this last one! }; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index b34dd0b28..89446e3be 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -609,16 +609,18 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool break; } case DIV_SYSTEM_PCM_DAC: { + // default to 44100Hz 16-bit stereo + if (!flags) copyOfFlags=flags=0x1f0000|44099; int sampRate=(flags&65535)+1; int bitDepth=((flags>>16)&15)+1; bool stereo=(flags>>20)&1; ImGui::Text("Output rate:"); - if (CWSliderInt("##SampRate",&sampRate,1,65536)) { - if (sampRate<1) sampRate=1; + if (CWSliderInt("##SampRate",&sampRate,1000,65536)) { + if (sampRate<1000) sampRate=1000; if (sampRate>65536) sampRate=65536; copyOfFlags=(flags&(~65535))|(sampRate-1); } rightClickable - ImGui::Text("Output depth:"); + ImGui::Text("Output bit depth:"); if (CWSliderInt("##BitDepth",&bitDepth,1,16)) { if (bitDepth<1) bitDepth=1; if (bitDepth>16) bitDepth=16; From caa1c2c93daaf9d1b0aca321dd156b2f25f3ec73 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 3 Jul 2022 01:29:41 -0500 Subject: [PATCH 012/515] D E M O --- demos/massive_x_opz.fur | Bin 0 -> 5836 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/massive_x_opz.fur diff --git a/demos/massive_x_opz.fur b/demos/massive_x_opz.fur new file mode 100644 index 0000000000000000000000000000000000000000..f32a1f26c6c6201f8d664037d5396a532135b79d GIT binary patch literal 5836 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 Date: Sun, 3 Jul 2022 20:11:04 +0700 Subject: [PATCH 013/515] Fix GCC errors --- src/engine/platform/pcmdac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h index c372219c2..60d2a6fc0 100644 --- a/src/engine/platform/pcmdac.h +++ b/src/engine/platform/pcmdac.h @@ -55,9 +55,9 @@ class DivPlatformPCMDAC: public DivDispatch { sample(-1), wave(-1), ins(-1), + note(0), panL(255), panR(255), - note(0), active(false), insChanged(true), freqChanged(false), From c3a693e804c3e5f9a33af368f22aafa7df54c345 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 3 Jul 2022 23:02:25 -0500 Subject: [PATCH 014/515] GUI: possibly fix replace crashes --- src/gui/findReplace.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 78abce7cb..69303c6f9 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -997,16 +997,16 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextColumn(); ImGui::BeginDisabled(!queryReplaceEffectValDo[i]); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##ERMode",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::Combo("##ERModeV",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SET) { - if (ImGui::InputScalar("##ERValueH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (ImGui::InputScalar("##ERValueVH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; } } else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { - if (ImGui::InputInt("##ERValue",&queryReplaceEffectVal[i],1,12)) { + if (ImGui::InputInt("##ERValueV",&queryReplaceEffectVal[i],1,12)) { if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255; if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; } From 4b1db78a0ba115a6f287d223a612c992adc22f61 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 3 Jul 2022 23:02:45 -0500 Subject: [PATCH 015/515] GUI: remove debug message --- src/gui/findReplace.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 69303c6f9..e982882d4 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -447,7 +447,6 @@ void FurnaceGUI::doReplace() { } if (!us.pat.empty()) { - printf("pusher\n"); undoHist.push_back(us); redoHist.clear(); if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front(); From 0ec28f168ee64a3b66cc2d2fd1d902ee680d6284 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 3 Jul 2022 23:31:35 -0500 Subject: [PATCH 016/515] more .dmf compatibility stuff --- src/engine/playback.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index d672c2d47..329c5b54d 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -334,6 +334,11 @@ void DivEngine::processRow(int i, bool afterDelay) { if (chan[i].lastIns!=pat->data[whatRow][2]) { chan[i].lastIns=pat->data[whatRow][2]; insChanged=true; + if (song.legacyVolumeSlides && chan[i].volume==chan[i].volMax+1) { + logV("forcing volume"); + chan[i].volume=chan[i].volMax; + dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + } } } // note From 949e29305390e5747bad7d7bd821568e6facc683 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 3 Jul 2022 23:43:13 -0500 Subject: [PATCH 017/515] SMS: aaaand more .dmf compatibility --- src/engine/platform/sms.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index f16d53351..28462027d 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -133,7 +133,7 @@ void DivPlatformSMS::tick(bool sysTick) { if (i==3) CHIP_DIVIDER=noiseDivider; chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); + chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,15); if (chan[i].outVol<0) chan[i].outVol=0; // old formula // ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; From f4a85bebff2de4a3b3af5556a1d3ac6974ae6ca1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 4 Jul 2022 01:43:59 -0500 Subject: [PATCH 018/515] dev101 - fix SMSFM_intro.dmf --- papers/format.md | 4 +++- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 14 ++++++++++++-- src/engine/platform/amiga.cpp | 1 + src/engine/platform/arcade.cpp | 1 + src/engine/platform/ay.cpp | 1 + src/engine/platform/ay8930.cpp | 1 + src/engine/platform/bubsyswsg.cpp | 1 + src/engine/platform/c64.cpp | 1 + src/engine/platform/fds.cpp | 1 + src/engine/platform/gb.cpp | 1 + src/engine/platform/lynx.cpp | 1 + src/engine/platform/mmc5.cpp | 1 + src/engine/platform/n163.cpp | 1 + src/engine/platform/namcowsg.cpp | 1 + src/engine/platform/nes.cpp | 1 + src/engine/platform/opl.cpp | 3 +++ src/engine/platform/opll.cpp | 1 + src/engine/platform/pce.cpp | 1 + src/engine/platform/pcspkr.cpp | 1 + src/engine/platform/pet.cpp | 1 + src/engine/platform/qsound.cpp | 1 + src/engine/platform/rf5c68.cpp | 1 + src/engine/platform/saa.cpp | 1 + src/engine/platform/scc.cpp | 1 + src/engine/platform/segapcm.cpp | 1 + src/engine/platform/sms.cpp | 3 +-- src/engine/platform/su.cpp | 1 + src/engine/platform/swan.cpp | 1 + src/engine/platform/tia.cpp | 1 + src/engine/platform/tx81z.cpp | 1 + src/engine/platform/vera.cpp | 1 + src/engine/platform/vic20.cpp | 1 + src/engine/platform/vrc6.cpp | 1 + src/engine/platform/x1_010.cpp | 1 + src/engine/platform/ymz280b.cpp | 1 + src/engine/platform/zxbeeper.cpp | 1 + src/engine/song.h | 4 +++- src/gui/compatFlags.cpp | 18 +++++++++++------- 39 files changed, 67 insertions(+), 15 deletions(-) diff --git a/papers/format.md b/papers/format.md index bef8b1f81..3e3583463 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 101: Furnace 0.6pre1 (dev101) - 100: Furnace 0.6pre1 - 99: Furnace dev99 - 98: Furnace dev98 @@ -318,7 +319,8 @@ size | description 1 | volume macro still applies after end (>=99) or reserved 1 | broken outVol (>=99) or reserved 1 | E1xy and E2xy stop on same note (>=100) or reserved - 8 | reserved + 1 | broken initial position of porta after arp (>=101) or reserved + 7 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved diff --git a/src/engine/engine.h b/src/engine/engine.h index 962e0fcca..5f5ab1a35 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1" -#define DIV_ENGINE_VERSION 100 +#define DIV_VERSION "0.6pre1 (dev101)" +#define DIV_ENGINE_VERSION 101 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index d4c453239..ddc5edf6b 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -172,6 +172,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.volMacroLinger=false; ds.brokenOutVol=true; // ??? ds.e1e2StopOnSameNote=true; + ds.brokenPortaArp=false; // 1.1 compat flags if (ds.version>24) { @@ -1047,6 +1048,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<100) { ds.e1e2StopOnSameNote=false; } + if (ds.version<101) { + ds.brokenPortaArp=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1448,7 +1452,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<8; i++) { + if (ds.version>=101) { + ds.brokenPortaArp=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<7; i++) { reader.readC(); } } @@ -2922,7 +2931,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.volMacroLinger); w->writeC(song.brokenOutVol); w->writeC(song.e1e2StopOnSameNote); - for (int i=0; i<8; i++) { + w->writeC(song.brokenPortaArp); + for (int i=0; i<7; i++) { w->writeC(0); } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 8037feafe..65b44136f 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -355,6 +355,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 1be61fa23..41042cd5c 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -827,6 +827,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: + 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_PRE_NOTE: diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 073776105..7018824b9 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -474,6 +474,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 0fad4025b..581ebb9e8 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -506,6 +506,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 48a078803..5fe4462f4 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -250,6 +250,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index a55b53906..640df54e6 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -369,6 +369,7 @@ int DivPlatformC64::dispatch(DivCommand c) { chan[c.chan].keyOn=true; } } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index ea4b83e9d..f9fc5b50b 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -406,6 +406,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 999d31b91..2b7dcf6df 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -393,6 +393,7 @@ int DivPlatformGB::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GB_SWEEP_DIR: diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 4fd30db98..3f5e92c03 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -387,6 +387,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 2b97f46f6..dc9e5abad 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -324,6 +324,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 50f9d8363..b20b460e0 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -562,6 +562,7 @@ int DivPlatformN163::dispatch(DivCommand c) { chan[c.chan].keyOn=true; } } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 6bcf43d27..00b127930 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -442,6 +442,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) { 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_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 67ad28521..d801fe664 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -573,6 +573,7 @@ int DivPlatformNES::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 9373d0cd8..823e764bc 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1434,6 +1434,9 @@ int DivPlatformOPL::dispatch(DivCommand c) { return 63; break; case DIV_CMD_PRE_PORTA: + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) { + chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(chan[c.chan].note)):(NOTE_FREQUENCY(chan[c.chan].note)); + } chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 08292be68..5c9611b43 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -831,6 +831,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (c.chan>=9 && !properDrums) return 0; + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index b8c580e51..9e1302a0f 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -445,6 +445,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { 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_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 57c72b677..d40a297ae 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -471,6 +471,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 9b3c99886..493436271 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -239,6 +239,7 @@ int DivPlatformPET::dispatch(DivCommand c) { if (chan.active && c.value2) { if (parent->song.resetMacroOnPorta) chan.macroInit(parent->getIns(chan.ins,DIV_INS_PET)); } + if (!chan.inPorta && c.value && !parent->song.brokenPortaArp && chan.std.arp.will) chan.baseFreq=NOTE_PERIODIC(chan.note); chan.inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 8af565df4..6eb14be7f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -496,6 +496,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 2106a5a72..176b6e7c7 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -265,6 +265,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index c562838a2..103c3348f 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -335,6 +335,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index 8175bc01b..485839bf1 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -267,6 +267,7 @@ int DivPlatformSCC::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 19b8eb82e..71d45298a 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -365,6 +365,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=(chan[c.chan].note<<6); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 28462027d..3d11a5ac9 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -353,9 +353,8 @@ int DivPlatformSMS::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; - // TODO: pre porta cancel arp compat flag - //if (chan[c.chan].inPorta) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); break; case DIV_CMD_GET_VOLMAX: return 15; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index c6860afbb..f3be01a78 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -454,6 +454,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 905fa82a5..b3e833198 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -431,6 +431,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index da3472446..ddb380844 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -259,6 +259,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=(chan[c.chan].note<<8); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 123d1193c..9d24e4db5 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -933,6 +933,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: + 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_PRE_NOTE: diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 62e1ea682..092bbb6ac 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -359,6 +359,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=calcNoteFreq(c.chan,chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_STD_NOISE_MODE: diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 8475b0e53..771b87d1e 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -243,6 +243,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 08c6d0538..88fcb37b4 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -399,6 +399,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index dc5c7ed22..e2e360b1b 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -732,6 +732,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_FREQ: diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 45631a940..d8d98478d 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -293,6 +293,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 524d3c117..01702dc5d 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -224,6 +224,7 @@ int DivPlatformZXBeeper::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/song.h b/src/engine/song.h index d06c57377..185cac8a2 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -497,6 +497,7 @@ struct DivSong { bool volMacroLinger; bool brokenOutVol; bool e1e2StopOnSameNote; + bool brokenPortaArp; std::vector ins; std::vector wave; @@ -595,7 +596,8 @@ struct DivSong { newVolumeScaling(true), volMacroLinger(true), brokenOutVol(false), - e1e2StopOnSameNote(false) { + e1e2StopOnSameNote(false), + brokenPortaArp(false) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 8e5d75172..9024992e7 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -207,31 +207,35 @@ void FurnaceGUI::drawCompatFlags() { } ImGui::Checkbox("Stop portamento on note off",&e->song.stopPortaOnNoteOff); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("Allow instrument change during slides",&e->song.newInsTriggersInPorta); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("Reset note to base on arpeggio stop",&e->song.arp0Reset); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("ExtCh channel status is shared among operators",&e->song.sharedExtStat); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("New SegaPCM features (macros and better panning)",&e->song.newSegaPCM); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("Old FM octave boundary behavior",&e->song.oldOctaveBoundary); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("No OPN2 DAC volume control",&e->song.noOPN2Vol); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); + } + ImGui::Checkbox("Broken initial position of portamento after arpeggio",&e->song.brokenPortaArp); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6pre1.5"); } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; From b39924c9d6a7948013a69418f881ad54b0b8ff3b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 4 Jul 2022 23:54:56 -0500 Subject: [PATCH 019/515] AY: TODO fix wtr_envelope.dmf --- src/engine/platform/ay.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 7018824b9..8df5bd4ce 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -471,6 +471,8 @@ int DivPlatformAY8910::dispatch(DivCommand c) { return 15; break; case DIV_CMD_PRE_PORTA: + // TODO: FIX wtr_envelope.dmf + // the brokenPortaArp update broke it if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY)); } From 1ed6fdd405920830e5964d8d2c045e6b77b910ae Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 5 Jul 2022 14:02:40 -0500 Subject: [PATCH 020/515] and another demo song requested by Crisps --- .../Rise_against_the_ashes_to_the_new_dawn.fur | Bin 0 -> 29292 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Rise_against_the_ashes_to_the_new_dawn.fur diff --git a/demos/Rise_against_the_ashes_to_the_new_dawn.fur b/demos/Rise_against_the_ashes_to_the_new_dawn.fur new file mode 100644 index 0000000000000000000000000000000000000000..be28182fc422cc43fdf7c3eb57c53ac124fbc10d GIT binary patch literal 29292 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 MVJ`qkQa;ZA0_tTL Date: Thu, 7 Jul 2022 04:09:50 +0900 Subject: [PATCH 021/515] Fix typo --- src/gui/sysConf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index b34dd0b28..9cd963cc3 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -569,7 +569,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_OPL3: case DIV_SYSTEM_OPL3_DRUMS: { ImGui::Text("Clock rate:"); - if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==0)) { + if (ImGui::RadioButton("14.32MHz (NTSC)",(flags&255)==0)) { copyOfFlags=(flags&(~255))|0; } if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==1)) { @@ -591,7 +591,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("16.9344MHz",(flags&255)==0)) { copyOfFlags=(flags&(~255))|0; } - if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==1)) { + if (ImGui::RadioButton("14.32MHz (NTSC)",(flags&255)==1)) { copyOfFlags=(flags&(~255))|1; } if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==3)) { From fe94ea8e041d7c9662f999f6661fd8b453d1a387 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 7 Jul 2022 04:10:32 +0900 Subject: [PATCH 022/515] Fix typo --- src/engine/song.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/song.h b/src/engine/song.h index 185cac8a2..26640fdd4 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -353,7 +353,7 @@ struct DivSong { // - 1: stereo // - YM2203: // - bit 0-4: clock rate - // - 0: 3.58MHz (MTSC) + // - 0: 3.58MHz (NTSC) // - 1: 3.55MHz (PAL) // - 2: 4MHz // - 3: 3MHz @@ -373,7 +373,7 @@ struct DivSong { // - 2: FM: clock / 48, SSG: clock / 8 // - YM3526, YM3812, Y8950: // - bit 0-7: clock rate - // - 0: 3.58MHz (MTSC) + // - 0: 3.58MHz (NTSC) // - 1: 3.55MHz (PAL) // - 2: 4MHz // - 3: 3MHz @@ -381,7 +381,7 @@ struct DivSong { // - 5: 3.5MHz // - YMF262: // - bit 0-7: clock rate - // - 0: 14.32MHz (MTSC) + // - 0: 14.32MHz (NTSC) // - 1: 14.19MHz (PAL) // - 2: 14MHz // - 3: 16MHz @@ -389,7 +389,7 @@ struct DivSong { // - YMF289B: (TODO) // - bit 0-7: clock rate // - 0: 33.8688MHz - // - 1: 28.64MHz (MTSC) + // - 1: 28.64MHz (NTSC) // - 2: 28.38MHz (PAL) // - MSM6295: // - bit 0-6: clock rate @@ -420,7 +420,7 @@ struct DivSong { // - YMZ280B: // - bit 0-7: clock rate // - 0: 16.9344MHz - // - 1: 14.32MHz (MTSC) + // - 1: 14.32MHz (NTSC) // - 2: 14.19MHz (PAL) // - 3: 16MHz // - 4: 16.67MHz From 899fa9e494037769a305adfd51ed5b74984a1ffa Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Thu, 7 Jul 2022 08:34:04 +0900 Subject: [PATCH 023/515] Made new FM presets to include in Furnace's repo. --- instruments/FM/bass/Acoustic Bass.dmp | Bin 0 -> 51 bytes instruments/FM/bass/Electric Finger Bass.dmp | Bin 0 -> 51 bytes instruments/FM/bass/Electric Fretless Bass.dmp | Bin 0 -> 51 bytes instruments/FM/bass/Electric Picked Bass.dmp | Bin 0 -> 51 bytes instruments/FM/bass/Electric Slap Bass.dmp | Bin 0 -> 51 bytes instruments/FM/bass/SC-55 Synth Bass 1.dmp | Bin 0 -> 51 bytes instruments/FM/bass/SC-55 SynthBass101.dmp | Bin 0 -> 51 bytes instruments/FM/bass/Yamaha MU Synth Bass 2.dmp | Bin 0 -> 51 bytes 8 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/FM/bass/Acoustic Bass.dmp create mode 100644 instruments/FM/bass/Electric Finger Bass.dmp create mode 100644 instruments/FM/bass/Electric Fretless Bass.dmp create mode 100644 instruments/FM/bass/Electric Picked Bass.dmp create mode 100644 instruments/FM/bass/Electric Slap Bass.dmp create mode 100644 instruments/FM/bass/SC-55 Synth Bass 1.dmp create mode 100644 instruments/FM/bass/SC-55 SynthBass101.dmp create mode 100644 instruments/FM/bass/Yamaha MU Synth Bass 2.dmp diff --git a/instruments/FM/bass/Acoustic Bass.dmp b/instruments/FM/bass/Acoustic Bass.dmp new file mode 100644 index 0000000000000000000000000000000000000000..fb37c096d2dbf510c129efa4704d151ee2a75d56 GIT binary patch literal 51 zcmd;PVq^dURvAelW;O-}Mm`2cQE7I5Ad>}%h1FaBccIm literal 0 HcmV?d00001 diff --git a/instruments/FM/bass/SC-55 Synth Bass 1.dmp b/instruments/FM/bass/SC-55 Synth Bass 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..9ac496227582b59815395d3b7d5b5939cad5f126 GIT binary patch literal 51 xcmW;ASqcCk2tdK7iO>Re1L>q)z2$G1u7WEvb3{QMWTheSxU+>pxg=}!zXvR~0l@$O literal 0 HcmV?d00001 diff --git a/instruments/FM/bass/SC-55 SynthBass101.dmp b/instruments/FM/bass/SC-55 SynthBass101.dmp new file mode 100644 index 0000000000000000000000000000000000000000..2feefab3fad45e906cdf4dc318a80bb5182350d9 GIT binary patch literal 51 wcmW;AISv3I2mrwa)I=$0>3FJN_vj|$Ds)A&JPaKmS%kpjt`!aJlA7Uv4=w!x$^ZZW literal 0 HcmV?d00001 diff --git a/instruments/FM/bass/Yamaha MU Synth Bass 2.dmp b/instruments/FM/bass/Yamaha MU Synth Bass 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..08f8faca499186c66b47d5adba4c61930dae1ffe GIT binary patch literal 51 zcmWm2I}!j83_!sbpD@VK&?wyhmgsi2Iw1yR?vg5^kv5lU#;YOz@D}YjJ3W66E+(=8 Ai2wiq literal 0 HcmV?d00001 From af33876caf4c01ee9370507828183e558ab96191 Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Thu, 7 Jul 2022 08:34:53 +0900 Subject: [PATCH 024/515] To be used with acoustic string instruments. --- instruments/FM/effect/Acoustic String Slap SFX.dmp | Bin 0 -> 51 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/FM/effect/Acoustic String Slap SFX.dmp diff --git a/instruments/FM/effect/Acoustic String Slap SFX.dmp b/instruments/FM/effect/Acoustic String Slap SFX.dmp new file mode 100644 index 0000000000000000000000000000000000000000..a60d21e9cee9d279fd6c9e9ef9f91f6d0aab69c3 GIT binary patch literal 51 ycmWlO%MJh#48S^s;4rVV{r_K@q=%;MK`0609@-!{!h%F60Regd literal 0 HcmV?d00001 From b2134472ebc6426b3ef26316cdc2e0aa86181324 Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Thu, 7 Jul 2022 08:35:34 +0900 Subject: [PATCH 025/515] Made new FM presets to include in Furnace's repo. --- instruments/FM/bass/Basses.opm | 87 ++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 instruments/FM/bass/Basses.opm diff --git a/instruments/FM/bass/Basses.opm b/instruments/FM/bass/Basses.opm new file mode 100644 index 000000000..0b308cbf8 --- /dev/null +++ b/instruments/FM/bass/Basses.opm @@ -0,0 +1,87 @@ +//LFO: LFRQ AMD PMD WF NFRQ +//@:[Num] [Name] +//CH: PAN FL CON AMS PMS SLOT NE +//OP: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN + +// vgm offset = 000001d3, channels used = 1------- +@:0 Acoustic Bass +LFO: 0 0 0 0 0 +CH: 64 0 0 0 0 120 0 +M1: 25 18 14 6 3 28 0 5 6 0 0 +C1: 28 26 8 6 7 31 0 4 2 0 0 +M2: 27 7 0 6 15 21 0 1 1 0 0 +C2: 29 11 10 8 2 0 0 1 3 0 0 + +// vgm offset = 0000024e, channels used = 12------ +@:1 StringSlapSFX +LFO: 0 0 0 0 0 +CH: 64 7 4 0 0 120 0 +M1: 19 16 0 10 15 3 0 0 5 0 0 +C1: 31 20 0 9 15 4 0 7 0 0 0 +M2: 31 18 0 1 15 16 0 2 3 0 0 +C2: 31 17 0 9 15 30 0 1 3 0 0 + +// vgm offset = 0000093e, channels used = 1------- +@:2 Finger Bass +LFO: 0 0 0 0 0 +CH: 64 0 0 0 0 120 0 +M1: 31 15 0 11 1 31 0 3 3 0 0 +C1: 31 13 0 10 1 46 0 2 3 0 0 +M2: 31 10 0 10 1 24 0 1 3 0 0 +C2: 31 4 0 11 15 0 0 1 3 0 0 + +// vgm offset = 00000b30, channels used = 1------- +@:3 Fretless Bass +LFO: 0 0 0 0 0 +CH: 64 0 0 0 0 120 0 +M1: 31 0 0 3 15 21 0 1 5 0 0 +C1: 31 0 0 6 15 54 0 1 0 0 0 +M2: 31 0 0 7 11 26 0 1 5 0 0 +C2: 31 4 0 12 15 2 0 1 0 0 0 + +// vgm offset = 00000d2b, channels used = 1------- +@:4 Picked Bass +LFO: 0 0 0 0 0 +CH: 64 0 0 0 0 120 0 +M1: 31 18 1 11 3 24 0 5 3 0 0 +C1: 31 18 2 10 1 33 0 3 3 0 0 +M2: 31 10 3 10 1 33 0 1 3 0 0 +C2: 31 4 0 11 15 0 0 1 3 0 0 + +// vgm offset = 00000f2c, channels used = 1------- +@:5 Slap Bass +LFO: 0 0 0 0 0 +CH: 64 0 2 0 0 120 0 +M1: 31 20 0 3 15 0 1 0 0 0 0 +C1: 31 23 0 4 0 43 0 15 3 0 0 +M2: 31 17 0 1 2 16 1 1 3 0 0 +C2: 31 9 0 10 15 2 0 1 3 0 0 + +// vgm offset = 00001444, channels used = 1------- +@:6 Synth Bass 1 +LFO: 0 0 0 0 0 +CH: 64 6 2 0 0 120 0 +M1: 31 12 0 3 15 16 2 1 3 0 0 +C1: 31 10 0 4 15 127 0 1 0 0 0 +M2: 31 4 0 1 0 33 0 1 3 0 0 +C2: 31 9 0 11 15 0 0 1 3 0 0 + +// vgm offset = 0000189b, channels used = 1------- +@:7 SynthBass101 +LFO: 0 0 0 0 0 +CH: 64 5 2 0 0 120 0 +M1: 31 11 0 3 15 24 2 2 3 0 0 +C1: 31 10 0 4 15 127 0 1 0 0 0 +M2: 31 0 0 1 15 24 0 1 3 0 0 +C2: 31 9 0 11 15 0 0 1 3 0 0 + +// vgm offset = 00001d22, channels used = 1------- +@:8 Synth Bass 2 +LFO: 0 0 0 0 0 +CH: 64 5 4 0 0 120 0 +M1: 27 10 5 11 7 21 1 1 3 0 0 +C1: 31 0 15 11 7 3 0 1 3 0 0 +M2: 22 13 13 8 6 21 3 12 3 0 0 +C2: 31 15 16 11 8 13 0 2 3 0 0 + + From c2f1385703c70dddd82f26dfc22d7ab09e3714d9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Jul 2022 02:25:25 -0500 Subject: [PATCH 026/515] MSM6258: fix position not being reset in furnace s ample mode --- src/engine/platform/msm6258.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 731bf8f28..dc81950ef 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -121,6 +121,7 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { chan[c.chan].outVol=chan[c.chan].vol; } sample=ins->amiga.getSample(c.value); + samplePos=0; if (sample>=0 && samplesong.sampleLen) { //DivSample* s=parent->getSample(chan[c.chan].sample); if (c.value!=DIV_NOTE_NULL) { @@ -144,8 +145,8 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { //DivSample* s=parent->getSample(12*sampleBank+c.value%12); sample=12*sampleBank+c.value%12; samplePos=0; - msm->ctrl_w(1); - msm->ctrl_w(2); + rWrite(0,1); + rWrite(0,2); } break; } From c85b67b1da57a282cef3191de38a61ef6c51ccd0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Jul 2022 15:55:27 -0500 Subject: [PATCH 027/515] NES + chip -> Famicom + chip --- src/engine/sysDef.cpp | 12 ++++++------ src/gui/presets.cpp | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 04815866d..a5b689b2b 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -165,25 +165,25 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC6) { - return "NES + Konami VRC6"; + return "Famicom + Konami VRC6"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC7) { - return "NES + Konami VRC7"; + return "Famicom + Konami VRC7"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_OPLL) { - return "NES + Yamaha OPLL"; + return "Family Noraebang"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_FDS) { return "Famicom Disk System"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_N163) { - return "NES + Namco C163"; + return "Famicom + Namco C163"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_MMC5) { - return "NES + MMC5"; + return "Famicom + MMC5"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_AY8910) { - return "NES + Sunsoft 5B"; + return "Famicom + Sunsoft 5B"; } if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910) { diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index a3a494963..3774f232c 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -589,49 +589,49 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Konami VRC6", { + "Famicom with Konami VRC6", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_VRC6, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Konami VRC7", { + "Famicom with Konami VRC7", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_VRC7, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with MMC5", { + "Famicom with MMC5", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_MMC5, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Sunsoft 5B", { + "Famicom with Sunsoft 5B", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 32, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Namco C163", { + "Famicom with Namco C163", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_N163, 64, 0, 112, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Family Noraebang", { + "Comboy with Family Noraebang", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_OPLL, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Family Noraebang (drums mode)", { + "Comboy with Family Noraebang (drums mode)", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 @@ -2094,7 +2094,7 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "NES with Konami VRC7", { + "Famicom with Konami VRC7", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_VRC7, 64, 0, 0, 0 From 8104b717cdebdc1305e8d56e18d36d1b2a7201aa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Jul 2022 13:48:37 -0500 Subject: [PATCH 028/515] i knew it --- .../bass/{acoustic bass.dmp => Acoustic Bass 2.dmp} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename instruments/FM/bass/{acoustic bass.dmp => Acoustic Bass 2.dmp} (100%) diff --git a/instruments/FM/bass/acoustic bass.dmp b/instruments/FM/bass/Acoustic Bass 2.dmp similarity index 100% rename from instruments/FM/bass/acoustic bass.dmp rename to instruments/FM/bass/Acoustic Bass 2.dmp From 15ab8cc49bbf120dc821a2046cde39c9d7cf497d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 12 Jul 2022 18:45:54 -0500 Subject: [PATCH 029/515] YM2612: fix a CSM issue with key off --- src/engine/platform/genesisext.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 1c44bcfb9..bfe771a6d 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -418,6 +418,16 @@ void DivPlatformGenesisExt::tick(bool sysTick) { } } if (writeSomething) { + if (chan[7].active) { // CSM + writeMask^=0xf0; + } + /*printf( + "Mask: %c %c %c %c\n", + (writeMask&0x10)?'1':'-', + (writeMask&0x20)?'2':'-', + (writeMask&0x40)?'3':'-', + (writeMask&0x80)?'4':'-' + );*/ immWrite(0x28,writeMask); } } @@ -478,6 +488,13 @@ void DivPlatformGenesisExt::tick(bool sysTick) { if (chan[7].active) { // CSM writeMask^=0xf0; } + /*printf( + "Mask: %c %c %c %c\n", + (writeMask&0x10)?'1':'-', + (writeMask&0x20)?'2':'-', + (writeMask&0x40)?'3':'-', + (writeMask&0x80)?'4':'-' + );*/ immWrite(0x28,writeMask); } From 2f98da56756ccb82b940bc69f4591eed17de1e7d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 12 Jul 2022 19:15:10 -0500 Subject: [PATCH 030/515] GUI: sample editor icon improvements --- src/gui/sampleEdit.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 7264baed5..b684a0c77 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -335,7 +335,7 @@ void FurnaceGUI::drawSampleEdit() { if (silenceSize<0) silenceSize=0; if (silenceSize>16777215) silenceSize=16777215; } - if (ImGui::Button("Resize")) { + if (ImGui::Button("Go")) { int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?sample->samples:sampleSelStart; sample->prepareUndo(true); e->lockEngine([this,sample,pos]() { @@ -512,14 +512,14 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::SameLine(); - if (ImGui::Button(ICON_FA_VOLUME_UP "##PreviewSample")) { + if (ImGui::Button(ICON_FA_PLAY "##PreviewSample")) { e->previewSample(curSample); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Preview sample"); } ImGui::SameLine(); - if (ImGui::Button(ICON_FA_VOLUME_OFF "##StopSample")) { + if (ImGui::Button(ICON_FA_STOP "##StopSample")) { e->stopSamplePreview(); } if (ImGui::IsItemHovered()) { @@ -991,7 +991,7 @@ void FurnaceGUI::drawSampleEdit() { if (silenceSize<0) silenceSize=0; if (silenceSize>16777215) silenceSize=16777215; } - if (ImGui::Button("Resize")) { + if (ImGui::Button("Go")) { int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?sample->samples:sampleSelStart; sample->prepareUndo(true); e->lockEngine([this,sample,pos]() { From 936a95c1123780f4eff04058b20dd02d579c86b2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 13 Jul 2022 16:47:09 -0500 Subject: [PATCH 031/515] fix build on Arch not my fault that PipeWire is shipped in a broken state --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5312692a6..8f0c46698 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,11 @@ if (USE_SDL2) set(SDL_SHARED OFF CACHE BOOL "Force no dynamically-linked SDL" FORCE) set(SDL_STATIC ON CACHE BOOL "Force statically-linked SDL" FORCE) endif() + # https://github.com/libsdl-org/SDL/issues/5535 + # disable PipeWire support due to an unfixable bug: + # Looks like their headers have a C90 violation... I imagine they're probably on C99 so not the craziest bug in the world. Definitely file this at the PipeWire repository as well so they know this is out there. + set(SDL_PIPEWIRE OFF CACHE BOOL "Use Pipewire audio" FORCE) + # https://github.com/libsdl-org/SDL/issues/1481 # On 2014-06-22 17:15:50 +0000, Sam Lantinga wrote: # If you link SDL statically, you also need to define HAVE_LIBC so it builds with the C runtime that your application uses. From 5f92a6ffa6fe41f1b229c00a3a46f5fcbc56f270 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 14 Jul 2022 00:14:33 -0500 Subject: [PATCH 032/515] possibly fix major issue with NFD --- extern/nfd-modified/src/nfd_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp index 9273bb1e7..b4fa5a5fa 100644 --- a/extern/nfd-modified/src/nfd_win.cpp +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -368,7 +368,7 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath ) { - if ( !defaultPath || strlen(defaultPath) == 0 ) + if ( !defaultPath || strlen(defaultPath) == 0 || strcmp(defaultPath,"\\")==0 ) return NFD_OKAY; wchar_t *defaultPathW = {0}; From 28a2db7a57ac3c8a3586144c5697d2eaeb4ee820 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 14 Jul 2022 01:59:55 -0500 Subject: [PATCH 033/515] GUI: system file picker error feedback --- src/gui/fileDialog.cpp | 20 +++++++++++++++----- src/gui/fileDialog.h | 3 +++ src/gui/gui.cpp | 7 +++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index f64f72cbb..bd54bf0fe 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -25,9 +25,10 @@ struct NFDState { }; // TODO: filter -void _nfdThread(const NFDState state, std::atomic* ok, String* result) { +void _nfdThread(const NFDState state, std::atomic* ok, String* result, bool* errorOutput) { nfdchar_t* out=NULL; nfdresult_t ret=NFD_CANCEL; + errorOutput=false; if (state.isSave) { ret=NFD_SaveDialog(state.filter,state.path.c_str(),&out,state.clickCallback); @@ -49,6 +50,7 @@ void _nfdThread(const NFDState state, std::atomic* ok, String* result) { case NFD_ERROR: (*result)=""; logE("NFD error! %s\n",NFD_GetError()); + (*errorOutput)=true; break; default: logE("NFD unknown return code %d!\n",ret); @@ -68,14 +70,16 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c #ifdef USE_NFD dialogOK=false; #ifdef NFD_NON_THREADED - _nfdThread(NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult); + _nfdThread(NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult,&hasError); #else - dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult); + dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult,&hasError); #endif #else dialogO=new pfd::open_file(header,path,filter); + hasError=!pfd::settings::available(); #endif } else { + hasError=false; ImGuiFileDialog::Instance()->DpiScale=dpiScale; ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,0,clickCallback); } @@ -92,14 +96,16 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c #ifdef USE_NFD dialogOK=false; #ifdef NFD_NON_THREADED - _nfdThread(NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult); + _nfdThread(NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult,&hasError); #else - dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult); + dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult,&hasError); #endif #else dialogS=new pfd::save_file(header,path,filter); + hasError=!pfd::settings::available(); #endif } else { + hasError=false; ImGuiFileDialog::Instance()->DpiScale=dpiScale; ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite); } @@ -193,6 +199,10 @@ bool FurnaceGUIFileDialog::isOpen() { return opened; } +bool FurnaceGUIFileDialog::isError() { + return hasError; +} + String FurnaceGUIFileDialog::getPath() { if (sysDialog) { if (curPath.size()>1) { diff --git a/src/gui/fileDialog.h b/src/gui/fileDialog.h index 6724eb951..f3edd2884 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -28,6 +28,7 @@ class FurnaceGUIFileDialog { bool sysDialog; bool opened; bool saving; + bool hasError; String curPath; String fileName; #ifdef USE_NFD @@ -46,12 +47,14 @@ class FurnaceGUIFileDialog { void close(); bool render(const ImVec2& min, const ImVec2& max); bool isOpen(); + bool isError(); String getPath(); String getFileName(); explicit FurnaceGUIFileDialog(bool system): sysDialog(system), opened(false), saving(false), + hasError(false), dialogO(NULL), dialogS(NULL) {} }; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 642572d38..c6a58c083 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3221,6 +3221,13 @@ bool FurnaceGUI::loop() { workingDirROM=fileDialog->getPath()+DIR_SEPARATOR_STR; break; } + if (fileDialog->isError()) { +#if defined(_WIN32) || defined(__APPLE__) + showError("there was an error in the file dialog! you may want to report this issue to:\nhttps://github.com/tildearrow/furnace/issues\ncheck the Log Viewer (window > log viewer) for more information.\n\nfor now please disable the system file picker in Settings > General."); +#else + showError("Zenity/KDialog not available!\nplease install one of these, or disable the system file picker in Settings > General."); +#endif + } if (fileDialog->accepted()) { fileName=fileDialog->getFileName(); if (fileName!="") { From bad11bc21e38466690e1c230c17b207ac0a4b95c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 14 Jul 2022 02:00:51 -0500 Subject: [PATCH 034/515] whoops --- src/gui/fileDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index bd54bf0fe..0bcc00a4b 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -28,7 +28,7 @@ struct NFDState { void _nfdThread(const NFDState state, std::atomic* ok, String* result, bool* errorOutput) { nfdchar_t* out=NULL; nfdresult_t ret=NFD_CANCEL; - errorOutput=false; + (*errorOutput)=false; if (state.isSave) { ret=NFD_SaveDialog(state.filter,state.path.c_str(),&out,state.clickCallback); From 6f90124d82f8cb8ef20724e27998367d23cbea41 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 14 Jul 2022 22:15:14 -0500 Subject: [PATCH 035/515] issue #588, part 1 --- CMakeLists.txt | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f0c46698..41818e96d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,8 @@ set(USE_SDL2_DEFAULT ON) set(USE_SNDFILE_DEFAULT ON) set(SYSTEM_SDL2_DEFAULT OFF) +include(CheckIncludeFile) + if (ANDROID) set(USE_RTMIDI_DEFAULT OFF) set(USE_BACKWARD_DEFAULT OFF) @@ -31,7 +33,17 @@ if (ANDROID) endif() else() set(USE_RTMIDI_DEFAULT ON) - set(USE_BACKWARD_DEFAULT ON) + CHECK_INCLUDE_FILE(execinfo.h EXECINFO_FOUND) + if (EXECINFO_FOUND) + set(USE_BACKWARD_DEFAULT ON) + else() + find_library(EXECINFO_IS_LIBRARY execinfo) + if (EXECINFO_IS_LIBRARY) + set(USE_BACKWARD_DEFAULT ON) + else() + set(USE_BACKWARD_DEFAULT OFF) + endif() + endif() endif() find_package(PkgConfig) @@ -548,8 +560,6 @@ endif() if (NOT WIN32 AND NOT APPLE) list(APPEND GUI_SOURCES src/gui/icon.c) - include(CheckIncludeFile) - CHECK_INCLUDE_FILE(sys/io.h SYS_IO_FOUND) CHECK_INCLUDE_FILE(linux/input.h LINUX_INPUT_FOUND) CHECK_INCLUDE_FILE(linux/kd.h LINUX_KD_FOUND) @@ -574,6 +584,10 @@ if (USE_BACKWARD) if (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") list(APPEND DEPENDENCIES_LIBRARIES dbghelp psapi) endif() + find_library(EXECINFO_IS_LIBRARY execinfo) + if (EXECINFO_IS_LIBRARY) + list(APPEND DEPENDENCIES_LIBRARIES execinfo) + endif() message(STATUS "Using backward-cpp") else() message(STATUS "Not using backward-cpp") From 3df5a6e2b6a0f6b4171280d4b172f2633f6c5f21 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 14 Jul 2022 22:17:05 -0500 Subject: [PATCH 036/515] issue #588, part 2 --- extern/backward/backward.hpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/extern/backward/backward.hpp b/extern/backward/backward.hpp index 5edda65ad..04032a4dc 100644 --- a/extern/backward/backward.hpp +++ b/extern/backward/backward.hpp @@ -221,6 +221,14 @@ #include #include #include +// https://github.com/tildearrow/furnace/issues/588 +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#else +#include +#endif #if BACKWARD_HAS_BFD == 1 // NOTE: defining PACKAGE{,_VERSION} is required before including @@ -233,13 +241,6 @@ #define PACKAGE_VERSION #endif #include -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#include -#undef _GNU_SOURCE -#else -#include -#endif #endif #if BACKWARD_HAS_DW == 1 @@ -254,13 +255,6 @@ #include #include #include -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#include -#undef _GNU_SOURCE -#else -#include -#endif #endif #if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) From d085f76c7f97da826712b62fe0b13025f42b957b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 14 Jul 2022 22:29:04 -0500 Subject: [PATCH 037/515] issue #588, part 3 add check for the existence of inb() and outb() --- CMakeLists.txt | 9 +++++++-- src/check/check_sysIO.c | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 src/check/check_sysIO.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 41818e96d..977f194aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -564,8 +564,13 @@ if (NOT WIN32 AND NOT APPLE) CHECK_INCLUDE_FILE(linux/input.h LINUX_INPUT_FOUND) CHECK_INCLUDE_FILE(linux/kd.h LINUX_KD_FOUND) if (SYS_IO_FOUND) - list(APPEND DEPENDENCIES_DEFINES HAVE_SYS_IO) - message(STATUS "PC speaker output: outb()") + try_compile(HAVE_INOUTB ${CMAKE_BINARY_DIR}/check SOURCES ${CMAKE_SOURCE_DIR}/src/check/check_sysIO.c) + if (HAVE_INOUTB) + list(APPEND DEPENDENCIES_DEFINES HAVE_SYS_IO) + message(STATUS "PC speaker output: outb()") + else() + message(STATUS "sys/io.h found but inb()/outb() not present") + endif() endif() if (LINUX_INPUT_FOUND) list(APPEND DEPENDENCIES_DEFINES HAVE_LINUX_INPUT) diff --git a/src/check/check_sysIO.c b/src/check/check_sysIO.c new file mode 100644 index 000000000..653721e6d --- /dev/null +++ b/src/check/check_sysIO.c @@ -0,0 +1,6 @@ +#include + +int main(int, char**) { + inb(0x61); + outb(0x00,0x61); +} From 666b0d581a274856157366aa7f377b6a2c541737 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Jul 2022 02:23:16 -0500 Subject: [PATCH 038/515] GUI: add multi-selection capability to file dialog --- src/gui/debugWindow.cpp | 14 +++++++++ src/gui/fileDialog.cpp | 65 +++++++++++++++++++++++++---------------- src/gui/fileDialog.h | 6 ++-- src/gui/gui.cpp | 64 +++++++++++++++++++++++++++++++++++++++- src/gui/gui.h | 8 +++-- 5 files changed, 126 insertions(+), 31 deletions(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 22527a7b8..d9739f68d 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -260,6 +260,20 @@ void FurnaceGUI::drawDebug() { ImGui::Unindent(); ImGui::TreePop(); } + if (ImGui::TreeNode("File Selection Test")) { + if (ImGui::Button("Test Open")) { + openFileDialog(GUI_FILE_TEST_OPEN); + } + ImGui::SameLine(); + if (ImGui::Button("Test Open Multi")) { + openFileDialog(GUI_FILE_TEST_OPEN_MULTI); + } + ImGui::SameLine(); + if (ImGui::Button("Test Save")) { + openFileDialog(GUI_FILE_TEST_SAVE); + } + ImGui::TreePop(); + } if (ImGui::TreeNode("Playground")) { if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0; if (ImGui::BeginCombo("System",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) { diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index 0bcc00a4b..d59a3cd03 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -10,13 +10,14 @@ #ifdef USE_NFD struct NFDState { - bool isSave; + bool isSave, allowMultiple; String header; std::vector filter; String path; FileDialogSelectCallback clickCallback; - NFDState(bool save, String h, std::vector filt, String pa, FileDialogSelectCallback cc): + NFDState(bool save, String h, std::vector filt, String pa, FileDialogSelectCallback cc, bool multi): isSave(save), + allowMultiple(multi), header(h), filter(filt), path(pa), @@ -61,7 +62,7 @@ void _nfdThread(const NFDState state, std::atomic* ok, String* result, boo } #endif -bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback) { +bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback, bool allowMultiple) { if (opened) return false; saving=false; curPath=path; @@ -70,18 +71,18 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c #ifdef USE_NFD dialogOK=false; #ifdef NFD_NON_THREADED - _nfdThread(NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult,&hasError); + _nfdThread(NFDState(false,header,filter,path,clickCallback,allowMultiple),&dialogOK,&nfdResult,&hasError); #else - dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback),&dialogOK,&nfdResult,&hasError); + dialogO=new std::thread(_nfdThread,NFDState(false,header,filter,path,clickCallback,allowMultiple),&dialogOK,&nfdResult,&hasError); #endif #else - dialogO=new pfd::open_file(header,path,filter); + dialogO=new pfd::open_file(header,path,filter,allowMultiple?(pfd::opt::multiselect):(pfd::opt::none)); hasError=!pfd::settings::available(); #endif } else { hasError=false; ImGuiFileDialog::Instance()->DpiScale=dpiScale; - ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,0,clickCallback); + ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,allowMultiple?999:1,nullptr,0,clickCallback); } opened=true; return true; @@ -96,9 +97,9 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c #ifdef USE_NFD dialogOK=false; #ifdef NFD_NON_THREADED - _nfdThread(NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult,&hasError); + _nfdThread(NFDState(true,header,filter,path,NULL,false),&dialogOK,&nfdResult,&hasError); #else - dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL),&dialogOK,&nfdResult,&hasError); + dialogS=new std::thread(_nfdThread,NFDState(true,header,filter,path,NULL,false),&dialogOK,&nfdResult,&hasError); #endif #else dialogS=new pfd::save_file(header,path,filter); @@ -115,7 +116,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c bool FurnaceGUIFileDialog::accepted() { if (sysDialog) { - return (fileName!=""); + return (!fileName.empty()); } else { return ImGuiFileDialog::Instance()->IsOk(); } @@ -153,10 +154,15 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (sysDialog) { #ifdef USE_NFD if (dialogOK) { - fileName=nfdResult; - size_t dsPos=fileName.rfind(DIR_SEPARATOR); - if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos); - logD("returning %s",fileName.c_str()); + fileName.clear(); + fileName.push_back(nfdResult); + if (!fileName.empty()) { + size_t dsPos=fileName[0].rfind(DIR_SEPARATOR); + if (dsPos!=String::npos) curPath=fileName[0].substr(0,dsPos); + } + for (String& i: fileName) { + logD("- returning %s",i); + } dialogOK=false; return true; } @@ -165,10 +171,11 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (saving) { if (dialogS!=NULL) { if (dialogS->ready(0)) { - fileName=dialogS->result(); - size_t dsPos=fileName.rfind(DIR_SEPARATOR); - if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos); - logD("returning %s",fileName.c_str()); + fileName.clear(); + fileName.push_back(dialogS->result()); + size_t dsPos=fileName[0].rfind(DIR_SEPARATOR); + if (dsPos!=String::npos) curPath=fileName[0].substr(0,dsPos); + logD("returning %s",fileName[0]); return true; } } @@ -176,13 +183,19 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (dialogO!=NULL) { if (dialogO->ready(0)) { if (dialogO->result().empty()) { - fileName=""; + fileName.clear(); logD("returning nothing"); } else { - fileName=dialogO->result()[0]; - size_t dsPos=fileName.rfind(DIR_SEPARATOR); - if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos); - logD("returning %s",fileName.c_str()); + fileName=dialogO->result(); + if (fileName.empty()) { + // don't touch + } else { + size_t dsPos=fileName[0].rfind(DIR_SEPARATOR); + if (dsPos!=String::npos) curPath=fileName[0].substr(0,dsPos); + for (String& i: fileName) { + logD("- returning %s",i); + } + } } return true; } @@ -217,10 +230,12 @@ String FurnaceGUIFileDialog::getPath() { } } -String FurnaceGUIFileDialog::getFileName() { +std::vector& FurnaceGUIFileDialog::getFileName() { if (sysDialog) { return fileName; } else { - return ImGuiFileDialog::Instance()->GetFilePathName(); + fileName.clear(); + fileName.push_back(ImGuiFileDialog::Instance()->GetFilePathName()); + return fileName; } } diff --git a/src/gui/fileDialog.h b/src/gui/fileDialog.h index f3edd2884..54b83c28a 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -30,7 +30,7 @@ class FurnaceGUIFileDialog { bool saving; bool hasError; String curPath; - String fileName; + std::vector fileName; #ifdef USE_NFD std::thread* dialogO; std::thread* dialogS; @@ -41,7 +41,7 @@ class FurnaceGUIFileDialog { pfd::save_file* dialogS; #endif public: - bool openLoad(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback=NULL); + bool openLoad(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale, FileDialogSelectCallback clickCallback=NULL, bool allowMultiple=false); bool openSave(String header, std::vector filter, const char* noSysFilter, String path, double dpiScale); bool accepted(); void close(); @@ -49,7 +49,7 @@ class FurnaceGUIFileDialog { bool isOpen(); bool isError(); String getPath(); - String getFileName(); + std::vector& getFileName(); explicit FurnaceGUIFileDialog(bool system): sysDialog(system), opened(false), diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c6a58c083..32e698073 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1495,6 +1495,43 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { dpiScale ); break; + case GUI_FILE_TEST_OPEN: + if (!dirExists(workingDirTest)) workingDirTest=getHomeDir(); + hasOpened=fileDialog->openLoad( + "Open Test", + {"compatible files", "*.fur *.dmf *.mod", + "another option", "*.wav *.ttf", + "all files", ".*"}, + "compatible files{.fur,.dmf,.mod},another option{.wav,.ttf},.*", + workingDirTest, + dpiScale + ); + break; + case GUI_FILE_TEST_OPEN_MULTI: + if (!dirExists(workingDirTest)) workingDirTest=getHomeDir(); + hasOpened=fileDialog->openLoad( + "Open Test (Multi)", + {"compatible files", "*.fur *.dmf *.mod", + "another option", "*.wav *.ttf", + "all files", ".*"}, + "compatible files{.fur,.dmf,.mod},another option{.wav,.ttf},.*", + workingDirTest, + dpiScale, + NULL, + true + ); + break; + case GUI_FILE_TEST_SAVE: + if (!dirExists(workingDirTest)) workingDirTest=getHomeDir(); + hasOpened=fileDialog->openSave( + "Save Test", + {"Furnace song", "*.fur", + "DefleMask module", "*.dmf"}, + "Furnace song{.fur},DefleMask module{.dmf}", + workingDirTest, + dpiScale + ); + break; } if (hasOpened) curFileDialog=type; //ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_NavEnableKeyboard; @@ -3220,6 +3257,11 @@ bool FurnaceGUI::loop() { case GUI_FILE_MU5_ROM_OPEN: workingDirROM=fileDialog->getPath()+DIR_SEPARATOR_STR; break; + case GUI_FILE_TEST_OPEN: + case GUI_FILE_TEST_OPEN_MULTI: + case GUI_FILE_TEST_SAVE: + workingDirTest=fileDialog->getPath()+DIR_SEPARATOR_STR; + break; } if (fileDialog->isError()) { #if defined(_WIN32) || defined(__APPLE__) @@ -3229,7 +3271,11 @@ bool FurnaceGUI::loop() { #endif } if (fileDialog->accepted()) { - fileName=fileDialog->getFileName(); + if (fileDialog->getFileName().empty()) { + fileName=""; + } else { + fileName=fileDialog->getFileName()[0]; + } if (fileName!="") { if (curFileDialog==GUI_FILE_SAVE) { // we can't tell whether the user chose .dmf or .fur in the system file picker @@ -3468,6 +3514,20 @@ bool FurnaceGUI::loop() { case GUI_FILE_MU5_ROM_OPEN: settings.mu5Path=copyOfName; break; + case GUI_FILE_TEST_OPEN: + showWarning(fmt::sprintf("You opened: %s",copyOfName),GUI_WARN_GENERIC); + break; + case GUI_FILE_TEST_OPEN_MULTI: { + String msg="You opened:"; + for (String i: fileDialog->getFileName()) { + msg+=fmt::sprintf("\n- %s",i); + } + showWarning(msg,GUI_WARN_GENERIC); + break; + } + case GUI_FILE_TEST_SAVE: + showWarning(fmt::sprintf("You saved: %s",copyOfName),GUI_WARN_GENERIC); + break; } curFileDialog=GUI_FILE_OPEN; } @@ -4018,6 +4078,7 @@ bool FurnaceGUI::init() { workingDirColors=e->getConfString("lastDirColors",workingDir); workingDirKeybinds=e->getConfString("lastDirKeybinds",workingDir); workingDirLayout=e->getConfString("lastDirLayout",workingDir); + workingDirTest=e->getConfString("lastDirTest",workingDir); editControlsOpen=e->getConfBool("editControlsOpen",true); ordersOpen=e->getConfBool("ordersOpen",true); @@ -4255,6 +4316,7 @@ bool FurnaceGUI::finish() { e->setConf("lastDirColors",workingDirColors); e->setConf("lastDirKeybinds",workingDirKeybinds); e->setConf("lastDirLayout",workingDirLayout); + e->setConf("lastDirTest",workingDirTest); // commit last open windows e->setConf("editControlsOpen",editControlsOpen); diff --git a/src/gui/gui.h b/src/gui/gui.h index b3393a5a9..2966d594e 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -277,7 +277,11 @@ enum FurnaceGUIFileDialogs { GUI_FILE_EXPORT_LAYOUT, GUI_FILE_YRW801_ROM_OPEN, GUI_FILE_TG100_ROM_OPEN, - GUI_FILE_MU5_ROM_OPEN + GUI_FILE_MU5_ROM_OPEN, + + GUI_FILE_TEST_OPEN, + GUI_FILE_TEST_OPEN_MULTI, + GUI_FILE_TEST_SAVE }; enum FurnaceGUIWarnings { @@ -943,7 +947,7 @@ class FurnaceGUI { bool updateSampleTex; String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; - String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM; + String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM, workingDirTest; String mmlString[32]; String mmlStringW; From 96b7e5d3538c11c7876f56244b229fc3fbfa51df Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Jul 2022 01:52:15 -0500 Subject: [PATCH 039/515] GUI: implement multi sel on NFD and IGFD --- src/gui/fileDialog.cpp | 39 +++++++++++++++++++++++++++++---------- src/gui/fileDialog.h | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index d59a3cd03..8d524ab46 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -26,36 +26,48 @@ struct NFDState { }; // TODO: filter -void _nfdThread(const NFDState state, std::atomic* ok, String* result, bool* errorOutput) { +void _nfdThread(const NFDState state, std::atomic* ok, std::vector* result, bool* errorOutput) { nfdchar_t* out=NULL; nfdresult_t ret=NFD_CANCEL; (*errorOutput)=false; + nfdpathset_t paths; + + result->clear(); if (state.isSave) { ret=NFD_SaveDialog(state.filter,state.path.c_str(),&out,state.clickCallback); } else { - ret=NFD_OpenDialog(state.filter,state.path.c_str(),&out,state.clickCallback); + if (state.allowMultiple) { + ret=NFD_OpenDialogMultiple(state.filter,state.path.c_str(),&paths,state.clickCallback); + } else { + ret=NFD_OpenDialog(state.filter,state.path.c_str(),&out,state.clickCallback); + } } switch (ret) { case NFD_OKAY: - if (out!=NULL) { - (*result)=out; + if (state.allowMultiple) { + logD("pushing multi path"); + for (size_t i=0; ipush_back(String(NFD_PathSet_GetPath(&paths,i))); + } + NFD_PathSet_Free(&paths); } else { - (*result)=""; + logD("pushing single path"); + if (out!=NULL) { + logD("we have it"); + result->push_back(String(out)); + } } break; case NFD_CANCEL: - (*result)=""; break; case NFD_ERROR: - (*result)=""; logE("NFD error! %s\n",NFD_GetError()); (*errorOutput)=true; break; default: logE("NFD unknown return code %d!\n",ret); - (*result)=""; break; } (*ok)=true; @@ -155,7 +167,7 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { #ifdef USE_NFD if (dialogOK) { fileName.clear(); - fileName.push_back(nfdResult); + fileName=nfdResult; if (!fileName.empty()) { size_t dsPos=fileName[0].rfind(DIR_SEPARATOR); if (dsPos!=String::npos) curPath=fileName[0].substr(0,dsPos); @@ -235,7 +247,14 @@ std::vector& FurnaceGUIFileDialog::getFileName() { return fileName; } else { fileName.clear(); - fileName.push_back(ImGuiFileDialog::Instance()->GetFilePathName()); + if (saving) { + fileName.push_back(ImGuiFileDialog::Instance()->GetFilePathName()); + } else { + for (auto& i: ImGuiFileDialog::Instance()->GetSelection()) { + fileName.push_back(i.second); + } + } + // return fileName; } } diff --git a/src/gui/fileDialog.h b/src/gui/fileDialog.h index 54b83c28a..7990b0370 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -35,7 +35,7 @@ class FurnaceGUIFileDialog { std::thread* dialogO; std::thread* dialogS; std::atomic dialogOK; - String nfdResult; + std::vector nfdResult; #else pfd::open_file* dialogO; pfd::save_file* dialogS; From 707dc30f1558c1cd61741b94a5e75d34df3062e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Jul 2022 00:05:56 -0500 Subject: [PATCH 040/515] Revert "Fix issue #567: LFO disable/enable behavior for YM2151." --- src/engine/platform/arcade.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 29a2f67d0..41042cd5c 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -172,7 +172,7 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si w.addrOrVal=true; } } - + OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,NULL,NULL,NULL,NULL); @@ -182,13 +182,13 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si for (int i=0; i<8; i++) { oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]; } - + if (o[0]<-32768) o[0]=-32768; if (o[0]>32767) o[0]=32767; if (o[1]<-32768) o[1]=-32768; if (o[1]>32767) o[1]=32767; - + bufL[h]=o[0]; bufR[h]=o[1]; } @@ -211,7 +211,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz delay=1; } } - + fm_ymfm->generate(&out_ymfm); for (int i=0; i<8; i++) { @@ -225,7 +225,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz os[1]=out_ymfm.data[1]; if (os[1]<-32768) os[1]=-32768; if (os[1]>32767) os[1]=32767; - + bufL[h]=os[0]; bufR[h]=os[1]; } @@ -616,12 +616,6 @@ int DivPlatformArcade::dispatch(DivCommand c) { break; } case DIV_CMD_FM_LFO: { - if(c.value==0) { - rWrite(0x01,0x02); - } - else { - rWrite(0x01,0x00); - } rWrite(0x18,c.value); break; } @@ -945,8 +939,6 @@ void DivPlatformArcade::reset() { pmDepth=0x7f; //rWrite(0x18,0x10); - immWrite(0x01,0x02); // LFO Off - immWrite(0x18,0x00); // LFO Freq Off immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); //rWrite(0x1b,0x00); From 60a52d3b9f0b29173c10d74c880c70f7696d0f7d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Jul 2022 00:06:04 -0500 Subject: [PATCH 041/515] Revert "Revert "Fix issue #567: LFO disable/enable behavior for YM2151."" --- src/engine/platform/arcade.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 41042cd5c..29a2f67d0 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -172,7 +172,7 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si w.addrOrVal=true; } } - + OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,NULL,NULL,NULL,NULL); @@ -182,13 +182,13 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si for (int i=0; i<8; i++) { oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]; } - + if (o[0]<-32768) o[0]=-32768; if (o[0]>32767) o[0]=32767; if (o[1]<-32768) o[1]=-32768; if (o[1]>32767) o[1]=32767; - + bufL[h]=o[0]; bufR[h]=o[1]; } @@ -211,7 +211,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz delay=1; } } - + fm_ymfm->generate(&out_ymfm); for (int i=0; i<8; i++) { @@ -225,7 +225,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz os[1]=out_ymfm.data[1]; if (os[1]<-32768) os[1]=-32768; if (os[1]>32767) os[1]=32767; - + bufL[h]=os[0]; bufR[h]=os[1]; } @@ -616,6 +616,12 @@ int DivPlatformArcade::dispatch(DivCommand c) { break; } case DIV_CMD_FM_LFO: { + if(c.value==0) { + rWrite(0x01,0x02); + } + else { + rWrite(0x01,0x00); + } rWrite(0x18,c.value); break; } @@ -939,6 +945,8 @@ void DivPlatformArcade::reset() { pmDepth=0x7f; //rWrite(0x18,0x10); + immWrite(0x01,0x02); // LFO Off + immWrite(0x18,0x00); // LFO Freq Off immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); //rWrite(0x1b,0x00); From a4741861cef7e8162b0398a5fe46d781b2ecc8cf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Jul 2022 15:57:06 -0500 Subject: [PATCH 042/515] fix audio output being reset on cmd line export --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index e68208ea8..d49764cc3 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3081,7 +3081,7 @@ bool DivEngine::deinitAudioBackend() { output->quit(); delete output; output=NULL; - audioEngine=DIV_AUDIO_NULL; + //audioEngine=DIV_AUDIO_NULL; } return true; } From cd7b333b2df8ae6727e500a4f059fadfdff5e04d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Jul 2022 17:01:19 -0500 Subject: [PATCH 043/515] introduce a benchmark mode --- src/asm/6502/macroInt.s | 32 ++++++++++++++++++++++ src/engine/engine.cpp | 60 +++++++++++++++++++++++++++++++++++++++-- src/engine/engine.h | 4 +++ src/main.cpp | 25 +++++++++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/asm/6502/macroInt.s diff --git a/src/asm/6502/macroInt.s b/src/asm/6502/macroInt.s new file mode 100644 index 000000000..c115a807e --- /dev/null +++ b/src/asm/6502/macroInt.s @@ -0,0 +1,32 @@ +macroState=$50 ; pointer to state +macroAddr=$52 ; pointer to address + +; macro state takes 4 bytes +; macroPos bits: +; 7: had +; 6: will + +; x: macro +macroIntRun: + lda macroAddr,x + ora macroAddr+1,x + beq :+ + + ; do macro +: rts + +; set the macro address, then call +; x: macro +macroIntInit: + lda #0 + sta macroState,x + sta macroPos,x + txa + rol + tax + lda macroAddr,x + ora macroAddr+1,x + beq :+ + lda #$40 + sta macroState,x +: rts diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index d49764cc3..9b3fa06fd 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -36,6 +36,7 @@ #include "../audio/jack.h" #endif #include +#include #ifdef HAVE_SNDFILE #include "sfWrapper.h" #endif @@ -181,6 +182,63 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) { } } +#define EXPORT_BUFSIZE 2048 + +double DivEngine::benchmarkPlayback() { + float* outBuf[2]; + outBuf[0]=new float[EXPORT_BUFSIZE]; + outBuf[1]=new float[EXPORT_BUFSIZE]; + + curOrder=0; + prevOrder=0; + remainingLoops=1; + playSub(false); + + std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now(); + + // benchmark + while (playing) { + nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); + } + + std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); + + delete[] outBuf[0]; + delete[] outBuf[1]; + + double t=(double)(std::chrono::duration_cast(timeEnd-timeStart).count())/1000000.0; + printf("[RESULT] %fs\n",t); + return t; +} + +double DivEngine::benchmarkSeek() { + double t[20]; + curOrder=curSubSong->ordersLen-1; + prevOrder=curSubSong->ordersLen-1; + + // benchmark + for (int i=0; i<20; i++) { + std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now(); + playSub(false); + std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); + t[i]=(double)(std::chrono::duration_cast(timeEnd-timeStart).count())/1000000.0; + printf("[#%d] %fs\n",i+1,t[i]); + } + + double tMin=DBL_MAX; + double tMax=0.0; + double tAvg=0.0; + for (int i=0; i<20; i++) { + if (t[i]tMax) tMax=t[i]; + tAvg+=t[i]; + } + tAvg/=20.0; + + printf("[RESULT] min %fs max %fs average %fs\n",tMin,tMax,tAvg); + return tAvg; +} + void _runExportThread(DivEngine* caller) { caller->runExportThread(); } @@ -189,8 +247,6 @@ bool DivEngine::isExporting() { return exporting; } -#define EXPORT_BUFSIZE 2048 - #ifdef HAVE_SNDFILE void DivEngine::runExportThread() { size_t fadeOutSamples=got.rate*exportFadeOut; diff --git a/src/engine/engine.h b/src/engine/engine.h index 5f5ab1a35..4bf4cb65d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -477,6 +477,10 @@ class DivEngine { // notify wavetable change void notifyWaveChange(int wave); + // benchmark (returns time in seconds) + double benchmarkPlayback(); + double benchmarkSeek(); + // returns the minimum VGM version which may carry the specified system, or 0 if none. int minVGMVersion(DivSystem which); diff --git a/src/main.cpp b/src/main.cpp index 1f5f9560a..970bc784f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,7 @@ FurnaceGUI g; String outName; String vgmOutName; int loops=1; +int benchMode=0; DivAudioExportModes outMode=DIV_EXPORT_MODE_ONE; #ifdef HAVE_GUI @@ -220,6 +221,19 @@ TAParamResult pOutMode(String val) { return TA_PARAM_SUCCESS; } +TAParamResult pBenchmark(String val) { + if (val=="render") { + benchMode=1; + } else if (val=="seek") { + benchMode=2; + } else { + logE("invalid value for benchmark! valid values are: render and seek."); + return TA_PARAM_ERROR; + } + e.setAudio(DIV_AUDIO_DUMMY); + return TA_PARAM_SUCCESS; +} + TAParamResult pOutput(String val) { outName=val; e.setAudio(DIV_AUDIO_DUMMY); @@ -254,6 +268,8 @@ void initParams() { params.push_back(TAParam("l","loops",true,pLoops,"","set number of loops (-1 means loop forever)")); params.push_back(TAParam("o","outmode",true,pOutMode,"one|persys|perchan","set file output mode")); + params.push_back(TAParam("B","benchmark",true,pBenchmark,"render|seek","run performance test")); + params.push_back(TAParam("V","version",false,pVersion,"","view information about Furnace.")); params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer.")); } @@ -414,6 +430,15 @@ int main(int argc, char** argv) { displayEngineFailError=true; } } + if (benchMode) { + logI("starting benchmark!"); + if (benchMode==2) { + e.benchmarkSeek(); + } else { + e.benchmarkPlayback(); + } + return 0; + } if (outName!="" || vgmOutName!="") { if (vgmOutName!="") { SafeWriter* w=e.saveVGM(); From dff7c61b79213b8f33f0d3c7f22f161ce738f83d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 20 Jul 2022 00:32:06 -0500 Subject: [PATCH 044/515] GUI: add option to disable threaded input --- src/gui/gui.cpp | 9 ++++++++- src/gui/gui.h | 2 ++ src/gui/settings.cpp | 11 +++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 32e698073..14b1b99e3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2479,7 +2479,13 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { } bool FurnaceGUI::loop() { - SDL_SetEventFilter(_processEvent,this); + bool doThreadedInput=!settings.noThreadedInput; + if (doThreadedInput) { + logD("key input: event filter"); + SDL_SetEventFilter(_processEvent,this); + } else { + logD("key input: main thread"); + } while (!quit) { SDL_Event ev; @@ -2495,6 +2501,7 @@ bool FurnaceGUI::loop() { WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); processPoint(ev); + if (!doThreadedInput) processEvent(&ev); switch (ev.type) { case SDL_MOUSEMOTION: { int motionX=ev.motion.x; diff --git a/src/gui/gui.h b/src/gui/gui.h index 2966d594e..21bb0cf7d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1091,6 +1091,7 @@ class FurnaceGUI { int blankIns; int dragMovesSelection; int unsignedDetune; + int noThreadedInput; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1193,6 +1194,7 @@ class FurnaceGUI { blankIns(0), dragMovesSelection(1), unsignedDetune(0), + noThreadedInput(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index cb2064e62..9984e4996 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -460,6 +460,14 @@ void FurnaceGUI::drawSettings() { ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!"); } + bool noThreadedInputB=settings.noThreadedInput; + if (ImGui::Checkbox("Disable threaded input (restart after changing!)",&noThreadedInputB)) { + settings.noThreadedInput=noThreadedInputB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("threaded input processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.\nhowever, crashes have been reported when threaded input is on. enable this option if that is the case."); + } + bool blankInsB=settings.blankIns; if (ImGui::Checkbox("New instruments are blank",&blankInsB)) { settings.blankIns=blankInsB; @@ -2055,6 +2063,7 @@ void FurnaceGUI::syncSettings() { settings.blankIns=e->getConfInt("blankIns",0); settings.dragMovesSelection=e->getConfInt("dragMovesSelection",2); settings.unsignedDetune=e->getConfInt("unsignedDetune",0); + settings.noThreadedInput=e->getConfInt("noThreadedInput",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2141,6 +2150,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.blankIns,0,1); clampSetting(settings.dragMovesSelection,0,2); clampSetting(settings.unsignedDetune,0,1); + clampSetting(settings.noThreadedInput,0,1); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2276,6 +2286,7 @@ void FurnaceGUI::commitSettings() { e->setConf("blankIns",settings.blankIns); e->setConf("dragMovesSelection",settings.dragMovesSelection); e->setConf("unsignedDetune",settings.unsignedDetune); + e->setConf("noThreadedInput",settings.noThreadedInput); // colors for (int i=0; i Date: Wed, 20 Jul 2022 23:01:06 +0900 Subject: [PATCH 045/515] Struct-ize sample map variable --- src/engine/fileOps.cpp | 4 ++-- src/engine/instrument.cpp | 16 ++++++++++++---- src/engine/instrument.h | 19 +++++++++++++------ src/gui/insEdit.cpp | 25 +++++++++++++------------ 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index ddc5edf6b..3aa432fdb 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2445,8 +2445,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { const int dpcmNotes=(blockVersion>=2)?96:72; for (int j=0; jamiga.noteMap[j]=(short)((unsigned char)reader.readC())-1; - ins->amiga.noteFreq[j]=(unsigned char)reader.readC(); + ins->amiga.noteMap[j].map=(short)((unsigned char)reader.readC())-1; + ins->amiga.noteMap[j].freq=(unsigned char)reader.readC(); if (blockVersion>=6) { reader.readC(); // DMC value } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 196764d0f..a76588561 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -387,8 +387,12 @@ void DivInstrument::putInsData(SafeWriter* w) { // sample map w->writeC(amiga.useNoteMap); if (amiga.useNoteMap) { - w->write(amiga.noteFreq,120*sizeof(unsigned int)); - w->write(amiga.noteMap,120*sizeof(short)); + for (int note=0; note<120; note++) { + w->writeI(amiga.noteMap[note].freq); + } + for (int note=0; note<120; note++) { + w->writeS(amiga.noteMap[note].map); + } } // N163 @@ -932,8 +936,12 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { if (version>=67) { amiga.useNoteMap=reader.readC(); if (amiga.useNoteMap) { - reader.read(amiga.noteFreq,120*sizeof(unsigned int)); - reader.read(amiga.noteMap,120*sizeof(short)); + for (int note=0; note<120; note++) { + amiga.noteMap[note].freq=reader.readI(); + } + for (int note=0; note<120; note++) { + amiga.noteMap[note].map=reader.readS(); + } } } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c4af6f042..18bf2c5f7 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -306,12 +306,18 @@ struct DivInstrumentC64 { }; struct DivInstrumentAmiga { + struct SampleMap { + int freq; + short map; + SampleMap(int f=0, short m=-1): + freq(f), + map(m) {} + }; short initSample; bool useNoteMap; bool useWave; unsigned char waveLen; - int noteFreq[120]; - short noteMap[120]; + SampleMap noteMap[120]; /** * get the sample at specified note. @@ -321,7 +327,7 @@ struct DivInstrumentAmiga { if (useNoteMap) { if (note<0) note=0; if (note>119) note=119; - return noteMap[note]; + return noteMap[note].map; } return initSample; } @@ -334,7 +340,7 @@ struct DivInstrumentAmiga { if (useNoteMap) { if (note<0) note=0; if (note>119) note=119; - return noteFreq[note]; + return noteMap[note].freq; } return -1; } @@ -344,8 +350,9 @@ struct DivInstrumentAmiga { useNoteMap(false), useWave(false), waveLen(31) { - memset(noteMap,-1,120*sizeof(short)); - memset(noteFreq,0,120*sizeof(int)); + for (SampleMap& elem: noteMap) { + elem=SampleMap(); + } } }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 45f7c6757..5633bb895 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3011,7 +3011,7 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + //ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupScrollFreeze(0,1); @@ -3022,37 +3022,38 @@ void FurnaceGUI::drawInsEdit() { /*ImGui::TableNextColumn(); ImGui::Text("Frequency");*/ for (int i=0; i<120; i++) { + DivInstrumentAmiga::SampleMap sampleMap=ins->amiga.noteMap[i]; ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); ImGui::TableNextColumn(); ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (ins->amiga.noteMap[i]<0 || ins->amiga.noteMap[i]>=e->song.sampleLen) { + if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { sName="-- empty --"; - ins->amiga.noteMap[i]=-1; + sampleMap.map=-1; } else { - sName=e->song.sample[ins->amiga.noteMap[i]]->name; + sName=e->song.sample[sampleMap.map]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SM",sName.c_str())) { String id; - if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i]==-1)) { PARAMETER - ins->amiga.noteMap[i]=-1; + if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER + sampleMap.map=-1; } for (int j=0; jsong.sampleLen; j++) { id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i]==j)) { PARAMETER - ins->amiga.noteMap[i]=j; - if (ins->amiga.noteFreq[i]<=0) ins->amiga.noteFreq[i]=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + if (ImGui::Selectable(id.c_str(),sampleMap.map==j)) { PARAMETER + sampleMap.map=j; + if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); } } ImGui::EndCombo(); } /*ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SF",&ins->amiga.noteFreq[i],50,500)) { PARAMETER - if (ins->amiga.noteFreq[i]<0) ins->amiga.noteFreq[i]=0; - if (ins->amiga.noteFreq[i]>262144) ins->amiga.noteFreq[i]=262144; + if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER + if (sampleMap.freq<0) sampleMap.freq=0; + if (sampleMap.freq>262144) sampleMap.freq=262144; }*/ ImGui::PopID(); } From 4e8d71fc22b95bd0cc4f7fde846d191f74d86868 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 21 Jul 2022 13:42:20 +0900 Subject: [PATCH 046/515] Fix sample map struct Structize sample map variable is for easily extend features. --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 5633bb895..18e286802 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3022,7 +3022,7 @@ void FurnaceGUI::drawInsEdit() { /*ImGui::TableNextColumn(); ImGui::Text("Frequency");*/ for (int i=0; i<120; i++) { - DivInstrumentAmiga::SampleMap sampleMap=ins->amiga.noteMap[i]; + DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); ImGui::TableNextColumn(); From d8dff3c20794ccc8850e8481168dffd97d731942 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 20 Jul 2022 23:52:35 -0500 Subject: [PATCH 047/515] add demo song requested by LovelyA72 --- demos/Phoenix_cover.fur | Bin 0 -> 1299 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Phoenix_cover.fur diff --git a/demos/Phoenix_cover.fur b/demos/Phoenix_cover.fur new file mode 100644 index 0000000000000000000000000000000000000000..1a031443ada73d84d39666d43f60319881eb190b GIT binary patch literal 1299 zcmV+u1?>8Gob6j*ZyQArpF7*}zoZvMf)+}fMIbdniWFNF1tf&sC_#}z5~ZO$U+r~b zVf%s|qviprujK>q03QKfctiq;F906_z5=g^2bewI#p~1?dmJCxt9R{5#<#OGznz=8 z+1)s6Titfct#H=#s@(=(;{d>*-?n$R_MY3wWHJ`O$-@#PAi0pO_~A`}U)~1z{T}we1Mt@xjwk>u-3NH<0l@ta05(4acw7QF+5mXE z1@L?u;M*O5@Am+HJ^=XbQ(?yLy)D0;Lq0sNcNo6i9$Mzr*y%B6;Y{3i#jSF7+1;+>RT1@H~N_D&F5>xiu!culv3(TD)c zO|QKQ7;XSRqKE%MTE`EM_I5vhD8`)!q>TY7lr0O?zM%jr);R)N73(r@Bg{K(H!t-MHU>oNighfZ*WraJf{1`e- z5sI%Z>e#rqY5S6@-`E*tXLgFvXXVG63qnIFxFDYFLVgiRln-%`{wmTfq}P#dBfWui z2kGvFbSKaubiIajGqAH1*cC-U9Iu5(X%~;q!Xq*3iX?O-0^RArrkMMF`S2hs-S(t! zwSTYV`!2v%lNL2UPxMdJ^1Atl8b7K{zG`!>+T^QFN6G%_ zCq(~mJkxfP%%?QFfwpFNbPI6Z@K7HZWWJve{co;N6zEn_@|xj^I-scYrQRkveSH~h8n@{-9UgyCnNmn%fLXc8US;A^|r4)7dLf`rH5H~1&QFDFF! z9lxG}9MJ)3qP)>>^lPX;ObGd(LB=&=c*DPRd_N)npJP|U8(wR^pAeHByBgl`FBLB@ znanAZ;b)$gmrN!h3_tU{Tp{FRS4XpBGlzKWXYd>R6XBN=LOynNh{swE@z~7hH~O{I J{~u)b{&=X>hxh;h literal 0 HcmV?d00001 From 962dab012cf86eed89bb4334674f4d56cde30ca4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 02:49:19 -0500 Subject: [PATCH 048/515] GUI: improve wavetable editor, part 1 --- src/gui/gui.cpp | 3 + src/gui/gui.h | 1 + src/gui/waveEdit.cpp | 129 +++++++++++++++++++------------------------ 3 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 14b1b99e3..012925323 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4116,6 +4116,7 @@ bool FurnaceGUI::init() { tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); + waveEditStyle=e->getConfInt("waveEditStyle",0); lockLayout=e->getConfBool("lockLayout",false); #ifdef IS_MOBILE fullScreen=true; @@ -4359,6 +4360,7 @@ bool FurnaceGUI::finish() { e->setConf("tempoView",tempoView); e->setConf("waveHex",waveHex); + e->setConf("waveEditStyle",waveEditStyle); e->setConf("lockLayout",lockLayout); e->setConf("fullScreen",fullScreen); e->setConf("mobileUI",mobileUI); @@ -4438,6 +4440,7 @@ FurnaceGUI::FurnaceGUI(): vgmExportVersion(0x171), drawHalt(10), macroPointSize(16), + waveEditStyle(0), globalWinFlags(0), curFileDialog(GUI_FILE_OPEN), warnAction(GUI_WARN_OPEN), diff --git a/src/gui/gui.h b/src/gui/gui.h index 21bb0cf7d..e87b24ba9 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -958,6 +958,7 @@ class FurnaceGUI { int vgmExportVersion; int drawHalt; int macroPointSize; + int waveEditStyle; ImGuiWindowFlags globalWinFlags; diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 4ff2182e2..549bddb12 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -36,31 +36,45 @@ void FurnaceGUI::drawWaveEdit() { if (curWave<0 || curWave>=(int)e->song.wave.size()) { ImGui::Text("no wavetable selected"); } else { - ImGui::SetNextItemWidth(80.0f*dpiScale); - if (ImGui::InputInt("##CurWave",&curWave,1,1)) { - if (curWave<0) curWave=0; - if (curWave>=(int)e->song.wave.size()) curWave=e->song.wave.size()-1; - } - ImGui::SameLine(); - // TODO: load replace - if (ImGui::Button(ICON_FA_FOLDER_OPEN "##WELoad")) { - doAction(GUI_ACTION_WAVE_LIST_OPEN); - } - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_FLOPPY_O "##WESave")) { - doAction(GUI_ACTION_WAVE_LIST_SAVE); - } - ImGui::SameLine(); - DivWavetable* wave=e->song.wave[curWave]; - - if (!settings.waveLayout){ + + if (ImGui::BeginTable("WEProps",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(80.0f*dpiScale); + if (ImGui::InputInt("##CurWave",&curWave,1,1)) { + if (curWave<0) curWave=0; + if (curWave>=(int)e->song.wave.size()) curWave=e->song.wave.size()-1; + } + ImGui::SameLine(); + // TODO: load replace + if (ImGui::Button(ICON_FA_FOLDER_OPEN "##WELoad")) { + doAction(GUI_ACTION_WAVE_LIST_OPEN); + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FLOPPY_O "##WESave")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE); + } + ImGui::SameLine(); + + if (ImGui::RadioButton("Steps",waveEditStyle==0)) { + waveEditStyle=0; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Lines",waveEditStyle==1)) { + waveEditStyle=1; + } + + ImGui::TableNextColumn(); ImGui::Text("Width"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("use a width of:\n- any on Amiga/N163\n- 32 on Game Boy, PC Engine and WonderSwan\n- 64 on FDS\n- 128 on X1-010\nany other widths will be scaled during playback."); } ImGui::SameLine(); - ImGui::SetNextItemWidth(128.0f*dpiScale); + ImGui::SetNextItemWidth(96.0f*dpiScale); if (ImGui::InputInt("##_WTW",&wave->len,1,2)) { if (wave->len>256) wave->len=256; if (wave->len<1) wave->len=1; @@ -74,56 +88,15 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SetTooltip("use a height of:\n- 15 for Game Boy, WonderSwan, X1-010 Envelope shape and N163\n- 31 for PC Engine\n- 63 for FDS\n- 255 for X1-010\nany other heights will be scaled during playback."); } ImGui::SameLine(); - ImGui::SetNextItemWidth(128.0f*dpiScale); + ImGui::SetNextItemWidth(96.0f*dpiScale); if (ImGui::InputInt("##_WTH",&wave->max,1,2)) { if (wave->max>255) wave->max=255; if (wave->max<1) wave->max=1; e->notifyWaveChange(curWave); MARK_MODIFIED; } - } - ImGui::SameLine(); - if (ImGui::RadioButton("Dec",!waveHex)) { - waveHex=false; - } - ImGui::SameLine(); - if (ImGui::RadioButton("Hex",waveHex)) { - waveHex=true; - } - if (settings.waveLayout){ - if (ImGui::BeginTable("WaveProps",2,ImGuiTableFlags_SizingStretchSame)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Width"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("use a width of:\n- any on Amiga/N163\n- 32 on Game Boy, PC Engine and WonderSwan\n- 64 on FDS\n- 128 on X1-010\nany other widths will be scaled during playback."); - } - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##_WTW",&wave->len,1,2)) { - if (wave->len>256) wave->len=256; - if (wave->len<1) wave->len=1; - e->notifyWaveChange(curWave); - if (wavePreviewOn) e->previewWave(curWave,wavePreviewNote); - MARK_MODIFIED; - } - ImGui::TableNextColumn(); - ImGui::SameLine(); - ImGui::Text("Height"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("use a height of:\n- 15 for Game Boy, WonderSwan, X1-010 Envelope shape and N163\n- 31 for PC Engine\n- 63 for FDS\n- 255 for X1-010\nany other heights will be scaled during playback."); - } - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##_WTH",&wave->max,1,2)) { - if (wave->max>255) wave->max=255; - if (wave->max<1) wave->max=1; - e->notifyWaveChange(curWave); - MARK_MODIFIED; - } - ImGui::EndTable(); - } + ImGui::EndTable(); } for (int i=0; ilen; i++) { @@ -131,21 +104,19 @@ void FurnaceGUI::drawWaveEdit() { wavePreview[i]=wave->data[i]; } if (wave->len>0) wavePreview[wave->len]=wave->data[wave->len-1]; - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); // wavetable text input size found here - if (ImGui::InputText("##MMLWave",&mmlStringW)) { - decodeMMLStrW(mmlStringW,wave->data,wave->len,wave->max,waveHex); - } - if (!ImGui::IsItemActive()) { - encodeMMLStr(mmlStringW,wave->data,wave->len,-1,-1,waveHex); - } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); ImVec2 contentRegion=ImGui::GetContentRegionAvail(); // wavetable graph size determined here - if (ImGui::GetContentRegionAvail().y > (ImGui::GetContentRegionAvail().x / 2.0f)) { + contentRegion.y-=ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().WindowPadding.y; + /*if (ImGui::GetContentRegionAvail().y > (ImGui::GetContentRegionAvail().x / 2.0f)) { contentRegion=ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetContentRegionAvail().x / 2.0f); + }*/ + if (waveEditStyle) { + PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion); + } else { + PlotCustom("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,true); } - PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { waveDragStart=ImGui::GetItemRectMin(); waveDragAreaSize=contentRegion; @@ -159,6 +130,22 @@ void FurnaceGUI::drawWaveEdit() { modified=true; } ImGui::PopStyleVar(); + + if (ImGui::RadioButton("Dec",!waveHex)) { + waveHex=false; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Hex",waveHex)) { + waveHex=true; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); // wavetable text input size found here + if (ImGui::InputText("##MMLWave",&mmlStringW)) { + decodeMMLStrW(mmlStringW,wave->data,wave->len,wave->max,waveHex); + } + if (!ImGui::IsItemActive()) { + encodeMMLStr(mmlStringW,wave->data,wave->len,-1,-1,waveHex); + } } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_WAVE_EDIT; From 191a0dedf90635b934657d497566a433ae6f165f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 03:14:52 -0500 Subject: [PATCH 049/515] GUI: improve wavetable editor, part 2 --- src/gui/gui.cpp | 3 ++ src/gui/gui.h | 2 +- src/gui/waveEdit.cpp | 74 ++++++++++++++++++++++++++++++-------------- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 012925323..90925b934 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4116,6 +4116,7 @@ bool FurnaceGUI::init() { tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); + waveGenVisible=e->getConfBool("waveGenVisible",false); waveEditStyle=e->getConfInt("waveEditStyle",0); lockLayout=e->getConfBool("lockLayout",false); #ifdef IS_MOBILE @@ -4360,6 +4361,7 @@ bool FurnaceGUI::finish() { e->setConf("tempoView",tempoView); e->setConf("waveHex",waveHex); + e->setConf("waveGenVisible",waveGenVisible); e->setConf("waveEditStyle",waveEditStyle); e->setConf("lockLayout",lockLayout); e->setConf("fullScreen",fullScreen); @@ -4535,6 +4537,7 @@ FurnaceGUI::FurnaceGUI(): firstFrame(true), tempoView(true), waveHex(false), + waveGenVisible(false), lockLayout(false), editOptsVisible(false), latchNibble(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index e87b24ba9..656b358e5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1222,7 +1222,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, lockLayout, editOptsVisible, latchNibble, nonLatchNibble; + bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble; FurnaceGUIWindows curWindow, nextWindow, curWindowLast; float peak[2]; float patChanX[DIV_MAX_CHANS+1]; diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 549bddb12..f8c27b1fa 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -96,6 +96,11 @@ void FurnaceGUI::drawWaveEdit() { MARK_MODIFIED; } + ImGui::SameLine(); + if (ImGui::Button(waveGenVisible?(ICON_FA_CHEVRON_RIGHT "##WEWaveGen"):(ICON_FA_CHEVRON_LEFT "##WEWaveGen"))) { + waveGenVisible=!waveGenVisible; + } + ImGui::EndTable(); } @@ -105,31 +110,54 @@ void FurnaceGUI::drawWaveEdit() { } if (wave->len>0) wavePreview[wave->len]=wave->data[wave->len-1]; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); + if (ImGui::BeginTable("WEWaveSection",waveGenVisible?2:1)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); + if (waveGenVisible) ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,250.0f*dpiScale); + ImGui::TableNextRow(); - ImVec2 contentRegion=ImGui::GetContentRegionAvail(); // wavetable graph size determined here - contentRegion.y-=ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().WindowPadding.y; - /*if (ImGui::GetContentRegionAvail().y > (ImGui::GetContentRegionAvail().x / 2.0f)) { - contentRegion=ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetContentRegionAvail().x / 2.0f); - }*/ - if (waveEditStyle) { - PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion); - } else { - PlotCustom("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,true); + ImGui::TableNextColumn(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); + + ImVec2 contentRegion=ImGui::GetContentRegionAvail(); // wavetable graph size determined here + contentRegion.y-=ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().WindowPadding.y; + if (waveEditStyle) { + PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion); + } else { + PlotCustom("##Waveform",wavePreview,wave->len,0,NULL,0,wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,true); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + waveDragStart=ImGui::GetItemRectMin(); + waveDragAreaSize=contentRegion; + waveDragMin=0; + waveDragMax=wave->max; + waveDragLen=wave->len; + waveDragActive=true; + waveDragTarget=wave->data; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + e->notifyWaveChange(curWave); + modified=true; + } + ImGui::PopStyleVar(); + + if (waveGenVisible) { + ImGui::TableNextColumn(); + + if (ImGui::BeginTabBar("WaveGenOpt")) { + if (ImGui::BeginTabItem("Shapes")) { + ImGui::Button("Square"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("FM")) { + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Mangle")) { + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + } + ImGui::EndTable(); } - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - waveDragStart=ImGui::GetItemRectMin(); - waveDragAreaSize=contentRegion; - waveDragMin=0; - waveDragMax=wave->max; - waveDragLen=wave->len; - waveDragActive=true; - waveDragTarget=wave->data; - processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); - e->notifyWaveChange(curWave); - modified=true; - } - ImGui::PopStyleVar(); if (ImGui::RadioButton("Dec",!waveHex)) { waveHex=false; From 09b47fafe3e6d8f242b6467f0183f68f3ba7245b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 14:49:42 -0500 Subject: [PATCH 050/515] update demo songs --- demos/Melody_of_Certain_Feelings.fur | Bin 17076 -> 0 bytes demos/UNATCOPCM.fur | Bin 205943 -> 0 bytes demos/ecolove.fur | Bin 57810 -> 0 bytes demos/neon_night_riders_TFMX.fur | Bin 160437 -> 0 bytes demos/wolf3d.fur | Bin 29910 -> 0 bytes src/gui/about.cpp | 1 - 6 files changed, 1 deletion(-) delete mode 100644 demos/Melody_of_Certain_Feelings.fur delete mode 100644 demos/UNATCOPCM.fur delete mode 100644 demos/ecolove.fur delete mode 100644 demos/neon_night_riders_TFMX.fur delete mode 100644 demos/wolf3d.fur diff --git a/demos/Melody_of_Certain_Feelings.fur b/demos/Melody_of_Certain_Feelings.fur deleted file mode 100644 index 6ccf4e13cb18a3104f26a94ef12f2314b34d2046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17076 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%0DiuQr6TUsnZmi*avrsHpyLAXuy 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 diff --git a/demos/ecolove.fur b/demos/ecolove.fur deleted file mode 100644 index 744b0c9f6d563860bcf687ba08cea23176473a0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57810 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%0Dn#%v8oaAO=Y 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�UycrE!j& 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 Ph;?zo9Dx)Sn*{tXqkx=4 diff --git a/demos/neon_night_riders_TFMX.fur b/demos/neon_night_riders_TFMX.fur deleted file mode 100644 index a15f448922687b0c04126fa55d40ddbd4930aee1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160437 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

-OcJe!kv4X-v@A0I5J$zg#ARSFrWyV-Ihx(6Fg2 zIwi6;ap(H2j&WNkmIMk$=Zb-4@MuIlgD;hdg(4A$MJLmFQngkk63g=|np!qCm%2W9 z`>iXf!Xk$Gmyf<2p>BNs`P~X4t6=^1ovpX z+M>#ee{Sn~pprbPbLW>JPtgyoj+ls1He0d}drX z*f;JZvdG?vTQ@o^jGX#vIg^NIi;Ej-$|S^eDup9t;vVDD;)*LvW)M?hm(35H9ZzJ4 zRNA64twJJ}L$qwHD-ltEo>P&yxmd#TcYgADcQorB`S{G~^H-fTvh~`x-}a^(jva2H zx~3MXii#>h!aUS7Z>LB(H2=)t@N$&JBP`v$a(l*0=4(_UdX_F!=4piVWB_$VM7_ZH z4HjRT!r^nM#59g2FQ_U}Nf>NJVOe>;go!6{rFj}TA0jK&Kk@15Z|p@?l(A3#`@-*D zGAq#W?T44`qJjdJXR%vHkheA!3Q|U$KFpPfNgnSkIO`z;}mq`$`DBNs+wC%>4w1` zt5`Wox zvvcw!8Ha9h)fGvlLLR3loTaiL82X&PIF2RY(orS?-N6b4Jk(jspyI(X27w?l*i0IM z#1d#5TU*L=sPVP2g@AzL9=h@Ky*WFR799QY+iTM%91Ul`^V^jXN18~8o0fI9w6eTh z%S<@j)ST+pQUN|3p(qMVL@DcV|Jc0MWiu`=n!IUZHW6?+y@W@ocF=mJ6_g(VUx zax}RLAuSya$Kk-UXy_`B!Dch5bdFG|R`N53DJxsSh)(?e%OCgWLkazzAHM&+bJk?h zk6ruy#<(krC#U?@Rab(QmzN`AaV3RKZJX+I*bD|wEacHrfYn?+pVwtK8&S&;a+$$E zAP|aY2{aD6bCt-Dl(m$HZf?138Znd35~(x_2~VW4MRJ9NM`!V*xdjDz;UF-bypFiCiU3OUJ2LHU)H(`!tGcmWt>Z7Vlsw$K`4o_WD-B_6`W^-f! zJz>)le&EEBNYHK7udW$QW~K{E5!L6?gTCwajZ;^PRtryPRr{2%;fBnZf#|DdUo0D^mv_Civ`KK zI0KOsnS;u==uB)-1rkozz}KN%0UBG$<+8CW77~F-$fB7UXz(G0M554Xq)f&@=`p0=J8Zi|OM-n(ZJ`)f7U3Qxl zyQcAbTy{)V#D|1ITrP**YBrdx4kQ_iE|c+OI=Z5hp!X&{=mj$ugvLG#rj$atd@B8R41`5_I;3Vt5A9DaHf8XI zqmc|nsFDg;3?`kJOh9Z&_)JLf6)CD4omiqLjT$$S846ejk41>sj3z5e%LZZ)=Gi=v zLZiu1ViQ>eEK<_%Seu;~o19y-dLmgWU#e8eg-kLblT4+v>4?j`rnfmgPK(82_l437 zkxVXT!os3FDH_^{LqHstiiDFmSWToHra(OdVyOU}DuY2ud-X`Oe8ChVh}4B;W#uJW zF*D^btgILvZkKtsujBUpp|RNooyir!F_3i>^sV3sYVMZ1dEgj7)HBp+@CQ7;}M@}rnkF) zVs?7)`j7v-bZgS&bOTq}JvCW|joX>#Nuq&vlv$V6;98Tk+v zB?1H?#&#kD$t)A40WO^zDL?JzSzi`g20rG#LZj{2MqXCR!Ri`Cjf ztxC!yW??-j@LZu-Do1iU+y{9!iBciqB=sYAZVgQ7OslhlcP?MP)jvBwb@#`wKmO+S zVjxLj(wSUEL4j7rq)<4@g36Zaq8u)ZCz7jV0%|&yrV2G$m5`KhLu~Me!@%v$;FukL zcv&Q01UN~E#_b3s@MDpz5MKa6Jri<3G=Xmj0kt4f*ixm8M@*n`@+qVVk;S8QGfJUy zr8xzK0HWcAQ3gc7LDG5lwVBb8kcw1ED9mkWFp`q)1Y?LOABT(n( z$(YfVvAefA`et+n-PpZ9fBp4Z|IDh@X3OP-@GsjRLjE6h`g zSrmLS1OYdJBf*DB?bwP1XB$6P}7!DJ>QpoSLqvl?u@?=4y zmXKo#K5%*zDg(R!P-=4X^YhT)j2w+x$|Xd7E_X1IA+p5^b&f(v%|tv7FgZLS8;^t& zLuM@l≫4aAoh0*>xoU+7UI9(Kke~rXS`8o^ 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

8oPtwaPQWwi4{DL+(V5#D@e}p)XmwMif`pxQ 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%0Dk$t<&$LQT6%0t}G#;&~ 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 M4Zc9H`O1j?AI$LVc>n+a diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 70e09e727..d3d1d9e48 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -83,7 +83,6 @@ const char* aboutLine[]={ "Miker", "nicco1690", "NikonTeen", - "SnugglyValeria", "SuperJet Spade", "TheDuccinator", "theloredev", From 5aa287eeceee9fe361038ba2749764e1dc8383bf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 14:51:26 -0500 Subject: [PATCH 051/515] update format.md - CSM for all OPN chips soon --- papers/format.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/papers/format.md b/papers/format.md index 3e3583463..6281293ab 100644 --- a/papers/format.md +++ b/papers/format.md @@ -238,6 +238,10 @@ size | description | - 0xbe: YM2612 extra features - 7 channels | - 0xbf: T6W28 - 4 channels | - 0xc0: PCM DAC - 1 channel + | - 0xc1: YM2612 CSM - 10 channels + | - 0xc2: Neo Geo CSM (YM2610) - 18 channels + | - 0xc3: OPN CSM - 10 channels + | - 0xc4: PC-98 CSM - 20 channels | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels | - 0xfd: Dummy System - 8 channels From f6b45d3d9bee96d661fcfc5a19f63d21379bcbee Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 15:21:29 -0500 Subject: [PATCH 052/515] GUI: add Namco C163 chip name option --- CONTRIBUTING.md | 5 +++++ src/engine/engine.h | 1 + src/engine/sysDef.cpp | 17 ++++++++++++++--- src/gui/gui.h | 4 +++- src/gui/insEdit.cpp | 2 +- src/gui/settings.cpp | 15 ++++++++++++++- 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 97efdf8cd..51903d8b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,11 @@ the coding style is described here: - don't use `auto` unless needed. - use `String` for `std::string` (this is typedef'd in ta-utils.h). - prefer using operator for String (std::string) comparisons (a==""). +- if you have to work with C strings, only use safe C string operations: + - snprintf + - strncpy + - strncat + - any other operation which specifies a limit some files (particularly the ones in `src/engine/platform/sound` and `extern/`) don't follow this style. diff --git a/src/engine/engine.h b/src/engine/engine.h index 4bf4cb65d..896c083a2 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -355,6 +355,7 @@ class DivEngine { short vibTable[64]; int reversePitchTable[4096]; int pitchTable[4096]; + char c163NameCS[1024]; int midiBaseChan; bool midiPoly; size_t midiAgeCounter; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index a5b689b2b..25e35227f 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -54,7 +54,7 @@ std::vector& DivEngine::getPossibleInsTypes() { return possibleInsTypes; } -// TODO: rewrite this function (again). it's an unreliable mess. +// TODO: deprecate when I add "system name" field in the file. String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { switch (song.systemLen) { case 0: @@ -177,7 +177,9 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { return "Famicom Disk System"; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_N163) { - return "Famicom + Namco C163"; + String ret="Famicom + "; + ret+=getConfString("c163Name","Namco C163"); + return ret; } if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_MMC5) { return "Famicom + MMC5"; @@ -205,7 +207,11 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { String ret=""; for (int i=0; i0) ret+=" + "; - ret+=getSystemName(song.system[i]); + if (song.system[i]==DIV_SYSTEM_N163) { + ret+=getConfString("c163Name","Namco C163"); + } else { + ret+=getSystemName(song.system[i]); + } } return ret; @@ -213,6 +219,11 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { const char* DivEngine::getSystemName(DivSystem sys) { if (sysDefs[sys]==NULL) return "Unknown"; + if (sys==DIV_SYSTEM_N163) { + String c1=getConfString("c163Name","Namco C163"); + strncpy(c163NameCS,c1.c_str(),1023); + return c163NameCS; + } return sysDefs[sys]->name; } diff --git a/src/gui/gui.h b/src/gui/gui.h index 656b358e5..851e10aa1 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1099,6 +1099,7 @@ class FurnaceGUI { String audioDevice; String midiInDevice; String midiOutDevice; + String c163Name; std::vector initialSys; Settings(): @@ -1201,7 +1202,8 @@ class FurnaceGUI { patFontPath(""), audioDevice(""), midiInDevice(""), - midiOutDevice("") {} + midiOutDevice(""), + c163Name("") {} } settings; char finalLayoutPath[4096]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 18e286802..81626b777 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3063,7 +3063,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem("Namco 163")) { + if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem(settings.c163Name.c_str())) { if (ImGui::InputInt("Waveform##WAVE",&ins->n163.wave,1,10)) { PARAMETER if (ins->n163.wave<0) ins->n163.wave=0; if (ins->n163.wave>=e->song.waveLen) ins->n163.wave=e->song.waveLen-1; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 9984e4996..2d05ab5ac 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1156,6 +1156,12 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); + ImGui::Text("N163/C163 chip name"); + ImGui::SameLine(); + ImGui::InputTextWithHint("##C163Name","Namco C163",&settings.c163Name); + + ImGui::Separator(); + bool insEditColorizeB=settings.insEditColorize; if (ImGui::Checkbox("Colorize instrument editor using instrument type",&insEditColorizeB)) { settings.insEditColorize=insEditColorizeB; @@ -1453,7 +1459,11 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL,"FM (OPL)"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_FDS,"FDS"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_VBOY,"Virtual Boy"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_N163,"Namco 163"); + // special case + String c163Label=fmt::sprintf("%s##CC_GUI_COLOR_INSTR_N163",settings.c163Name); + if (ImGui::ColorEdit4(c163Label.c_str(),(float*)&uiColors[GUI_COLOR_INSTR_N163])) { + applyUISettings(false); + } UI_COLOR_CONFIG(GUI_COLOR_INSTR_SCC,"Konami SCC"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPZ,"FM (OPZ)"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_POKEY,"POKEY"); @@ -1972,6 +1982,8 @@ void FurnaceGUI::syncSettings() { settings.audioDevice=e->getConfString("audioDevice",""); settings.midiInDevice=e->getConfString("midiInDevice",""); settings.midiOutDevice=e->getConfString("midiOutDevice",""); + // I'm sorry, but the C163 education program has failed... + settings.c163Name=e->getConfString("c163Name","Namco C163"); settings.audioQuality=e->getConfInt("audioQuality",0); settings.audioBufSize=e->getConfInt("audioBufSize",1024); settings.audioRate=e->getConfInt("audioRate",44100); @@ -2194,6 +2206,7 @@ void FurnaceGUI::commitSettings() { e->setConf("audioDevice",settings.audioDevice); e->setConf("midiInDevice",settings.midiInDevice); e->setConf("midiOutDevice",settings.midiOutDevice); + e->setConf("c163Name",settings.c163Name); e->setConf("audioQuality",settings.audioQuality); e->setConf("audioBufSize",settings.audioBufSize); e->setConf("audioRate",settings.audioRate); From e295cea2384ec7e5c0b389d1e5d13b25d0617144 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 15:28:24 -0500 Subject: [PATCH 053/515] whoops --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b75db0d05..1a2d88a7d 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a - SID (6581/8580) used in Commodore 64 - Mikey used in Atari Lynx - ZX Spectrum beeper (SFX-like engine) + - Commodore PET - TIA used in Atari 2600 - Game Boy - modern/fantasy: From a137eefd209add604bf57986dfb8808b3d6ec6d1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Jul 2022 19:00:32 -0500 Subject: [PATCH 054/515] GUI: refine the Namco [C]163 chip name option --- src/gui/dataList.cpp | 1 + src/gui/insEdit.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 62b93479b..3a536951f 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -184,6 +184,7 @@ void FurnaceGUI::drawInsList() { if (i>=0) { DivInstrument* ins=e->song.ins[i]; insType=(ins->type>DIV_INS_MAX)?"Unknown":insTypes[ins->type]; + if (ins->type==DIV_INS_N163) insType=settings.c163Name.c_str(); switch (ins->type) { case DIV_INS_FM: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_FM]); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 81626b777..25ee330b6 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1416,7 +1416,7 @@ void FurnaceGUI::drawInsEdit() { ins->type=(DivInstrumentType)insType; } */ - if (ImGui::BeginCombo("##Type",insTypes[insType])) { + if (ImGui::BeginCombo("##Type",insType==DIV_INS_N163?settings.c163Name.c_str():insTypes[insType])) { std::vector insTypeList; if (settings.displayAllInsTypes) { for (int i=0; insTypes[i]; i++) { @@ -1426,7 +1426,7 @@ void FurnaceGUI::drawInsEdit() { insTypeList=e->getPossibleInsTypes(); } for (DivInstrumentType i: insTypeList) { - if (ImGui::Selectable(insTypes[i],insType==i)) { + if (ImGui::Selectable(i==DIV_INS_N163?settings.c163Name.c_str():insTypes[i],insType==i)) { ins->type=i; // reset macro zoom From 5127d5ef180aa53dc33df6fac9a7b6dba0c91c25 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 22 Jul 2022 13:36:42 +0900 Subject: [PATCH 055/515] Implement sample loop end position, enum-ise sample depth (#557) TODO: new sample format --- src/engine/engine.cpp | 7 +- src/engine/fileOps.cpp | 34 ++-- src/engine/platform/amiga.cpp | 10 +- src/engine/platform/genesis.cpp | 30 ++-- src/engine/platform/lynx.cpp | 10 +- src/engine/platform/mmc5.cpp | 11 +- src/engine/platform/nes.cpp | 11 +- src/engine/platform/opl.cpp | 4 +- src/engine/platform/pce.cpp | 10 +- src/engine/platform/qsound.cpp | 2 +- src/engine/platform/rf5c68.cpp | 4 +- src/engine/platform/segapcm.cpp | 14 +- src/engine/platform/su.cpp | 4 +- src/engine/platform/swan.cpp | 10 +- src/engine/platform/vera.cpp | 16 +- src/engine/platform/vrc6.cpp | 12 +- src/engine/platform/ym2608.cpp | 4 +- src/engine/platform/ym2610.cpp | 4 +- src/engine/platform/ym2610b.cpp | 4 +- src/engine/platform/ymz280b.cpp | 44 ++--- src/engine/playback.cpp | 10 +- src/engine/sample.cpp | 287 ++++++++++++++++++++------------ src/engine/sample.h | 57 ++++++- src/engine/vgmOps.cpp | 14 +- src/gui/debugWindow.cpp | 13 +- src/gui/doAction.cpp | 37 ++-- src/gui/guiConst.cpp | 2 +- src/gui/guiConst.h | 2 +- src/gui/sampleEdit.cpp | 100 +++++++---- 29 files changed, 461 insertions(+), 306 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 9b3fa06fd..659ea6b9a 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2226,7 +2226,7 @@ int DivEngine::addSampleFromFile(const char* path) { sample->rate=33144; sample->centerRate=33144; - sample->depth=1; + sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM; sample->init(len*8); if (fread(sample->dataDPCM,1,len,f)==0) { @@ -2301,9 +2301,9 @@ int DivEngine::addSampleFromFile(const char* path) { int index=0; if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { - sample->depth=8; + sample->depth=DIV_SAMPLE_DEPTH_8BIT; } else { - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } sample->init(si.frames); if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { @@ -2358,6 +2358,7 @@ int DivEngine::addSampleFromFile(const char* path) { if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD) { sample->loopStart=inst.loops[0].start; + sample->loopEnd=inst.loops[0].end; if(inst.loops[0].end < (unsigned int)sampleCount) sampleCount=inst.loops[0].end; } diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 3aa432fdb..40932a378 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -799,17 +799,17 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { sample->rate=ymuSampleRate*400; } if (ds.version>0x15) { - sample->depth=reader.readC(); - if (sample->depth!=8 && sample->depth!=16) { + sample->depth=(DivSampleDepth)reader.readC(); + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { logW("%d: sample depth is wrong! (%d)",i,sample->depth); - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } } else { if (ds.version>0x08) { - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } else { // it appears samples were stored as ADPCM back then - sample->depth=3; + sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM; } } if (length>0) { @@ -838,7 +838,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (k>=sample->samples) { break; } - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { float next=(float)(data[(unsigned int)j]-0x80)*mult; sample->data8[k++]=fmin(fmax(next,-128),127); } else { @@ -1631,7 +1631,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { logD("reading sample %d at %x...",i,samplePtr[i]); sample->name=reader.readString(); - sample->samples=reader.readI(); + sample->samples=sample->loopEnd=reader.readI(); sample->rate=reader.readI(); if (ds.version<58) { vol=reader.readS(); @@ -1639,7 +1639,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readI(); } - sample->depth=reader.readC(); + sample->depth=(DivSampleDepth)reader.readC(); // reserved reader.readC(); @@ -1657,6 +1657,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { reader.readI(); } +/* + if (ds.version>=100) { + sample->loopEnd=reader.readI(); + } else { + reader.readI(); + } +*/ if (ds.version>=58) { // modern sample sample->init(sample->samples); reader.read(sample->getCurBuf(),sample->getCurBufLen()); @@ -1670,9 +1677,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } // render data - if (sample->depth!=8 && sample->depth!=16) { + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { logW("%d: sample depth is wrong! (%d)",i,sample->depth); - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } sample->samples=(double)sample->samples/samplePitches[pitch]; sample->init(sample->samples); @@ -1683,7 +1690,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (k>=sample->samples) { break; } - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { float next=(float)(data[(unsigned int)j]-0x80)*mult; sample->data8[k++]=fmin(fmax(next,-128),127); } else { @@ -1877,7 +1884,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { logD("reading samples... (%d)",insCount); for (int i=0; idepth=8; + sample->depth=DIV_SAMPLE_DEPTH_8BIT; sample->name=reader.readString(22); logD("%d: %s",i+1,sample->name); int slen=((unsigned short)reader.readS_BE())*2; @@ -1897,8 +1904,8 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { loopLen=0; } if (loopLen>=2) { - if (loopEndloopStart=loopStart; + sample->loopEnd=loopEnd; } sample->init(slen); ds.sample.push_back(sample); @@ -3043,6 +3050,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(0); w->writeS(sample->centerRate); w->writeI(sample->loopStart); + //w->writeI(sample->loopEnd); w->write(sample->getCurBuf(),sample->getCurBufLen()); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 65b44136f..1b0075307 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -114,12 +114,10 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le if (chan[i].audPossamples) { writeAudDat(s->data8[chan[i].audPos++]); } - if (chan[i].audPos>=s->samples || chan[i].audPos>=131071) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan[i].audPos=s->loopStart; - } else { - chan[i].sample=-1; - } + if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) { + chan[i].audPos=s->loopStart; + } else if (chan[i].audPos>=MIN(131071,s->samples)) { + chan[i].sample=-1; } } else { chan[i].sample=-1; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index afd59b336..b6dbb8d12 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -153,14 +153,13 @@ void DivPlatformGenesis::processDAC() { if (chan[i].dacPeriod>=(chipClock/576)) { if (s->samples>0) { while (chan[i].dacPeriod>=(chipClock/576)) { - if (++chan[i].dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples && !chan[i].dacDirection) { - chan[i].dacPos=s->loopStart; - } else { - chan[i].dacSample=-1; - chan[i].dacPeriod=0; - break; - } + ++chan[i].dacPos; + if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=s->getEndPosition())) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { + chan[i].dacSample=-1; + chan[i].dacPeriod=0; + break; } chan[i].dacPeriod-=(chipClock/576); } @@ -200,14 +199,13 @@ void DivPlatformGenesis::processDAC() { chan[5].dacReady=false; } } - if (++chan[5].dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples && !chan[5].dacDirection) { - chan[5].dacPos=s->loopStart; - } else { - chan[5].dacSample=-1; - if (parent->song.brokenDACMode) { - rWrite(0x2b,0); - } + chan[5].dacPos++; + if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=s->getEndPosition())) { + chan[5].dacPos=s->loopStart; + } else if (chan[5].dacPos>=s->samples) { + chan[5].dacSample=-1; + if (parent->song.brokenDACMode) { + rWrite(0x2b,0); } } while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate; diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 3f5e92c03..7c349e5a5 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -158,12 +158,10 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7); } - if (chan[i].samplePos>=(int)s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan[i].samplePos=s->loopStart; - } else { - chan[i].sample=-1; - } + if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) { + chan[i].samplePos=s->loopStart; + } else if (chan[i].samplePos>=(int)s->samples) { + chan[i].sample=-1; } } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index dc9e5abad..bafbda3fb 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -62,12 +62,11 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len if (!isMuted[2]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } - if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - dacPos=s->loopStart; - } else { - dacSample=-1; - } + dacPos++; + if (s->isLoopable() && dacPos>=s->getEndPosition()) { + dacPos=s->loopStart; + } else if (dacPos>=s->samples) { + dacSample=-1; } dacPeriod-=rate; } else { diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index d801fe664..bd1be94a8 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -108,12 +108,11 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { rWrite(0x4011,next); \ } \ } \ - if (++dacPos>=s->samples) { \ - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { \ - dacPos=s->loopStart; \ - } else { \ - dacSample=-1; \ - } \ + dacPos++; \ + if (s->isLoopable() && dacPos>=s->getEndPosition()) { \ + dacPos=s->loopStart; \ + } else if (dacPos>=s->samples) { \ + dacSample=-1; \ } \ dacPeriod-=rate; \ } else { \ diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 823e764bc..36dd2c66b 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -771,7 +771,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { int end=s->offB+s->lengthB-1; immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); - immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat + immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -807,7 +807,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { int end=s->offB+s->lengthB-1; immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); - immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat + immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat int freq=(65536.0*(double)s->rate)/(double)chipRateBase; immWrite(16,freq&0xff); immWrite(17,(freq>>8)&0xff); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 9e1302a0f..f1eb5a108 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -90,12 +90,10 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x04,0xdf); chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); chan[i].dacPos++; - if (chan[i].dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan[i].dacPos=s->loopStart; - } else { - chan[i].dacSample=-1; - } + if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { + chan[i].dacSample=-1; } chan[i].dacPeriod-=rate; } diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 6eb14be7f..faeaf6a9d 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -301,7 +301,7 @@ void DivPlatformQSound::tick(bool sysTick) { qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_addr = s->offQSound & 0xffff; - int length = s->samples; + int length = s->getEndPosition(); if (length > 65536 - 16) { length = 65536 - 16; } diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 176b6e7c7..e4a39d44e 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -142,7 +142,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { if (chan[i].audPos>0) { start=start+MIN(chan[i].audPos,s->length8); } - if (s->loopStart>=0) { + if (s->isLoopable()) { loop=start+s->loopStart; } start=MIN(start,getSampleMemCapacity()-31); @@ -393,7 +393,7 @@ void DivPlatformRF5C68::renderSamples() { size_t memPos=0; for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; - int length=s->length8; + int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT); int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length); if (actualLength>0) { s->offRF5C68=memPos; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 71d45298a..d66fcce0b 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -56,12 +56,10 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); } chan[i].pcm.pos+=chan[i].pcm.freq; - if (chan[i].pcm.pos>=(s->samples<<8)) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan[i].pcm.pos=s->loopStart<<8; - } else { - chan[i].pcm.sample=-1; - } + if (s->isLoopable() && chan[i].pcm.pos>=(s->getEndPosition()<<8)) { + chan[i].pcm.pos=s->loopStart<<8; + } else if (chan[i].pcm.pos>=(s->samples<<8)) { + chan[i].pcm.sample=-1; } } else { oscBuf[i]->data[oscBuf[i]->needle++]=0; @@ -202,7 +200,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int actualLength=(int)s->length8; + int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)); if (actualLength>0xfeff) actualLength=0xfeff; addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); @@ -235,7 +233,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].furnacePCM=false; if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int actualLength=(int)s->length8; + int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)); if (actualLength>65536) actualLength=65536; addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index f3be01a78..48d0ba9a1 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -213,7 +213,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note)); if (sample!=NULL) { - unsigned int sampleEnd=sample->offSU+sample->samples; + unsigned int sampleEnd=sample->offSU+(sample->getEndPosition()); unsigned int off=sample->offSU+chan[i].hasOffset; chan[i].hasOffset=0; if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1; @@ -221,7 +221,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chWrite(i,0x0b,off>>8); chWrite(i,0x0c,sampleEnd&0xff); chWrite(i,0x0d,sampleEnd>>8); - if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples) { + if (sample->isLoopable()) { unsigned int sampleLoop=sample->offSU+sample->loopStart; if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1; chWrite(i,0x0e,sampleLoop&0xff); diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index b3e833198..b6da23271 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -83,12 +83,10 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len continue; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - dacPos=s->loopStart; - } else { - dacSample=-1; - } + if (s->isLoopable() && dacPos>=s->getEndPosition()) { + dacPos=s->loopStart; + } else if (dacPos>=s->samples) { + dacSample=-1; } dacPeriod-=rate; } diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 092bbb6ac..6376cc19e 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -96,13 +96,11 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len rWritePCMData(tmp_r&0xff); } chan[16].pcm.pos++; - if (chan[16].pcm.pos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan[16].pcm.pos=s->loopStart; - } else { - chan[16].pcm.sample=-1; - break; - } + if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) { + chan[16].pcm.pos=s->loopStart; + } else if (chan[16].pcm.pos>=s->samples) { + chan[16].pcm.sample=-1; + break; } } } else { @@ -267,12 +265,12 @@ int DivPlatformVERA::dispatch(DivCommand c) { chan[16].pcm.pos=0; DivSample* s=parent->getSample(chan[16].pcm.sample); unsigned char ctrl=0x90|chan[16].vol; // always stereo - if (s->depth==16) { + if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { chan[16].pcm.depth16=true; ctrl|=0x20; } else { chan[16].pcm.depth16=false; - if (s->depth!=8) chan[16].pcm.sample=-1; + if (s->depth!=DIV_SAMPLE_DEPTH_8BIT) chan[16].pcm.sample=-1; } rWritePCMCtrl(ctrl); } diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 88fcb37b4..8a34d9252 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -77,13 +77,11 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chWrite(i,0,0x80|chan[i].dacOut); } chan[i].dacPos++; - if (chan[i].dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan[i].dacPos=s->loopStart; - } else { - chan[i].dacSample=-1; - chWrite(i,0,0); - } + if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { + chan[i].dacSample=-1; + chWrite(i,0,0); } chan[i].dacPeriod-=rate; } diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index b70efaf03..c3cf52a06 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -761,7 +761,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { immWrite(0x104,(end>>5)&0xff); immWrite(0x105,(end>>13)&0xff); immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); - immWrite(0x100,(s->loopStart>=0)?0xb0:0xa0); // start/repeat + immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -796,7 +796,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { immWrite(0x104,(end>>5)&0xff); immWrite(0x105,(end>>13)&0xff); immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); - immWrite(0x100,(s->loopStart>=0)?0xb0:0xa0); // start/repeat + immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); immWrite(0x109,freq&0xff); immWrite(0x10a,(freq>>8)&0xff); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 1a67c4288..4e01b005c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -793,7 +793,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -828,7 +828,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); immWrite(0x19,freq&0xff); immWrite(0x1a,(freq>>8)&0xff); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 600c89fd3..1a1f7f0ae 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -775,7 +775,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -810,7 +810,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); immWrite(0x19,freq&0xff); immWrite(0x1a,(freq>>8)&0xff); diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index d8d98478d..87193da50 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -136,9 +136,9 @@ void DivPlatformYMZ280B::tick(bool sysTick) { DivSample* s=parent->getSample(chan[i].sample); unsigned char ctrl; switch (s->depth) { - case 3: ctrl=0x20; break; - case 8: ctrl=0x40; break; - case 16: ctrl=0x60; break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: ctrl=0x20; break; + case DIV_SAMPLE_DEPTH_8BIT: ctrl=0x40; break; + case DIV_SAMPLE_DEPTH_16BIT: ctrl=0x60; break; default: ctrl=0; } double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; @@ -146,40 +146,44 @@ void DivPlatformYMZ280B::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>511) chan[i].freq=511; // ADPCM has half the range - if (s->depth==3 && chan[i].freq>255) chan[i].freq=255; - ctrl|=(chan[i].active?0x80:0)|((s->loopStart>=0)?0x10:0)|(chan[i].freq>>8); + if (s->depth==DIV_SAMPLE_DEPTH_YMZ_ADPCM && chan[i].freq>255) chan[i].freq=255; + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|(chan[i].freq>>8); if (chan[i].keyOn) { unsigned int start=s->offYMZ280B; - unsigned int loop=0; + unsigned int loopStart=0; + unsigned int loopEnd=0; unsigned int end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1); if (chan[i].audPos>0) { switch (s->depth) { - case 3: start+=chan[i].audPos/2; break; - case 8: start+=chan[i].audPos; break; - case 16: start+=chan[i].audPos*2; break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: start+=chan[i].audPos/2; break; + case DIV_SAMPLE_DEPTH_8BIT: start+=chan[i].audPos; break; + case DIV_SAMPLE_DEPTH_16BIT: start+=chan[i].audPos*2; break; + default: break; } start=MIN(start,end); } - if (s->loopStart>=0) { + if (s->isLoopable()) { switch (s->depth) { - case 3: loop=start+s->loopStart/2; break; - case 8: loop=start+s->loopStart; break; - case 16: loop=start+s->loopStart*2; break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: loopStart=start+s->loopStart/2; loopEnd=start+s->loopEnd/2; break; + case DIV_SAMPLE_DEPTH_8BIT: loopStart=start+s->loopStart; loopEnd=start+s->loopEnd; break; + case DIV_SAMPLE_DEPTH_16BIT: loopStart=start+s->loopStart*2; loopEnd=start+s->loopEnd*2; break; + default: break; } - loop=MIN(loop,end); + loopEnd=MIN(loopEnd,end); + loopStart=MIN(loopStart,loopEnd); } rWrite(0x01+i*4,ctrl&~0x80); // force keyoff first rWrite(0x20+i*4,(start>>16)&0xff); - rWrite(0x21+i*4,(loop>>16)&0xff); - rWrite(0x22+i*4,(end>>16)&0xff); + rWrite(0x21+i*4,(loopStart>>16)&0xff); + rWrite(0x22+i*4,(loopEnd>>16)&0xff); rWrite(0x23+i*4,(end>>16)&0xff); rWrite(0x40+i*4,(start>>8)&0xff); - rWrite(0x41+i*4,(loop>>8)&0xff); - rWrite(0x42+i*4,(end>>8)&0xff); + rWrite(0x41+i*4,(loopStart>>8)&0xff); + rWrite(0x42+i*4,(loopEnd>>8)&0xff); rWrite(0x43+i*4,(end>>8)&0xff); rWrite(0x60+i*4,start&0xff); - rWrite(0x61+i*4,loop&0xff); - rWrite(0x62+i*4,end&0xff); + rWrite(0x61+i*4,loopStart&0xff); + rWrite(0x62+i*4,loopEnd&0xff); rWrite(0x63+i*4,end&0xff); if (!chan[i].std.vol.had) { chan[i].outVol=chan[i].vol; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 329c5b54d..bff0c3c3f 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1204,17 +1204,17 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); samp_prevSample=samp_temp; - if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples && (int)sPreview.pos>=s->loopStart) { + if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) { sPreview.pos=s->loopStart; } } } - if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples && (int)sPreview.pos>=s->loopStart) { + if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) { sPreview.pos=s->loopStart; - } else { + } else if (sPreview.pos>=s->samples) { sPreview.sample=-1; } } diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 908b9a0d8..60eb35bb2 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -38,6 +38,65 @@ DivSampleHistory::~DivSampleHistory() { if (data!=NULL) delete[] data; } +bool DivSample::isLoopable() { + return (loopStart>=0 && loopStartloopStart && loopEnd<=(int)samples); +} + +unsigned int DivSample::getEndPosition(DivSampleDepth depth) { + int end=loopEnd; + unsigned int len=samples; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + end=(loopEnd+7)/8; + len=length1; + break; + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + end=(loopEnd+7)/8; + len=lengthDPCM; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + end=(loopEnd+1)/2; + len=lengthZ; + break; + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + end=(loopEnd+1)/2; + len=lengthQSoundA; + break; + case DIV_SAMPLE_DEPTH_ADPCM_A: + end=(loopEnd+1)/2; + len=lengthA; + break; + case DIV_SAMPLE_DEPTH_ADPCM_B: + end=(loopEnd+1)/2; + len=lengthB; + break; + case DIV_SAMPLE_DEPTH_8BIT: + end=loopEnd; + len=length8; + break; + case DIV_SAMPLE_DEPTH_BRR: + end=9*((loopEnd+15)/16); + len=lengthBRR; + break; + case DIV_SAMPLE_DEPTH_VOX: + end=(loopEnd+1)/2; + len=lengthVOX; + break; + case DIV_SAMPLE_DEPTH_16BIT: + end=loopEnd*2; + len=length16; + break; + default: + break; + } + return isLoopable()?end:len; +} + +void DivSample::setSampleCount(unsigned int count) { + samples=count; + if ((!isLoopable()) || loopEnd<0 || loopEnd>(int)samples) loopEnd=samples; +} + bool DivSample::save(const char* path) { #ifndef HAVE_SNDFILE logE("Furnace was not compiled with libsndfile!"); @@ -53,7 +112,7 @@ bool DivSample::save(const char* path) { si.channels=1; si.samplerate=rate; switch (depth) { - case 8: // 8-bit + case DIV_SAMPLE_DEPTH_8BIT: // 8-bit si.format=SF_FORMAT_PCM_U8|SF_FORMAT_WAV; break; default: // 16-bit @@ -76,17 +135,17 @@ bool DivSample::save(const char* path) { inst.detune = 50 - (pitch % 100); inst.velocity_hi = 0x7f; inst.key_hi = 0x7f; - if(loopStart != -1) + if(isLoopable()) { inst.loop_count = 1; inst.loops[0].mode = SF_LOOP_FORWARD; inst.loops[0].start = loopStart; - inst.loops[0].end = samples; + inst.loops[0].end = loopEnd; } sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst)); switch (depth) { - case 8: { + case DIV_SAMPLE_DEPTH_8BIT: { // convert from signed to unsigned unsigned char* buf=new unsigned char[length8]; for (size_t i=0; isamples) end=samples; int count=samples-(end-begin); if (count<=0) return resize(0); - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); if (begin>0) { memcpy(data8,oldData8,begin); } @@ -234,13 +293,13 @@ bool DivSample::strip(unsigned int begin, unsigned int end) { // do nothing return true; } - samples=count; + setSampleCount(count); return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); if (begin>0) { memcpy(data16,oldData16,sizeof(short)*begin); } @@ -252,7 +311,7 @@ bool DivSample::strip(unsigned int begin, unsigned int end) { // do nothing return true; } - samples=count; + setSampleCount(count); return true; } return false; @@ -262,31 +321,31 @@ bool DivSample::trim(unsigned int begin, unsigned int end) { int count=end-begin; if (count==0) return true; if (begin==0 && end==samples) return true; - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); memcpy(data8,oldData8+begin,count); delete[] oldData8; } else { // do nothing return true; } - samples=count; + setSampleCount(count); return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); memcpy(data16,&(oldData16[begin]),sizeof(short)*count); delete[] oldData16; } else { // do nothing return true; } - samples=count; + setSampleCount(count); return true; } return false; @@ -294,11 +353,11 @@ bool DivSample::trim(unsigned int begin, unsigned int end) { bool DivSample::insert(unsigned int pos, unsigned int length) { unsigned int count=samples+length; - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); if (pos>0) { memcpy(data8,oldData8,pos); } @@ -307,15 +366,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { } delete[] oldData8; } else { - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); } - samples=count; + setSampleCount(count); return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); if (pos>0) { memcpy(data16,oldData16,sizeof(short)*pos); } @@ -324,9 +383,9 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { } delete[] oldData16; } else { - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); } - samples=count; + setSampleCount(count); return true; } return false; @@ -337,15 +396,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { int finalCount=(double)samples*(r/(double)rate); \ signed char* oldData8=data8; \ short* oldData16=data16; \ - if (depth==16) { \ + if (depth==DIV_SAMPLE_DEPTH_16BIT) { \ if (data16!=NULL) { \ data16=NULL; \ - initInternal(16,finalCount); \ + initInternal(DIV_SAMPLE_DEPTH_16BIT,finalCount); \ } \ - } else if (depth==8) { \ + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \ if (data8!=NULL) { \ data8=NULL; \ - initInternal(8,finalCount); \ + initInternal(DIV_SAMPLE_DEPTH_8BIT,finalCount); \ } \ } else { \ return false; \ @@ -353,19 +412,20 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { #define RESAMPLE_END \ if (loopStart>=0) loopStart=(double)loopStart*(r/(double)rate); \ + if (loopEnd>=0) loopEnd=(double)loopEnd*(r/(double)rate); \ centerRate=(int)((double)centerRate*(r/(double)rate)); \ rate=r; \ samples=finalCount; \ - if (depth==16) { \ + if (depth==DIV_SAMPLE_DEPTH_16BIT) { \ delete[] oldData16; \ - } else if (depth==8) { \ + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \ delete[] oldData8; \ } bool DivSample::resampleNone(double r) { RESAMPLE_BEGIN; - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples) { @@ -374,7 +434,7 @@ bool DivSample::resampleNone(double r) { data16[i]=oldData16[pos]; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i=samples) { @@ -396,7 +456,7 @@ bool DivSample::resampleLinear(double r) { unsigned int posInt=0; double factor=(double)rate/r; - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples)?0:oldData16[posInt]; short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1]; @@ -409,7 +469,7 @@ bool DivSample::resampleLinear(double r) { posInt++; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i=samples)?0:oldData8[posInt]; short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1]; @@ -436,7 +496,7 @@ bool DivSample::resampleCubic(double r) { double factor=(double)rate/r; float* cubicTable=DivFilterTables::getCubicTable(); - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples)?0:oldData16[posInt]; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i>3]>>(i&7))&1)?0x7fff:-0x7fff; } break; - case 1: { // DPCM + case DIV_SAMPLE_DEPTH_1BIT_DPCM: { // DPCM int accum=0; for (unsigned int i=0; i>3]>>(i&7))&1)?1:-1; @@ -687,27 +747,27 @@ void DivSample::render() { } break; } - case 3: // YMZ ADPCM + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: // YMZ ADPCM ymz_decode(dataZ,data16,samples); break; - case 4: // QSound ADPCM + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM bs_decode(dataQSoundA,data16,samples); break; - case 5: // ADPCM-A + case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A yma_decode(dataA,data16,samples); break; - case 6: // ADPCM-B + case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B ymb_decode(dataB,data16,samples); break; - case 8: // 8-bit PCM + case DIV_SAMPLE_DEPTH_8BIT: // 8-bit PCM for (unsigned int i=0; i0) { data1[i>>3]|=1<<(i&7); } } } - if (depth!=1) { // DPCM - if (!initInternal(1,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_1BIT_DPCM) { // DPCM + if (!initInternal(DIV_SAMPLE_DEPTH_1BIT_DPCM,samples)) return; int accum=63; for (unsigned int i=0; i>9; @@ -739,84 +799,88 @@ void DivSample::render() { if (accum>127) accum=127; } } - if (depth!=3) { // YMZ ADPCM - if (!initInternal(3,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_YMZ_ADPCM) { // YMZ ADPCM + if (!initInternal(DIV_SAMPLE_DEPTH_YMZ_ADPCM,samples)) return; ymz_encode(data16,dataZ,(samples+7)&(~0x7)); } - if (depth!=4) { // QSound ADPCM - if (!initInternal(4,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_QSOUND_ADPCM) { // QSound ADPCM + if (!initInternal(DIV_SAMPLE_DEPTH_QSOUND_ADPCM,samples)) return; bs_encode(data16,dataQSoundA,samples); } // TODO: pad to 256. - if (depth!=5) { // ADPCM-A - if (!initInternal(5,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_ADPCM_A) { // ADPCM-A + if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_A,samples)) return; yma_encode(data16,dataA,(samples+511)&(~0x1ff)); } - if (depth!=6) { // ADPCM-B - if (!initInternal(6,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_ADPCM_B) { // ADPCM-B + if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_B,samples)) return; ymb_encode(data16,dataB,(samples+511)&(~0x1ff)); } - if (depth!=8) { // 8-bit PCM - if (!initInternal(8,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_8BIT) { // 8-bit PCM + if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return; for (unsigned int i=0; i>8; } } // TODO: BRR! - if (depth!=10) { // VOX - if (!initInternal(10,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX + if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return; oki_encode(data16,dataVOX,samples); } } void* DivSample::getCurBuf() { switch (depth) { - case 0: + case DIV_SAMPLE_DEPTH_1BIT: return data1; - case 1: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: return dataDPCM; - case 3: + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: return dataZ; - case 4: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: return dataQSoundA; - case 5: + case DIV_SAMPLE_DEPTH_ADPCM_A: return dataA; - case 6: + case DIV_SAMPLE_DEPTH_ADPCM_B: return dataB; - case 8: + case DIV_SAMPLE_DEPTH_8BIT: return data8; - case 9: + case DIV_SAMPLE_DEPTH_BRR: return dataBRR; - case 10: + case DIV_SAMPLE_DEPTH_VOX: return dataVOX; - case 16: + case DIV_SAMPLE_DEPTH_16BIT: return data16; + default: + return NULL; } return NULL; } unsigned int DivSample::getCurBufLen() { switch (depth) { - case 0: + case DIV_SAMPLE_DEPTH_1BIT: return length1; - case 1: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: return lengthDPCM; - case 3: + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: return lengthZ; - case 4: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: return lengthQSoundA; - case 5: + case DIV_SAMPLE_DEPTH_ADPCM_A: return lengthA; - case 6: + case DIV_SAMPLE_DEPTH_ADPCM_B: return lengthB; - case 8: + case DIV_SAMPLE_DEPTH_8BIT: return length8; - case 9: + case DIV_SAMPLE_DEPTH_BRR: return lengthBRR; - case 10: + case DIV_SAMPLE_DEPTH_VOX: return lengthVOX; - case 16: + case DIV_SAMPLE_DEPTH_16BIT: return length16; + default: + return 0; } return 0; } @@ -831,9 +895,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { duplicate=new unsigned char[getCurBufLen()]; memcpy(duplicate,getCurBuf(),getCurBufLen()); } - h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart); + h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd); } else { - h=new DivSampleHistory(depth,rate,centerRate,loopStart); + h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd); } if (!doNotPush) { while (!redoHist.empty()) { @@ -863,7 +927,8 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { } \ rate=h->rate; \ centerRate=h->centerRate; \ - loopStart=h->loopStart; + loopStart=h->loopStart; \ + loopEnd=h->loopEnd; int DivSample::undo() { diff --git a/src/engine/sample.h b/src/engine/sample.h index 70f8418cf..103bcaa27 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -17,9 +17,28 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef _SAMPLE_H +#define _SAMPLE_H + +#pragma once + #include "../ta-utils.h" #include +enum DivSampleDepth: unsigned char { + DIV_SAMPLE_DEPTH_1BIT=0, + DIV_SAMPLE_DEPTH_1BIT_DPCM=1, + DIV_SAMPLE_DEPTH_YMZ_ADPCM=3, + DIV_SAMPLE_DEPTH_QSOUND_ADPCM=4, + DIV_SAMPLE_DEPTH_ADPCM_A=5, + DIV_SAMPLE_DEPTH_ADPCM_B=6, + DIV_SAMPLE_DEPTH_8BIT=8, + DIV_SAMPLE_DEPTH_BRR=9, + DIV_SAMPLE_DEPTH_VOX=10, + DIV_SAMPLE_DEPTH_16BIT=16, + DIV_SAMPLE_DEPTH_MAX // boundary for sample depth +}; + enum DivResampleFilters { DIV_RESAMPLE_NONE=0, DIV_RESAMPLE_LINEAR, @@ -32,10 +51,10 @@ enum DivResampleFilters { struct DivSampleHistory { unsigned char* data; unsigned int length, samples; - unsigned char depth; - int rate, centerRate, loopStart; + DivSampleDepth depth; + int rate, centerRate, loopStart, loopEnd; bool hasSample; - DivSampleHistory(void* d, unsigned int l, unsigned int s, unsigned char de, int r, int cr, int ls): + DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le): data((unsigned char*)d), length(l), samples(s), @@ -43,8 +62,9 @@ struct DivSampleHistory { rate(r), centerRate(cr), loopStart(ls), + loopEnd(le), hasSample(true) {} - DivSampleHistory(unsigned char de, int r, int cr, int ls): + DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le): data(NULL), length(0), samples(0), @@ -52,13 +72,14 @@ struct DivSampleHistory { rate(r), centerRate(cr), loopStart(ls), + loopEnd(le), hasSample(false) {} ~DivSampleHistory(); }; struct DivSample { String name; - int rate, centerRate, loopStart, loopOffP; + int rate, centerRate, loopStart, loopEnd, loopOffP; // valid values are: // - 0: ZX Spectrum overlay drum (1-bit) // - 1: 1-bit NES DPCM (1-bit) @@ -70,7 +91,7 @@ struct DivSample { // - 9: BRR (SNES) // - 10: VOX ADPCM // - 16: 16-bit PCM - unsigned char depth; + DivSampleDepth depth; // these are the new data structures. signed char* data8; // 8 @@ -93,6 +114,23 @@ struct DivSample { std::deque undoHist; std::deque redoHist; + /** + * check if sample is loopable. + * @return whether it is loopable. + */ + bool isLoopable(); + + /** + * get sample end position + * @return the samples end position. + */ + unsigned int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + + /** + * @warning DO NOT USE - internal functions + */ + void setSampleCount(unsigned int count); + /** * @warning DO NOT USE - internal functions */ @@ -116,7 +154,7 @@ struct DivSample { * @param count number of samples. * @return whether it was successful. */ - bool initInternal(unsigned char d, int count); + bool initInternal(DivSampleDepth d, int count); /** * initialize sample data. make sure you have set `depth` before doing so. @@ -212,8 +250,9 @@ struct DivSample { rate(32000), centerRate(8363), loopStart(-1), + loopEnd(-1), loopOffP(0), - depth(16), + depth(DIV_SAMPLE_DEPTH_16BIT), data8(NULL), data16(NULL), data1(NULL), @@ -253,3 +292,5 @@ struct DivSample { samples(0) {} ~DivSample(); }; + +#endif diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 0d1ad4f52..ef1c5dc37 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -512,7 +512,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(streamID); w->writeS(write.val); // sample number w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags - if (sample->loopStart>0 && !sampleDir[streamID]) { + if (sample->isLoopable() && !sampleDir[streamID]) { loopTimer[streamID]=sample->length8; loopSample[streamID]=write.val; } @@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { size_t memPos=0; for (int i=0; ilength8+0xff)&(~0xff); + unsigned int alignedSize=(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff); if (alignedSize>65536) alignedSize=65536; if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) { memPos=(memPos+0xffff)&0xff0000; @@ -1559,8 +1559,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { sample->offSegaPCM=memPos; unsigned int readPos=0; for (unsigned int j=0; j=sample->length8) { - if (sample->loopStart>=0 && sample->loopStart<(int)sample->length8) { + if (readPos>=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (sample->isLoopable()) { readPos=sample->loopStart; pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); } else { @@ -1663,7 +1663,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen); for (int i=0; idepth==16) { + if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { unsigned int pos=s->offYMZ280B; for (unsigned int j=0; jsamples; j++) { unsigned char lo=sampleMem[pos+j*2]; @@ -1871,12 +1871,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { if (loopSample[nextToTouch]loopStart<(int)sample->length8) { + if (sample->loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { w->writeC(0x93); w->writeC(nextToTouch); w->writeI(sample->off8+sample->loopStart); w->writeC(0x81); - w->writeI(sample->length8-sample->loopStart); + w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart); } } loopSample[nextToTouch]=-1; diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index d9739f68d..12e775b53 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -18,6 +18,7 @@ */ #include "gui.h" +#include "guiConst.h" #include "debug.h" #include "IconsFontAwesome4.h" #include @@ -154,12 +155,19 @@ void FurnaceGUI::drawDebug() { ImGui::Text("rate: %d",sample->rate); ImGui::Text("centerRate: %d",sample->centerRate); ImGui::Text("loopStart: %d",sample->loopStart); + ImGui::Text("loopEnd: %d", sample->loopEnd); ImGui::Text("loopOffP: %d",sample->loopOffP); - ImGui::Text("depth: %d",sample->depth); + if (sampleDepths[sample->depth]!=NULL) { + ImGui::Text("depth: %d (%s)",(unsigned char)sample->depth,sampleDepths[sample->depth]); + } else { + ImGui::Text("depth: %d ()",(unsigned char)sample->depth); + } + ImGui::Text("length8: %d",sample->length8); ImGui::Text("length16: %d",sample->length16); ImGui::Text("length1: %d",sample->length1); ImGui::Text("lengthDPCM: %d",sample->lengthDPCM); + ImGui::Text("lengthZ: %d",sample->lengthZ); ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA); ImGui::Text("lengthA: %d",sample->lengthA); ImGui::Text("lengthB: %d",sample->lengthB); @@ -170,6 +178,7 @@ void FurnaceGUI::drawDebug() { ImGui::Text("off16: %x",sample->off16); ImGui::Text("off1: %x",sample->off1); ImGui::Text("offDPCM: %x",sample->offDPCM); + ImGui::Text("offZ: %x",sample->offZ); ImGui::Text("offQSoundA: %x",sample->offQSoundA); ImGui::Text("offA: %x",sample->offA); ImGui::Text("offB: %x",sample->offB); @@ -179,6 +188,8 @@ void FurnaceGUI::drawDebug() { ImGui::Text("offQSound: %x",sample->offQSound); ImGui::Text("offX1_010: %x",sample->offX1_010); ImGui::Text("offSU: %x",sample->offSU); + ImGui::Text("offYMZ280B: %x",sample->offYMZ280B); + ImGui::Text("offRF5C68: %x",sample->offRF5C68); ImGui::Text("samples: %d",sample->samples); ImGui::TreePop(); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 60c9d5c3a..ca640d627 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -709,6 +709,7 @@ void FurnaceGUI::doAction(int what) { sample->centerRate=prevSample->centerRate; sample->name=prevSample->name; sample->loopStart=prevSample->loopStart; + sample->loopEnd=prevSample->loopEnd; sample->depth=prevSample->depth; if (sample->init(prevSample->samples)) { if (prevSample->getCurBuf()!=NULL) { @@ -838,7 +839,7 @@ void FurnaceGUI::doAction(int what) { if (!sample->insert(pos,sampleClipboardLen)) { showError("couldn't paste! make sure your sample is 8 or 16-bit."); } else { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (size_t i=0; idata8[pos+i]=sampleClipboard[i]>>8; } @@ -864,7 +865,7 @@ void FurnaceGUI::doAction(int what) { if (pos<0) pos=0; e->lockEngine([this,sample,pos]() { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (size_t i=0; i=sample->samples) break; sample->data8[pos+i]=sampleClipboard[i]>>8; @@ -894,7 +895,7 @@ void FurnaceGUI::doAction(int what) { if (pos<0) pos=0; e->lockEngine([this,sample,pos]() { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (size_t i=0; i=sample->samples) break; int val=sample->data8[pos+i]+(sampleClipboard[i]>>8); @@ -948,7 +949,7 @@ void FurnaceGUI::doAction(int what) { SAMPLE_OP_BEGIN; float maxVal=0.0f; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]/32767.0f); if (val>maxVal) maxVal=val; @@ -963,7 +964,7 @@ void FurnaceGUI::doAction(int what) { sample->data16[i]=val; } } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]/127.0f); if (val>maxVal) maxVal=val; @@ -994,14 +995,14 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*float(i-start)/float(end-start); if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*float(i-start)/float(end-start); if (val<-128) val=-128; @@ -1024,14 +1025,14 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*float(end-i)/float(end-start); if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*float(end-i)/float(end-start); if (val<-128) val=-128; @@ -1058,11 +1059,11 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]=0; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]=0; } @@ -1116,7 +1117,7 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[ri]^=sample->data16[i]; sample->data16[i]^=sample->data16[ri]; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; ilockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]=-sample->data16[i]; if (sample->data16[i]==-32768) sample->data16[i]=32767; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]=-sample->data8[i]; if (sample->data16[i]==-128) sample->data16[i]=127; @@ -1174,11 +1175,11 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]^=0x8000; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]^=0x80; } @@ -1261,8 +1262,8 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - sample->trim(0,end); sample->loopStart=start; + sample->loopEnd=end; updateSampleTex=true; e->renderSamples(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 80f9b5d85..64e7b18db 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -116,7 +116,7 @@ const char* insTypes[DIV_INS_MAX+1]={ NULL }; -const char* sampleDepths[17]={ +const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={ "1-bit PCM", "1-bit DPCM", NULL, diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index 69085c324..a6df68f62 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -40,7 +40,7 @@ extern const char* noteNames[180]; extern const char* noteNamesG[180]; extern const char* pitchLabel[11]; extern const char* insTypes[]; -extern const char* sampleDepths[17]; +extern const char* sampleDepths[]; extern const char* resampleStrats[]; extern const int availableSystems[]; extern const FurnaceGUIActionDef guiActions[]; diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index b684a0c77..e9b5cfb35 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -41,7 +41,7 @@ void FurnaceGUI::drawSampleEdit() { } else { DivSample* sample=e->song.sample[curSample]; String sampleType="Invalid"; - if (sample->depth<17) { + if (sample->depthdepth]!=NULL) { sampleType=sampleDepths[sample->depth]; } @@ -61,11 +61,11 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) { - for (int i=0; i<17; i++) { + for (int i=0; iprepareUndo(true); - sample->depth=i; + sample->depth=(DivSampleDepth)i; e->renderSamplesP(); updateSampleTex=true; MARK_MODIFIED; @@ -93,22 +93,43 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::TableNextColumn(); - bool doLoop=(sample->loopStart>=0); + bool doLoop=(sample->isLoopable()); if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { sample->loopStart=0; + sample->loopEnd=sample->samples; } else { sample->loopStart=-1; + sample->loopEnd=sample->samples; } updateSampleTex=true; } if (doLoop) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Loop Start"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED - if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { + if (ImGui::InputInt("##LoopStartPosition",&sample->loopStart,1,10)) { MARK_MODIFIED + if (sample->loopStart<0) { sample->loopStart=0; } + if (sample->loopStart>sample->loopEnd) { + sample->loopStart=sample->loopEnd; + } + updateSampleTex=true; + } + ImGui::TableNextColumn(); + ImGui::Text("Loop End"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##LoopEndPosition",&sample->loopEnd,1,10)) { MARK_MODIFIED + if (sample->loopEndloopStart) { + sample->loopEnd=sample->loopStart; + } + if (sample->loopEnd>=(int)sample->samples) { + sample->loopEnd=sample->samples; + } updateSampleTex=true; } } @@ -123,7 +144,7 @@ void FurnaceGUI::drawSampleEdit() { */ ImGui::Separator(); - ImGui::BeginDisabled(sample->depth!=8 && sample->depth!=16); + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { @@ -275,14 +296,14 @@ void FurnaceGUI::drawSampleEdit() { SAMPLE_OP_BEGIN; float vol=amplifyVol/100.0f; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*vol; if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*vol; if (val<-128) val=-128; @@ -466,7 +487,7 @@ void FurnaceGUI::drawSampleEdit() { double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; irate))*M_PI); @@ -482,7 +503,7 @@ void FurnaceGUI::drawSampleEdit() { if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; irate))*M_PI); @@ -574,11 +595,11 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) { - for (int i=0; i<17; i++) { + for (int i=0; iprepareUndo(true); - sample->depth=i; + sample->depth=(DivSampleDepth)i; e->renderSamplesP(); updateSampleTex=true; MARK_MODIFIED; @@ -607,22 +628,43 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::TableNextColumn(); - bool doLoop=(sample->loopStart>=0); + bool doLoop=(sample->isLoopable()); if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { sample->loopStart=0; + sample->loopEnd=sample->samples; } else { sample->loopStart=-1; + sample->loopEnd=sample->samples; } updateSampleTex=true; } if (doLoop) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Loop Start"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED - if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { + if (ImGui::InputInt("##LoopStartPosition",&sample->loopStart,1,10)) { MARK_MODIFIED + if (sample->loopStart<0) { sample->loopStart=0; } + if (sample->loopStart>sample->loopEnd) { + sample->loopStart=sample->loopEnd; + } + updateSampleTex=true; + } + ImGui::TableNextColumn(); + ImGui::Text("Loop End"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##LoopEndPosition",&sample->loopEnd,1,10)) { MARK_MODIFIED + if (sample->loopEndloopStart) { + sample->loopEnd=sample->loopStart; + } + if (sample->loopEnd>=(int)sample->samples) { + sample->loopEnd=sample->samples; + } updateSampleTex=true; } } @@ -637,7 +679,7 @@ void FurnaceGUI::drawSampleEdit() { */ ImGui::Separator(); - ImGui::BeginDisabled(sample->depth!=8 && sample->depth!=16); + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { @@ -820,7 +862,7 @@ void FurnaceGUI::drawSampleEdit() { double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; irate))*M_PI); @@ -836,7 +878,7 @@ void FurnaceGUI::drawSampleEdit() { if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; irate))*M_PI); @@ -890,14 +932,14 @@ void FurnaceGUI::drawSampleEdit() { SAMPLE_OP_BEGIN; float vol=amplifyVol/100.0f; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*vol; if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*vol; if (val<-128) val=-128; @@ -1138,7 +1180,7 @@ void FurnaceGUI::drawSampleEdit() { for (int i=0; iloopStart>=0 && sample->loopStart<(int)sample->samples && scaledPos>=sample->loopStart) { + if (sample->isLoopable() && (scaledPos>=sample->loopStart && scaledPos<=sample->loopEnd)) { data[i*availX+j]=bgColorLoop; } else { data[i*availX+j]=bgColor; @@ -1158,7 +1200,7 @@ void FurnaceGUI::drawSampleEdit() { if (xCoarse>=sample->samples) break; int y1, y2; int totalAdvance=0; - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; } else { y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; @@ -1171,7 +1213,7 @@ void FurnaceGUI::drawSampleEdit() { totalAdvance+=xAdvanceCoarse; if (xCoarse>=sample->samples) break; do { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; } else { y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; @@ -1209,11 +1251,11 @@ void FurnaceGUI::drawSampleEdit() { sampleSelStart=0; sampleSelEnd=sample->samples; } else { - if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) { + if (sample->samples>0 && (sample->depth==DIV_SAMPLE_DEPTH_16BIT || sample->depth==DIV_SAMPLE_DEPTH_8BIT)) { sampleDragStart=rectMin; sampleDragAreaSize=rectSize; - sampleDrag16=(sample->depth==16); - sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8); + sampleDrag16=(sample->depth==DIV_SAMPLE_DEPTH_16BIT); + sampleDragTarget=(sample->depth==DIV_SAMPLE_DEPTH_16BIT)?((void*)sample->data16):((void*)sample->data8); sampleDragLen=sample->samples; sampleDragActive=true; sampleSelStart=-1; @@ -1312,7 +1354,7 @@ void FurnaceGUI::drawSampleEdit() { posX=samplePos+pos.x*sampleZoom; if (posX>(int)sample->samples) posX=-1; } - posY=(0.5-pos.y/rectSize.y)*((sample->depth==8)?255:32767); + posY=(0.5-pos.y/rectSize.y)*((sample->depth==DIV_SAMPLE_DEPTH_8BIT)?255:32767); if (posX>=0) { statusBar+=fmt::sprintf(" | (%d, %d)",posX,posY); } @@ -1362,7 +1404,7 @@ void FurnaceGUI::drawSampleEdit() { } } - if (sample->depth!=8 && sample->depth!=16) { + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { statusBar="Non-8/16-bit samples cannot be edited without prior conversion."; } From 7bc3166ed5eac383364595541c966a6ca14fe337 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 22 Jul 2022 00:01:29 -0500 Subject: [PATCH 056/515] YMZ280B: frequency precision improvement frequency is now multiplied by 256 and then fed to the chip divided by 256 to increase freq precision --- src/engine/platform/ymz280b.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 87193da50..b690d30cb 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -23,7 +23,7 @@ #include #include -#define CHIP_FREQBASE 98304 +#define CHIP_FREQBASE 25165824 #define rWrite(a,v) {if(!skipRegisterWrites) {ymz280b.write(0,a); ymz280b.write(1,v); regPool[a]=v; if(dumpWrites) addWrite(a,v); }} @@ -142,7 +142,7 @@ void DivPlatformYMZ280B::tick(bool sysTick) { default: ctrl=0; } double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; - chan[i].freq=(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE))-1; + chan[i].freq=(int)round(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE)/256.0)-1; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>511) chan[i].freq=511; // ADPCM has half the range @@ -267,14 +267,15 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) { case DIV_CMD_NOTE_PORTA: { int destFreq=NOTE_FREQUENCY(c.value2); bool return2=false; + int multiplier=(parent->song.linearPitch==2)?1:256; if (destFreq>chan[c.chan].baseFreq) { - chan[c.chan].baseFreq+=c.value; + chan[c.chan].baseFreq+=c.value*multiplier; if (chan[c.chan].baseFreq>=destFreq) { chan[c.chan].baseFreq=destFreq; return2=true; } } else { - chan[c.chan].baseFreq-=c.value; + chan[c.chan].baseFreq-=c.value*multiplier; if (chan[c.chan].baseFreq<=destFreq) { chan[c.chan].baseFreq=destFreq; return2=true; From d004629a58d750015fddad09ce3ac415267f6a45 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 22 Jul 2022 02:29:01 -0500 Subject: [PATCH 057/515] dev102 - new sample storage format --- papers/format.md | 44 +++++++++++++++++++++-- src/engine/engine.h | 4 +-- src/engine/fileOps.cpp | 81 ++++++++++++++++++++++++++---------------- 3 files changed, 95 insertions(+), 34 deletions(-) diff --git a/papers/format.md b/papers/format.md index 6281293ab..080914c1e 100644 --- a/papers/format.md +++ b/papers/format.md @@ -816,7 +816,47 @@ size | description 4?? | wavetable data ``` -# sample +# sample (>=102) + +this is the new sample storage format used in Furnace dev102 and higher. + +``` +size | description +-----|------------------------------------ + 4 | "SMP2" block ID + 4 | size of this block + STR | sample name + 4 | length + 4 | compatibility rate + 4 | C-4 rate + 1 | depth + | - 0: ZX Spectrum overlay drum (1-bit) + | - 1: 1-bit NES DPCM (1-bit) + | - 3: YMZ ADPCM + | - 4: QSound ADPCM + | - 5: ADPCM-A + | - 6: ADPCM-B + | - 8: 8-bit PCM + | - 9: BRR (SNES) + | - 10: VOX + | - 16: 16-bit PCM + 3 | reserved + 4 | loop start + | - -1 means no loop + 4 | loop end + | - -1 means no loop + 16 | sample presence bitfields + | - for future use. + | - indicates whether the sample should be present in the memory of a system. + | - read 4 32-bit numbers (for 4 memory banks per system, e.g. YM2610 + | does ADPCM-A and ADPCM-B on separate memory banks). + ??? | sample data + | - size is length +``` + +# old sample (<102) + +this format is present when saving using previous Furnace versions. ``` size | description @@ -825,7 +865,7 @@ size | description 4 | size of this block STR | sample name 4 | length - 4 | rate + 4 | compatibility rate 2 | volume (<58) or reserved 2 | pitch (<58) or reserved 1 | depth diff --git a/src/engine/engine.h b/src/engine/engine.h index 896c083a2..21fde0a70 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1 (dev101)" -#define DIV_ENGINE_VERSION 101 +#define DIV_VERSION "0.6pre1 (dev102)" +#define DIV_ENGINE_VERSION 102 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 40932a378..110259050 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1619,51 +1619,67 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } reader.read(magic,4); - if (strcmp(magic,"SMPL")!=0) { + if (strcmp(magic,"SMPL")!=0 && strcmp(magic,"SMP2")!=0) { logE("%d: invalid sample header!",i); lastError="invalid sample header!"; ds.unload(); delete[] file; return false; } + bool isNewSample=(strcmp(magic,"SMP2")==0); reader.readI(); DivSample* sample=new DivSample; logD("reading sample %d at %x...",i,samplePtr[i]); + if (!isNewSample) logV("(old sample)"); sample->name=reader.readString(); - sample->samples=sample->loopEnd=reader.readI(); + sample->samples=reader.readI(); + if (!isNewSample) { + sample->loopEnd=sample->samples; + } sample->rate=reader.readI(); - if (ds.version<58) { - vol=reader.readS(); - pitch=reader.readS(); - } else { - reader.readI(); - } - sample->depth=(DivSampleDepth)reader.readC(); - // reserved - reader.readC(); + if (isNewSample) { + sample->centerRate=reader.readI(); + sample->depth=(DivSampleDepth)reader.readC(); - // while version 32 stored this value, it was unused. - if (ds.version>=38) { - sample->centerRate=(unsigned short) reader.readS(); - } else { - reader.readS(); - } + // reserved + reader.readC(); + reader.readC(); + reader.readC(); - if (ds.version>=19) { sample->loopStart=reader.readI(); + sample->loopEnd=reader.readI(); + + for (int i=0; i<4; i++) { + reader.readI(); + } } else { - reader.readI(); + if (ds.version<58) { + vol=reader.readS(); + pitch=reader.readS(); + } else { + reader.readI(); + } + sample->depth=(DivSampleDepth)reader.readC(); + + // reserved + reader.readC(); + + // while version 32 stored this value, it was unused. + if (ds.version>=38) { + sample->centerRate=(unsigned short)reader.readS(); + } else { + reader.readS(); + } + + if (ds.version>=19) { + sample->loopStart=reader.readI(); + } else { + reader.readI(); + } } -/* - if (ds.version>=100) { - sample->loopEnd=reader.readI(); - } else { - reader.readI(); - } -*/ if (ds.version>=58) { // modern sample sample->init(sample->samples); reader.read(sample->getCurBuf(),sample->getCurBufLen()); @@ -3038,19 +3054,24 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { for (int i=0; itell()); - w->write("SMPL",4); + w->write("SMP2",4); blockStartSeek=w->tell(); w->writeI(0); w->writeString(sample->name,false); w->writeI(sample->samples); w->writeI(sample->rate); - w->writeI(0); // reserved (for now) + w->writeI(sample->centerRate); w->writeC(sample->depth); + w->writeC(0); // reserved + w->writeC(0); w->writeC(0); - w->writeS(sample->centerRate); w->writeI(sample->loopStart); - //w->writeI(sample->loopEnd); + w->writeI(sample->loopEnd); + + for (int i=0; i<4; i++) { + w->writeI(0xffffffff); + } w->write(sample->getCurBuf(),sample->getCurBufLen()); From 8d88ac766c109872114e7055988a819e9f62478e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 17:02:03 -0500 Subject: [PATCH 058/515] dev103 - store system name and other info in song --- TODO.md | 3 -- papers/format.md | 9 +++++ src/engine/engine.cpp | 13 ++++++- src/engine/engine.h | 8 ++-- src/engine/fileOps.cpp | 32 ++++++++++++++++ src/engine/song.h | 5 ++- src/engine/sysDef.cpp | 86 +++++++++++++++++++++--------------------- src/engine/vgmOps.cpp | 24 +++++------- src/gui/gui.cpp | 4 +- src/gui/gui.h | 1 + src/gui/newSong.cpp | 3 +- src/gui/songInfo.cpp | 27 +++++++++++++ 12 files changed, 146 insertions(+), 69 deletions(-) diff --git a/TODO.md b/TODO.md index 5032ea32e..46773705a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,5 @@ # to-do for 0.6pre1.5-0.6pre2 -- rewrite the system name detection function anyway - - this involves the addition of a new "system" field in the song (which solves the problem) - - songs made in older versions will go through old system name detection for compatibility - Game Boy envelope macro/sequence - volume commands should work on Game Boy - ability to customize `OFF`, `===` and `REL` diff --git a/papers/format.md b/papers/format.md index 080914c1e..537150215 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 103: Furnace dev103 +- 102: Furnace 0.6pre1 (dev102) - 101: Furnace 0.6pre1 (dev101) - 100: Furnace 0.6pre1 - 99: Furnace dev99 @@ -334,6 +336,13 @@ size | description 1 | number of additional subsongs 3 | reserved 4?? | pointers to subsong data + --- | **additional metadata** (>=103) + STR | system name + STR | album/category/game name + STR | song name (Japanese) + STR | song author (Japanese) + STR | system name (Japanese) + STR | album/category/game name (Japanese) ``` # subsong diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 659ea6b9a..f1e8dc043 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -842,7 +842,7 @@ void DivEngine::initSongWithDesc(const int* description) { } } -void DivEngine::createNew(const int* description) { +void DivEngine::createNew(const int* description, String sysName) { quitDispatch(); BUSY_BEGIN; saveLock.lock(); @@ -852,6 +852,11 @@ void DivEngine::createNew(const int* description) { if (description!=NULL) { initSongWithDesc(description); } + if (sysName=="") { + song.systemName=getSongSystemLegacyName(song,getConfInt("noMultiSystem",0)); + } else { + song.systemName=sysName; + } recalcChans(); saveLock.unlock(); BUSY_END; @@ -3197,6 +3202,12 @@ bool DivEngine::init() { preset.push_back(0); initSongWithDesc(preset.data()); } + String sysName=getConfString("initialSysName",""); + if (sysName=="") { + song.systemName=getSongSystemLegacyName(song,getConfInt("noMultiSystem",0)); + } else { + song.systemName=sysName; + } hasLoadedSomething=true; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 21fde0a70..f6567dd3a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1 (dev102)" -#define DIV_ENGINE_VERSION 102 +#define DIV_VERSION "dev103" +#define DIV_ENGINE_VERSION 103 // for imports #define DIV_VERSION_MOD 0xff01 @@ -454,7 +454,7 @@ class DivEngine { String encodeSysDesc(std::vector& desc); std::vector decodeSysDesc(String desc); // start fresh - void createNew(const int* description); + void createNew(const int* description, String sysName); // load a file. bool load(unsigned char* f, size_t length); // save as .dmf. @@ -576,7 +576,7 @@ class DivEngine { DivInstrumentType getPreferInsSecondType(int ch); // get song system name - String getSongSystemName(bool isMultiSystemAcceptable=true); + String getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAcceptable=true); // get sys name const char* getSystemName(DivSystem sys); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 110259050..e66e2c8d9 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -907,6 +907,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.system[1]=DIV_SYSTEM_FDS; } + ds.systemName=getSongSystemLegacyName(ds,getConfInt("noMultiSystem",0)); + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); @@ -1482,7 +1484,22 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { for (int i=0; i=103) { + ds.systemName=reader.readString(); + ds.category=reader.readString(); + ds.nameJ=reader.readString(); + ds.authorJ=reader.readString(); + ds.systemNameJ=reader.readString(); + ds.categoryJ=reader.readString(); + } else { + ds.systemName=getSongSystemLegacyName(ds,getConfInt("noMultiSystem",0)); + } + + // read subsongs + if (ds.version>=95) { for (int i=0; i='1' && magic[0]<='9') { logD("detected a FastTracker module"); + ds.systemName="PC"; chCount=magic[0]-'0'; } else if (memcmp(magic,"FLT",3)==0 && magic[3]>='1' && magic[3]<='9') { logD("detected a Fairlight module"); + ds.systemName="Amiga"; chCount=magic[3]-'0'; } else if (memcmp(magic,"TDZ",3)==0 && magic[3]>='1' && magic[3]<='9') { logD("detected a TakeTracker module"); + ds.systemName="PC"; chCount=magic[3]-'0'; } else if ((memcmp(magic+2,"CH",2)==0 || memcmp(magic+2,"CN",2)==0) && (magic[0]>='1' && magic[0]<='9' && magic[1]>='0' && magic[1]<='9')) { logD("detected a Fast/TakeTracker module"); + ds.systemName="PC"; chCount=((magic[0]-'0')*10)+(magic[1]-'0'); } else { insCount=15; logD("possibly a Soundtracker module"); + ds.systemName="Amiga"; chCount=4; } @@ -2976,6 +3000,14 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeI(0); } + // additional metadata + w->writeString(song.systemName,false); + w->writeString(song.category,false); + w->writeString(song.nameJ,false); + w->writeString(song.authorJ,false); + w->writeString(song.systemNameJ,false); + w->writeString(song.categoryJ,false); + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); diff --git a/src/engine/song.h b/src/engine/song.h index 26640fdd4..8375fc561 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -428,7 +428,7 @@ struct DivSong { unsigned int systemFlags[32]; // song information - String name, author; + String name, author, systemName; // legacy song information // those will be stored in .fur and mapped to VGM as: @@ -438,7 +438,7 @@ struct DivSong { String carrier, composer, vendor, category, writer, arranger, copyright, manGroup, manInfo, createdDate, revisionDate; // more VGM specific stuff - String nameJ, authorJ, categoryJ; + String nameJ, authorJ, categoryJ, systemNameJ; // other things String notes; @@ -541,6 +541,7 @@ struct DivSong { systemLen(2), name(""), author(""), + systemName(""), carrier(""), composer(""), vendor(""), diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 25e35227f..813e409e5 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -54,14 +54,14 @@ std::vector& DivEngine::getPossibleInsTypes() { return possibleInsTypes; } -// TODO: deprecate when I add "system name" field in the file. -String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { - switch (song.systemLen) { +// for pre-dev103 modules +String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAcceptable) { + switch (ds.systemLen) { case 0: return "help! what's going on!"; case 1: - if (song.system[0]==DIV_SYSTEM_AY8910) { - switch (song.systemFlags[0]&0x3f) { + if (ds.system[0]==DIV_SYSTEM_AY8910) { + switch (ds.systemFlags[0]&0x3f) { case 0: // AY-3-8910, 1.79MHz case 1: // AY-3-8910, 1.77MHz case 2: // AY-3-8910, 1.75MHz @@ -88,116 +88,116 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { return "Intellivision (PAL)"; default: - if ((song.systemFlags[0]&0x30)==0x00) { + if ((ds.systemFlags[0]&0x30)==0x00) { return "AY-3-8910"; - } else if ((song.systemFlags[0]&0x30)==0x10) { + } else if ((ds.systemFlags[0]&0x30)==0x10) { return "Yamaha YM2149"; - } else if ((song.systemFlags[0]&0x30)==0x20) { + } else if ((ds.systemFlags[0]&0x30)==0x20) { return "Overclocked Sunsoft 5B"; - } else if ((song.systemFlags[0]&0x30)==0x30) { + } else if ((ds.systemFlags[0]&0x30)==0x30) { return "Intellivision"; } } - } else if (song.system[0]==DIV_SYSTEM_SMS) { - switch (song.systemFlags[0]&0x0f) { + } else if (ds.system[0]==DIV_SYSTEM_SMS) { + switch (ds.systemFlags[0]&0x0f) { case 0: case 1: return "Sega Master System"; case 6: return "BBC Micro"; } - } else if (song.system[0]==DIV_SYSTEM_YM2612) { - switch (song.systemFlags[0]&3) { + } else if (ds.system[0]==DIV_SYSTEM_YM2612) { + switch (ds.systemFlags[0]&3) { case 2: return "FM Towns"; } - } else if (song.system[0]==DIV_SYSTEM_YM2151) { - switch (song.systemFlags[0]&3) { + } else if (ds.system[0]==DIV_SYSTEM_YM2151) { + switch (ds.systemFlags[0]&3) { case 2: return "Sharp X68000"; } - } else if (song.system[0]==DIV_SYSTEM_SAA1099) { - switch (song.systemFlags[0]&3) { + } else if (ds.system[0]==DIV_SYSTEM_SAA1099) { + switch (ds.systemFlags[0]&3) { case 0: return "SAM Coupé"; } } - return getSystemName(song.system[0]); + return getSystemName(ds.system[0]); case 2: - if (song.system[0]==DIV_SYSTEM_YM2612 && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_YM2612 && ds.system[1]==DIV_SYSTEM_SMS) { return "Sega Genesis/Mega Drive"; } - if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_YM2612_EXT && ds.system[1]==DIV_SYSTEM_SMS) { return "Sega Genesis Extended Channel 3"; } - if (song.system[0]==DIV_SYSTEM_OPLL && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_OPLL && ds.system[1]==DIV_SYSTEM_SMS) { return "NTSC-J Sega Master System"; } - if (song.system[0]==DIV_SYSTEM_OPLL_DRUMS && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_OPLL_DRUMS && ds.system[1]==DIV_SYSTEM_SMS) { return "NTSC-J Sega Master System + drums"; } - if (song.system[0]==DIV_SYSTEM_OPLL && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_OPLL && ds.system[1]==DIV_SYSTEM_AY8910) { return "MSX-MUSIC"; } - if (song.system[0]==DIV_SYSTEM_OPLL_DRUMS && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_OPLL_DRUMS && ds.system[1]==DIV_SYSTEM_AY8910) { return "MSX-MUSIC + drums"; } - if (song.system[0]==DIV_SYSTEM_C64_6581 && song.system[1]==DIV_SYSTEM_C64_6581) { + if (ds.system[0]==DIV_SYSTEM_C64_6581 && ds.system[1]==DIV_SYSTEM_C64_6581) { return "Commodore 64 with dual 6581"; } - if (song.system[0]==DIV_SYSTEM_C64_8580 && song.system[1]==DIV_SYSTEM_C64_8580) { + if (ds.system[0]==DIV_SYSTEM_C64_8580 && ds.system[1]==DIV_SYSTEM_C64_8580) { return "Commodore 64 with dual 8580"; } - if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) { + if (ds.system[0]==DIV_SYSTEM_YM2151 && ds.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) { return "YM2151 + SegaPCM Arcade (compatibility)"; } - if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM) { + if (ds.system[0]==DIV_SYSTEM_YM2151 && ds.system[1]==DIV_SYSTEM_SEGAPCM) { return "YM2151 + SegaPCM Arcade"; } - if (song.system[0]==DIV_SYSTEM_SAA1099 && song.system[1]==DIV_SYSTEM_SAA1099) { + if (ds.system[0]==DIV_SYSTEM_SAA1099 && ds.system[1]==DIV_SYSTEM_SAA1099) { return "Creative Music System"; } - if (song.system[0]==DIV_SYSTEM_GB && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_GB && ds.system[1]==DIV_SYSTEM_AY8910) { return "Game Boy with AY expansion"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC6) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_VRC6) { return "Famicom + Konami VRC6"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC7) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_VRC7) { return "Famicom + Konami VRC7"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_OPLL) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_OPLL) { return "Family Noraebang"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_FDS) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_FDS) { return "Famicom Disk System"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_N163) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_N163) { String ret="Famicom + "; ret+=getConfString("c163Name","Namco C163"); return ret; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_MMC5) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_MMC5) { return "Famicom + MMC5"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_AY8910) { return "Famicom + Sunsoft 5B"; } - if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_AY8910 && ds.system[1]==DIV_SYSTEM_AY8910) { return "Bally Midway MCR"; } - if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_VERA) { + if (ds.system[0]==DIV_SYSTEM_YM2151 && ds.system[1]==DIV_SYSTEM_VERA) { return "Commander X16"; } break; case 3: - if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910 && song.system[2]==DIV_SYSTEM_BUBSYS_WSG) { + if (ds.system[0]==DIV_SYSTEM_AY8910 && ds.system[1]==DIV_SYSTEM_AY8910 && ds.system[2]==DIV_SYSTEM_BUBSYS_WSG) { return "Konami Bubble System"; } break; @@ -205,12 +205,12 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { if (isMultiSystemAcceptable) return "multi-system"; String ret=""; - for (int i=0; i0) ret+=" + "; - if (song.system[i]==DIV_SYSTEM_N163) { + if (ds.system[i]==DIV_SYSTEM_N163) { ret+=getConfString("c163Name","Namco C163"); } else { - ret+=getSystemName(song.system[i]); + ret+=getSystemName(ds.system[i]); } } diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index ef1c5dc37..a500b4848 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1920,24 +1920,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { WString ws; ws=utf8To16(song.name.c_str()); w->writeWString(ws,false); // name - w->writeS(0); // japanese name - w->writeS(0); // game name - w->writeS(0); // japanese game name - if (song.systemLen>1) { - ws=L"Multiple Systems"; - } else { - ws=utf8To16(getSystemName(song.system[0])); - } + ws=utf8To16(song.nameJ.c_str()); + w->writeWString(ws,false); // japanese name + ws=utf8To16(song.category.c_str()); + w->writeWString(ws,false); // game name + ws=utf8To16(song.categoryJ.c_str()); + w->writeWString(ws,false); // japanese game name + ws=utf8To16(song.systemName.c_str()); w->writeWString(ws,false); // system name - if (song.systemLen>1) { - ws=L"複数システム"; - } else { - ws=utf8To16(getSystemNameJ(song.system[0])); - } + ws=utf8To16(song.systemNameJ.c_str()); w->writeWString(ws,false); // japanese system name ws=utf8To16(song.author.c_str()); w->writeWString(ws,false); // author name - w->writeS(0); // japanese author name + ws=utf8To16(song.authorJ.c_str()); + w->writeWString(ws,false); // japanese author name w->writeS(0); // date w->writeWString(L"Furnace Tracker",false); // ripper w->writeS(0); // notes diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 90925b934..97c1d78e1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -551,7 +551,9 @@ void FurnaceGUI::updateWindowTitle() { } if (settings.titleBarSys) { - title+=fmt::sprintf(" (%s)",e->getSongSystemName(!settings.noMultiSystem)); + if (e->song.systemName!="") { + title+=fmt::sprintf(" (%s)",e->song.systemName); + } } if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str()); diff --git a/src/gui/gui.h b/src/gui/gui.h index 851e10aa1..c267fcab5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1230,6 +1230,7 @@ class FurnaceGUI { float patChanX[DIV_MAX_CHANS+1]; float patChanSlideY[DIV_MAX_CHANS+1]; const int* nextDesc; + String nextDescName; OperationMask opMaskDelete, opMaskPullDelete, opMaskInsert, opMaskPaste, opMaskTransposeNote, opMaskTransposeValue; OperationMask opMaskInterpolate, opMaskFade, opMaskInvertVal, opMaskScale; diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index 0dea772b7..26fddf9fb 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -65,6 +65,7 @@ void FurnaceGUI::drawNewSong() { ImGui::TableNextColumn(); if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) { nextDesc=i.definition.data(); + nextDescName=i.name; accepted=true; } } @@ -97,7 +98,7 @@ void FurnaceGUI::drawNewSong() { } if (accepted) { - e->createNew(nextDesc); + e->createNew(nextDesc,nextDescName); undoHist.clear(); redoHist.clear(); curFileName=""; diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index e90043b7a..b823d085c 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -207,6 +207,33 @@ void FurnaceGUI::drawSongInfo() { } ImGui::EndTable(); } + + if (ImGui::TreeNode("Additional Information")) { + if (ImGui::BeginTable("ExtraData",2,ImGuiTableFlags_SizingStretchProp)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Album"); + ImGui::TableNextColumn(); + float avail=ImGui::GetContentRegionAvail().x; + ImGui::SetNextItemWidth(avail); + if (ImGui::InputText("##Category",&e->song.category)) { + MARK_MODIFIED; + } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("System"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputText("##SystemName",&e->song.systemName)) { + MARK_MODIFIED; + updateWindowTitle(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO; ImGui::End(); From 6051f92e684f031b790504b705cd601307a30a62 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 18:22:42 -0500 Subject: [PATCH 059/515] GUI: add setting to customize initial system name --- src/gui/gui.h | 4 +++- src/gui/settings.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index c267fcab5..bd2a5494c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1100,6 +1100,7 @@ class FurnaceGUI { String midiInDevice; String midiOutDevice; String c163Name; + String initialSysName; std::vector initialSys; Settings(): @@ -1203,7 +1204,8 @@ class FurnaceGUI { audioDevice(""), midiInDevice(""), midiOutDevice(""), - c163Name("") {} + c163Name(""), + initialSysName("Sega Genesis/Mega Drive") {} } settings; char finalLayoutPath[4096]; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 2d05ab5ac..b97390831 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -252,9 +252,9 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); - ImGui::Text("Initial system/chips:"); + ImGui::Text("Initial system:"); ImGui::SameLine(); - if (ImGui::Button("Current systems")) { + if (ImGui::Button("Current system")) { settings.initialSys.clear(); for (int i=0; isong.systemLen; i++) { settings.initialSys.push_back(e->song.system[i]); @@ -262,6 +262,7 @@ void FurnaceGUI::drawSettings() { settings.initialSys.push_back(e->song.systemPan[i]); settings.initialSys.push_back(e->song.systemFlags[i]); } + settings.initialSysName=e->song.systemName; } ImGui::SameLine(); if (ImGui::Button("Randomize")) { @@ -282,6 +283,31 @@ void FurnaceGUI::drawSettings() { settings.initialSys.push_back(0); settings.initialSys.push_back(0); } + // randomize system name + std::vector wordPool[6]; + for (size_t i=0; igetSystemName((DivSystem)settings.initialSys[i*4]); + String nameWord; + sName+=" "; + for (char& i: sName) { + if (i==' ') { + if (nameWord!="") { + wordPool[wpPos++].push_back(nameWord); + if (wpPos>=6) break; + nameWord=""; + } + } else { + nameWord+=i; + } + } + } + settings.initialSysName=""; + for (int i=0; i<6; i++) { + if (wordPool[i].empty()) continue; + settings.initialSysName+=wordPool[i][rand()%wordPool[i].size()]; + settings.initialSysName+=" "; + } } ImGui::SameLine(); if (ImGui::Button("Reset to defaults")) { @@ -294,7 +320,14 @@ void FurnaceGUI::drawSettings() { settings.initialSys.push_back(32); settings.initialSys.push_back(0); settings.initialSys.push_back(0); + settings.initialSysName="Sega Genesis/Mega Drive"; } + + ImGui::Text("Name"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::InputText("##InitSysName",&settings.initialSysName); + for (size_t i=0; igetConfInt("dragMovesSelection",2); settings.unsignedDetune=e->getConfInt("unsignedDetune",0); settings.noThreadedInput=e->getConfInt("noThreadedInput",0); + settings.initialSysName=e->getConfString("initialSysName",""); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2286,6 +2320,7 @@ void FurnaceGUI::commitSettings() { e->setConf("moveWindowTitle",settings.moveWindowTitle); e->setConf("hiddenSystems",settings.hiddenSystems); e->setConf("initialSys",e->encodeSysDesc(settings.initialSys)); + e->setConf("initialSysName",settings.initialSysName); e->setConf("horizontalDataView",settings.horizontalDataView); e->setConf("noMultiSystem",settings.noMultiSystem); e->setConf("oldMacroVSlider",settings.oldMacroVSlider); From efa75a4480d44f21fe579e767c44978b0eeebb33 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 18:40:48 -0500 Subject: [PATCH 060/515] GUI: sub-song info experiment --- src/gui/songInfo.cpp | 49 +++++++--------- src/gui/subSongs.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 28 deletions(-) diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index b823d085c..41ec082ac 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -64,6 +64,25 @@ void FurnaceGUI::drawSongInfo() { if (ImGui::InputText("##Author",&e->song.author)) { MARK_MODIFIED; } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Album"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputText("##Category",&e->song.category)) { + MARK_MODIFIED; + } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("System"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputText("##SystemName",&e->song.systemName)) { + MARK_MODIFIED; + updateWindowTitle(); + } + ImGui::EndTable(); } @@ -72,6 +91,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); + /* ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("TimeBase"); @@ -193,12 +213,14 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("NTSC"); } } + */ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Tuning (A-4)"); ImGui::TableNextColumn(); float tune=e->song.tuning; + float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); if (ImGui::InputFloat("##Tuning",&tune,1.0f,3.0f,"%g")) { MARK_MODIFIED if (tune<220.0f) tune=220.0f; @@ -207,33 +229,6 @@ void FurnaceGUI::drawSongInfo() { } ImGui::EndTable(); } - - if (ImGui::TreeNode("Additional Information")) { - if (ImGui::BeginTable("ExtraData",2,ImGuiTableFlags_SizingStretchProp)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Album"); - ImGui::TableNextColumn(); - float avail=ImGui::GetContentRegionAvail().x; - ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Category",&e->song.category)) { - MARK_MODIFIED; - } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("System"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##SystemName",&e->song.systemName)) { - MARK_MODIFIED; - updateWindowTitle(); - } - ImGui::EndTable(); - } - ImGui::TreePop(); - } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO; ImGui::End(); diff --git a/src/gui/subSongs.cpp b/src/gui/subSongs.cpp index b13b84204..c100600d1 100644 --- a/src/gui/subSongs.cpp +++ b/src/gui/subSongs.cpp @@ -2,6 +2,7 @@ #include "imgui.h" #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" +#include "intConst.h" void FurnaceGUI::drawSubSongs() { if (nextWindow==GUI_WINDOW_SUBSONGS) { @@ -11,7 +12,7 @@ void FurnaceGUI::drawSubSongs() { } if (!subSongsOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); - if (ImGui::Begin("Subsongs",&subSongsOpen,ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar|globalWinFlags)) { + if (ImGui::Begin("Subsongs",&subSongsOpen,globalWinFlags)) { char id[1024]; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-ImGui::GetFrameHeightWithSpacing()*2.0f-ImGui::GetStyle().ItemSpacing.x); if (e->curSubSong->name.empty()) { @@ -93,6 +94,136 @@ void FurnaceGUI::drawSubSongs() { if (ImGui::InputText("##SubSongName",&e->curSubSong->name)) { MARK_MODIFIED; } + + if (ImGui::BeginTable("OtherSubProps",3,ImGuiTableFlags_SizingStretchProp)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("TimeBase"); + ImGui::TableNextColumn(); + float avail=ImGui::GetContentRegionAvail().x; + ImGui::SetNextItemWidth(avail); + unsigned char realTB=e->curSubSong->timeBase+1; + if (ImGui::InputScalar("##TimeBase",ImGuiDataType_U8,&realTB,&_ONE,&_THREE)) { MARK_MODIFIED + if (realTB<1) realTB=1; + if (realTB>16) realTB=16; + e->curSubSong->timeBase=realTB-1; + } + ImGui::TableNextColumn(); + ImGui::Text("%.2f BPM",calcBPM(e->curSubSong->speed1,e->curSubSong->speed2,e->curSubSong->hz,e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Speed"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputScalar("##Speed1",ImGuiDataType_U8,&e->curSubSong->speed1,&_ONE,&_THREE)) { MARK_MODIFIED + if (e->curSubSong->speed1<1) e->curSubSong->speed1=1; + if (e->isPlaying()) play(); + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputScalar("##Speed2",ImGuiDataType_U8,&e->curSubSong->speed2,&_ONE,&_THREE)) { MARK_MODIFIED + if (e->curSubSong->speed2<1) e->curSubSong->speed2=1; + if (e->isPlaying()) play(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Virtual Tempo"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputScalar("##VTempoN",ImGuiDataType_S16,&e->curSubSong->virtualTempoN,&_ONE,&_THREE)) { MARK_MODIFIED + if (e->curSubSong->virtualTempoN<1) e->curSubSong->virtualTempoN=1; + if (e->curSubSong->virtualTempoN>255) e->curSubSong->virtualTempoN=255; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Numerator"); + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputScalar("##VTempoD",ImGuiDataType_S16,&e->curSubSong->virtualTempoD,&_ONE,&_THREE)) { MARK_MODIFIED + if (e->curSubSong->virtualTempoD<1) e->curSubSong->virtualTempoD=1; + if (e->curSubSong->virtualTempoD>255) e->curSubSong->virtualTempoD=255; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Denominator (set to base tempo)"); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Highlight"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputScalar("##Highlight1",ImGuiDataType_U8,&e->curSubSong->hilightA,&_ONE,&_THREE)) { + MARK_MODIFIED; + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputScalar("##Highlight2",ImGuiDataType_U8,&e->curSubSong->hilightB,&_ONE,&_THREE)) { + MARK_MODIFIED; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Pattern Length"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + int patLen=e->curSubSong->patLen; + if (ImGui::InputInt("##PatLength",&patLen,1,3)) { MARK_MODIFIED + if (patLen<1) patLen=1; + if (patLen>256) patLen=256; + e->curSubSong->patLen=patLen; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Song Length"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + int ordLen=e->curSubSong->ordersLen; + if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED + if (ordLen<1) ordLen=1; + if (ordLen>256) ordLen=256; + e->curSubSong->ordersLen=ordLen; + if (curOrder>=ordLen) { + setOrder(ordLen-1); + } + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Selectable(tempoView?"Base Tempo##TempoOrHz":"Tick Rate##TempoOrHz")) { + tempoView=!tempoView; + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + float setHz=tempoView?e->curSubSong->hz*2.5:e->curSubSong->hz; + if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { MARK_MODIFIED + if (tempoView) setHz/=2.5; + if (setHz<10) setHz=10; + if (setHz>999) setHz=999; + e->setSongRate(setHz,setHz<52); + } + if (tempoView) { + ImGui::TableNextColumn(); + ImGui::Text("= %gHz",e->curSubSong->hz); + } else { + if (e->curSubSong->hz>=49.98 && e->curSubSong->hz<=50.02) { + ImGui::TableNextColumn(); + ImGui::Text("PAL"); + } + if (e->curSubSong->hz>=59.9 && e->curSubSong->hz<=60.11) { + ImGui::TableNextColumn(); + ImGui::Text("NTSC"); + } + } + + ImGui::EndTable(); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SUBSONGS; ImGui::End(); From dfcb9551e7a371b70da3003ab8a07b46bb0de48e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 18:53:42 -0500 Subject: [PATCH 061/515] GUI: update credits --- src/gui/about.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index d3d1d9e48..210040c8f 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -27,8 +27,8 @@ const char* aboutLine[]={ "", ("Furnace " DIV_VERSION), "", - "the free software multi-system chiptune tracker,", - "compatible with DefleMask modules.", + "the biggest multi-system chiptune tracker!", + "featuring DefleMask song compatibility.", "", "zero disassembly.", "just clean-room design,", @@ -78,6 +78,7 @@ const char* aboutLine[]={ "kleeder", "jaezu", "Laggy", + "LovelyA72", "LunaMoth", "Mahbod Karamoozian", "Miker", From 984d61d0818c8a1ab01f4cd1a83c0284a6b840a9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 18:53:49 -0500 Subject: [PATCH 062/515] GUI: update song information --- src/gui/songInfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 41ec082ac..9cdf508a9 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -229,6 +229,8 @@ void FurnaceGUI::drawSongInfo() { } ImGui::EndTable(); } + + ImGui::TextWrapped("if this feels incomplete, go to Subsongs.\nthe outcome of this Song Information window will be determined by a poll on the Furnace Discord."); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO; ImGui::End(); From 26d60dd1079c28d8d63a83246e38f15a0e0e39f3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 19:01:30 -0500 Subject: [PATCH 063/515] GUI: fix per-chan osc debug crash fixes #600 --- src/gui/debugWindow.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 12e775b53..6ad2ddddf 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -220,24 +220,34 @@ void FurnaceGUI::drawDebug() { ImGui::Text("Data"); for (int j=0; jgetChannelCount(system); j++, c++) { + DivDispatchOscBuffer* oscBuf=e->getOscBuffer(c); + if (oscBuf==NULL) { + ImGui::TableNextRow(); + // channel + ImGui::TableNextColumn(); + ImGui::Text("%d",j); + ImGui::TableNextColumn(); + ImGui::Text(""); + continue; + } ImGui::TableNextRow(); // channel ImGui::TableNextColumn(); ImGui::Text("%d",j); // follow ImGui::TableNextColumn(); - ImGui::Checkbox(fmt::sprintf("##%d_OSCFollow_%d",i,c).c_str(),&e->getOscBuffer(c)->follow); + ImGui::Checkbox(fmt::sprintf("##%d_OSCFollow_%d",i,c).c_str(),&oscBuf->follow); // address ImGui::TableNextColumn(); - int needle=e->getOscBuffer(c)->follow?e->getOscBuffer(c)->needle:e->getOscBuffer(c)->followNeedle; - ImGui::BeginDisabled(e->getOscBuffer(c)->follow); + int needle=oscBuf->follow?oscBuf->needle:oscBuf->followNeedle; + ImGui::BeginDisabled(oscBuf->follow); if (ImGui::InputInt(fmt::sprintf("##%d_OSCFollowNeedle_%d",i,c).c_str(),&needle,1,100)) { - e->getOscBuffer(c)->followNeedle=MIN(MAX(needle,0),65535); + oscBuf->followNeedle=MIN(MAX(needle,0),65535); } ImGui::EndDisabled(); // data ImGui::TableNextColumn(); - ImGui::Text("%d",e->getOscBuffer(c)->data[needle]); + ImGui::Text("%d",oscBuf->data[needle]); } ImGui::EndTable(); } From 78b54190047667b6b8b1d4a906c58a31687f064c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 19:08:39 -0500 Subject: [PATCH 064/515] GUI: fix effect list hotkey --- src/gui/guiConst.cpp | 2 +- src/gui/settings.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 64e7b18db..9228d1c7f 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -489,9 +489,9 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_CHANNELS", "Channels", 0), D("WINDOW_REGISTER_VIEW", "Register View", 0), D("WINDOW_LOG", "Log Viewer", 0), - D("WINDOW_SUBSONGS", "Subsongs", 0), D("EFFECT_LIST", "Effect List", 0), D("WINDOW_CHAN_OSC", "Oscilloscope (per-channel)", 0), + D("WINDOW_SUBSONGS", "Subsongs", 0), D("WINDOW_FIND", "Find/Replace", FURKMOD_CMD|SDLK_f), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index b97390831..3067eed8c 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1653,6 +1653,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_DEBUG); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_OSCILLOSCOPE); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHAN_OSC); + UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_EFFECT_LIST); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_VOL_METER); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_STATS); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_COMPAT_FLAGS); From 8011e7adc765632c3bed4614284b42c6744cae34 Mon Sep 17 00:00:00 2001 From: Aleksi Knutsi <53163105+host12prog@users.noreply.github.com> Date: Sun, 24 Jul 2022 07:13:30 +0700 Subject: [PATCH 065/515] Implement Phase Reset Timer macro for Sound Unit (#573) * Implement Phase Reset Timer Macro * And make the macro actually work * Delete ex4Max variable --- src/engine/platform/su.cpp | 7 +++++++ src/gui/insEdit.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 48d0ba9a1..c2cd6b25e 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -187,6 +187,13 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chan[i].control=chan[i].std.ex3.val&15; writeControl(i); } + if (chan[i].std.ex4.had) { + chan[i].syncTimer=chan[i].std.ex4.val&65535; + chan[i].timerSync=(chan[i].syncTimer>0); + chWrite(i,0x1e,chan[i].syncTimer&0xff); + chWrite(i,0x1f,chan[i].syncTimer>>8); + writeControlUpper(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,2,chan[i].pitch2,chipClock,CHIP_FREQBASE); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 25ee330b6..f0d6d3da3 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3678,6 +3678,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,suControlBits)); + macroList.push_back(FurnaceGUIMacroDesc("Phase Reset Timer",&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); // again reuse code from resonance macro but use ex4 instead } drawMacros(macroList); From de77d51d7af16116537dc8f70663fbb2d8bcb386 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 21:19:43 -0500 Subject: [PATCH 066/515] GUI: update credits --- src/gui/about.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 210040c8f..00d899f81 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -96,6 +96,7 @@ const char* aboutLine[]={ "-- additional feedback/fixes --", "fd", "GENATARi", + "host12prog", "plane", "TheEssem", "", From e08399156a863cac9da2f4b60829c73f8fdda436 Mon Sep 17 00:00:00 2001 From: Christoph Neidahl Date: Sun, 24 Jul 2022 05:11:30 +0200 Subject: [PATCH 067/515] Haiku support (#596) * Don't apply Wayland videodriver workaround on Haiku * dirent.d_type-less type detecting in IGFD The Dumb Way(tm). `stat`'s `st_mode` should be nicer? * CMake check for dirent.d_type, stat-based fallback * Move config dir setup to separate function Nicer to work with than macro kerfuffle. * Default sysFileDialog to off on Haiku * Logging stuff * Honour CMAKE_INSTALL_BINDIR * Use find_directory on Haiku Includes forgotten configPath line when home==NULL. * Address PR review notes --- CMakeLists.txt | 14 +++++-- extern/igfd/ImGuiFileDialog.cpp | 69 +++++++++++++++++++++---------- src/check/check_dirent_type.c | 7 ++++ src/engine/config.cpp | 73 +++++++++++++++++++++++++++++++++ src/engine/engine.cpp | 72 +------------------------------- src/engine/engine.h | 3 ++ src/gui/settings.cpp | 9 +++- src/main.cpp | 2 +- 8 files changed, 152 insertions(+), 97 deletions(-) create mode 100644 src/check/check_dirent_type.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e7190ece4..5331d8bcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -583,6 +583,13 @@ if (NOT WIN32 AND NOT APPLE) endif() endif() +if (NOT WIN32) + try_compile(HAVE_DIRENT_TYPE ${CMAKE_BINARY_DIR}/check SOURCES ${CMAKE_SOURCE_DIR}/src/check/check_dirent_type.c) + if (HAVE_DIRENT_TYPE) + list(APPEND DEPENDENCIES_DEFINES HAVE_DIRENT_TYPE) + endif() +endif() + set(USED_SOURCES ${ENGINE_SOURCES} ${AUDIO_SOURCES} src/main.cpp) if (USE_BACKWARD) @@ -692,10 +699,9 @@ if (PKG_CONFIG_FOUND AND (SYSTEM_FMT OR SYSTEM_LIBSNDFILE OR SYSTEM_ZLIB OR SYST endif() if (NOT ANDROID OR TERMUX) - install(TARGETS furnace RUNTIME DESTINATION bin) - if (NOT WIN32 AND NOT APPLE) include(GNUInstallDirs) + install(TARGETS furnace RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES res/furnace.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) install(FILES res/furnace.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) install(DIRECTORY papers DESTINATION ${CMAKE_INSTALL_DOCDIR}) @@ -708,8 +714,10 @@ if (NOT ANDROID OR TERMUX) install(FILES res/icon.iconset/icon_${res}@2x.png RENAME furnace.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${res}@2/apps) endforeach() install(FILES res/logo.png RENAME furnace.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/1024x1024/apps) + else() + install(TARGETS furnace RUNTIME DESTINATION bin) endif() - + set(CPACK_PACKAGE_NAME "Furnace") set(CPACK_PACKAGE_VENDOR "tildearrow") set(CPACK_PACKAGE_DESCRIPTION "free and open-source chiptune tracker") diff --git a/extern/igfd/ImGuiFileDialog.cpp b/extern/igfd/ImGuiFileDialog.cpp index 776ad3738..63ae3b879 100644 --- a/extern/igfd/ImGuiFileDialog.cpp +++ b/extern/igfd/ImGuiFileDialog.cpp @@ -58,13 +58,13 @@ SOFTWARE. #ifndef PATH_MAX #define PATH_MAX 260 #endif // PATH_MAX -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined (__EMSCRIPTEN__) +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined (__EMSCRIPTEN__) || defined(__HAIKU__) #define UNIX #define stricmp strcasecmp #include // this option need c++17 #ifndef USE_STD_FILESYSTEM - #include + #include #endif // USE_STD_FILESYSTEM #define PATH_SEP '/' #endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) @@ -1547,28 +1547,53 @@ namespace IGFD for (i = 0; i < n; i++) { struct dirent* ent = files[i]; - + std::string where = path + std::string("/") + std::string(ent->d_name); char fileType = 0; - switch (ent->d_type) +#ifdef HAVE_DIRENT_TYPE + if (ent->d_type != DT_UNKNOWN) { - case DT_REG: - fileType = 'f'; break; - case DT_DIR: - fileType = 'd'; break; - case DT_LNK: - std::string where = path+std::string("/")+std::string(ent->d_name); - DIR* dirTest = opendir(where.c_str()); - if (dirTest==NULL) { - if (errno==ENOTDIR) { - fileType = 'f'; - } else { - fileType = 'l'; - } - } else { - fileType = 'd'; - closedir(dirTest); - } - break; + switch (ent->d_type) + { + case DT_REG: + fileType = 'f'; break; + case DT_DIR: + fileType = 'd'; break; + case DT_LNK: + DIR* dirTest = opendir(where.c_str()); + if (dirTest == NULL) + { + if (errno == ENOTDIR) + { + fileType = 'f'; + } + else + { + fileType = 'l'; + } + } + else + { + fileType = 'd'; + closedir(dirTest); + } + break; + } + } + else +#endif // HAVE_DIRENT_TYPE + { + struct stat filestat; + if (stat(where.c_str(), &filestat) == 0) + { + if (S_ISDIR(filestat.st_mode)) + { + fileType = 'd'; + } + else + { + fileType = 'f'; + } + } } auto fileNameExt = ent->d_name; diff --git a/src/check/check_dirent_type.c b/src/check/check_dirent_type.c new file mode 100644 index 000000000..e65a0d6be --- /dev/null +++ b/src/check/check_dirent_type.c @@ -0,0 +1,7 @@ +#include + +int main(int, char**) { + struct dirent deTest = { }; + unsigned char deType = deTest.d_type; + return 0; +} diff --git a/src/engine/config.cpp b/src/engine/config.cpp index 92866a9f9..f404c0a4f 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -23,11 +23,84 @@ #include #ifdef _WIN32 +#include "winStuff.h" #define CONFIG_FILE "\\furnace.cfg" #else +#ifdef __HAIKU__ +#include +#include +#endif +#include +#include +#include #define CONFIG_FILE "/furnace.cfg" #endif +void DivEngine::initConfDir() { +#ifdef _WIN32 + // maybe move this function in here instead? + configPath=getWinConfigPath(); +#elif defined (IS_MOBILE) + configPath=SDL_GetPrefPath(); +#else +#ifdef __HAIKU__ + char userSettingsDir[PATH_MAX]; + status_t findUserDir = find_directory(B_USER_SETTINGS_DIRECTORY,0,true,userSettingsDir,PATH_MAX); + if (findUserDir==B_OK) { + configPath=userSettingsDir; + } else { + logW("unable to find/create user settings directory (%s)!",strerror(findUserDir)); + configPath="."; + return; + } +#else + // TODO this should check XDG_CONFIG_HOME first + char* home=getenv("HOME"); + if (home==NULL) { + int uid=getuid(); + struct passwd* entry=getpwuid(uid); + if (entry==NULL) { + logW("unable to determine home directory (%s)!",strerror(errno)); + configPath="."; + return; + } else { + configPath=entry->pw_dir; + } + } else { + configPath=home; + } +#ifdef __APPLE__ + configPath+="/Library/Application Support"; +#else + // FIXME this doesn't honour XDG_CONFIG_HOME *at all* + configPath+="/.config"; +#endif // __APPLE__ +#endif // __HAIKU__ +#ifdef __APPLE__ + configPath+="/Furnace"; +#else + configPath+="/furnace"; +#endif // __APPLE__ + struct stat st; + std::string pathSep="/"; + configPath+=pathSep; + size_t sepPos=configPath.find(pathSep,1); + while (sepPos!=std::string::npos) { + std::string subpath=configPath.substr(0,sepPos++); + if (stat(subpath.c_str(),&st)!=0) { + logI("creating config path element %s ...",subpath.c_str()); + if (mkdir(subpath.c_str(),0755)!=0) { + logW("could not create config path element %s! (%s)",subpath.c_str(),strerror(errno)); + configPath="."; + return; + } + } + sepPos=configPath.find(pathSep,sepPos); + } + configPath.resize(configPath.length()-pathSep.length()); +#endif // _WIN32 +} + bool DivEngine::saveConf() { configFile=configPath+String(CONFIG_FILE); FILE* f=ps_fopen(configFile.c_str(),"wb"); diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index f1e8dc043..98947ead3 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -27,11 +27,6 @@ #include "../audio/sdlAudio.h" #endif #include -#ifndef _WIN32 -#include -#include -#include -#endif #ifdef HAVE_JACK #include "../audio/jack.h" #endif @@ -2989,36 +2984,6 @@ void DivEngine::quitDispatch() { BUSY_END; } -#define CHECK_CONFIG_DIR_MAC() \ - configPath+="/Library/Application Support/Furnace"; \ - if (stat(configPath.c_str(),&st)<0) { \ - logI("creating config dir..."); \ - if (mkdir(configPath.c_str(),0755)<0) { \ - logW("could not make config dir! (%s)",strerror(errno)); \ - configPath="."; \ - } \ - } - -#define CHECK_CONFIG_DIR() \ - configPath+="/.config"; \ - if (stat(configPath.c_str(),&st)<0) { \ - logI("creating user config dir..."); \ - if (mkdir(configPath.c_str(),0755)<0) { \ - logW("could not make user config dir! (%s)",strerror(errno)); \ - configPath="."; \ - } \ - } \ - if (configPath!=".") { \ - configPath+="/furnace"; \ - if (stat(configPath.c_str(),&st)<0) { \ - logI("creating config dir..."); \ - if (mkdir(configPath.c_str(),0755)<0) { \ - logW("could not make config dir! (%s)",strerror(errno)); \ - configPath="."; \ - } \ - } \ - } - bool DivEngine::initAudioBackend() { // load values if (audioEngine==DIV_AUDIO_NULL) { @@ -3148,45 +3113,12 @@ bool DivEngine::deinitAudioBackend() { return true; } -#ifdef _WIN32 -#include "winStuff.h" -#endif - bool DivEngine::init() { // register systems if (!systemsRegistered) registerSystems(); - + // init config -#ifdef _WIN32 - configPath=getWinConfigPath(); -#elif defined(IS_MOBILE) - configPath=SDL_GetPrefPath("tildearrow","furnace"); -#else - struct stat st; - char* home=getenv("HOME"); - if (home==NULL) { - int uid=getuid(); - struct passwd* entry=getpwuid(uid); - if (entry==NULL) { - logW("unable to determine config directory! (%s)",strerror(errno)); - configPath="."; - } else { - configPath=entry->pw_dir; -#ifdef __APPLE__ - CHECK_CONFIG_DIR_MAC(); -#else - CHECK_CONFIG_DIR(); -#endif - } - } else { - configPath=home; -#ifdef __APPLE__ - CHECK_CONFIG_DIR_MAC(); -#else - CHECK_CONFIG_DIR(); -#endif - } -#endif + initConfDir(); logD("config path: %s",configPath.c_str()); loadConf(); diff --git a/src/engine/engine.h b/src/engine/engine.h index f6567dd3a..0ec74eb5c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -485,6 +485,9 @@ class DivEngine { // returns the minimum VGM version which may carry the specified system, or 0 if none. int minVGMVersion(DivSystem which); + // determine and setup config dir + void initConfDir(); + // save config bool saveConf(); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 3067eed8c..f67671194 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -39,6 +39,13 @@ #define POWER_SAVE_DEFAULT 0 #endif +#ifdef __HAIKU__ +// NFD doesn't support Haiku +#define SYS_FILE_DIALOG_DEFAULT 0 +#else +#define SYS_FILE_DIALOG_DEFAULT 1 +#endif + const char* mainFonts[]={ "IBM Plex Sans", "Liberation Sans", @@ -2062,7 +2069,7 @@ void FurnaceGUI::syncSettings() { settings.insFocusesPattern=e->getConfInt("insFocusesPattern",1); settings.stepOnInsert=e->getConfInt("stepOnInsert",0); settings.unifiedDataView=e->getConfInt("unifiedDataView",0); - settings.sysFileDialog=e->getConfInt("sysFileDialog",1); + settings.sysFileDialog=e->getConfInt("sysFileDialog",SYS_FILE_DIALOG_DEFAULT); settings.roundedWindows=e->getConfInt("roundedWindows",1); settings.roundedButtons=e->getConfInt("roundedButtons",1); settings.roundedMenus=e->getConfInt("roundedMenus",0); diff --git a/src/main.cpp b/src/main.cpp index 970bc784f..2ef45c23d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -295,7 +295,7 @@ int main(int argc, char** argv) { logE("CoInitializeEx failed!"); } #endif -#if !(defined(__APPLE__) || defined(_WIN32) || defined(ANDROID)) +#if !(defined(__APPLE__) || defined(_WIN32) || defined(ANDROID) || defined(__HAIKU__)) // workaround for Wayland HiDPI issue if (getenv("SDL_VIDEODRIVER")==NULL) { setenv("SDL_VIDEODRIVER","x11",1); From 617569b6b8b92c95204fdd7f4e570238e1a582a0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 22:19:07 -0500 Subject: [PATCH 068/515] re-enable backward on Windows/macOS --- CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7190ece4..ab1f0f226 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,12 +33,11 @@ if (ANDROID) endif() else() set(USE_RTMIDI_DEFAULT ON) - CHECK_INCLUDE_FILE(execinfo.h EXECINFO_FOUND) - if (EXECINFO_FOUND) + if (WIN32 OR APPLE) set(USE_BACKWARD_DEFAULT ON) else() - find_library(EXECINFO_IS_LIBRARY execinfo) - if (EXECINFO_IS_LIBRARY) + CHECK_INCLUDE_FILE(execinfo.h EXECINFO_FOUND) + if (EXECINFO_FOUND) set(USE_BACKWARD_DEFAULT ON) else() set(USE_BACKWARD_DEFAULT OFF) From 84c955058ba6fc89c6d89fb5152e04867ae77c94 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 22:22:05 -0500 Subject: [PATCH 069/515] GUI: Z280 whoops issue #576 --- src/gui/sysConf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 2cb177984..e54074861 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -594,7 +594,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("14.32MHz (NTSC)",(flags&255)==1)) { copyOfFlags=(flags&(~255))|1; } - if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==3)) { + if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==2)) { copyOfFlags=(flags&(~255))|2; } if (ImGui::RadioButton("16MHz",(flags&255)==3)) { From b48b7c8bc5979b140d4e4e713653c9e6f9d5446b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 24 Jul 2022 12:23:38 +0900 Subject: [PATCH 070/515] Apply loop end position for generic DAC --- src/engine/platform/pcmdac.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 314ba7dd1..213cb85a3 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -50,12 +50,10 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l } else { DivSample* s=parent->getSample(chan.sample); if (s->samples>0) { - if (chan.audPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - chan.audPos=s->loopStart; - } else { - chan.sample=-1; - } + if (s->isLoopable() && chan.audPos>=s->getEndPosition()) { + chan.audPos=s->loopStart; + } else if (chan.audPos>=s->samples) { + chan.sample=-1; } if (chan.audPossamples) { output=s->data16[chan.audPos]; From 6697be4d9555fbef2433a6eb3d8cadc6cf1916d1 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 24 Jul 2022 13:28:26 +0900 Subject: [PATCH 071/515] Add/Update more presets Williams/Midway ADPCM Sound board Used for conjunction with their Y/T unit, it has ordinary de facto standard OPM+MSM6295 on this era with software controlled DAC from predecessors. Konami Battlantis Used at Battlantis arcade hardware, It is early SB Pro but mono configuration. Sega System 24 This Sega's early arcade system featured to floppy disk and high resolution graphics. Sound hardware is similar as their System 16, but ADPCM is replaced to software controlled DAC. Namco System 86 Predecessor of System 1(a.k.a. System 87), It features similar sound hardware and optional ROM and DAC expansion. Namco Thunder Ceptor Used at Thunder Ceptor, their Front view arcade machine. Namco system 86 and System 1 sound system is directly derived from this machine's sound system. Irem M72 Irem's first arcade system with FM sound system, All released game except R-Type is featured also LOUD software controlled DAC, inherited from their predecessors sound system. --- src/gui/presets.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 3774f232c..ef2236223 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1241,6 +1241,15 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Williams/Midway Y/T unit w/ADPCM sound board", { + // ADPCM sound board + DIV_SYSTEM_YM2151, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 15624|(7<<16), // variable via OPM timer? + DIV_SYSTEM_MSM6295, 64, 0, 0, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Konami Gyruss", { DIV_SYSTEM_AY8910, 64, 0, 0, @@ -1261,6 +1270,34 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Konami Battlantis", { + DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPL2, 64, 0, 3, // "" + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Konami Battlantis (drums mode on first OPL2)", { + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPL2, 64, 0, 3, // "" + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Konami Battlantis (drums mode on second OPL2)", { + DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Konami Battlantis (drums mode on both OPL2s)", { + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Konami Hexion", { DIV_SYSTEM_SCC, 64, 0, 2, // 1.5MHz (3MHz input) @@ -1326,6 +1363,13 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Sega System 24", { + DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 61499|(7<<16), // software controlled, variable rate via configurable timers + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Sega System 18", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 @@ -1863,7 +1907,7 @@ void FurnaceGUI::initSystemPresets() { "Alpha denshi Alpha-68K", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz - // software controlled 8 bit DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } )); @@ -1871,7 +1915,7 @@ void FurnaceGUI::initSystemPresets() { "Alpha denshi Alpha-68K (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz - // software controlled 8 bit DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } )); @@ -1879,7 +1923,7 @@ void FurnaceGUI::initSystemPresets() { "Alpha denshi Alpha-68K (drums mode)", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz - // software controlled 8 bit DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } )); @@ -1887,7 +1931,7 @@ void FurnaceGUI::initSystemPresets() { "Alpha denshi Alpha-68K (extended channel 3; drums mode)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz - // software controlled 8 bit DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } )); @@ -1929,10 +1973,27 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Namco System 86", { // without expansion board case; Hopping Mappy, etc + DIV_SYSTEM_YM2151, 64, 0, 0, + DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0 + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Namco Thunder Ceptor", { + DIV_SYSTEM_YM2151, 64, 0, 0, + DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 7999|(7<<16), // M65C02 software driven, correct sample rate? + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Namco System 1", { DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // sample rate verified from https://github.com/mamedev/mame/blob/master/src/devices/sound/n63701x.cpp + DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // "" 0 } )); @@ -2045,6 +2106,13 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Irem M72", { + DIV_SYSTEM_YM2151, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 7811|(7<<16), + 0 + } + )); sysCategories.push_back(cat); cat=FurnaceGUISysCategory("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); From 588f3f737ca84f2d377e8feb774909da986377d9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Jul 2022 01:57:10 -0500 Subject: [PATCH 072/515] preliminary Future Composer module loading only loads patterns and doesn't deduplicate conversion required to fit in the Furnace format (no transpose ins/note) even the pattern loader itself isn't complete due to how different the format is --- src/engine/engine.h | 2 + src/engine/fileOps.cpp | 230 +++++++++++++++++++++++++++++++++++++++++ src/gui/gui.cpp | 4 +- src/gui/songInfo.cpp | 3 - 4 files changed, 234 insertions(+), 5 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 0ec74eb5c..b5c158058 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -50,6 +50,7 @@ // for imports #define DIV_VERSION_MOD 0xff01 +#define DIV_VERSION_FC 0xff02 enum DivStatusView { DIV_STATUS_NOTHING=0, @@ -397,6 +398,7 @@ class DivEngine { bool loadFur(unsigned char* file, size_t len); bool loadMod(unsigned char* file, size_t len); bool loadFTM(unsigned char* file, size_t len); + bool loadFC(unsigned char* file, size_t len); void loadDMP(SafeReader& reader, std::vector& ret, String& stripPath); void loadTFI(SafeReader& reader, std::vector& ret, String& stripPath); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index e66e2c8d9..aebff43bc 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -28,6 +28,8 @@ #define DIV_DMF_MAGIC ".DelekDefleMask." #define DIV_FUR_MAGIC "-Furnace module-" #define DIV_FTM_MAGIC "FamiTracker Module" +#define DIV_FC13_MAGIC "SMOD" +#define DIV_FC14_MAGIC "FC14" struct InflateBlock { unsigned char* buf; @@ -2259,6 +2261,232 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { return success; } +bool DivEngine::loadFC(unsigned char* file, size_t len) { + struct InvalidHeaderException {}; + bool success=false; + char magic[4]={0,0,0,0}; + SafeReader reader=SafeReader(file,len); + warnings=""; + bool isFC14=false; + unsigned int patPtr, freqMacroPtr, volMacroPtr, samplePtr; + unsigned int seqLen, patLen, freqMacroLen, volMacroLen, sampleLen; + + struct FCSequence { + unsigned char pat[4]; + signed char transpose[4]; + signed char offsetIns[4]; + unsigned char speed; + }; + std::vector seq; + struct FCPattern { + unsigned char note[32]; + unsigned char val[32]; + }; + std::vector pat; + + struct FCSample { + unsigned short loopLen, len, loopStart; + } sample[10]; + + try { + DivSong ds; + ds.tuning=436.0; + ds.version=DIV_VERSION_FC; + ds.linearPitch=0; + ds.noSlidesOnFirstTick=true; + ds.rowResetsArpPos=true; + ds.ignoreJumpAtEnd=false; + + // load here + if (!reader.seek(0,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete[] file; + return false; + } + reader.read(magic,4); + + if (memcmp(magic,DIV_FC13_MAGIC,4)==0) { + isFC14=false; + } else if (memcmp(magic,DIV_FC14_MAGIC,4)==0) { + isFC14=true; + } else { + logW("the magic isn't complete"); + throw EndOfFileException(&reader,reader.tell()); + } + + ds.systemLen=1; + ds.system[0]=DIV_SYSTEM_DUMMY; + ds.systemVol[0]=64; + ds.systemPan[0]=0; + ds.systemFlags[0]=1|(80<<8); // PAL + ds.systemName="Amiga"; + + seqLen=reader.readI_BE(); + if (seqLen%13) { + logW("sequence length is not multiple of 13 (%d)",seqLen); + //throw EndOfFileException(&reader,reader.tell()); + } + patPtr=reader.readI_BE(); + patLen=reader.readI_BE(); + if (patLen%64) { + logW("pattern length is not multiple of 64 (%d)",patLen); + throw EndOfFileException(&reader,reader.tell()); + } + freqMacroPtr=reader.readI_BE(); + freqMacroLen=reader.readI_BE(); + volMacroPtr=reader.readI_BE(); + volMacroLen=reader.readI_BE(); + samplePtr=reader.readI_BE(); + if (isFC14) { + reader.readI_BE(); // wave len + } else { + sampleLen=reader.readI_BE(); + } + + logD("patPtr: %d",patPtr); + logD("patLen: %d",patLen); + logD("freqMacroPtr: %d",freqMacroPtr); + logD("freqMacroLen: %d",freqMacroLen); + logD("volMacroPtr: %d",volMacroPtr); + logD("volMacroLen: %d",volMacroLen); + logD("samplePtr: %d",samplePtr); + logD("sampleLen: %d",sampleLen); + + // sample info + logD("samples:"); + for (int i=0; i<10; i++) { + sample[i].loopLen=reader.readS_BE(); + sample[i].len=reader.readS_BE(); + sample[i].loopStart=reader.readS_BE(); + + logD("- %d: %d (%d, %d)",i,sample[i].len,sample[i].loopStart,sample[i].loopLen); + } + + // wavetable lengths + if (isFC14) for (int i=0; i<20; i++) { + reader.readS_BE(); + reader.readS_BE(); + } + + // sequences + seqLen/=13; + logD("reading sequences... (%d)",seqLen); + for (unsigned int i=0; iordersLen=seqLen; + ds.subsong[0]->patLen=32; + ds.subsong[0]->hz=50; + ds.subsong[0]->pal=true; + ds.subsong[0]->customTempo=true; + ds.subsong[0]->pat[3].effectCols=3; + ds.subsong[0]->speed1=3; + ds.subsong[0]->speed2=3; + + for (unsigned int i=0; iorders.ord[j][i]=i; + DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true); + if (j==3 && seq[i].speed) { + p->data[0][6]=0x09; + p->data[0][7]=seq[i].speed; + p->data[0][8]=0x0f; + p->data[0][9]=seq[i].speed; + } + + for (int k=0; k<32; k++) { + FCPattern& fp=pat[seq[i].pat[j]]; + if (fp.note[k]>0 && fp.note[k]<0x49) { + short note=(fp.note[k]+seq[i].transpose[j])%12; + short octave=2+((fp.note[k]+seq[i].transpose[j])/12); + if (fp.note[k]>=0x3d) octave-=6; + if (note==0) { + note=12; + octave--; + } + octave&=0xff; + p->data[k][0]=note; + p->data[k][1]=octave; + if (fp.val[k]) { + if (fp.val[k]&0xe0) { + + } else { + p->data[k][2]=fp.val[k]-1; + } + } + } + } + } + } + + if (active) quitDispatch(); + BUSY_BEGIN_SOFT; + saveLock.lock(); + song.unload(); + song=ds; + changeSong(0); + recalcChans(); + saveLock.unlock(); + BUSY_END; + if (active) { + initDispatch(); + BUSY_BEGIN; + renderSamples(); + reset(); + BUSY_END; + } + success=true; + } catch (EndOfFileException& e) { + //logE("premature end of file!"); + lastError="incomplete file"; + } catch (InvalidHeaderException& e) { + //logE("invalid header!"); + lastError="invalid header!"; + } + return success; +} + #define CHECK_BLOCK_VERSION(x) \ if (blockVersion>x) { \ logE("incompatible block version %d for %s!",blockVersion,blockName); \ @@ -2731,6 +2959,8 @@ bool DivEngine::load(unsigned char* f, size_t slen) { return loadFTM(file,len); } else if (memcmp(file,DIV_FUR_MAGIC,16)==0) { return loadFur(file,len); + } else if (memcmp(file,DIV_FC13_MAGIC,4)==0 || memcmp(file,DIV_FC14_MAGIC,4)==0) { + return loadFC(file,len); } // step 3: try loading as .mod diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 97c1d78e1..2c80c5fbe 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1226,9 +1226,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirSong)) workingDirSong=getHomeDir(); hasOpened=fileDialog->openLoad( "Open File", - {"compatible files", "*.fur *.dmf *.mod", + {"compatible files", "*.fur *.dmf *.mod *.fc13 *.fc14 *.smod", "all files", ".*"}, - "compatible files{.fur,.dmf,.mod},.*", + "compatible files{.fur,.dmf,.mod,.fc13,.fc14,.smod},.*", workingDirSong, dpiScale ); diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 9cdf508a9..f1428db5e 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -91,7 +91,6 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); - /* ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("TimeBase"); @@ -213,14 +212,12 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("NTSC"); } } - */ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Tuning (A-4)"); ImGui::TableNextColumn(); float tune=e->song.tuning; - float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); if (ImGui::InputFloat("##Tuning",&tune,1.0f,3.0f,"%g")) { MARK_MODIFIED if (tune<220.0f) tune=220.0f; From ffe06013d7a23f974b0af1001f9b8cabb6583957 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Jul 2022 01:58:14 -0500 Subject: [PATCH 073/515] GUI: fix preset typo --- src/gui/presets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index ef2236223..f8e7a522c 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1976,7 +1976,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "Namco System 86", { // without expansion board case; Hopping Mappy, etc DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0 + DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, 0 } )); From 9a0609ae1a6bc666449891cad9b956d4c9a1e8e9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Jul 2022 02:24:57 -0500 Subject: [PATCH 074/515] fix build... --- src/engine/fileOps.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index aebff43bc..71b8f90d1 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2340,6 +2340,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { samplePtr=reader.readI_BE(); if (isFC14) { reader.readI_BE(); // wave len + sampleLen=0; } else { sampleLen=reader.readI_BE(); } From 1d777196408652036df388368b612ba579087247 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Jul 2022 02:45:21 -0500 Subject: [PATCH 075/515] prevent exception in MIDI in/out from crashing --- src/audio/rtmidi.cpp | 49 +++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/audio/rtmidi.cpp b/src/audio/rtmidi.cpp index 31a3e66ae..dd8a0a75e 100644 --- a/src/audio/rtmidi.cpp +++ b/src/audio/rtmidi.cpp @@ -46,23 +46,28 @@ String sanitizePortName(const String& name) { bool TAMidiInRtMidi::gather() { std::vector msg; if (port==NULL) return false; - while (true) { - TAMidiMessage m; - double t=port->getMessage(&msg); - if (msg.empty()) break; + try { + while (true) { + TAMidiMessage m; + double t=port->getMessage(&msg); + if (msg.empty()) break; - // parse message - m.time=t; - m.type=msg[0]; - if (m.type!=TA_MIDI_SYSEX && msg.size()>1) { - memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7)); - } else if (m.type==TA_MIDI_SYSEX) { - m.sysExData.reset(new unsigned char[msg.size()]); - m.sysExLen=msg.size(); - logD("got a SysEx of length %ld!",msg.size()); - memcpy(m.sysExData.get(),msg.data(),msg.size()); + // parse message + m.time=t; + m.type=msg[0]; + if (m.type!=TA_MIDI_SYSEX && msg.size()>1) { + memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7)); + } else if (m.type==TA_MIDI_SYSEX) { + m.sysExData.reset(new unsigned char[msg.size()]); + m.sysExLen=msg.size(); + logD("got a SysEx of length %ld!",msg.size()); + memcpy(m.sysExData.get(),msg.data(),msg.size()); + } + queue.push(m); } - queue.push(m); + } catch (RtMidiError& e) { + logE("MIDI input error! %s",e.what()); + return false; } return true; } @@ -180,7 +185,12 @@ bool TAMidiOutRtMidi::send(const TAMidiMessage& what) { return false; } len=what.sysExLen; - port->sendMessage(what.sysExData.get(),len); + try { + port->sendMessage(what.sysExData.get(),len); + } catch (RtMidiError& e) { + logE("MIDI output error! %s",e.what()); + return false; + } return true; break; case TA_MIDI_MTC_FRAME: @@ -194,7 +204,12 @@ bool TAMidiOutRtMidi::send(const TAMidiMessage& what) { len=1; break; } - port->sendMessage((const unsigned char*)&what.type,len); + try { + port->sendMessage((const unsigned char*)&what.type,len); + } catch (RtMidiError& e) { + logE("MIDI output error! %s",e.what()); + return false; + } return true; } From b75787603aec96eff8896c4a5b560211eb1b9357 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Jul 2022 02:52:39 -0500 Subject: [PATCH 076/515] I missed something --- papers/format.md | 1 + 1 file changed, 1 insertion(+) diff --git a/papers/format.md b/papers/format.md index 537150215..ca8092a5a 100644 --- a/papers/format.md +++ b/papers/format.md @@ -244,6 +244,7 @@ size | description | - 0xc2: Neo Geo CSM (YM2610) - 18 channels | - 0xc3: OPN CSM - 10 channels | - 0xc4: PC-98 CSM - 20 channels + | - 0xc5: YM2610B CSM - 20 channels | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels | - 0xfd: Dummy System - 8 channels From 542a46e89b4a90fe73fb1b8e9870e5347c92f3bf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Jul 2022 03:41:01 -0500 Subject: [PATCH 077/515] remove log spam (hopefully) --- src/audio/rtmidi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/audio/rtmidi.cpp b/src/audio/rtmidi.cpp index dd8a0a75e..258f69292 100644 --- a/src/audio/rtmidi.cpp +++ b/src/audio/rtmidi.cpp @@ -67,6 +67,7 @@ bool TAMidiInRtMidi::gather() { } } catch (RtMidiError& e) { logE("MIDI input error! %s",e.what()); + closeDevice(); return false; } return true; From 3183400019d6c822fa6d687b72d9ed74a8b49070 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 25 Jul 2022 16:21:39 -0500 Subject: [PATCH 078/515] it appears SDL2 takes over interrupt in console mode --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2ef45c23d..9ff5b9934 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ #include #include #include -#ifdef HAVE_GUI +#ifdef HAVE_SDL2 #include "SDL_events.h" #endif #include "ta-log.h" @@ -467,7 +467,7 @@ int main(int argc, char** argv) { if (consoleMode) { logI("playing..."); e.play(); -#ifdef HAVE_GUI +#ifdef HAVE_SDL2 SDL_Event ev; while (true) { SDL_WaitEvent(&ev); From 83386d082d1da5609fc4d7d9f2ba673750ca9020 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 25 Jul 2022 17:23:56 -0500 Subject: [PATCH 079/515] add a proper CLI featuring skip order (left/right) and pause (space)! currently available on macOS and Linux only. --- CMakeLists.txt | 6 +- src/cli/cli.cpp | 137 ++++++++++++++++++++++++++++++++++++++++ src/cli/cli.h | 55 ++++++++++++++++ src/engine/playback.cpp | 6 +- src/main.cpp | 40 ++++++++---- 5 files changed, 229 insertions(+), 15 deletions(-) create mode 100644 src/cli/cli.cpp create mode 100644 src/cli/cli.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 861392563..78792c983 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -478,6 +478,10 @@ if (WIN32) list(APPEND ENGINE_SOURCES res/furnace.rc) endif() +set(CLI_SOURCES +src/cli/cli.cpp +) + set(GUI_SOURCES extern/imgui_patched/imgui.cpp extern/imgui_patched/imgui_draw.cpp @@ -589,7 +593,7 @@ if (NOT WIN32) endif() endif() -set(USED_SOURCES ${ENGINE_SOURCES} ${AUDIO_SOURCES} src/main.cpp) +set(USED_SOURCES ${ENGINE_SOURCES} ${AUDIO_SOURCES} ${CLI_SOURCES} src/main.cpp) if (USE_BACKWARD) list(APPEND USED_SOURCES src/backtrace.cpp) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp new file mode 100644 index 000000000..956796001 --- /dev/null +++ b/src/cli/cli.cpp @@ -0,0 +1,137 @@ +/** + * 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 "cli.h" +#include "../ta-log.h" + +bool cliQuit=false; + +static void handleTerm(int) { + cliQuit=true; +} + +void FurnaceCLI::bindEngine(DivEngine* eng) { + e=eng; +} + +bool FurnaceCLI::loop() { + bool escape=false; + bool escapeSecondStage=false; + while (!cliQuit) { + unsigned char c; + if (read(STDIN_FILENO,&c,1)<=0) continue; + if (escape) { + if (escapeSecondStage) { + switch (c) { + case 'C': // right + e->setOrder(e->getOrder()+1); + escape=false; + escapeSecondStage=false; + break; + case 'D': // left + e->setOrder(e->getOrder()-1); + escape=false; + escapeSecondStage=false; + break; + default: + escape=false; + escapeSecondStage=false; + break; + } + } else { + switch (c) { + case '[': case 'O': + escapeSecondStage=true; + break; + default: + escape=false; + break; + } + } + } else { + switch (c) { + case 0x1b: // + escape=true; + break; + case 'h': // left + e->setOrder(e->getOrder()-1); + break; + case 'l': // right + e->setOrder(e->getOrder()+1); + break; + case ' ': + if (e->isHalted()) { + e->resume(); + } else { + e->halt(); + } + break; + } + } + } + printf("\n"); + return true; +} + +bool FurnaceCLI::finish() { + if (tcsetattr(0,TCSAFLUSH,&termpropold)!=0) { + logE("could not set console attributes!"); + logE("you may have to run `reset` on your terminal."); + return false; + } + return true; +} + +// blatantly copied from tildearrow/tfmxplay +bool FurnaceCLI::init() { +#ifdef _WIN32 + winin=GetStdHandle(STD_INPUT_HANDLE); + winout=GetStdHandle(STD_OUTPUT_HANDLE); + int termprop=0; + int termpropi=0; + GetConsoleMode(winout,(LPDWORD)&termprop); + GetConsoleMode(winin,(LPDWORD)&termpropi); + termprop|=ENABLE_VIRTUAL_TERMINAL_PROCESSING; + termpropi&=~ENABLE_LINE_INPUT; + SetConsoleMode(winout,termprop); + SetConsoleMode(winin,termpropi); +#else + sigemptyset(&intsa.sa_mask); + intsa.sa_flags=0; + intsa.sa_handler=handleTerm; + sigaction(SIGINT,&intsa,NULL); + + if (tcgetattr(0,&termprop)!=0) { + logE("could not get console attributes!"); + return false; + } + memcpy(&termpropold,&termprop,sizeof(struct termios)); + termprop.c_lflag&=~ECHO; + termprop.c_lflag&=~ICANON; + if (tcsetattr(0,TCSAFLUSH,&termprop)!=0) { + logE("could not set console attributes!"); + return false; + } +#endif + return true; +} + +FurnaceCLI::FurnaceCLI(): + e(NULL) { +} diff --git a/src/cli/cli.h b/src/cli/cli.h new file mode 100644 index 000000000..0df6658e3 --- /dev/null +++ b/src/cli/cli.h @@ -0,0 +1,55 @@ +/** + * 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 _FUR_CLI_H +#define _FUR_CLI_H + +#include +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#endif + +#include "../engine/engine.h" + +class FurnaceCLI { + DivEngine* e; + +#ifdef _WIN32 + HANDLE winin; + HANDLE winout; +#else + struct sigaction intsa; + struct termios termprop; + struct termios termpropold; +#endif + + public: + void bindEngine(DivEngine* eng); + bool loop(); + bool finish(); + bool init(); + FurnaceCLI(); +}; + +#endif diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index bff0c3c3f..e9d5aa952 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -201,7 +201,7 @@ const char* formatNote(unsigned char note, unsigned char octave) { int DivEngine::dispatchCmd(DivCommand c) { if (view==DIV_STATUS_COMMANDS) { - printf("%8d | %d: %s(%d, %d)\n",totalTicksR,c.chan,cmdName[c.cmd],c.value,c.value2); + if (!skipping) printf("%8d | %d: %s(%d, %d)\n",totalTicksR,c.chan,cmdName[c.cmd],c.value,c.value2); } totalCmds++; if (cmdStreamEnabled && cmdStream.size()<2000) { @@ -771,7 +771,7 @@ void DivEngine::nextRow() { static char pb1[4096]; static char pb2[4096]; static char pb3[4096]; - if (view==DIV_STATUS_PATTERN) { + if (view==DIV_STATUS_PATTERN && !skipping) { strcpy(pb1,""); strcpy(pb3,""); for (int i=0; i %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,curSubSong->ordersLen,curRow,curSubSong->patLen,cmdsPerSecond); + if (consoleMode && subticks<=1 && !skipping) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,curSubSong->ordersLen,curRow,curSubSong->patLen,cmdsPerSecond); } if (haltOn==DIV_HALT_TICK) halted=true; diff --git a/src/main.cpp b/src/main.cpp index 9ff5b9934..f25d08e77 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,6 +36,8 @@ #include #endif +#include "cli/cli.h" + #ifdef HAVE_GUI #include "gui/gui.h" #endif @@ -46,6 +48,8 @@ DivEngine e; FurnaceGUI g; #endif +FurnaceCLI cli; + String outName; String vgmOutName; int loops=1; @@ -465,25 +469,39 @@ int main(int argc, char** argv) { } if (consoleMode) { + bool cliSuccess=false; + cli.bindEngine(&e); + if (!cli.init()) { + reportError("error while starting CLI!"); + } else { + cliSuccess=true; + } logI("playing..."); e.play(); + if (cliSuccess) { + cli.loop(); + cli.finish(); + e.quit(); + return 0; + } else { #ifdef HAVE_SDL2 - SDL_Event ev; - while (true) { - SDL_WaitEvent(&ev); - if (ev.type==SDL_QUIT) break; - } - e.quit(); - return 0; + SDL_Event ev; + while (true) { + SDL_WaitEvent(&ev); + if (ev.type==SDL_QUIT) break; + } + e.quit(); + return 0; #else - while (true) { + while (true) { #ifdef _WIN32 - Sleep(500); + Sleep(500); #else - usleep(500000); + usleep(500000); +#endif + } #endif } -#endif } #ifdef HAVE_GUI From b0c2b10135d4e8daa0b3462300e25666ccb85416 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 25 Jul 2022 18:32:26 -0500 Subject: [PATCH 080/515] GUI: add "scale" option to find/replace --- src/gui/findReplace.cpp | 62 ++++++++++++++++++++++++++++++++++++++++- src/gui/gui.h | 1 + 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index e982882d4..559d7f7ff 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -39,6 +39,7 @@ const char* queryReplaceModes[GUI_QUERY_REPLACE_MAX]={ "set", "add", "add (overflow)", + "scale", "clear" }; @@ -292,6 +293,8 @@ void FurnaceGUI::doReplace() { } } break; + case GUI_QUERY_REPLACE_SCALE: + break; case GUI_QUERY_REPLACE_CLEAR: p->data[i.y][0]=0; p->data[i.y][1]=0; @@ -314,6 +317,13 @@ void FurnaceGUI::doReplace() { case GUI_QUERY_REPLACE_ADD_OVERFLOW: if (p->data[i.y][2]>=0) p->data[i.y][2]=(p->data[i.y][2]+queryReplaceIns)&0xff; break; + case GUI_QUERY_REPLACE_SCALE: + if (p->data[i.y][2]>=0) { + p->data[i.y][2]=(p->data[i.y][2]*queryReplaceIns)/100; + if (p->data[i.y][2]<0) p->data[i.y][2]=0; + if (p->data[i.y][2]>255) p->data[i.y][2]=255; + } + break; case GUI_QUERY_REPLACE_CLEAR: p->data[i.y][2]=-1; break; @@ -335,6 +345,13 @@ void FurnaceGUI::doReplace() { case GUI_QUERY_REPLACE_ADD_OVERFLOW: if (p->data[i.y][3]>=0) p->data[i.y][3]=(p->data[i.y][3]+queryReplaceVol)&0xff; break; + case GUI_QUERY_REPLACE_SCALE: + if (p->data[i.y][3]>=0) { + p->data[i.y][3]=(p->data[i.y][3]*queryReplaceVol)/100; + if (p->data[i.y][3]<0) p->data[i.y][3]=0; + if (p->data[i.y][3]>255) p->data[i.y][3]=255; + } + break; case GUI_QUERY_REPLACE_CLEAR: p->data[i.y][3]=-1; break; @@ -402,6 +419,13 @@ void FurnaceGUI::doReplace() { case GUI_QUERY_REPLACE_ADD_OVERFLOW: if (p->data[i.y][4+pos*2]>=0) p->data[i.y][4+pos*2]=(p->data[i.y][4+pos*2]+queryReplaceEffect[j])&0xff; break; + case GUI_QUERY_REPLACE_SCALE: + if (p->data[i.y][4+pos*2]>=0) { + p->data[i.y][4+pos*2]=(p->data[i.y][4+pos*2]*queryReplaceEffect[j])/100; + if (p->data[i.y][4+pos*2]<0) p->data[i.y][4+pos*2]=0; + if (p->data[i.y][4+pos*2]>255) p->data[i.y][4+pos*2]=255; + } + break; case GUI_QUERY_REPLACE_CLEAR: p->data[i.y][4+pos*2]=-1; break; @@ -423,6 +447,13 @@ void FurnaceGUI::doReplace() { case GUI_QUERY_REPLACE_ADD_OVERFLOW: if (p->data[i.y][5+pos*2]>=0) p->data[i.y][5+pos*2]=(p->data[i.y][5+pos*2]+queryReplaceEffectVal[j])&0xff; break; + case GUI_QUERY_REPLACE_SCALE: + if (p->data[i.y][5+pos*2]>=0) { + p->data[i.y][5+pos*2]=(p->data[i.y][5+pos*2]*queryReplaceEffectVal[j])/100; + if (p->data[i.y][5+pos*2]<0) p->data[i.y][5+pos*2]=0; + if (p->data[i.y][5+pos*2]>255) p->data[i.y][5+pos*2]=255; + } + break; case GUI_QUERY_REPLACE_CLEAR: p->data[i.y][5+pos*2]=-1; break; @@ -919,6 +950,8 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceNote<-180) queryReplaceNote=-180; if (queryReplaceNote>180) queryReplaceNote=180; } + } else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SCALE) { + ImGui::Text("INVALID"); } ImGui::EndDisabled(); @@ -941,6 +974,13 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceIns<-255) queryReplaceIns=-255; if (queryReplaceIns>255) queryReplaceIns=255; } + } else if (queryReplaceInsMode==GUI_QUERY_REPLACE_SCALE) { + if (queryReplaceIns<0) queryReplaceIns=0; + if (queryReplaceIns>400) queryReplaceIns=400; + if (ImGui::InputInt("##IRValue",&queryReplaceIns,1,12)) { + if (queryReplaceIns<0) queryReplaceIns=0; + if (queryReplaceIns>400) queryReplaceIns=400; + } } ImGui::EndDisabled(); @@ -963,6 +1003,13 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceVol<-255) queryReplaceVol=-255; if (queryReplaceVol>255) queryReplaceVol=255; } + } else if (queryReplaceVolMode==GUI_QUERY_REPLACE_SCALE) { + if (queryReplaceVol<0) queryReplaceVol=0; + if (queryReplaceVol>400) queryReplaceVol=400; + if (ImGui::InputInt("##VRValue",&queryReplaceVol,1,12)) { + if (queryReplaceVol<0) queryReplaceVol=0; + if (queryReplaceVol>400) queryReplaceVol=400; + } } ImGui::EndDisabled(); @@ -987,6 +1034,13 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceEffect[i]<-255) queryReplaceEffect[i]=-255; if (queryReplaceEffect[i]>255) queryReplaceEffect[i]=255; } + } else if (queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_SCALE) { + if (queryReplaceEffect[i]<0) queryReplaceEffect[i]=0; + if (queryReplaceEffect[i]>400) queryReplaceEffect[i]=400; + if (ImGui::InputInt("##ERValue",&queryReplaceEffect[i],1,12)) { + if (queryReplaceEffect[i]<0) queryReplaceEffect[i]=0; + if (queryReplaceEffect[i]>400) queryReplaceEffect[i]=400; + } } ImGui::EndDisabled(); @@ -1009,10 +1063,16 @@ void FurnaceGUI::drawFindReplace() { if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255; if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; } + } else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SCALE) { + if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; + if (queryReplaceEffectVal[i]>400) queryReplaceEffectVal[i]=400; + if (ImGui::InputInt("##ERValueV",&queryReplaceEffectVal[i],1,12)) { + if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; + if (queryReplaceEffectVal[i]>400) queryReplaceEffectVal[i]=400; + } } ImGui::EndDisabled(); - ImGui::PopID(); } diff --git a/src/gui/gui.h b/src/gui/gui.h index bd2a5494c..8fcf38b30 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -885,6 +885,7 @@ enum FurnaceGUIFindQueryReplaceModes { GUI_QUERY_REPLACE_SET=0, GUI_QUERY_REPLACE_ADD, GUI_QUERY_REPLACE_ADD_OVERFLOW, + GUI_QUERY_REPLACE_SCALE, GUI_QUERY_REPLACE_CLEAR, GUI_QUERY_REPLACE_MAX From 09e457003b31907a2e4047b3794cf3827420569c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 25 Jul 2022 18:41:47 -0500 Subject: [PATCH 081/515] add option for soft-clipping --- src/engine/engine.cpp | 1 + src/engine/engine.h | 1 + src/engine/playback.cpp | 8 ++++++++ src/gui/gui.h | 2 ++ src/gui/settings.cpp | 8 ++++++++ 5 files changed, 20 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 98947ead3..40a51bdc2 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2996,6 +2996,7 @@ bool DivEngine::initAudioBackend() { lowQuality=getConfInt("audioQuality",0); forceMono=getConfInt("forceMono",0); + clampSamples=getConfInt("clampSamples",0); lowLatency=getConfInt("lowLatency",0); metroVol=(float)(getConfInt("metroVol",100))/100.0f; if (metroVol<0.0f) metroVol=0.0f; diff --git a/src/engine/engine.h b/src/engine/engine.h index b5c158058..482b58dcb 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -298,6 +298,7 @@ class DivEngine { bool stopExport; bool halted; bool forceMono; + bool clampSamples; bool cmdStreamEnabled; bool softLocked; bool firstTick; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index e9d5aa952..662e2ddb4 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1413,6 +1413,14 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi out[1][i]=out[0][i]; } } + if (clampSamples) { + for (size_t i=0; i1.0) out[0][i]=1.0; + if (out[1][i]<-1.0) out[1][i]=-1.0; + if (out[1][i]>1.0) out[1][i]=1.0; + } + } isBusy.unlock(); std::chrono::steady_clock::time_point ts_processEnd=std::chrono::steady_clock::now(); diff --git a/src/gui/gui.h b/src/gui/gui.h index 8fcf38b30..875501d24 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1094,6 +1094,7 @@ class FurnaceGUI { int dragMovesSelection; int unsignedDetune; int noThreadedInput; + int clampSamples; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1199,6 +1200,7 @@ class FurnaceGUI { dragMovesSelection(1), unsignedDetune(0), noThreadedInput(0), + clampSamples(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index f67671194..eae165d27 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -659,6 +659,11 @@ void FurnaceGUI::drawSettings() { settings.forceMono=forceMonoB; } + bool clampSamplesB=settings.clampSamples; + if (ImGui::Checkbox("Software clipping",&clampSamplesB)) { + settings.clampSamples=clampSamplesB; + } + TAAudioDesc& audioWant=e->getAudioDescWant(); TAAudioDesc& audioGot=e->getAudioDescGot(); @@ -2118,6 +2123,7 @@ void FurnaceGUI::syncSettings() { settings.unsignedDetune=e->getConfInt("unsignedDetune",0); settings.noThreadedInput=e->getConfInt("noThreadedInput",0); settings.initialSysName=e->getConfString("initialSysName",""); + settings.clampSamples=e->getConfInt("clampSamples",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2205,6 +2211,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.dragMovesSelection,0,2); clampSetting(settings.unsignedDetune,0,1); clampSetting(settings.noThreadedInput,0,1); + clampSetting(settings.clampSamples,0,1); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2343,6 +2350,7 @@ void FurnaceGUI::commitSettings() { e->setConf("dragMovesSelection",settings.dragMovesSelection); e->setConf("unsignedDetune",settings.unsignedDetune); e->setConf("noThreadedInput",settings.noThreadedInput); + e->setConf("clampSamples",settings.clampSamples); // colors for (int i=0; i Date: Mon, 25 Jul 2022 19:09:42 -0500 Subject: [PATCH 082/515] FC loader: read slides --- src/engine/fileOps.cpp | 43 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 71b8f90d1..30a9db943 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2292,10 +2292,10 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { DivSong ds; ds.tuning=436.0; ds.version=DIV_VERSION_FC; - ds.linearPitch=0; - ds.noSlidesOnFirstTick=true; - ds.rowResetsArpPos=true; - ds.ignoreJumpAtEnd=false; + //ds.linearPitch=0; + //ds.noSlidesOnFirstTick=true; + //ds.rowResetsArpPos=true; + //ds.ignoreJumpAtEnd=false; // load here if (!reader.seek(0,SEEK_SET)) { @@ -2436,6 +2436,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { p->data[0][9]=seq[i].speed; } + bool ignoreNext=false; + bool isSliding=false; + for (int k=0; k<32; k++) { FCPattern& fp=pat[seq[i].pat[j]]; if (fp.note[k]>0 && fp.note[k]<0x49) { @@ -2449,9 +2452,37 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { octave&=0xff; p->data[k][0]=note; p->data[k][1]=octave; - if (fp.val[k]) { + if (isSliding) { + isSliding=false; + p->data[k][4]=2; + p->data[k][5]=0; + } + } + if (fp.val[k]) { + if (ignoreNext) { + ignoreNext=false; + } else { if (fp.val[k]&0xe0) { - + if (fp.val[k]&0x40) { + p->data[k][4]=2; + p->data[k][5]=0; + isSliding=false; + } else if (fp.val[k]&0x80) { + isSliding=true; + if (k<31) { + if (fp.val[k+1]&0x20) { + p->data[k][4]=2; + p->data[k][5]=fp.val[k+1]&0x1f; + } else { + p->data[k][4]=1; + p->data[k][5]=fp.val[k+1]&0x1f; + } + ignoreNext=true; + } else { + p->data[k][4]=2; + p->data[k][5]=0; + } + } } else { p->data[k][2]=fp.val[k]-1; } From 8d17500315a1fb15de0b297e4975b27957e65f77 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 25 Jul 2022 19:45:49 -0500 Subject: [PATCH 083/515] jlhafasjkhdgkdhjasfd --- src/engine/fileOps.cpp | 164 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 7 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 30a9db943..6a6685b20 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2268,9 +2268,12 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { SafeReader reader=SafeReader(file,len); warnings=""; bool isFC14=false; - unsigned int patPtr, freqMacroPtr, volMacroPtr, samplePtr; + unsigned int patPtr, freqMacroPtr, volMacroPtr, samplePtr, wavePtr; unsigned int seqLen, patLen, freqMacroLen, volMacroLen, sampleLen; + unsigned char waveLen[40]; + unsigned char waveLoopLen[40]; + struct FCSequence { unsigned char pat[4]; signed char transpose[4]; @@ -2283,6 +2286,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { unsigned char val[32]; }; std::vector pat; + struct FCMacro { + unsigned char val[64]; + }; + std::vector freqMacros; + std::vector volMacros; struct FCSample { unsigned short loopLen, len, loopStart; @@ -2335,14 +2343,23 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } freqMacroPtr=reader.readI_BE(); freqMacroLen=reader.readI_BE(); + if (freqMacroLen%64) { + logW("freq sequence length is not multiple of 64 (%d)",freqMacroLen); + //throw EndOfFileException(&reader,reader.tell()); + } volMacroPtr=reader.readI_BE(); volMacroLen=reader.readI_BE(); + if (volMacroLen%64) { + logW("vol sequence length is not multiple of 64 (%d)",volMacroLen); + //throw EndOfFileException(&reader,reader.tell()); + } samplePtr=reader.readI_BE(); if (isFC14) { - reader.readI_BE(); // wave len + wavePtr=reader.readI_BE(); // wave len sampleLen=0; } else { sampleLen=reader.readI_BE(); + wavePtr=0; } logD("patPtr: %d",patPtr); @@ -2352,7 +2369,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { logD("volMacroPtr: %d",volMacroPtr); logD("volMacroLen: %d",volMacroLen); logD("samplePtr: %d",samplePtr); - logD("sampleLen: %d",sampleLen); + if (isFC14) { + logD("wavePtr: %d",wavePtr); + } else { + logD("sampleLen: %d",sampleLen); + } // sample info logD("samples:"); @@ -2365,9 +2386,14 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } // wavetable lengths - if (isFC14) for (int i=0; i<20; i++) { - reader.readS_BE(); - reader.readS_BE(); + if (isFC14) { + logD("wavetables:"); + for (int i=0; i<40; i++) { + waveLen[i]=reader.readC(); + waveLoopLen[i]=reader.readC(); + + logD("- %d: %.4x (%.4x)",i,waveLen[i],waveLoopLen[i]); + } } // sequences @@ -2413,7 +2439,96 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { pat.push_back(p); } - // TODO: read the rest + // freq sequences + if (!reader.seek(freqMacroPtr,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete[] file; + return false; + } + freqMacroLen/=64; + logD("reading freq sequences... (%d)",freqMacroLen); + for (unsigned int i=0; idepth=DIV_SAMPLE_DEPTH_8BIT; + if (sample[i].len>0) { + s->init(sample[i].len); + } + s->loopStart=sample[i].loopStart*2; + s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; + reader.read(s->data8,sample[i].len); + ds.sample.push_back(s); + } + ds.sampleLen=(int)ds.sample.size(); + + // wavetables + if (isFC14) { + if (!reader.seek(wavePtr,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete[] file; + return false; + } + logD("reading wavetables..."); + for (int i=0; i<40; i++) { + DivWavetable* w=new DivWavetable; + w->min=0; + w->max=255; + w->len=MIN(256,waveLoopLen[i]*2); + + for (int i=0; i<256; i++) { + w->data[i]=128; + } + + if (waveLen[i]>0) { + signed char* waveArray=new signed char[waveLen[i]*2]; + reader.read(waveArray,waveLen[i]*2); + int howMany=MIN(waveLen[i]*2,waveLoopLen[i]*2); + if (howMany>256) howMany=256; + for (int i=0; idata[i]=waveArray[i]; + } + delete[] waveArray; + } else { + w->len=32; + for (int i=0; i<32; i++) { + w->data[i]=(i*255)/31; + } + } + + ds.wave.push_back(w); + } + } + ds.waveLen=(int)ds.wave.size(); // convert ds.subsong[0]->ordersLen=seqLen; @@ -2492,6 +2607,41 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } + // convert instruments + for (unsigned int i=0; itype=DIV_INS_AMIGA; + ins->name=fmt::sprintf("Instrument %d",i); + unsigned char seqSpeed=m.val[0]; + unsigned char freqMacro=m.val[1]; + unsigned char vibSpeed=m.val[2]; + unsigned char vibDepth=m.val[3]; + unsigned char vibDelay=m.val[4]; + + ins->std.volMacro.len=0; + for (int j=5; j<64; j++) { + unsigned char pos=ins->std.volMacro.len; + if (++ins->std.volMacro.len>=128) break; + if (m.val[j]==0xe1) { + + } else if (m.val[j]==0xe0) { + + } else if (m.val[j]==0xe8) { + + } else if (m.val[j]==0xe9) { + + } else { + ins->std.volMacro.val[ins->std.volMacro.len]=m.val[j]; + } + + } + + ds.ins.push_back(ins); + } + ds.insLen=(int)ds.ins.size(); + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); From 280592cf333e28853657fa05e3992c193346bb76 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 01:42:34 -0500 Subject: [PATCH 084/515] fix build --- src/engine/fileOps.cpp | 112 ++++++++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 18 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 6a6685b20..d480167ee 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2324,7 +2324,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } ds.systemLen=1; - ds.system[0]=DIV_SYSTEM_DUMMY; + ds.system[0]=DIV_SYSTEM_AMIGA; ds.systemVol[0]=64; ds.systemPan[0]=0; ds.systemFlags[0]=1|(80<<8); // PAL @@ -2515,7 +2515,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { int howMany=MIN(waveLen[i]*2,waveLoopLen[i]*2); if (howMany>256) howMany=256; for (int i=0; idata[i]=waveArray[i]; + w->data[i]=waveArray[i]+128; } delete[] waveArray; } else { @@ -2599,7 +2599,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } } else { - p->data[k][2]=fp.val[k]-1; + p->data[k][2]=fp.val[k]&0x3f; } } } @@ -2614,28 +2614,104 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->type=DIV_INS_AMIGA; ins->name=fmt::sprintf("Instrument %d",i); - unsigned char seqSpeed=m.val[0]; + ins->amiga.useWave=true; + //unsigned char seqSpeed=m.val[0]; unsigned char freqMacro=m.val[1]; - unsigned char vibSpeed=m.val[2]; - unsigned char vibDepth=m.val[3]; - unsigned char vibDelay=m.val[4]; + //unsigned char vibSpeed=m.val[2]; + //unsigned char vibDepth=m.val[3]; + //unsigned char vibDelay=m.val[4]; + unsigned char lastVal=m.val[5]; + + signed char loopMap[64]; + memset(loopMap,-1,64); + + // volume sequence ins->std.volMacro.len=0; for (int j=5; j<64; j++) { - unsigned char pos=ins->std.volMacro.len; - if (++ins->std.volMacro.len>=128) break; - if (m.val[j]==0xe1) { - - } else if (m.val[j]==0xe0) { - - } else if (m.val[j]==0xe8) { - - } else if (m.val[j]==0xe9) { - + loopMap[j]=ins->std.volMacro.len; + if (m.val[j]==0xe1) { // end + break; + } else if (m.val[j]==0xe0) { // loop + if (++j>=64) break; + ins->std.volMacro.loop=loopMap[m.val[j]&63]; + break; + } else if (m.val[j]==0xe8) { // sustain + if (++j>=64) break; + unsigned char susTime=m.val[j]; + // TODO: <= or std.volMacro.val[ins->std.volMacro.len]=lastVal; + if (++ins->std.volMacro.len>=128) break; + } + } else if (m.val[j]==0xe9 || m.val[j]==0xea) { // volume slide + if (++j>=64) break; + signed char slideStep=m.val[j]; + if (++j>=64) break; + unsigned char slideTime=m.val[j]; + // TODO: <= or 0) { + lastVal+=slideStep; + if (lastVal>63) lastVal=63; + } else { + if (-slideStep>lastVal) { + lastVal=0; + } else { + lastVal-=slideStep; + } + } + ins->std.volMacro.val[ins->std.volMacro.len]=lastVal; + if (++ins->std.volMacro.len>=128) break; + } } else { ins->std.volMacro.val[ins->std.volMacro.len]=m.val[j]; + lastVal=m.val[j]; + if (++ins->std.volMacro.len>=128) break; + } + } + + // frequency sequence + lastVal=0; + ins->amiga.initSample=-1; + if (freqMacro=64) break; + unsigned char wave=fm.val[j]; + if (wave<10) { // sample + if (ins->amiga.initSample==-1) { + ins->amiga.initSample=wave; + ins->amiga.useWave=false; + } + } else { // waveform + ins->std.waveMacro.val[ins->std.waveMacro.len]=wave-10; + ins->std.waveMacro.open=true; + lastVal=wave; + if (++ins->std.waveMacro.len>=128) break; + if (++ins->std.arpMacro.len>=128) break; + } + } else if (fm.val[j]==0xe0) { + logV("unhandled loop!"); + } else if (fm.val[j]==0xe3) { + logV("unhandled vibrato!"); + } else if (fm.val[j]==0xe8) { + logV("unhandled sustain!"); + } else if (fm.val[j]==0xe7) { + logV("unhandled newseq!"); + } else if (fm.val[j]==0xe9) { + logV("unhandled pack!"); + } else if (fm.val[j]==0xea) { + logV("unhandled pitch!"); + } else { + ins->std.arpMacro.val[ins->std.arpMacro.len]=(signed char)fm.val[j]; + ins->std.arpMacro.open=true; + if (++ins->std.arpMacro.len>=128) break; + } } - } ds.ins.push_back(ins); From 26176f58eb65806a51d25b3726491549b10c5355 Mon Sep 17 00:00:00 2001 From: 20Enderdude20 Date: Tue, 26 Jul 2022 00:12:34 -0700 Subject: [PATCH 085/515] Use this effect in lower notes like c -1 to C-0 --- instruments/FM/effect/GEN_Wind.fui | Bin 0 -> 1763 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/FM/effect/GEN_Wind.fui diff --git a/instruments/FM/effect/GEN_Wind.fui b/instruments/FM/effect/GEN_Wind.fui new file mode 100644 index 0000000000000000000000000000000000000000..181d90d7f303bcc3d85f9de651f6d57d1b0d9e4d GIT binary patch literal 1763 zcmeHH%TB{E5S%*e7YLch2gFA>lyBeyh)ab85@!Uc>LrH)U&n<%gWalboG7UUhznwr z)lR(jjJ;7jy?9+V_YY5T(LBE_Pp5MLkt5-1c60k?fH@{OzC53u#JffF2ulDzKn)$t zK2W6vy<9_uaIme8;10LdcLI(^>jCPFcLun1aLQ0;yhuL^NCIM&AWMX&rLvV3mbu>N(~(Fg&M7{ezK5gm*G literal 0 HcmV?d00001 From a9bfe7f452de711168aef64ebf8868fbb20cc7ed Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 02:13:19 -0500 Subject: [PATCH 086/515] fix build... again! --- src/cli/cli.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 956796001..55ac3a865 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -34,8 +34,14 @@ bool FurnaceCLI::loop() { bool escape=false; bool escapeSecondStage=false; while (!cliQuit) { +#ifdef _WIN32 + int c; + c=fgetc(stdin); + if (c==EOF) break; +#else unsigned char c; if (read(STDIN_FILENO,&c,1)<=0) continue; +#endif if (escape) { if (escapeSecondStage) { switch (c) { From e7938ccd11e36900fbbd9d52c93f0ca1796268a5 Mon Sep 17 00:00:00 2001 From: Aleksi Knutsi <53163105+host12prog@users.noreply.github.com> Date: Tue, 26 Jul 2022 14:16:24 +0700 Subject: [PATCH 087/515] Fix 1 typo and 2 capitalization errors --- papers/doc/7-systems/x1-010.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/papers/doc/7-systems/x1-010.md b/papers/doc/7-systems/x1-010.md index 411afb3e7..80b5b41a3 100644 --- a/papers/doc/7-systems/x1-010.md +++ b/papers/doc/7-systems/x1-010.md @@ -8,9 +8,9 @@ Allumer rebadged it for their own arcade hardware. It has 16 channels, which can all be switched between PCM sample or wavetable playback mode. Wavetable playback needs to paired with envelope, similar to AY PSG, but shapes are stored in RAM and as such are user-definable. -In furnace, this chip can be configured for original arcade mono output or stereo output - it simulates early 'incorrect' emulation on some mono hardware, but it is also based on the assumption that each channel is connected to each output. +In Furnace, this chip can be configured for original arcade mono output or stereo output - it simulates early 'incorrect' emulation on some mono hardware, but it is also based on the assumption that each channel is connected to each output. -# waveform types +# Waveform types This chip supports 2 types of waveforms, needs to be paired to external 8 KB RAM to access these features: @@ -44,4 +44,4 @@ In furnace, you can enable the envelope shape split mode. When it is set, its wa - `y` is the denominator. - if `x` or `y` are 0 this will disable auto-envelope mode. -* PCM frequency: 255 step, fomula: `step * (Chip clock / 8192)`; 1.95KHz to 498KHz if Chip clock is 16MHz. +* PCM frequency: 255 step, formula: `step * (Chip clock / 8192)`; 1.95KHz to 498KHz if Chip clock is 16MHz. From c6d5f55335125f9f618ef2c47d43d64c79bd421f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 02:28:28 -0500 Subject: [PATCH 088/515] AND REALLY FIX IT THIS TIME --- src/cli/cli.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 55ac3a865..2ac4a492f 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -96,11 +96,14 @@ bool FurnaceCLI::loop() { } bool FurnaceCLI::finish() { +#ifdef _WIN32 +#else if (tcsetattr(0,TCSAFLUSH,&termpropold)!=0) { logE("could not set console attributes!"); logE("you may have to run `reset` on your terminal."); return false; } +#endif return true; } From 606215ef9f33c7e11abf77cca2c018fd8024255b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 02:54:35 -0500 Subject: [PATCH 089/515] OH MY --- src/cli/cli.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 2ac4a492f..87bf76dda 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -22,9 +22,11 @@ bool cliQuit=false; +#ifndef _WIN32 static void handleTerm(int) { cliQuit=true; } +#endif void FurnaceCLI::bindEngine(DivEngine* eng) { e=eng; From 92c3e75bee907cc229432c4c1da143b79ad6d2ed Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 03:11:46 -0500 Subject: [PATCH 090/515] why! --- src/cli/cli.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cli/cli.h b/src/cli/cli.h index 0df6658e3..55ad36b38 100644 --- a/src/cli/cli.h +++ b/src/cli/cli.h @@ -20,6 +20,9 @@ #ifndef _FUR_CLI_H #define _FUR_CLI_H + +#include "../engine/engine.h" + #include #ifdef _WIN32 #include @@ -30,8 +33,6 @@ #include #endif -#include "../engine/engine.h" - class FurnaceCLI { DivEngine* e; From 47aba6186dee6bc453175911ee9f0b135b56a514 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 03:34:41 -0500 Subject: [PATCH 091/515] GUI: fix possible crash in sample editing actions --- src/gui/sampleUtil.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/sampleUtil.h b/src/gui/sampleUtil.h index 981a56046..187f5ebf6 100644 --- a/src/gui/sampleUtil.h +++ b/src/gui/sampleUtil.h @@ -20,6 +20,10 @@ #define SAMPLE_OP_BEGIN \ unsigned int start=0; \ unsigned int end=sample->samples; \ + if (sampleSelStart<0) sampleSelStart=0; \ + if (sampleSelStart>(int)sample->samples) sampleSelStart=sample->samples; \ + if (sampleSelEnd<0) sampleSelEnd=0; \ + if (sampleSelEnd>(int)sample->samples) sampleSelEnd=sample->samples; \ if (sampleSelStart!=-1 && sampleSelEnd!=-1 && sampleSelStart!=sampleSelEnd) { \ start=sampleSelStart; \ end=sampleSelEnd; \ From 173e9b0df9590536e25b3126c17663cd1b08ffe7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 26 Jul 2022 18:23:01 -0500 Subject: [PATCH 092/515] **Namco C163** --- papers/doc/7-systems/n163.md | 22 +++++++++++++++++++++- src/engine/engine.h | 3 +++ src/engine/sysDef.cpp | 8 ++++---- src/gui/gui.cpp | 6 +++++- src/gui/gui.h | 11 +++++++++++ src/gui/settings.cpp | 4 ++-- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 6057fa3c9..d3ece830f 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,4 +1,24 @@ -# Namco C163 +# - ANNOUNCEMENT - + +Start calling it C163! The TRUE name of the chip! + +The line will be consistent with your help: +- Namco C15 +- Namco C30 +- Namco C140 +- **Namco C163** +- Namco C219 +- Namco C352 + +The C names are official as indicated by: + +- MAME +- VGMPlay +- Korg × Bandai Namco (from Kamata info page) + +C stands for Custom! Call it C163! + +# Namco 163 (also called Namco C163, 106, 160 or 129) This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 128 byte of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consumes 8 bytes for each channel. You must avoid conflict with channel register area and waveform for avoid broken channel playback. diff --git a/src/engine/engine.h b/src/engine/engine.h index 482b58dcb..3030cfadb 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -52,6 +52,9 @@ #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 +// "Namco C163" +#define DIV_C163_DEFAULT_NAME "Namco 163" + enum DivStatusView { DIV_STATUS_NOTHING=0, DIV_STATUS_PATTERN, diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 813e409e5..740854071 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -178,7 +178,7 @@ String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAccepta } if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_N163) { String ret="Famicom + "; - ret+=getConfString("c163Name","Namco C163"); + ret+=getConfString("c163Name",DIV_C163_DEFAULT_NAME); return ret; } if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_MMC5) { @@ -208,7 +208,7 @@ String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAccepta for (int i=0; i0) ret+=" + "; if (ds.system[i]==DIV_SYSTEM_N163) { - ret+=getConfString("c163Name","Namco C163"); + ret+=getConfString("c163Name",DIV_C163_DEFAULT_NAME); } else { ret+=getSystemName(ds.system[i]); } @@ -220,7 +220,7 @@ String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAccepta const char* DivEngine::getSystemName(DivSystem sys) { if (sysDefs[sys]==NULL) return "Unknown"; if (sys==DIV_SYSTEM_N163) { - String c1=getConfString("c163Name","Namco C163"); + String c1=getConfString("c163Name",DIV_C163_DEFAULT_NAME); strncpy(c163NameCS,c1.c_str(),1023); return c163NameCS; } @@ -1246,7 +1246,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_N163]=new DivSysDef( - "Namco C163", NULL, 0x8c, 0, 8, false, true, 0, false, + "Namco 163/C163/129/160/106/whatever", NULL, 0x8c, 0, 8, false, true, 0, false, "an expansion chip for the Famicom, with full wavetable.", {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"}, {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2c80c5fbe..b883935ea 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4716,7 +4716,11 @@ FurnaceGUI::FurnaceGUI(): pianoView(0), pianoInputPadMode(0), #endif - hasACED(false) { + hasACED(false), + waveGenBaseShape(0), + waveGenDuty(0.0f), + waveGenPower(0.0f), + waveGenInvertPoint(0.0f) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; diff --git a/src/gui/gui.h b/src/gui/gui.h index 875501d24..3b98f77ff 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1466,6 +1466,17 @@ class FurnaceGUI { bool hasACED; unsigned char acedData[23]; + // wave generator + int waveGenBaseShape; + float waveGenDuty, waveGenPower, waveGenInvertPoint; + float waveGenAmp[16]; + float waveGenPhase[16]; + float waveGenTL[4]; + float waveGenFB[4]; + bool waveGenFMCon1[4]; + bool waveGenFMCon2[3]; + bool waveGenFMCon3[2]; + void drawSSGEnv(unsigned char type, const ImVec2& size); void drawWaveform(unsigned char type, bool opz, const ImVec2& size); void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index eae165d27..6582a4e21 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1203,7 +1203,7 @@ void FurnaceGUI::drawSettings() { ImGui::Text("N163/C163 chip name"); ImGui::SameLine(); - ImGui::InputTextWithHint("##C163Name","Namco C163",&settings.c163Name); + ImGui::InputTextWithHint("##C163Name",DIV_C163_DEFAULT_NAME,&settings.c163Name); ImGui::Separator(); @@ -2029,7 +2029,7 @@ void FurnaceGUI::syncSettings() { settings.midiInDevice=e->getConfString("midiInDevice",""); settings.midiOutDevice=e->getConfString("midiOutDevice",""); // I'm sorry, but the C163 education program has failed... - settings.c163Name=e->getConfString("c163Name","Namco C163"); + settings.c163Name=e->getConfString("c163Name",DIV_C163_DEFAULT_NAME); settings.audioQuality=e->getConfInt("audioQuality",0); settings.audioBufSize=e->getConfInt("audioBufSize",1024); settings.audioRate=e->getConfInt("audioRate",44100); From 7d5f5a91c67a9cf3abc4ee43f850479d00aa8202 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 01:20:26 -0500 Subject: [PATCH 093/515] GUI: wave generator, part 1 --- src/gui/gui.cpp | 17 +++++++++++- src/gui/gui.h | 4 +++ src/gui/waveEdit.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b883935ea..565ff7db5 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4720,7 +4720,8 @@ FurnaceGUI::FurnaceGUI(): waveGenBaseShape(0), waveGenDuty(0.0f), waveGenPower(0.0f), - waveGenInvertPoint(0.0f) { + waveGenInvertPoint(0.0f), + waveGenFM(false) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; @@ -4782,6 +4783,20 @@ FurnaceGUI::FurnaceGUI(): memset(acedData,0,23); + memset(waveGenAmp,0,sizeof(float)*16); + memset(waveGenPhase,0,sizeof(float)*16); + memset(waveGenTL,0,sizeof(float)*4); + memset(waveGenMult,0,sizeof(int)*4); + memset(waveGenFB,0,sizeof(float)*4); + memset(waveGenFMCon1,0,sizeof(bool)*4); + memset(waveGenFMCon2,0,sizeof(bool)*3); + memset(waveGenFMCon3,0,sizeof(bool)*2); + + waveGenAmp[0]=1.0f; + waveGenFMCon1[0]=true; + waveGenFMCon2[0]=true; + waveGenFMCon3[0]=true; + memset(pianoKeyHit,0,sizeof(float)*180); memset(pianoKeyPressed,0,sizeof(bool)*180); diff --git a/src/gui/gui.h b/src/gui/gui.h index 3b98f77ff..df3dcd16d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1472,10 +1472,12 @@ class FurnaceGUI { float waveGenAmp[16]; float waveGenPhase[16]; float waveGenTL[4]; + int waveGenMult[4]; float waveGenFB[4]; bool waveGenFMCon1[4]; bool waveGenFMCon2[3]; bool waveGenFMCon3[2]; + bool waveGenFM; void drawSSGEnv(unsigned char type, const ImVec2& size); void drawWaveform(unsigned char type, bool opz, const ImVec2& size); @@ -1600,6 +1602,8 @@ class FurnaceGUI { void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); + void doGenerateWave(); + void doUndoSample(); void doRedoSample(); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index f8c27b1fa..0d65f5e68 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -17,12 +17,60 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _USE_MATH_DEFINES #include "gui.h" #include "plot_nolerp.h" #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" +#include #include +const char* waveGenBaseShapes[4]={ + "Sine", + "Triangle", + "Saw", + "Pulse" +}; + +void FurnaceGUI::doGenerateWave() { + float finalResult[256]; + if (curWave<0 || curWave>=(int)e->song.wave.size()) return; + + DivWavetable* wave=e->song.wave[curWave]; + memset(finalResult,0,sizeof(float)*256); + + if (waveGenFM) { + + } else { + switch (waveGenBaseShape) { + case 0: // sine + for (int i=0; ilen; i++) { + finalResult[i]=0.5*(1.0+sin(i*2.0*M_PI/(double)wave->len)); + } + break; + case 1: // triangle + for (int i=0; ilen; i++) { + finalResult[i]=2.0*(0.5-fabs(0.5-(i/(double)(wave->len-1)))); + } + break; + case 2: // saw + for (int i=0; ilen; i++) { + finalResult[i]=i/(double)(wave->len-1); + } + break; + case 3: // pulse + for (int i=0; ilen; i++) { + finalResult[i]=(i>=(wave->len/2))?1:0; + } + break; + } + } + + for (int i=0; ilen; i++) { + wave->data[i]=round(finalResult[i]*wave->max); + } +} + void FurnaceGUI::drawWaveEdit() { if (nextWindow==GUI_WINDOW_WAVE_EDIT) { waveEditOpen=true; @@ -144,10 +192,21 @@ void FurnaceGUI::drawWaveEdit() { if (ImGui::BeginTabBar("WaveGenOpt")) { if (ImGui::BeginTabItem("Shapes")) { - ImGui::Button("Square"); + waveGenFM=false; + + if (waveGenBaseShape<0) waveGenBaseShape=0; + if (waveGenBaseShape>3) waveGenBaseShape=3; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##WGShape",&waveGenBaseShape,0,3,waveGenBaseShapes[waveGenBaseShape])) { + if (waveGenBaseShape<0) waveGenBaseShape=0; + if (waveGenBaseShape>3) waveGenBaseShape=3; + doGenerateWave(); + } ImGui::EndTabItem(); } if (ImGui::BeginTabItem("FM")) { + waveGenFM=true; + ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Mangle")) { From 693d457fffb8447727503dd42dee58e2d672f22a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 02:23:29 -0500 Subject: [PATCH 094/515] GUI: wave generator, part 2 --- src/gui/gui.cpp | 6 +-- src/gui/gui.h | 4 +- src/gui/waveEdit.cpp | 114 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 8 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 565ff7db5..ab4b3d63c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4718,9 +4718,9 @@ FurnaceGUI::FurnaceGUI(): #endif hasACED(false), waveGenBaseShape(0), - waveGenDuty(0.0f), - waveGenPower(0.0f), - waveGenInvertPoint(0.0f), + waveGenDuty(0.5f), + waveGenPower(1), + waveGenInvertPoint(1.0f), waveGenFM(false) { // value keys valueKeys[SDLK_0]=0; diff --git a/src/gui/gui.h b/src/gui/gui.h index df3dcd16d..30113953f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1468,7 +1468,9 @@ class FurnaceGUI { // wave generator int waveGenBaseShape; - float waveGenDuty, waveGenPower, waveGenInvertPoint; + float waveGenDuty; + int waveGenPower; + float waveGenInvertPoint; float waveGenAmp[16]; float waveGenPhase[16]; float waveGenTL[4]; diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 0d65f5e68..5dd9b1ccf 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -39,34 +39,67 @@ void FurnaceGUI::doGenerateWave() { DivWavetable* wave=e->song.wave[curWave]; memset(finalResult,0,sizeof(float)*256); + if (wave->len<2) return; + if (waveGenFM) { } else { switch (waveGenBaseShape) { case 0: // sine for (int i=0; ilen; i++) { - finalResult[i]=0.5*(1.0+sin(i*2.0*M_PI/(double)wave->len)); + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=sin((0.5+pos)*2.0*M_PI/(double)wave->len); + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; case 1: // triangle for (int i=0; ilen; i++) { - finalResult[i]=2.0*(0.5-fabs(0.5-(i/(double)(wave->len-1)))); + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=4.0*(0.5-fabs(0.5-(pos/(double)(wave->len-1))))-1.0; + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; case 2: // saw for (int i=0; ilen; i++) { - finalResult[i]=i/(double)(wave->len-1); + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=((2*pos)/(double)(wave->len-1))-1.0; + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; case 3: // pulse for (int i=0; ilen; i++) { - finalResult[i]=(i>=(wave->len/2))?1:0; + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=(pos>=(waveGenDuty*wave->len))?1:-1; + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; } } + for (int i=waveGenInvertPoint*wave->len; ilen; i++) { + finalResult[i]=-finalResult[i]; + } + for (int i=0; ilen; i++) { + finalResult[i]=(1.0+finalResult[i])*0.5; + if (finalResult[i]<0.0f) finalResult[i]=0.0f; + if (finalResult[i]>1.0f) finalResult[i]=1.0f; wave->data[i]=round(finalResult[i]*wave->max); } } @@ -202,6 +235,79 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenBaseShape>3) waveGenBaseShape=3; doGenerateWave(); } + + if (ImGui::BeginTable("WGShapeProps",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Duty"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGDuty",&waveGenDuty,0.0f,1.0f)) { + doGenerateWave(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Exponent"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##WGExp",&waveGenPower,1,8)) { + doGenerateWave(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("XOR Point"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGXOR",&waveGenInvertPoint,0.0f,1.0f)) { + doGenerateWave(); + } + + ImGui::EndTable(); + } + + if (ImGui::TreeNode("Amplitude/Phase")) { + if (ImGui::BeginTable("WGShapeProps",3)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.6f); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.4f); + + for (int i=0; i<16; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d",i+1); + ImGui::TableNextColumn(); + ImGui::PushID(140+i); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGAmp",&waveGenAmp[i],-1.0f,1.0f)) { + doGenerateWave(); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { + waveGenAmp[i]=0.0f; + doGenerateWave(); + } + ImGui::PopID(); + ImGui::TableNextColumn(); + ImGui::PushID(140+i); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGPhase",&waveGenPhase[i],0.0f,1.0f)) { + doGenerateWave(); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { + waveGenPhase[i]=0.0f; + doGenerateWave(); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + } + ImGui::TreePop(); + } ImGui::EndTabItem(); } if (ImGui::BeginTabItem("FM")) { From 185b283ef661bc3d7d0be02b60f1b8e0e0e9240a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 02:36:36 -0500 Subject: [PATCH 095/515] GUI: wave generator, part 3 --- src/gui/waveEdit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 5dd9b1ccf..4d8f197da 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -313,6 +313,7 @@ void FurnaceGUI::drawWaveEdit() { if (ImGui::BeginTabItem("FM")) { waveGenFM=true; + ImGui::Text("FM stuff here"); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Mangle")) { From 2b4b320a74f53370c43c6473fe0c60baa8c7876a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 02:36:48 -0500 Subject: [PATCH 096/515] fix noMultiSystem setting being inverted --- src/engine/engine.cpp | 4 ++-- src/engine/fileOps.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 40a51bdc2..2a000476d 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -848,7 +848,7 @@ void DivEngine::createNew(const int* description, String sysName) { initSongWithDesc(description); } if (sysName=="") { - song.systemName=getSongSystemLegacyName(song,getConfInt("noMultiSystem",0)); + song.systemName=getSongSystemLegacyName(song,!getConfInt("noMultiSystem",0)); } else { song.systemName=sysName; } @@ -3137,7 +3137,7 @@ bool DivEngine::init() { } String sysName=getConfString("initialSysName",""); if (sysName=="") { - song.systemName=getSongSystemLegacyName(song,getConfInt("noMultiSystem",0)); + song.systemName=getSongSystemLegacyName(song,!getConfInt("noMultiSystem",0)); } else { song.systemName=sysName; } diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index d480167ee..8dcd55d22 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -909,7 +909,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.system[1]=DIV_SYSTEM_FDS; } - ds.systemName=getSongSystemLegacyName(ds,getConfInt("noMultiSystem",0)); + ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); if (active) quitDispatch(); BUSY_BEGIN_SOFT; @@ -1497,7 +1497,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.systemNameJ=reader.readString(); ds.categoryJ=reader.readString(); } else { - ds.systemName=getSongSystemLegacyName(ds,getConfInt("noMultiSystem",0)); + ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); } // read subsongs From 9447442fede8c999515a02a8521b3d042e8b286c Mon Sep 17 00:00:00 2001 From: freq-mod Date: Wed, 27 Jul 2022 16:09:36 +0200 Subject: [PATCH 097/515] Update waveform editor height/width guide --- src/gui/waveEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 4d8f197da..ac06bcb7c 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -152,7 +152,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::TableNextColumn(); ImGui::Text("Width"); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("use a width of:\n- any on Amiga/N163\n- 32 on Game Boy, PC Engine and WonderSwan\n- 64 on FDS\n- 128 on X1-010\nany other widths will be scaled during playback."); + ImGui::SetTooltip("use a width of:\n- any on Amiga/N163\n- 32 on Game Boy, PC Engine, SCC, Konami Bubble System, Namco WSG and WonderSwan\n- 64 on FDS\n- 128 on X1-010\nany other widths will be scaled during playback."); } ImGui::SameLine(); ImGui::SetNextItemWidth(96.0f*dpiScale); @@ -166,7 +166,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::SameLine(); ImGui::Text("Height"); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("use a height of:\n- 15 for Game Boy, WonderSwan, X1-010 Envelope shape and N163\n- 31 for PC Engine\n- 63 for FDS\n- 255 for X1-010\nany other heights will be scaled during playback."); + ImGui::SetTooltip("use a height of:\n- 15 for Game Boy, WonderSwan, Namco WSG, Konami Bubble System, X1-010 Envelope shape and N163\n- 31 for PC Engine\n- 63 for FDS\n- 255 for X1-010 and SCC\nany other heights will be scaled during playback."); } ImGui::SameLine(); ImGui::SetNextItemWidth(96.0f*dpiScale); From b3e9f53ec47f30e1c520522c4728fd1f3288983d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 17:57:36 -0500 Subject: [PATCH 098/515] GUI: the poll --- src/gui/songInfo.cpp | 2 - src/gui/subSongs.cpp | 130 ------------------------------------------- 2 files changed, 132 deletions(-) diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index f1428db5e..7f7e026ed 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -226,8 +226,6 @@ void FurnaceGUI::drawSongInfo() { } ImGui::EndTable(); } - - ImGui::TextWrapped("if this feels incomplete, go to Subsongs.\nthe outcome of this Song Information window will be determined by a poll on the Furnace Discord."); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO; ImGui::End(); diff --git a/src/gui/subSongs.cpp b/src/gui/subSongs.cpp index c100600d1..c56bf6405 100644 --- a/src/gui/subSongs.cpp +++ b/src/gui/subSongs.cpp @@ -94,136 +94,6 @@ void FurnaceGUI::drawSubSongs() { if (ImGui::InputText("##SubSongName",&e->curSubSong->name)) { MARK_MODIFIED; } - - if (ImGui::BeginTable("OtherSubProps",3,ImGuiTableFlags_SizingStretchProp)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("TimeBase"); - ImGui::TableNextColumn(); - float avail=ImGui::GetContentRegionAvail().x; - ImGui::SetNextItemWidth(avail); - unsigned char realTB=e->curSubSong->timeBase+1; - if (ImGui::InputScalar("##TimeBase",ImGuiDataType_U8,&realTB,&_ONE,&_THREE)) { MARK_MODIFIED - if (realTB<1) realTB=1; - if (realTB>16) realTB=16; - e->curSubSong->timeBase=realTB-1; - } - ImGui::TableNextColumn(); - ImGui::Text("%.2f BPM",calcBPM(e->curSubSong->speed1,e->curSubSong->speed2,e->curSubSong->hz,e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD)); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Speed"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##Speed1",ImGuiDataType_U8,&e->curSubSong->speed1,&_ONE,&_THREE)) { MARK_MODIFIED - if (e->curSubSong->speed1<1) e->curSubSong->speed1=1; - if (e->isPlaying()) play(); - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##Speed2",ImGuiDataType_U8,&e->curSubSong->speed2,&_ONE,&_THREE)) { MARK_MODIFIED - if (e->curSubSong->speed2<1) e->curSubSong->speed2=1; - if (e->isPlaying()) play(); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Virtual Tempo"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##VTempoN",ImGuiDataType_S16,&e->curSubSong->virtualTempoN,&_ONE,&_THREE)) { MARK_MODIFIED - if (e->curSubSong->virtualTempoN<1) e->curSubSong->virtualTempoN=1; - if (e->curSubSong->virtualTempoN>255) e->curSubSong->virtualTempoN=255; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Numerator"); - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##VTempoD",ImGuiDataType_S16,&e->curSubSong->virtualTempoD,&_ONE,&_THREE)) { MARK_MODIFIED - if (e->curSubSong->virtualTempoD<1) e->curSubSong->virtualTempoD=1; - if (e->curSubSong->virtualTempoD>255) e->curSubSong->virtualTempoD=255; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Denominator (set to base tempo)"); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Highlight"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##Highlight1",ImGuiDataType_U8,&e->curSubSong->hilightA,&_ONE,&_THREE)) { - MARK_MODIFIED; - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##Highlight2",ImGuiDataType_U8,&e->curSubSong->hilightB,&_ONE,&_THREE)) { - MARK_MODIFIED; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Pattern Length"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - int patLen=e->curSubSong->patLen; - if (ImGui::InputInt("##PatLength",&patLen,1,3)) { MARK_MODIFIED - if (patLen<1) patLen=1; - if (patLen>256) patLen=256; - e->curSubSong->patLen=patLen; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Song Length"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - int ordLen=e->curSubSong->ordersLen; - if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED - if (ordLen<1) ordLen=1; - if (ordLen>256) ordLen=256; - e->curSubSong->ordersLen=ordLen; - if (curOrder>=ordLen) { - setOrder(ordLen-1); - } - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::Selectable(tempoView?"Base Tempo##TempoOrHz":"Tick Rate##TempoOrHz")) { - tempoView=!tempoView; - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); - float setHz=tempoView?e->curSubSong->hz*2.5:e->curSubSong->hz; - if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { MARK_MODIFIED - if (tempoView) setHz/=2.5; - if (setHz<10) setHz=10; - if (setHz>999) setHz=999; - e->setSongRate(setHz,setHz<52); - } - if (tempoView) { - ImGui::TableNextColumn(); - ImGui::Text("= %gHz",e->curSubSong->hz); - } else { - if (e->curSubSong->hz>=49.98 && e->curSubSong->hz<=50.02) { - ImGui::TableNextColumn(); - ImGui::Text("PAL"); - } - if (e->curSubSong->hz>=59.9 && e->curSubSong->hz<=60.11) { - ImGui::TableNextColumn(); - ImGui::Text("NTSC"); - } - } - - ImGui::EndTable(); - } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SUBSONGS; ImGui::End(); From 4666a8d61494187a6192d28d25c0f425fafdb014 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 17:57:45 -0500 Subject: [PATCH 099/515] update export-tech.md --- papers/export-tech.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/papers/export-tech.md b/papers/export-tech.md index 3bf715469..560aab324 100644 --- a/papers/export-tech.md +++ b/papers/export-tech.md @@ -4,6 +4,13 @@ TODO +## macro data + +read length, loop and then release (1 byte). +if it is a 2-byte macro, read a dummy byte. + +then read data. + ## pattern data read sequentially. From e7108c060ba3755d5d497a0223de06a98e0dfa4b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 28 Jul 2022 23:24:32 -0500 Subject: [PATCH 100/515] add Namco WSG section to doc/7-systems --- papers/doc/7-systems/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/papers/doc/7-systems/README.md b/papers/doc/7-systems/README.md index 6d428f3eb..e4b6cf5b9 100644 --- a/papers/doc/7-systems/README.md +++ b/papers/doc/7-systems/README.md @@ -26,7 +26,8 @@ this is a list of systems that Furnace supports, including each system's effects - [Seta/Allumer X1-010](x1-010.md) - [WonderSwan](wonderswan.md) - [Bubble System WSG](bubblesystem.md) -- [Namco 163](n163.md) +- [Namco C163](n163.md) +- [Namco WSG](namco.md) - [Yamaha OPL](opl.md) - [PC Speaker](pcspkr.md) - [Commodore PET](pet.md) From cd4af3c4babaa669992fbe13c94c99e46a06e4b0 Mon Sep 17 00:00:00 2001 From: Aleksi Knutsi <53163105+host12prog@users.noreply.github.com> Date: Fri, 29 Jul 2022 21:20:17 +0700 Subject: [PATCH 101/515] Update soundunit.md --- papers/doc/7-systems/soundunit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/soundunit.md b/papers/doc/7-systems/soundunit.md index d9d0abd70..89e346558 100644 --- a/papers/doc/7-systems/soundunit.md +++ b/papers/doc/7-systems/soundunit.md @@ -25,7 +25,7 @@ This is a fantasy sound chip, used in the specs2 fantasy computer designed by ti - `17xx`: set volume sweep period low byte - `18xx`: set volume sweep period high byte - `19xx`: set cutoff sweep period low byte -- `1Axx`: set cutoff sweep period low byte +- `1Axx`: set cutoff sweep period high byte - `1Bxx`: set frequency sweep boundary - `1Cxx`: set volume sweep boundary - `1Dxx`: set cutoff sweep boundary From 1921fd17595efa7ce7ed8212c33417bd031919a6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 30 Jul 2022 01:00:51 -0500 Subject: [PATCH 102/515] PCE: implement anti-click technology --- src/engine/platform/pce.cpp | 12 +++++++++++- src/engine/platform/pce.h | 5 ++++- src/gui/sysConf.cpp | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index f1eb5a108..a61b61836 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -136,8 +136,9 @@ void DivPlatformPCE::updateWave(int ch) { chWrite(ch,0x04,0x5f); chWrite(ch,0x04,0x1f); for (int i=0; i<32; i++) { - chWrite(ch,0x06,chan[ch].ws.output[i]); + chWrite(ch,0x06,chan[ch].ws.output[(i+chan[ch].antiClickWavePos)&31]); } + chan[ch].antiClickWavePos&=31; if (chan[ch].active) { chWrite(ch,0x04,0x80|chan[ch].outVol); } @@ -150,6 +151,13 @@ static unsigned char noiseFreq[12]={ void DivPlatformPCE::tick(bool sysTick) { for (int i=0; i<6; i++) { + // anti-click + if (antiClickEnabled && sysTick && chan[i].freq>0) { + chan[i].antiClickPeriodCount+=(chipClock/MAX(parent->getCurHz(),1.0f)); + chan[i].antiClickWavePos+=chan[i].antiClickPeriodCount/chan[i].freq; + chan[i].antiClickPeriodCount%=chan[i].freq; + } + chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LOG(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31); @@ -555,6 +563,8 @@ void DivPlatformPCE::setFlags(unsigned int flags) { } else { chipClock=COLOR_NTSC; } + // flags&4 will be chip revision + antiClickEnabled=!(flags&8); rate=chipClock/12; for (int i=0; i<6; i++) { oscBuf[i]->rate=rate; diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 870b5218a..22a24ddf8 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -28,7 +28,7 @@ class DivPlatformPCE: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, pitch2, note; + int freq, baseFreq, pitch, pitch2, note, antiClickPeriodCount, antiClickWavePos; int dacPeriod, dacRate; unsigned int dacPos; int dacSample, ins; @@ -47,6 +47,8 @@ class DivPlatformPCE: public DivDispatch { pitch(0), pitch2(0), note(0), + antiClickPeriodCount(0), + antiClickWavePos(0), dacPeriod(0), dacRate(0), dacPos(0), @@ -69,6 +71,7 @@ class DivPlatformPCE: public DivDispatch { Channel chan[6]; DivDispatchOscBuffer* oscBuf[6]; bool isMuted[6]; + bool antiClickEnabled; struct QueuedWrite { unsigned char addr; unsigned char val; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index e54074861..365312424 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -109,6 +109,24 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } break; } + case DIV_SYSTEM_PCE: { + sysPal=flags&1; + if (ImGui::Checkbox("Pseudo-PAL",&sysPal)) { + copyOfFlags=(flags&(~1))|(unsigned int)sysPal; + } + bool antiClick=flags&8; + if (ImGui::Checkbox("Disable anti-click",&antiClick)) { + copyOfFlags=(flags&(~8))|(antiClick<<3); + } + break; + } + case DIV_SYSTEM_GB: { + bool antiClick=flags&8; + if (ImGui::Checkbox("Disable anti-click",&antiClick)) { + copyOfFlags=(flags&(~8))|(antiClick<<3); + } + break; + } case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL_DRUMS: case DIV_SYSTEM_VRC7: { @@ -631,7 +649,6 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } break; } - case DIV_SYSTEM_GB: case DIV_SYSTEM_SWAN: case DIV_SYSTEM_VERA: case DIV_SYSTEM_BUBSYS_WSG: From 007024c86f1a9e1c7a34478004497bc0bccef725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szpilowski?= Date: Sat, 30 Jul 2022 18:47:05 +0200 Subject: [PATCH 103/515] Create MetalSlug_BaseCamp_SMS_TIA.fur New cover - MetalSlug BaseCamp (form GB Advnace) --- demos/MetalSlug_BaseCamp_SMS_TIA.fur | Bin 0 -> 1917 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/MetalSlug_BaseCamp_SMS_TIA.fur diff --git a/demos/MetalSlug_BaseCamp_SMS_TIA.fur b/demos/MetalSlug_BaseCamp_SMS_TIA.fur new file mode 100644 index 0000000000000000000000000000000000000000..dd2fa6af3138b5913f10da46d4095af644d0518c GIT binary patch literal 1917 zcmV-@2ZH!`ob6p-iyTD|ubJuD+1=S>MZpI_ZoxMpkZ{I;AYO73Jk%uQ67WHg(<~A7 zPP{*gf)M{Cq98;B^~HDn2>Rrc5Bd?*Z=fGQ$sfD7cXn!br*^t_dv3RHyF=$HJ=MRe zuI^vg^vv$%#QB5Wovqipo$a@;9lX^&aUB3Uke7`M=Py1VN}*N@0G>Oy22BtT)O*)f zWQ{(BiDj*%OzyoH<5Cz0S4F9A;81~~h*@-YlT z5s6q%S_qM-i8z6v7SzHh6fqiFL0f=IVK{C)6KE~1DnS3UfAt&rN0-g+^{vi}TYLN6 z-OlFw^2fGr-?*@O<)a#aT520Rd;7Zw+ufc0jtrRqP)iL~>T%STVT{LY>#`z(AU!$Z zdNUC12k8l2X#|aSNM3G3xTXdL^?n`cjsKxsP)Nn00+0&;?oTM%9!OS6ij`nxWfX&& zD3dbDH_G2~54|l@Tim{`7u&Jq;(I$~b~^E;_?Msu2%TtQ23TAs61Lsel`2FcI^|>{ z8oxYTOy;4D>M>bcBee{3`ZVOuhJ93Rar?SnY{!y|@9mV?S*}F%*HKACD`S_3i^)8w zSRL=zV)M==O zYTU0TxWTl$sDY2gYv*Vuh{LqS?dy869ZN30w^L?kxsuWMlgUUWjR?u3#bh2- zKheig6?=9^>ijEfy{{ukw~FnlkFbyfEh*EjsiU1Z4$~I5uj|EjEV=mJPMMwMN>ZPX zC#ff$Oj61P(U+$^F{#IOY2Or1bob=-yR!Z#t1!U!3CUes+`g_C+p*;0dpl)zmMbA0 zj3=ZsP9`LrD5gzFqaRBzIuVWb^N;M@wZ-l0da)f#F21)@W@mYl&!w|hE;mL-h~4sX z^|FxJE|gjJ7%YZAOD*Sw(7bA>?@P+b5%4h_?xIk3$J-l3JEflx?N!Sm(;rHo8n2K4 zWSJZPl=3qtMCb|O31RFHSKk%?5h3(pH&)+LpTmIYffoA{677_}Ex9GbXam1N;85e5 zmrRYfNwnLF4~0*~jVmVInCNo}#MP%Z z7;59JdPAyQ&Iu7aMF{Q=#obxvMTm$=2wQT(T*ysAzp-G1NXa{ls4PS17tDfEbU;o= zo?3g^%WOF#1pdgx+?`r7SrIwxeUWX|$A8{(P6%D}GjXMKbuc-T1?$ujit^_=SX zBSPrMu6{zsCkOA~m>ju2Et|wA9E?%x+neyil=b4u9@}T-e!rMJ7FBB_lN(4*k=!EM zv3_FEE`~6XZ#g0KQzlP{$-9;L4y6}JI_OK2CLJP#%^lDaVg^F!_Yl}YtQZqUT10zH z7&O6G2m5L9ao`iemS6@cVd8Tq0ps8ob}^EhLpsHA!0k-}#{@r_0bl)^j-psm^G?NN zm?%8_*dXQ2eBn;LGX5xFvS!Dm%(#zK5j1c(CKXZ4=%U+(BoD(Ad_;+@B7GR8nWkKL` z?Na)QCI2xFmct70XNiN4|Lph#A!?ow3os$B$KQ4T5h3!MCa&Wl!;zG!-(u<~Onpj@ z2^?Vw-h*&N zk^eS~(oPFJAX|i(7g1a%1osYL;pChU`aMK_!3LBq@DLsWlXfqA*$N@D8>Uw8aIG(L zWei-_u3r9dWG=q<-}^s}{{uqcUmrHO=w&Z2o17COdk>*b6SD(j94re0pKF)WPb~S5 zaj+a#fImwdY{j1&H%j02_#;AO?;$)PMsb#b5Vqp)y8nm}`aML<1h%EGp57F-w}^HM zhtj8HTlywMG_loW#?zKQ9na!+3dh>QWa@K?Lg^zy=wr35)XCMSc3vv*6wbT|O)VU1 zLMWU?i$A4rixAwtln%AoaL0uRA*Lb(cXB)-ChJE`f2!7};!oj_J1-$ut)DX28zO{$ z4>7L+*=qN)muHeQLS+AOL`&W}#f3YsklDk$9phkG-I~={JM#2)z5m{Su3h*at^NA) D#hbI` literal 0 HcmV?d00001 From 6ff51ce8f340803a743e024b33251fdf3e04baa3 Mon Sep 17 00:00:00 2001 From: Waldemar Pawlaszek Date: Sun, 31 Jul 2022 11:33:38 +0200 Subject: [PATCH 104/515] #511 Added dynamic popcnt dispatcher --- src/engine/platform/sound/lynx/Mikey.cpp | 63 +++++++++++++++--------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/src/engine/platform/sound/lynx/Mikey.cpp b/src/engine/platform/sound/lynx/Mikey.cpp index 270e21bdf..32612960b 100644 --- a/src/engine/platform/sound/lynx/Mikey.cpp +++ b/src/engine/platform/sound/lynx/Mikey.cpp @@ -26,6 +26,24 @@ #include #include +#if defined ( _MSC_VER ) +#include + +static void cpuid( int info[4], int infoType ) +{ + __cpuidex( info, infoType, 0 ); +} + +#else +#include + +static void cpuid( int info[4], int infoType ) +{ + __cpuid_count( infoType, 0, info[0], info[1], info[2], info[3] ); +} + +#endif + namespace Lynx { @@ -34,29 +52,7 @@ namespace static constexpr int64_t CNT_MAX = std::numeric_limits::max() & ~15; -#if defined ( __cpp_lib_bitops ) - -#define popcnt(X) std::popcount(X) - -#elif defined( _MSC_VER ) - -# include - -uint32_t popcnt( uint32_t x ) -{ - return __popcnt( x ); -} - -#elif defined( __GNUC__ ) - -uint32_t popcnt( uint32_t x ) -{ - return __builtin_popcount( x ); -} - -#else - -uint32_t popcnt( uint32_t x ) +uint32_t popcnt_generic( uint32_t x ) { int v = 0; while ( x != 0 ) @@ -67,7 +63,16 @@ uint32_t popcnt( uint32_t x ) return v; } +uint32_t popcnt_intrinsic( uint32_t x ) +{ +#if defined ( _MSC_VER ) + return __popcnt( x ); +#else + return __builtin_popcount( x ); #endif +} + +static uint32_t( *popcnt )( uint32_t x ); int32_t clamp( int32_t v, int32_t lo, int32_t hi ) { @@ -514,6 +519,18 @@ private: Mikey::Mikey( uint32_t sampleRate ) : mMikey{ std::make_unique() }, mQueue{ std::make_unique() }, mTick{}, mNextTick{}, mSampleRate{ sampleRate }, mSamplesRemainder{}, mTicksPerSample{ 16000000 / mSampleRate, 16000000 % mSampleRate } { enqueueSampling(); + + //detecting popcnt availability + int info[4]; + cpuid( info, 1 ); + if ( ( info[2] & ( (int)1 << 23 ) ) != 0 ) + { + popcnt = &popcnt_intrinsic; + } + else + { + popcnt = &popcnt_generic; + } } Mikey::~Mikey() From a9afcf873c5cabc7da2a491035f35ae4ed8cf9ff Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 31 Jul 2022 14:05:23 -0500 Subject: [PATCH 105/515] fix ARM build --- src/engine/platform/sound/lynx/Mikey.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/engine/platform/sound/lynx/Mikey.cpp b/src/engine/platform/sound/lynx/Mikey.cpp index 32612960b..718180033 100644 --- a/src/engine/platform/sound/lynx/Mikey.cpp +++ b/src/engine/platform/sound/lynx/Mikey.cpp @@ -26,6 +26,11 @@ #include #include +#if defined(i386) || defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) +#define IS_INTEL +#endif + +#ifdef IS_INTEL #if defined ( _MSC_VER ) #include @@ -42,6 +47,7 @@ static void cpuid( int info[4], int infoType ) __cpuid_count( infoType, 0, info[0], info[1], info[2], info[3] ); } +#endif #endif namespace Lynx @@ -63,6 +69,7 @@ uint32_t popcnt_generic( uint32_t x ) return v; } +#ifdef IS_INTEL uint32_t popcnt_intrinsic( uint32_t x ) { #if defined ( _MSC_VER ) @@ -71,6 +78,7 @@ uint32_t popcnt_intrinsic( uint32_t x ) return __builtin_popcount( x ); #endif } +#endif static uint32_t( *popcnt )( uint32_t x ); @@ -521,6 +529,7 @@ Mikey::Mikey( uint32_t sampleRate ) : mMikey{ std::make_unique() }, enqueueSampling(); //detecting popcnt availability +#ifdef IS_INTEL int info[4]; cpuid( info, 1 ); if ( ( info[2] & ( (int)1 << 23 ) ) != 0 ) @@ -531,6 +540,9 @@ Mikey::Mikey( uint32_t sampleRate ) : mMikey{ std::make_unique() }, { popcnt = &popcnt_generic; } +#else + popcnt = &popcnt_generic; +#endif } Mikey::~Mikey() From 5feba3a7167b54bbebb1bba7159dcbda91b41663 Mon Sep 17 00:00:00 2001 From: Waldemar Pawlaszek Date: Sun, 31 Jul 2022 22:26:59 +0200 Subject: [PATCH 106/515] More robust popcnt --- src/engine/platform/sound/lynx/Mikey.cpp | 105 +++++++++++------------ 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/engine/platform/sound/lynx/Mikey.cpp b/src/engine/platform/sound/lynx/Mikey.cpp index 718180033..791336c1b 100644 --- a/src/engine/platform/sound/lynx/Mikey.cpp +++ b/src/engine/platform/sound/lynx/Mikey.cpp @@ -26,39 +26,11 @@ #include #include -#if defined(i386) || defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) -#define IS_INTEL -#endif +#if defined( _MSC_VER ) -#ifdef IS_INTEL -#if defined ( _MSC_VER ) #include -static void cpuid( int info[4], int infoType ) -{ - __cpuidex( info, infoType, 0 ); -} - -#else -#include - -static void cpuid( int info[4], int infoType ) -{ - __cpuid_count( infoType, 0, info[0], info[1], info[2], info[3] ); -} - -#endif -#endif - -namespace Lynx -{ - -namespace -{ - -static constexpr int64_t CNT_MAX = std::numeric_limits::max() & ~15; - -uint32_t popcnt_generic( uint32_t x ) +static uint32_t popcnt_generic( uint32_t x ) { int v = 0; while ( x != 0 ) @@ -69,18 +41,60 @@ uint32_t popcnt_generic( uint32_t x ) return v; } -#ifdef IS_INTEL -uint32_t popcnt_intrinsic( uint32_t x ) +#if defined( _M_IX86 ) || defined( _M_X64 ) + +static uint32_t popcnt_intrinsic( uint32_t x ) { -#if defined ( _MSC_VER ) return __popcnt( x ); -#else - return __builtin_popcount( x ); -#endif } + +static uint32_t( *popcnt )( uint32_t ); + +//detecting popcnt availability on msvc intel +static void selectPOPCNT() +{ + int info[4]; + __cpuid( info, 1 ); + if ( ( info[2] & ( (int)1 << 23 ) ) != 0 ) + { + popcnt = &popcnt_intrinsic; + } + else + { + popcnt = &popcnt_generic; + } +} + +#else //defined( _M_IX86 ) || defined( _M_X64 ) + +//MSVC non INTEL should use generic implementation +inline void selectPOPCNT() +{ +} + +#define popcnt popcnt_generic + #endif -static uint32_t( *popcnt )( uint32_t x ); +#else //defined( _MSC_VER ) + +//non MVSC should use builtin implementation + +inline void selectPOPCNT() +{ +} + +#define popcnt __builtin_popcount + +#endif + +namespace Lynx +{ + +namespace +{ + +static constexpr int64_t CNT_MAX = std::numeric_limits::max() & ~15; int32_t clamp( int32_t v, int32_t lo, int32_t hi ) { @@ -526,23 +540,8 @@ private: Mikey::Mikey( uint32_t sampleRate ) : mMikey{ std::make_unique() }, mQueue{ std::make_unique() }, mTick{}, mNextTick{}, mSampleRate{ sampleRate }, mSamplesRemainder{}, mTicksPerSample{ 16000000 / mSampleRate, 16000000 % mSampleRate } { + selectPOPCNT(); enqueueSampling(); - - //detecting popcnt availability -#ifdef IS_INTEL - int info[4]; - cpuid( info, 1 ); - if ( ( info[2] & ( (int)1 << 23 ) ) != 0 ) - { - popcnt = &popcnt_intrinsic; - } - else - { - popcnt = &popcnt_generic; - } -#else - popcnt = &popcnt_generic; -#endif } Mikey::~Mikey() From fe07051f8963827568c957d315dba3f26692f528 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 1 Aug 2022 22:51:13 -0500 Subject: [PATCH 107/515] rename Envelope release to Macro release --- src/gui/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 6582a4e21..2ad3ef23c 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1712,7 +1712,7 @@ void FurnaceGUI::drawSettings() { ImGui::Text("%s",SDL_GetScancodeName((SDL_Scancode)i.scan)); ImGui::TableNextColumn(); if (i.val==102) { - snprintf(id,4095,"Envelope release##SNType_%d",i.scan); + snprintf(id,4095,"Macro release##SNType_%d",i.scan); if (ImGui::Button(id)) { noteKeys[i.scan]=0; } From 1f57d09fbf0019f93b0e40acd39607d6747bc5af Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 2 Aug 2022 23:16:42 -0500 Subject: [PATCH 108/515] GUI: display correct OPLL patch names --- src/gui/insEdit.cpp | 162 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 140 insertions(+), 22 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index f0d6d3da3..09d6f4066 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -43,24 +43,93 @@ const char* fmParamShortNames[3][32]={ {"ALG", "FB", "FMS", "AMS", "A", "D", "D2", "R", "S", "TL", "RS", "ML", "DT", "DT2", "SSG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS2", "AMS2"} }; -const char* opllInsNames[17]={ - "User", - "Violin", - "Guitar", - "Piano", - "Flute", - "Clarinet", - "Oboe", - "Trumpet", - "Organ", - "Horn", - "Synth", - "Harpsichord", - "Vibraphone", - "Synth Bass", - "Acoustic Bass", - "Electric Guitar", - "Drums" +const char* opllVariants[4]={ + "OPLL", + "YMF281", + "YM2423", + "VRC7" +}; + +const char* opllInsNames[4][17]={ + /* YM2413 */ { + "User", + "Violin", + "Guitar", + "Piano", + "Flute", + "Clarinet", + "Oboe", + "Trumpet", + "Organ", + "Horn", + "Synth", + "Harpsichord", + "Vibraphone", + "Synth Bass", + "Acoustic Bass", + "Electric Guitar", + "Drums" + }, + // help me get the names! + /* YMF281 */ { + "User", + "Name under Register-Wall #1", + "Name under Register-Wall #2", + "Piano", + "Flute", + "Clarinet", + "Name under Register-Wall #6", + "Trumpet", + "Name under Register-Wall #8", + "Name under Register-Wall #9", + "Name under Register-Wall #10", + "Name under Register-Wall #11", + "Name under Register-Wall #12", + "Name under Register-Wall #13", + "Name under Register-Wall #14", + "Name under Register-Wall #15", + "Drums" + }, + // help me get the names! + /* YM2423 */ { + "User", + "Violin", + "What is this", + "Some kind of space sound", + "Voice maybe", + "Clarinet", + "Slap something", + "Trumpet", + "AAAAAA", + "Wow!", + "Synth", + "Synth Key", + "Vibraphone", + "Space Bass", + "Synth Bass", + "Sound like the default Defle patch", + "Drums" + }, + // stolen from FamiTracker + /* VRC7 */ { + "User", + "Bell", + "Guitar", + "Piano", + "Flute", + "Clarinet", + "Rattling Bell", + "Trumpet", + "Reed Organ", + "Soft Bell", + "Xylophone", + "Vibraphone", + "Brass", + "Bass Guitar", + "Synth", + "Chorus", + "Drums" + } }; const char* oplWaveforms[8]={ @@ -1572,10 +1641,59 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##LLPreset",opllInsNames[ins->fm.opllPreset])) { - for (int i=0; i<17; i++) { - if (ImGui::Selectable(opllInsNames[i])) { - ins->fm.opllPreset=i; + + bool isPresent[4]; + int isPresentCount=0; + memset(isPresent,0,4*sizeof(bool)); + for (int i=0; isong.systemLen; i++) { + if (e->song.system[i]==DIV_SYSTEM_VRC7) { + isPresent[3]=true; + } else if (e->song.system[i]==DIV_SYSTEM_OPLL || e->song.system[i]==DIV_SYSTEM_OPLL_DRUMS) { + isPresent[(e->song.systemFlags[i]>>4)&3]=true; + } + } + if (!isPresent[0] && !isPresent[1] && !isPresent[2] && !isPresent[3]) { + isPresent[0]=true; + } + for (int i=0; i<4; i++) { + if (isPresent[i]) isPresentCount++; + } + int presentWhich=0; + for (int i=0; i<4; i++) { + if (isPresent[i]) { + presentWhich=i; + break; + } + } + + if (ImGui::BeginCombo("##LLPreset",opllInsNames[presentWhich][ins->fm.opllPreset])) { + if (isPresentCount>1) { + if (ImGui::BeginTable("LLPresetList",isPresentCount)) { + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + for (int i=0; i<4; i++) { + if (!isPresent[i]) continue; + ImGui::TableNextColumn(); + ImGui::Text("%s name",opllVariants[i]); + } + for (int i=0; i<17; i++) { + ImGui::TableNextRow(); + for (int j=0; j<4; j++) { + if (!isPresent[j]) continue; + ImGui::TableNextColumn(); + ImGui::PushID(j*17+i); + if (ImGui::Selectable(opllInsNames[j][i])) { + ins->fm.opllPreset=i; + } + ImGui::PopID(); + } + } + ImGui::EndTable(); + } + } else { + for (int i=0; i<17; i++) { + if (ImGui::Selectable(opllInsNames[presentWhich][i])) { + ins->fm.opllPreset=i; + } } } ImGui::EndCombo(); From d204ae868a66d288128ed80f76f5eeaabd8f496a Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Wed, 3 Aug 2022 14:03:08 +0900 Subject: [PATCH 109/515] Tweaked versions of the instruments These were originally made by me, but I tweaked them a little. --- instruments/FM/guitar/Acoustic Nylon Guitar.dmp | Bin 51 -> 51 bytes instruments/FM/guitar/Acoustic Steel Guitar.dmp | Bin 51 -> 51 bytes .../FM/guitar/Electric Guitar Harmonics.dmp | Bin 51 -> 51 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/instruments/FM/guitar/Acoustic Nylon Guitar.dmp b/instruments/FM/guitar/Acoustic Nylon Guitar.dmp index b79addcf1c60e804b0f268207fc6e4330fcb786e..35fac263c8a2cec190cd2aedd95271200427ca98 100644 GIT binary patch literal 51 wcmd;PVq{=oV&Kq~l;P)RU|<7s)a2Rufr3CLtA;!WKMR=2$RN+f&k1G%05H%2xBvhE literal 51 wcmd;PVq{=oV&E{6l;P)RU|fr3CLtA;!SKMR=2$RN+f&k1G%052T@pa1{> diff --git a/instruments/FM/guitar/Acoustic Steel Guitar.dmp b/instruments/FM/guitar/Acoustic Steel Guitar.dmp index 64e77b9c8b089a462abbbd0a8875b1406e6cfc0e..295a29d6e38c3e6a54124bdd7f23fb88bfe2b56b 100644 GIT binary patch literal 51 wcmd;PVq{=oV&G7hl;P)RU|?flVAPOjnamRM?EEYcQ3iP~eoinG04;O@m;e9( literal 51 wcmd;PVq{=oV&G7hl;P)RU|?ooVAPOjnamRMEc`4GQ3iP~eoinG04z}fi2wiq diff --git a/instruments/FM/guitar/Electric Guitar Harmonics.dmp b/instruments/FM/guitar/Electric Guitar Harmonics.dmp index 07f2103287a0c7b93f7bfbb4c403bf4c69ee084e..14a14b1184c4b47395c645ad75f3607714bbe17e 100644 GIT binary patch literal 51 ycmW;CF%AGA2mrAIi5eMT(vkT8Pnx)OsH-p(%{md#!FJ&S4dyMvK37%`|KR~B?g5Da literal 51 ycmd;PVq{=vVqg-G7w6|^U|?ooU=fpN;ARBU3=ABK@(lby8i<$} Date: Wed, 3 Aug 2022 00:05:58 -0500 Subject: [PATCH 110/515] SoundUnit: add 64K chip revision --- src/engine/platform/sound/su.cpp | 16 ++++++++-------- src/engine/platform/sound/su.h | 7 +++---- src/engine/platform/su.cpp | 11 ++++++++--- src/engine/platform/su.h | 1 + src/gui/sysConf.cpp | 17 +++++++++++++++++ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/engine/platform/sound/su.cpp b/src/engine/platform/sound/su.cpp index b7fa731a6..0dd6dcdc7 100644 --- a/src/engine/platform/sound/su.cpp +++ b/src/engine/platform/sound/su.cpp @@ -54,7 +54,7 @@ void SoundUnit::NextSample(short* l, short* r) { chan[i].pcmpos=chan[i].pcmrst; } } - chan[i].pcmpos&=(SOUNDCHIP_PCM_SIZE-1); + chan[i].pcmpos&=(pcmSize-1); } else if (chan[i].flags.pcmloop) { chan[i].pcmpos=chan[i].pcmrst; } @@ -228,9 +228,10 @@ void SoundUnit::NextSample(short* l, short* r) { *r=minval(32767,maxval(-32767,tnsR)); } -void SoundUnit::Init() { +void SoundUnit::Init(int sampleMemSize) { + pcmSize=sampleMemSize; Reset(); - memset(pcm,0,SOUNDCHIP_PCM_SIZE); + memset(pcm,0,pcmSize); for (int i=0; i<256; i++) { SCsine[i]=sin((i/128.0f)*M_PI)*127; SCtriangle[i]=(i>127)?(255-i):(i); @@ -242,9 +243,6 @@ void SoundUnit::Init() { SCpantabR[128+i]=i-1; } SCpantabR[128]=0; - for (int i=0; i<8; i++) { - muted[i]=false; - } } void SoundUnit::Reset() { @@ -282,6 +280,8 @@ void SoundUnit::Write(unsigned char addr, unsigned char data) { } SoundUnit::SoundUnit() { - Init(); - memset(pcm,0,SOUNDCHIP_PCM_SIZE); + Init(65536); // default + for (int i=0; i<8; i++) { + muted[i]=false; + } } diff --git a/src/engine/platform/sound/su.h b/src/engine/platform/sound/su.h index 3152e8568..3b125f030 100644 --- a/src/engine/platform/sound/su.h +++ b/src/engine/platform/sound/su.h @@ -3,8 +3,6 @@ #include #include -#define SOUNDCHIP_PCM_SIZE 8192 - class SoundUnit { signed char SCsine[256]; signed char SCtriangle[256]; @@ -24,6 +22,7 @@ class SoundUnit { int tnsL, tnsR; unsigned short oldfreq[8]; unsigned short oldflags[8]; + unsigned int pcmSize; public: unsigned short resetfreq[8]; unsigned short voldcycles[8]; @@ -84,7 +83,7 @@ class SoundUnit { unsigned short wc; unsigned short restimer; } chan[8]; - signed char pcm[SOUNDCHIP_PCM_SIZE]; + signed char pcm[65536]; bool muted[8]; void Write(unsigned char addr, unsigned char data); void NextSample(short* l, short* r); @@ -94,7 +93,7 @@ class SoundUnit { if (ret>32767) ret=32767; return ret; } - void Init(); + void Init(int sampleMemSize=8192); void Reset(); SoundUnit(); }; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index c2cd6b25e..2d1a38932 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -555,6 +555,11 @@ void DivPlatformSoundUnit::setFlags(unsigned int flags) { for (int i=0; i<8; i++) { oscBuf[i]->rate=rate; } + + sampleMemSize=flags&16; + + su->Init(sampleMemSize?65536:8192); + renderSamples(); } void DivPlatformSoundUnit::poke(unsigned int addr, unsigned short val) { @@ -570,7 +575,7 @@ const void* DivPlatformSoundUnit::getSampleMem(int index) { } size_t DivPlatformSoundUnit::getSampleMemCapacity(int index) { - return (index==0)?8192:0; + return (index==0)?(sampleMemSize?65536:8192):0; } size_t DivPlatformSoundUnit::getSampleMemUsage(int index) { @@ -583,6 +588,7 @@ void DivPlatformSoundUnit::renderSamples() { size_t memPos=0; for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; + if (s->data8==NULL) continue; int paddedLen=s->samples; if (memPos>=getSampleMemCapacity(0)) { logW("out of PCM memory for sample %d!",i); @@ -609,9 +615,8 @@ int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, unsigned isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - setFlags(flags); su=new SoundUnit(); - su->Init(); + setFlags(flags); reset(); return 6; } diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 1d39854f2..e882c398e 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -96,6 +96,7 @@ class DivPlatformSoundUnit: public DivDispatch { }; std::queue writes; unsigned char lastPan; + bool sampleMemSize; int cycles, curChan, delay; short tempL; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 365312424..7c624f309 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -120,6 +120,23 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } break; } + case DIV_SYSTEM_SOUND_UNIT: { + ImGui::Text("CPU rate:"); + if (ImGui::RadioButton("6.18MHz (NTSC)",(flags&15)==0)) { + copyOfFlags=(flags&(~15))|0; + } + if (ImGui::RadioButton("5.95MHz (PAL)",(flags&15)==1)) { + copyOfFlags=(flags&(~15))|1; + } + ImGui::Text("Chip revision (sample memory):"); + if (ImGui::RadioButton("A/B/E (8K)",(flags&16)==0)) { + copyOfFlags=(flags&(~16))|0; + } + if (ImGui::RadioButton("D/F (64K)",(flags&16)==16)) { + copyOfFlags=(flags&(~16))|16; + } + break; + } case DIV_SYSTEM_GB: { bool antiClick=flags&8; if (ImGui::Checkbox("Disable anti-click",&antiClick)) { From 034b4fd4f607f96e08c849b296053bb6b7a9baf5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 00:10:32 -0500 Subject: [PATCH 111/515] GUI: YMF281 patch names thanks nicco1690! --- src/gui/insEdit.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 09d6f4066..08b9fc577 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -70,24 +70,24 @@ const char* opllInsNames[4][17]={ "Electric Guitar", "Drums" }, - // help me get the names! + /* YMF281 */ { "User", - "Name under Register-Wall #1", - "Name under Register-Wall #2", - "Piano", - "Flute", + "Electric String", + "Bow wow", + "Electric Guitar", + "Organ", "Clarinet", - "Name under Register-Wall #6", + "Saxophone", "Trumpet", - "Name under Register-Wall #8", - "Name under Register-Wall #9", - "Name under Register-Wall #10", - "Name under Register-Wall #11", - "Name under Register-Wall #12", - "Name under Register-Wall #13", - "Name under Register-Wall #14", - "Name under Register-Wall #15", + "Street Organ", + "Synth Brass", + "Electric Piano", + "Bass", + "Vibraphone", + "Chime", + "Tom Tom II", + "Noise", "Drums" }, // help me get the names! From 717d99d65058495f38cf76ca7c754732bd9bc46d Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Wed, 3 Aug 2022 21:25:17 +0900 Subject: [PATCH 112/515] Two new OPL instruments --- .../OPL/Low Overdriven Guitar (Sine Carrier).fui | Bin 0 -> 1697 bytes .../Low Overdriven Guitar (Square Carrier).fui | Bin 0 -> 1699 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/OPL/Low Overdriven Guitar (Sine Carrier).fui create mode 100644 instruments/OPL/Low Overdriven Guitar (Square Carrier).fui diff --git a/instruments/OPL/Low Overdriven Guitar (Sine Carrier).fui b/instruments/OPL/Low Overdriven Guitar (Sine Carrier).fui new file mode 100644 index 0000000000000000000000000000000000000000..9fae9177ba4ca83fca5f3e3d7b3be6d46862832f GIT binary patch literal 1697 zcmdOOD=o@POioqE%quP_($h_6U|>)HVi@rB3l6DdV_-;U;A8N~FIVs{OD#$%$}CIG zQ*bZMEJ-X<&Z;Q zAg7QE(9I&mhuA}&jfBibmmdjsq5FBb^9iL>O8rmBe3<;GJ*Xi73l|0k2et)l4a^K6 fX$A#mgg6cssxhSVa2QLZFy4ZQpPzvNgmD1?J^VSR literal 0 HcmV?d00001 diff --git a/instruments/OPL/Low Overdriven Guitar (Square Carrier).fui b/instruments/OPL/Low Overdriven Guitar (Square Carrier).fui new file mode 100644 index 0000000000000000000000000000000000000000..dfb5eba1eb3bf90aa25522af55374d259e28f6d4 GIT binary patch literal 1699 zcmdOOD=o@POioqE%quP_($h_6U|>)HVi@rB3l6DfV_-;U;A8N~FIVs{OD#$%$}CIG zQ*bZMEJ-X<&8>8h~r?P8bdk{hp|Ko<1L8z`572M7#9El3xPU| literal 0 HcmV?d00001 From 89042f61eb57e14c6b1f966f47088e2dd0f7dc31 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 3 Aug 2022 21:56:22 +0900 Subject: [PATCH 113/515] Fix link for vgsound_emu (moved into https://gitlab.com/cam900/vgsound_emu) --- src/engine/platform/sound/k005289/k005289.cpp | 2 +- src/engine/platform/sound/k005289/k005289.hpp | 2 +- src/engine/platform/sound/n163/n163.cpp | 2 +- src/engine/platform/sound/n163/n163.hpp | 2 +- src/engine/platform/sound/oki/msm6295.cpp | 2 +- src/engine/platform/sound/oki/msm6295.hpp | 2 +- src/engine/platform/sound/oki/util.hpp | 2 +- src/engine/platform/sound/oki/vox.hpp | 2 +- src/engine/platform/sound/scc/scc.cpp | 2 +- src/engine/platform/sound/scc/scc.hpp | 2 +- src/engine/platform/sound/vrcvi/vrcvi.cpp | 2 +- src/engine/platform/sound/vrcvi/vrcvi.hpp | 2 +- src/engine/platform/sound/x1_010/x1_010.cpp | 2 +- src/engine/platform/sound/x1_010/x1_010.hpp | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/engine/platform/sound/k005289/k005289.cpp b/src/engine/platform/sound/k005289/k005289.cpp index 8b21245a1..c9bdf83ae 100644 --- a/src/engine/platform/sound/k005289/k005289.cpp +++ b/src/engine/platform/sound/k005289/k005289.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900 diff --git a/src/engine/platform/sound/k005289/k005289.hpp b/src/engine/platform/sound/k005289/k005289.hpp index d042e1d14..575a98b87 100644 --- a/src/engine/platform/sound/k005289/k005289.hpp +++ b/src/engine/platform/sound/k005289/k005289.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900 diff --git a/src/engine/platform/sound/n163/n163.cpp b/src/engine/platform/sound/n163/n163.cpp index 5d9deab1a..3fd30bc44 100644 --- a/src/engine/platform/sound/n163/n163.cpp +++ b/src/engine/platform/sound/n163/n163.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900, tildearrow diff --git a/src/engine/platform/sound/n163/n163.hpp b/src/engine/platform/sound/n163/n163.hpp index 800d1ea13..317a33b45 100644 --- a/src/engine/platform/sound/n163/n163.hpp +++ b/src/engine/platform/sound/n163/n163.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900, tildearrow diff --git a/src/engine/platform/sound/oki/msm6295.cpp b/src/engine/platform/sound/oki/msm6295.cpp index 1b7fe568a..e7f39d27e 100644 --- a/src/engine/platform/sound/oki/msm6295.cpp +++ b/src/engine/platform/sound/oki/msm6295.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: tildearrow diff --git a/src/engine/platform/sound/oki/msm6295.hpp b/src/engine/platform/sound/oki/msm6295.hpp index 5203f4340..ca8b81d41 100644 --- a/src/engine/platform/sound/oki/msm6295.hpp +++ b/src/engine/platform/sound/oki/msm6295.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: tildearrow diff --git a/src/engine/platform/sound/oki/util.hpp b/src/engine/platform/sound/oki/util.hpp index 731772acc..b9c50d7bf 100644 --- a/src/engine/platform/sound/oki/util.hpp +++ b/src/engine/platform/sound/oki/util.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: tildearrow diff --git a/src/engine/platform/sound/oki/vox.hpp b/src/engine/platform/sound/oki/vox.hpp index c085c0b7c..23fbfd78e 100644 --- a/src/engine/platform/sound/oki/vox.hpp +++ b/src/engine/platform/sound/oki/vox.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: tildearrow diff --git a/src/engine/platform/sound/scc/scc.cpp b/src/engine/platform/sound/scc/scc.cpp index 3e230447a..e2ebcf200 100644 --- a/src/engine/platform/sound/scc/scc.cpp +++ b/src/engine/platform/sound/scc/scc.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst diff --git a/src/engine/platform/sound/scc/scc.hpp b/src/engine/platform/sound/scc/scc.hpp index db99ec877..24a365ccf 100644 --- a/src/engine/platform/sound/scc/scc.hpp +++ b/src/engine/platform/sound/scc/scc.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst diff --git a/src/engine/platform/sound/vrcvi/vrcvi.cpp b/src/engine/platform/sound/vrcvi/vrcvi.cpp index 87ff05d7c..a811c2f44 100644 --- a/src/engine/platform/sound/vrcvi/vrcvi.cpp +++ b/src/engine/platform/sound/vrcvi/vrcvi.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900, tildearrow diff --git a/src/engine/platform/sound/vrcvi/vrcvi.hpp b/src/engine/platform/sound/vrcvi/vrcvi.hpp index 790061c82..4a80f7577 100644 --- a/src/engine/platform/sound/vrcvi/vrcvi.hpp +++ b/src/engine/platform/sound/vrcvi/vrcvi.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900, tildearrow diff --git a/src/engine/platform/sound/x1_010/x1_010.cpp b/src/engine/platform/sound/x1_010/x1_010.cpp index c047b854a..6b0041bad 100644 --- a/src/engine/platform/sound/x1_010/x1_010.cpp +++ b/src/engine/platform/sound/x1_010/x1_010.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900, tildearrow diff --git a/src/engine/platform/sound/x1_010/x1_010.hpp b/src/engine/platform/sound/x1_010/x1_010.hpp index 3f5d9d4e2..b533b66d8 100644 --- a/src/engine/platform/sound/x1_010/x1_010.hpp +++ b/src/engine/platform/sound/x1_010/x1_010.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details Copyright holder(s): cam900 Modifiers and Contributors for Furnace: cam900, tildearrow From 0183c5d9ff134700d65c68d4193986c0f36fe429 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 01:13:59 -0500 Subject: [PATCH 114/515] GUI: remove one new line --- src/gui/insEdit.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 08b9fc577..958f662d4 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -70,7 +70,6 @@ const char* opllInsNames[4][17]={ "Electric Guitar", "Drums" }, - /* YMF281 */ { "User", "Electric String", From 46425655ad548ad6cfe2f31cfdaa455a8efad7c7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 14:38:39 -0500 Subject: [PATCH 115/515] YM2612: fix possible ExtCh DualPCM muting issue --- src/engine/platform/genesisext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index bfe771a6d..1f320dd34 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -24,6 +24,8 @@ #define CHIP_FREQBASE fmFreqBase #define CHIP_DIVIDER fmDivBase +#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) + int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.chan<2) { return DivPlatformGenesis::dispatch(c); @@ -542,7 +544,7 @@ void DivPlatformGenesisExt::forceIns() { rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); - rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); if (chan[i].active) { chan[i].keyOn=true; chan[i].freqChanged=true; From 53120edd9985a1a633b5b0e052cced711c254f89 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 14:41:23 -0500 Subject: [PATCH 116/515] disable MIDI clock --- src/engine/playback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 662e2ddb4..dd58b0d1a 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -914,7 +914,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { // MIDI clock if (output) if (!skipping && output->midiOut!=NULL) { - output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0)); + //output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0)); } while (!pendingNotes.empty()) { From 52c3b1037392ea92ef55236f09fc73aae5697d0c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 16:21:30 -0500 Subject: [PATCH 117/515] add getWantPreNote() currently only C64 system requires this --- src/engine/dispatch.h | 6 ++++++ src/engine/platform/abstract.cpp | 4 ++++ src/engine/platform/c64.cpp | 4 ++++ src/engine/platform/c64.h | 1 + src/engine/playback.cpp | 4 +++- 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 03bc23ca6..f1418e481 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -399,6 +399,12 @@ class DivDispatch { */ virtual bool getDCOffRequired(); + /** + * check whether PRE_NOTE command is desired. + * @return truth. + */ + virtual bool getWantPreNote(); + /** * get a description of a dispatch-specific effect. * @param effect the effect. diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 54366e1ba..5b732e7e9 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -90,6 +90,10 @@ bool DivDispatch::getDCOffRequired() { return false; } +bool DivDispatch::getWantPreNote() { + return false; +} + const char* DivDispatch::getEffectName(unsigned char effect) { return NULL; } diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 640df54e6..9049ffec4 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -513,6 +513,10 @@ bool DivPlatformC64::getDCOffRequired() { return true; } +bool DivPlatformC64::getWantPreNote() { + return true; +} + void DivPlatformC64::reset() { for (int i=0; i<3; i++) { chan[i]=DivPlatformC64::Channel(); diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index d9dc08040..ae1034a82 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -97,6 +97,7 @@ class DivPlatformC64: public DivDispatch { void setFlags(unsigned int flags); void notifyInsChange(int ins); bool getDCOffRequired(); + bool getWantPreNote(); DivMacroInt* getChanMacroInt(int ch); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index dd58b0d1a..6c4376573 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -866,7 +866,9 @@ void DivEngine::nextRow() { if (!(pat->data[curRow][0]==0 && pat->data[curRow][1]==0)) { if (pat->data[curRow][0]!=100 && pat->data[curRow][0]!=101 && pat->data[curRow][0]!=102) { if (!chan[i].legato) { - dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks)); + if (disCont[dispatchOfChan[i]].dispatch!=NULL) { + if (disCont[dispatchOfChan[i]].dispatch->getWantPreNote()) dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks)); + } if (song.oneTickCut) { bool doPrepareCut=true; From fce03717563eaf4fced702c0684b8af810c47f3a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 17:21:47 -0500 Subject: [PATCH 118/515] add "hint" commands --- src/engine/dispatch.h | 8 ++++++++ src/engine/playback.cpp | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index f1418e481..86b2e229e 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -55,6 +55,14 @@ enum DivDispatchCmds { DIV_CMD_PRE_PORTA, // (inPorta, isPortaOrSlide) DIV_CMD_PRE_NOTE, // used in C64 (note) + // these will be used in ROM export. + // do NOT implement! + DIV_CMD_HINT_VIBRATO, // (speed, depth) + DIV_CMD_HINT_VIBRATO_SHAPE, // (shape) + DIV_CMD_HINT_PITCH, // (pitch) + DIV_CMD_HINT_ARPEGGIO, // (note1, note2) + DIV_CMD_HINT_VOL_SLIDE, // (amount, oneTick) + DIV_CMD_SAMPLE_MODE, // (enabled) DIV_CMD_SAMPLE_FREQ, // (frequency) DIV_CMD_SAMPLE_BANK, // (bank) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 6c4376573..b089b6f3e 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -57,6 +57,12 @@ const char* cmdName[]={ "PRE_PORTA", "PRE_NOTE", + "HINT_VIBRATO", + "HINT_VIBRATO_SHAPE", + "HINT_PITCH", + "HINT_ARPEGGIO", + "HINT_VOL_SLIDE", + "SAMPLE_MODE", "SAMPLE_FREQ", "SAMPLE_BANK", From eafbf24290567d9ba3f0e0cd6da0c2a5fba112e3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 17:31:00 -0500 Subject: [PATCH 119/515] GUI: YM2423 patch names thanks freq-mod! --- src/gui/insEdit.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 958f662d4..f991b9e2a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -89,24 +89,23 @@ const char* opllInsNames[4][17]={ "Noise", "Drums" }, - // help me get the names! /* YM2423 */ { "User", - "Violin", - "What is this", - "Some kind of space sound", - "Voice maybe", - "Clarinet", - "Slap something", + "Strings", + "Guitar", + "Electric Guitar", + "Electric Piano", + "Flute", + "Marimba", "Trumpet", - "AAAAAA", - "Wow!", - "Synth", - "Synth Key", + "Harmonica", + "Tuba", + "Synth Brass", + "Short Saw", "Vibraphone", - "Space Bass", + "Electric Guitar 2", "Synth Bass", - "Sound like the default Defle patch", + "Sitar", "Drums" }, // stolen from FamiTracker From 7ec4f7cb9e51c7016a753447d2b92ea7e9e8492a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 18:44:45 -0500 Subject: [PATCH 120/515] VGM export: add option to insert pattern change hi nts --- src/engine/engine.h | 4 +++- src/engine/vgmOps.cpp | 28 +++++++++++++++++++++++++++- src/gui/gui.cpp | 19 ++++++++++++++++++- src/gui/gui.h | 2 +- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 3030cfadb..8fd56ff91 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -472,7 +472,9 @@ class DivEngine { // specify system to build ROM for. SafeWriter* buildROM(int sys); // dump to VGM. - SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171); + SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false); + // dump command stream. + SafeWriter* saveCommand(bool binary=false); // export to an audio file bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0); // wait for audio export to finish diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index a500b4848..15de0156f 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -802,7 +802,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write } } -SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { +SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool patternHints) { if (version<0x150) { lastError="VGM version is too low"; return NULL; @@ -1795,6 +1795,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { playSub(false); size_t tickCount=0; bool writeLoop=false; + int ord=-1; + int exportChans=0; + for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(0xfe); + w->writeI(3+exportChans); + w->writeC(0x01); + w->writeC(prevOrder); + w->writeC(prevRow); + for (int i=0; iwriteC(curSubSong->orders.ord[i][prevOrder]); + } + } + } } // get register dumps for (int i=0; isong.systemLen; i++) { @@ -3468,7 +3484,7 @@ bool FurnaceGUI::loop() { } break; case GUI_FILE_EXPORT_VGM: { - SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion); + SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints); if (w!=NULL) { FILE* f=ps_fopen(copyOfName.c_str(),"wb"); if (f!=NULL) { @@ -4431,6 +4447,7 @@ FurnaceGUI::FurnaceGUI(): displayError(false), displayExporting(false), vgmExportLoop(true), + vgmExportPatternHints(false), wantCaptureKeyboard(false), oldWantCaptureKeyboard(false), displayMacroMenu(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 30113953f..cb61d48dc 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -952,7 +952,7 @@ class FurnaceGUI { String mmlString[32]; String mmlStringW; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; bool displayPendingIns, pendingInsSingle; bool willExport[32]; From a0d10aa60be74a54c27e48ca7b3ed3d7027947c6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 3 Aug 2022 19:17:18 -0500 Subject: [PATCH 121/515] Game Boy: implement anti-click --- src/engine/platform/gb.cpp | 19 +++++++++++++++++-- src/engine/platform/gb.h | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 2b7dcf6df..4d10d7d22 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -97,10 +97,11 @@ void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) void DivPlatformGB::updateWave() { rWrite(0x1a,0); for (int i=0; i<16; i++) { - int nibble1=15-ws.output[i<<1]; - int nibble2=15-ws.output[1+(i<<1)]; + int nibble1=15-ws.output[((i<<1)+antiClickWavePos)&31]; + int nibble2=15-ws.output[((1+(i<<1))+antiClickWavePos)&31]; rWrite(0x30+i,(nibble1<<4)|nibble2); } + antiClickWavePos&=31; } static unsigned char chanMuteMask[4]={ @@ -151,6 +152,12 @@ static unsigned char noiseTable[256]={ }; void DivPlatformGB::tick(bool sysTick) { + if (antiClickEnabled && sysTick && chan[2].freq>0) { + antiClickPeriodCount+=((chipClock>>1)/MAX(parent->getCurHz(),1.0f)); + antiClickWavePos+=antiClickPeriodCount/chan[2].freq; + antiClickPeriodCount%=chan[2].freq; + } + for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.arp.had) { @@ -471,6 +478,9 @@ void DivPlatformGB::reset() { lastPan=0xff; immWrite(0x25,procMute()); immWrite(0x24,0x77); + + antiClickPeriodCount=0; + antiClickWavePos=0; } bool DivPlatformGB::isStereo() { @@ -507,6 +517,10 @@ void DivPlatformGB::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) immWrite(i.addr,i.val); } +void DivPlatformGB::setFlags(unsigned int flags) { + antiClickEnabled=!(flags&8); +} + int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { chipClock=4194304; rate=chipClock/16; @@ -519,6 +533,7 @@ int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, unsigned int fl dumpWrites=false; skipRegisterWrites=false; gb=new GB_gameboy_t; + setFlags(flags); reset(); return 4; } diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index fe2f6e51b..b00458c2d 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -59,9 +59,12 @@ class DivPlatformGB: public DivDispatch { Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; + bool antiClickEnabled; unsigned char lastPan; DivWaveSynth ws; + int antiClickPeriodCount, antiClickWavePos; + GB_gameboy_t* gb; unsigned char regPool[128]; @@ -88,6 +91,7 @@ class DivPlatformGB: public DivDispatch { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); + void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformGB(); From d54d853ff83c14994151619b41f696a777b909e5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 00:51:47 -0500 Subject: [PATCH 122/515] add a command stream dump option --- src/engine/engine.cpp | 106 ++++++++++++++++++++++++++++++++++++++ src/engine/engine.h | 2 + src/engine/safeWriter.cpp | 3 ++ src/engine/safeWriter.h | 1 + src/gui/gui.cpp | 65 ++++++++++++++++++++++- src/gui/gui.h | 8 ++- 6 files changed, 182 insertions(+), 3 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 2a000476d..9b532c0bf 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "dispatch.h" #define _USE_MATH_DEFINES #include "engine.h" #include "instrument.h" @@ -234,6 +235,111 @@ double DivEngine::benchmarkSeek() { return tAvg; } +SafeWriter* DivEngine::saveCommand(bool binary) { + logI("implement! %d",binary); + stop(); + repeatPattern=false; + setOrder(0); + BUSY_BEGIN_SOFT; + // determine loop point + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + walkSong(loopOrder,loopRow,loopEnd); + logI("loop point: %d %d",loopOrder,loopRow); + + SafeWriter* w=new SafeWriter; + w->init(); + + // write header + w->writeText("# Furnace Command Stream\n\n"); + + w->writeText("[Information]\n"); + w->writeText(fmt::sprintf("name: %s\n",song.name)); + w->writeText(fmt::sprintf("author: %s\n",song.author)); + w->writeText(fmt::sprintf("category: %s\n",song.category)); + w->writeText(fmt::sprintf("system: %s\n",song.systemName)); + + w->writeText("\n"); + + w->writeText("[SubSongInformation]\n"); + w->writeText(fmt::sprintf("name: %s\n",curSubSong->name)); + w->writeText(fmt::sprintf("tickRate: %f\n",curSubSong->hz)); + + w->writeText("\n"); + + w->writeText("[SysDefinition]\n"); + // TODO + + w->writeText("\n"); + + // play the song ourselves + bool done=false; + playSub(false); + + w->writeText("[Stream]\n"); + int tick=0; + bool oldCmdStreamEnabled=cmdStreamEnabled; + cmdStreamEnabled=true; + double curDivider=divider; + while (!done) { + if (nextTick(false,true) || !playing) { + done=true; + } + // get command stream + bool wroteTick=false; + if (curDivider!=divider) { + curDivider=divider; + if (!wroteTick) { + wroteTick=true; + w->writeText(fmt::sprintf(">> TICK %d\n",tick)); + } + w->writeText(fmt::sprintf(">> SET_RATE %f\n",curDivider)); + } + for (DivCommand& i: cmdStream) { + switch (i.cmd) { + // strip away hinted/useless commands + case DIV_ALWAYS_SET_VOLUME: + break; + case DIV_CMD_GET_VOLUME: + break; + case DIV_CMD_VOLUME: + break; + case DIV_CMD_NOTE_PORTA: + break; + case DIV_CMD_LEGATO: + break; + case DIV_CMD_PITCH: + break; + default: + if (!wroteTick) { + wroteTick=true; + w->writeText(fmt::sprintf(">> TICK %d\n",tick)); + } + w->writeText(fmt::sprintf(" %d: %s %d %d\n",i.chan,cmdName[i.cmd],i.value,i.value2)); + break; + } + } + cmdStream.clear(); + tick++; + } + cmdStreamEnabled=oldCmdStreamEnabled; + + if (!playing) { + w->writeText(">> END\n"); + } else { + w->writeText(">> LOOP 0\n"); + } + + remainingLoops=-1; + playing=false; + freelance=false; + extValuePresent=false; + BUSY_END; + + return w; +} + void _runExportThread(DivEngine* caller) { caller->runExportThread(); } diff --git a/src/engine/engine.h b/src/engine/engine.h index 8fd56ff91..6f969efc9 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -280,6 +280,8 @@ enum DivChanTypes { DIV_CH_OP=5 }; +extern const char* cmdName[]; + class DivEngine { DivDispatchContainer disCont[32]; TAAudio* output; diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index f29800a4a..e61380936 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -120,6 +120,9 @@ int SafeWriter::writeWString(WString val, bool pascal) { return 2+val.size()*2; } } +int SafeWriter::writeText(String val) { + return write(val.c_str(),val.size()); +} void SafeWriter::init() { if (operative) return; diff --git a/src/engine/safeWriter.h b/src/engine/safeWriter.h index 9072c61d7..414417fd2 100644 --- a/src/engine/safeWriter.h +++ b/src/engine/safeWriter.h @@ -57,6 +57,7 @@ class SafeWriter { int writeD_BE(double val); int writeWString(WString val, bool pascal); int writeString(String val, bool pascal); + int writeText(String val); void init(); SafeReader* toReader(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c296ab2c3..28edd9e32 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1401,6 +1401,17 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { dpiScale ); break; + case GUI_FILE_EXPORT_CMDSTREAM: + if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir(); + hasOpened=fileDialog->openSave( + "Export Command Stream", + {"text file", "*.txt", + "binary file", "*.bin"}, + "text file{.txt},binary file{.bin}", + workingDirROMExport, + dpiScale + ); + break; case GUI_FILE_EXPORT_ROM: showError("Coming soon!"); break; @@ -2947,6 +2958,19 @@ bool FurnaceGUI::loop() { } ImGui::EndMenu(); } + if (ImGui::BeginMenu("export command stream...")) { + ImGui::Text( + "this option exports a text or binary file which\n" + "contains a dump of the internal command stream\n" + "produced when playing the song.\n\n" + + "technical/development use only!" + ); + if (ImGui::Button("export")) { + openFileDialog(GUI_FILE_EXPORT_CMDSTREAM); + } + ImGui::EndMenu(); + } ImGui::Separator(); if (ImGui::BeginMenu("add system...")) { for (int j=0; availableSystems[j]; j++) { @@ -3258,9 +3282,12 @@ bool FurnaceGUI::loop() { workingDirAudioExport=fileDialog->getPath()+DIR_SEPARATOR_STR; break; case GUI_FILE_EXPORT_VGM: - case GUI_FILE_EXPORT_ROM: workingDirVGMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; break; + case GUI_FILE_EXPORT_ROM: + case GUI_FILE_EXPORT_CMDSTREAM: + workingDirROMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; + break; case GUI_FILE_LOAD_MAIN_FONT: case GUI_FILE_LOAD_PAT_FONT: workingDirFont=fileDialog->getPath()+DIR_SEPARATOR_STR; @@ -3325,6 +3352,11 @@ bool FurnaceGUI::loop() { if (curFileDialog==GUI_FILE_EXPORT_VGM) { checkExtension(".vgm"); } + if (curFileDialog==GUI_FILE_EXPORT_CMDSTREAM) { + // we can't tell whether the user chose .txt or .bin in the system file picker + const char* fallbackExt=(settings.sysFileDialog || ImGuiFileDialog::Instance()->GetCurrentFilter()=="text file")?".txt":".bin"; + checkExtensionDual(".txt",".bin",fallbackExt); + } if (curFileDialog==GUI_FILE_EXPORT_COLORS) { checkExtension(".cfgc"); } @@ -3506,6 +3538,35 @@ bool FurnaceGUI::loop() { case GUI_FILE_EXPORT_ROM: showError("Coming soon!"); break; + case GUI_FILE_EXPORT_CMDSTREAM: { + String lowerCase=fileName; + for (char& i: lowerCase) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + bool isBinary=true; + if ((lowerCase.size()<4 || lowerCase.rfind(".txt")!=lowerCase.size()-4)) { + isBinary=false; + } + + SafeWriter* w=e->saveCommand(isBinary); + if (w!=NULL) { + FILE* f=ps_fopen(copyOfName.c_str(),"wb"); + if (f!=NULL) { + fwrite(w->getFinalBuf(),1,w->size(),f); + fclose(f); + } else { + showError("could not open file!"); + } + w->finish(); + delete w; + if (!e->getWarnings().empty()) { + showWarning(e->getWarnings(),GUI_WARN_GENERIC); + } + } else { + showError(fmt::sprintf("could not write command stream! (%s)",e->getLastError())); + } + break; + } case GUI_FILE_LOAD_MAIN_FONT: settings.mainFontPath=copyOfName; break; @@ -4099,6 +4160,7 @@ bool FurnaceGUI::init() { workingDirSample=e->getConfString("lastDirSample",workingDir); workingDirAudioExport=e->getConfString("lastDirAudioExport",workingDir); workingDirVGMExport=e->getConfString("lastDirVGMExport",workingDir); + workingDirROMExport=e->getConfString("lastDirROMExport",workingDir); workingDirFont=e->getConfString("lastDirFont",workingDir); workingDirColors=e->getConfString("lastDirColors",workingDir); workingDirKeybinds=e->getConfString("lastDirKeybinds",workingDir); @@ -4339,6 +4401,7 @@ bool FurnaceGUI::finish() { e->setConf("lastDirSample",workingDirSample); e->setConf("lastDirAudioExport",workingDirAudioExport); e->setConf("lastDirVGMExport",workingDirVGMExport); + e->setConf("lastDirROMExport",workingDirROMExport); e->setConf("lastDirFont",workingDirFont); e->setConf("lastDirColors",workingDirColors); e->setConf("lastDirKeybinds",workingDirKeybinds); diff --git a/src/gui/gui.h b/src/gui/gui.h index cb61d48dc..0ce4afaee 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -266,6 +266,7 @@ enum FurnaceGUIFileDialogs { GUI_FILE_EXPORT_AUDIO_PER_SYS, GUI_FILE_EXPORT_AUDIO_PER_CHANNEL, GUI_FILE_EXPORT_VGM, + GUI_FILE_EXPORT_CMDSTREAM, GUI_FILE_EXPORT_ROM, GUI_FILE_LOAD_MAIN_FONT, GUI_FILE_LOAD_PAT_FONT, @@ -948,11 +949,14 @@ class FurnaceGUI { bool updateSampleTex; String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; - String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM, workingDirTest; + String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport; + String workingDirVGMExport, workingDirROMExport, workingDirFont, workingDirColors, workingDirKeybinds; + String workingDirLayout, workingDirROM, workingDirTest; String mmlString[32]; String mmlStringW; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; + bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; bool displayPendingIns, pendingInsSingle; bool willExport[32]; From b030f8285d45c782c427b9ed8146fb47d6633d1e Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Thu, 4 Aug 2022 17:33:36 +1000 Subject: [PATCH 123/515] Bugfix for OPM file load - correctly handle AM-ENA where value is arbitrarily nonzero --- src/engine/fileOpsIns.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index b7ca22c1e..369b1238f 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -1262,7 +1262,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, St patchNameRead = lfoRead = characteristicRead = m1Read = c1Read = m2Read = c2Read = false; newPatch = NULL; }; - auto readIntStrWithinRange = [](String&& input, int limitLow, int limitHigh) -> int { + auto readIntStrWithinRange = [](String&& input, int limitLow = INT_MIN, int limitHigh = INT_MAX) -> int { int x = std::stoi(input.c_str()); if (x > limitHigh || x < limitLow) { throw std::invalid_argument(fmt::sprintf("%s is out of bounds of range [%d..%d]", input, limitLow, limitHigh)); @@ -1280,7 +1280,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, St op.mult = readIntStrWithinRange(reader.readStringToken(), 0, 15); op.dt = fmDtRegisterToFurnace(readIntStrWithinRange(reader.readStringToken(), 0, 7)); op.dt2 = readIntStrWithinRange(reader.readStringToken(), 0, 3); - op.am = readIntStrWithinRange(reader.readStringToken(), 0, 1); + op.am = readIntStrWithinRange(reader.readStringToken(), 0) > 0 ? 1 : 0; }; auto seekGroupValStart = [](SafeReader& reader, int pos) { // Seek to position then move to next ':' character From edb0f51131215cfb0b3b53b54c566e7a6b5ffef7 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Thu, 4 Aug 2022 17:43:42 +1000 Subject: [PATCH 124/515] stdint required --- src/engine/fileOpsIns.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 369b1238f..e5ea58abc 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -21,6 +21,7 @@ #include "../ta-log.h" #include "../fileutils.h" #include +#include enum DivInsFormats { DIV_INSFORMAT_DMP, From 810eabca99851f6b769540c17169e0ee0bf79491 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Thu, 4 Aug 2022 17:50:33 +1000 Subject: [PATCH 125/515] derp limits --- src/engine/fileOpsIns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index e5ea58abc..54e0eefc6 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -21,7 +21,7 @@ #include "../ta-log.h" #include "../fileutils.h" #include -#include +#include enum DivInsFormats { DIV_INSFORMAT_DMP, From 09e32c7050fba4ccd4c0b2a2dc82b66c28fb5d14 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 15:14:29 -0500 Subject: [PATCH 126/515] finish command dump hints --- src/engine/dispatch.h | 4 ++++ src/engine/playback.cpp | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 86b2e229e..fb9be5800 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -58,10 +58,14 @@ enum DivDispatchCmds { // these will be used in ROM export. // do NOT implement! DIV_CMD_HINT_VIBRATO, // (speed, depth) + DIV_CMD_HINT_VIBRATO_RANGE, // (range) DIV_CMD_HINT_VIBRATO_SHAPE, // (shape) DIV_CMD_HINT_PITCH, // (pitch) DIV_CMD_HINT_ARPEGGIO, // (note1, note2) + DIV_CMD_HINT_VOLUME, // (vol) DIV_CMD_HINT_VOL_SLIDE, // (amount, oneTick) + DIV_CMD_HINT_PORTA, // (target, speed) + DIV_CMD_HINT_LEGATO, // (note) DIV_CMD_SAMPLE_MODE, // (enabled) DIV_CMD_SAMPLE_FREQ, // (frequency) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index b089b6f3e..8fd20d5f9 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -58,10 +58,14 @@ const char* cmdName[]={ "PRE_NOTE", "HINT_VIBRATO", + "HINT_VIBRATO_RANGE", "HINT_VIBRATO_SHAPE", "HINT_PITCH", "HINT_ARPEGGIO", "HINT_VOL_SLIDE", + "HINT_VOLUME", + "HINT_PORTA", + "HINT_LEGATO", "SAMPLE_MODE", "SAMPLE_FREQ", @@ -344,6 +348,7 @@ void DivEngine::processRow(int i, bool afterDelay) { logV("forcing volume"); chan[i].volume=chan[i].volMax; dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); } } } @@ -356,11 +361,13 @@ void DivEngine::processRow(int i, bool afterDelay) { if (chan[i].stopOnOff) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].stopOnOff=false; } if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); /*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) { chan[i+1].portaNote=-1; chan[i+1].portaSpeed=-1; @@ -377,11 +384,13 @@ void DivEngine::processRow(int i, bool afterDelay) { if (chan[i].stopOnOff) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].stopOnOff=false; } if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); /*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) { chan[i+1].portaNote=-1; chan[i+1].portaSpeed=-1; @@ -398,6 +407,7 @@ void DivEngine::processRow(int i, bool afterDelay) { if (!chan[i].keyOn) { if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsArp(dispatchChanOfChan[i])) { chan[i].arp=0; + dispatchCmd(DivCommand(DIV_CMD_HINT_ARPEGGIO,i,chan[i].arp)); } } chan[i].doNote=true; @@ -414,6 +424,7 @@ void DivEngine::processRow(int i, bool afterDelay) { } chan[i].volume=pat->data[whatRow][3]<<8; dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); } } @@ -458,11 +469,13 @@ void DivEngine::processRow(int i, bool afterDelay) { if (effectVal==0) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].inPorta=false; if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); } else { chan[i].portaNote=song.limitSlides?0x60:255; chan[i].portaSpeed=effectVal; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].portaStop=true; chan[i].nowYouCanStop=false; chan[i].stopOnOff=false; @@ -478,11 +491,13 @@ void DivEngine::processRow(int i, bool afterDelay) { if (effectVal==0) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].inPorta=false; if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); } else { chan[i].portaNote=song.limitSlides?disCont[dispatchOfChan[i]].dispatch->getPortaFloor(dispatchChanOfChan[i]):-60; chan[i].portaSpeed=effectVal; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].portaStop=true; chan[i].nowYouCanStop=false; chan[i].stopOnOff=false; @@ -496,6 +511,7 @@ void DivEngine::processRow(int i, bool afterDelay) { if (effectVal==0) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].inPorta=false; dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); } else { @@ -509,6 +525,7 @@ void DivEngine::processRow(int i, bool afterDelay) { chan[i].inPorta=true; chan[i].wasShorthandPorta=false; } + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].portaStop=true; if (chan[i].keyOn) chan[i].doNote=false; chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?! @@ -520,6 +537,7 @@ void DivEngine::processRow(int i, bool afterDelay) { case 0x04: // vibrato chan[i].vibratoDepth=effectVal&15; chan[i].vibratoRate=effectVal>>4; + dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate)); dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); break; case 0x07: // tremolo @@ -543,12 +561,14 @@ void DivEngine::processRow(int i, bool afterDelay) { } else { chan[i].volSpeed=0; } + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); break; case 0x00: // arpeggio chan[i].arp=effectVal; if (chan[i].arp==0 && song.arp0Reset) { chan[i].resetArp=true; } + dispatchCmd(DivCommand(DIV_CMD_HINT_ARPEGGIO,i,chan[i].arp)); break; case 0x0c: // retrigger if (effectVal!=0) { @@ -580,6 +600,7 @@ void DivEngine::processRow(int i, bool afterDelay) { case 0xe1: // portamento up chan[i].portaNote=chan[i].note+(effectVal&15); chan[i].portaSpeed=(effectVal>>4)*4; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].portaStop=true; chan[i].nowYouCanStop=false; chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?! @@ -598,6 +619,7 @@ void DivEngine::processRow(int i, bool afterDelay) { case 0xe2: // portamento down chan[i].portaNote=chan[i].note-(effectVal&15); chan[i].portaSpeed=(effectVal>>4)*4; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].portaStop=true; chan[i].nowYouCanStop=false; chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?! @@ -615,9 +637,11 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xe3: // vibrato direction chan[i].vibratoDir=effectVal; + dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO_SHAPE,i,chan[i].vibratoDir)); break; case 0xe4: // vibrato fine chan[i].vibratoFine=effectVal; + dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO_RANGE,i,chan[i].vibratoFine)); break; case 0xe5: // pitch chan[i].pitch=effectVal-0x80; @@ -628,6 +652,7 @@ void DivEngine::processRow(int i, bool afterDelay) { } //chan[i].pitch+=globalPitch; dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); + dispatchCmd(DivCommand(DIV_CMD_HINT_PITCH,i,chan[i].pitch)); break; case 0xea: // legato mode chan[i].legato=effectVal; @@ -677,17 +702,21 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xf3: // fine volume ramp up chan[i].volSpeed=effectVal; + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); break; case 0xf4: // fine volume ramp down chan[i].volSpeed=-effectVal; + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); break; case 0xf8: // single volume ramp up chan[i].volume=MIN(chan[i].volume+effectVal*256,chan[i].volMax); dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); break; case 0xf9: // single volume ramp down chan[i].volume=MAX(chan[i].volume-effectVal*256,0); dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); break; case 0xfa: // fast volume ramp if (effectVal!=0) { @@ -699,6 +728,7 @@ void DivEngine::processRow(int i, bool afterDelay) { } else { chan[i].volSpeed=0; } + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); break; case 0xff: // stop song @@ -729,15 +759,18 @@ void DivEngine::processRow(int i, bool afterDelay) { dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); if (chan[i].legato) { dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note)); + dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note)); } else { if (chan[i].inPorta && chan[i].keyOn && !chan[i].shorthandPorta) { if (song.e1e2StopOnSameNote && chan[i].wasShorthandPorta) { chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); chan[i].wasShorthandPorta=false; chan[i].inPorta=false; } else { chan[i].portaNote=chan[i].note; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); } } else if (!chan[i].noteOnInhibit) { dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note,chan[i].volume>>8)); @@ -748,12 +781,14 @@ void DivEngine::processRow(int i, bool afterDelay) { if (!chan[i].keyOn && chan[i].scheduledSlideReset) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].scheduledSlideReset=false; chan[i].inPorta=false; } if (!chan[i].keyOn && chan[i].volume>chan[i].volMax) { chan[i].volume=chan[i].volMax; dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); } chan[i].keyOn=true; chan[i].keyOff=false; @@ -993,15 +1028,19 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { if (chan[i].volume>chan[i].volMax) { chan[i].volume=chan[i].volMax; chan[i].volSpeed=0; + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0)); } else if (chan[i].volume<0) { chan[i].volSpeed=0; + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,0)); if (song.legacyVolumeSlides) { chan[i].volume=chan[i].volMax+1; } else { chan[i].volume=0; } dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + dispatchCmd(DivCommand(DIV_CMD_HINT_VOLUME,i,chan[i].volume>>8)); } else { dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); } @@ -1030,10 +1069,12 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { if ((chan[i].keyOn || chan[i].keyOff) && chan[i].portaSpeed>0) { if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch==2?song.pitchSlideSpeed:1),chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) { chan[i].portaSpeed=0; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].oldNote=chan[i].note; chan[i].note=chan[i].portaNote; chan[i].inPorta=false; dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note)); + dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note)); } } } @@ -1047,11 +1088,13 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { if (chan[i].stopOnOff) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); chan[i].stopOnOff=false; } if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) { chan[i].portaNote=-1; chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,chan[i].portaNote,chan[i].portaSpeed)); /*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) { chan[i+1].portaNote=-1; chan[i+1].portaSpeed=-1; @@ -1065,6 +1108,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { } if (chan[i].resetArp) { dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note)); + dispatchCmd(DivCommand(DIV_CMD_HINT_LEGATO,i,chan[i].note)); chan[i].resetArp=false; } if (song.rowResetsArpPos && firstTick) { From 67e7e07048c30f781e3dce4433aa9d9e1bc985a4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 15:18:48 -0500 Subject: [PATCH 127/515] add -cmdout option --- src/main.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index f25d08e77..6e0173aba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,6 +52,7 @@ FurnaceCLI cli; String outName; String vgmOutName; +String cmdOutName; int loops=1; int benchMode=0; DivAudioExportModes outMode=DIV_EXPORT_MODE_ONE; @@ -250,6 +251,12 @@ TAParamResult pVGMOut(String val) { return TA_PARAM_SUCCESS; } +TAParamResult pCmdOut(String val) { + cmdOutName=val; + e.setAudio(DIV_AUDIO_DUMMY); + return TA_PARAM_SUCCESS; +} + bool needsValue(String param) { for (size_t i=0; i","output audio to file")); params.push_back(TAParam("O","vgmout",true,pVGMOut,"","output .vgm data")); + params.push_back(TAParam("C","cmdout",true,pCmdOut,"","output command stream")); params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)")); params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (pattern by default)")); params.push_back(TAParam("c","console",false,pConsole,"","enable console mode")); @@ -307,6 +315,7 @@ int main(int argc, char** argv) { #endif outName=""; vgmOutName=""; + cmdOutName=""; initParams(); @@ -443,7 +452,23 @@ int main(int argc, char** argv) { } return 0; } - if (outName!="" || vgmOutName!="") { + if (outName!="" || vgmOutName!="" || cmdOutName!="") { + if (cmdOutName!="") { + SafeWriter* w=e.saveCommand(false); + if (w!=NULL) { + FILE* f=fopen(cmdOutName.c_str(),"wb"); + if (f!=NULL) { + fwrite(w->getFinalBuf(),1,w->size(),f); + fclose(f); + } else { + reportError(fmt::sprintf("could not open file! (%s)",e.getLastError())); + } + w->finish(); + delete w; + } else { + reportError("could not write command stream!"); + } + } if (vgmOutName!="") { SafeWriter* w=e.saveVGM(); if (w!=NULL) { From 2e41d117d7b259ccb45c89a50602bdfdef368a67 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 17:47:59 -0500 Subject: [PATCH 128/515] fix some of these command hints --- src/engine/engine.cpp | 2 ++ src/engine/playback.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 9b532c0bf..5d9224002 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -311,6 +311,8 @@ SafeWriter* DivEngine::saveCommand(bool binary) { break; case DIV_CMD_PITCH: break; + case DIV_CMD_PRE_NOTE: + break; default: if (!wroteTick) { wroteTick=true; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8fd20d5f9..ee9115fd8 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -62,8 +62,8 @@ const char* cmdName[]={ "HINT_VIBRATO_SHAPE", "HINT_PITCH", "HINT_ARPEGGIO", - "HINT_VOL_SLIDE", "HINT_VOLUME", + "HINT_VOL_SLIDE", "HINT_PORTA", "HINT_LEGATO", @@ -340,8 +340,8 @@ void DivEngine::processRow(int i, bool afterDelay) { // instrument bool insChanged=false; if (pat->data[whatRow][2]!=-1) { - dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,i,pat->data[whatRow][2])); if (chan[i].lastIns!=pat->data[whatRow][2]) { + dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,i,pat->data[whatRow][2])); chan[i].lastIns=pat->data[whatRow][2]; insChanged=true; if (song.legacyVolumeSlides && chan[i].volume==chan[i].volMax+1) { From f2b6f854a99e12d6a8f026890f85d93d55c7dc7b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 17:48:10 -0500 Subject: [PATCH 129/515] add options to not install demo songs/ins --- CMakeLists.txt | 10 ++++++++-- README.md | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78792c983..e468d4073 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,8 @@ option(SYSTEM_RTMIDI "Use a system-installed version of RtMidi instead of the ve option(SYSTEM_ZLIB "Use a system-installed version of zlib instead of the vendored one" OFF) option(SYSTEM_SDL2 "Use a system-installed version of SDL2 instead of the vendored one" ${SYSTEM_SDL2_DEFAULT}) option(WARNINGS_ARE_ERRORS "Whether warnings in furnace's C++ code should be treated as errors" OFF) +option(WITH_DEMOS "Install demo songs" ON) +option(WITH_INSTRUMENTS "Install instruments" ON) set(DEPENDENCIES_INCLUDE_DIRS "") @@ -709,8 +711,12 @@ if (NOT ANDROID OR TERMUX) install(FILES res/furnace.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) install(DIRECTORY papers DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/furnace) - install(DIRECTORY demos DESTINATION ${CMAKE_INSTALL_DATADIR}/furnace) - install(DIRECTORY instruments DESTINATION ${CMAKE_INSTALL_DATADIR}/furnace) + if (WITH_DEMOS) + install(DIRECTORY demos DESTINATION ${CMAKE_INSTALL_DATADIR}/furnace) + endif() + if (WITH_INSTRUMENTS) + install(DIRECTORY instruments DESTINATION ${CMAKE_INSTALL_DATADIR}/furnace) + endif() foreach(num 16 32 64 128 256 512) set(res ${num}x${num}) install(FILES res/icon.iconset/icon_${res}.png RENAME furnace.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${res}/apps) diff --git a/README.md b/README.md index 1a2d88a7d..d2308dd75 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,8 @@ Available options: | `SYSTEM_ZLIB` | `OFF` | Use a system-installed version of zlib instead of the vendored one | | `SYSTEM_SDL2` | `OFF` | Use a system-installed version of SDL2 instead of the vendored one | | `WARNINGS_ARE_ERRORS` | `OFF` (but consider enabling this & reporting any errors that arise from it!) | Whether warnings in furnace's C++ code should be treated as errors | +| `WITH_DEMOS` | `ON` | Install demo songs on `make install` | +| `WITH_INSTRUMENTS` | `ON` | Install demo instruments on `make install` | ## console usage From 3a18e1e6fc4ef101b65a9d3ff5bc874fad430016 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 18:50:52 -0500 Subject: [PATCH 130/515] partially implement command stream binary mode --- papers/export-tech.md | 28 ++---- src/engine/engine.cpp | 192 ++++++++++++++++++++++++++++++++++++------ src/main.cpp | 9 +- 3 files changed, 181 insertions(+), 48 deletions(-) diff --git a/papers/export-tech.md b/papers/export-tech.md index 560aab324..dbfadece3 100644 --- a/papers/export-tech.md +++ b/papers/export-tech.md @@ -11,28 +11,16 @@ if it is a 2-byte macro, read a dummy byte. then read data. -## pattern data +## binary command stream -read sequentially. +read channel, command and values. -first byte determines what to read next: +if channel is 80 or higher, then it is a special command: ``` -NVI..EEE - -N: note -V: volume -I: instrument - -EEE: effect count (0-7) +fb xx xx xx xx: set tick rate +fc xx xx: wait xxxx ticks +fd xx: wait xx ticks +fe: wait one tick +ff: stop ``` - -if you read 0, end of pattern. -otherwise read in following order: - -1. note -2. volume -3. instrument -4. effect and effect value - -then read number of rows until next value, minus 1. diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5d9224002..fd94e521a 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -235,8 +235,131 @@ double DivEngine::benchmarkSeek() { return tAvg; } +#define WRITE_TICK \ + if (!wroteTick) { \ + wroteTick=true; \ + if (binary) { \ + if (tick-lastTick>255) { \ + w->writeC(0xfc); \ + w->writeS(tick-lastTick); \ + } else if (tick-lastTick>1) { \ + w->writeC(0xfd); \ + w->writeC(tick-lastTick); \ + } else { \ + w->writeC(0xfe); \ + } \ + } else { \ + w->writeText(fmt::sprintf(">> TICK %d\n",tick)); \ + } \ + lastTick=tick; \ + } + +void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { + w->writeC(c.cmd); + switch (c.cmd) { + case DIV_CMD_NOTE_ON: + case DIV_CMD_HINT_LEGATO: + if (c.value==DIV_NOTE_NULL) { + w->writeC(0xff); + } else { + w->writeC(c.value+60); + } + break; + case DIV_CMD_NOTE_OFF: + case DIV_CMD_NOTE_OFF_ENV: + case DIV_CMD_ENV_RELEASE: + break; + case DIV_CMD_INSTRUMENT: + case DIV_CMD_HINT_VIBRATO_RANGE: + case DIV_CMD_HINT_VIBRATO_SHAPE: + case DIV_CMD_HINT_PITCH: + case DIV_CMD_HINT_VOLUME: + case DIV_CMD_SAMPLE_MODE: + case DIV_CMD_SAMPLE_FREQ: + case DIV_CMD_SAMPLE_BANK: + case DIV_CMD_SAMPLE_POS: + case DIV_CMD_SAMPLE_DIR: + case DIV_CMD_FM_HARD_RESET: + case DIV_CMD_FM_LFO: + case DIV_CMD_FM_LFO_WAVE: + case DIV_CMD_FM_FB: + case DIV_CMD_FM_EXTCH: + case DIV_CMD_FM_AM_DEPTH: + case DIV_CMD_FM_PM_DEPTH: + case DIV_CMD_STD_NOISE_FREQ: + case DIV_CMD_STD_NOISE_MODE: + case DIV_CMD_WAVE: + case DIV_CMD_GB_SWEEP_TIME: + case DIV_CMD_GB_SWEEP_DIR: + case DIV_CMD_PCE_LFO_MODE: + case DIV_CMD_PCE_LFO_SPEED: + case DIV_CMD_NES_DMC: + case DIV_CMD_C64_CUTOFF: + case DIV_CMD_C64_RESONANCE: + case DIV_CMD_C64_FILTER_MODE: + case DIV_CMD_C64_RESET_TIME: + case DIV_CMD_C64_RESET_MASK: + case DIV_CMD_C64_FILTER_RESET: + case DIV_CMD_C64_DUTY_RESET: + case DIV_CMD_C64_EXTENDED: + case DIV_CMD_AY_ENVELOPE_SET: + case DIV_CMD_AY_ENVELOPE_LOW: + case DIV_CMD_AY_ENVELOPE_HIGH: + case DIV_CMD_AY_ENVELOPE_SLIDE: + case DIV_CMD_AY_NOISE_MASK_AND: + case DIV_CMD_AY_NOISE_MASK_OR: + case DIV_CMD_AY_AUTO_ENVELOPE: + w->writeC(c.value); + break; + case DIV_CMD_PANNING: + case DIV_CMD_HINT_VIBRATO: + case DIV_CMD_HINT_ARPEGGIO: + case DIV_CMD_HINT_PORTA: + case DIV_CMD_FM_TL: + case DIV_CMD_FM_AM: + case DIV_CMD_FM_AR: + case DIV_CMD_FM_DR: + case DIV_CMD_FM_SL: + case DIV_CMD_FM_D2R: + case DIV_CMD_FM_RR: + case DIV_CMD_FM_DT: + case DIV_CMD_FM_DT2: + case DIV_CMD_FM_RS: + case DIV_CMD_FM_KSR: + case DIV_CMD_FM_VIB: + case DIV_CMD_FM_SUS: + case DIV_CMD_FM_WS: + case DIV_CMD_FM_SSG: + case DIV_CMD_FM_REV: + case DIV_CMD_FM_EG_SHIFT: + case DIV_CMD_FM_MULT: + case DIV_CMD_FM_FINE: + case DIV_CMD_AY_IO_WRITE: + case DIV_CMD_AY_AUTO_PWM: + w->writeC(c.value); + w->writeC(c.value2); + break; + case DIV_CMD_PRE_PORTA: + w->writeC((c.value?0x80:0)|(c.value2?0x40:0)); + break; + case DIV_CMD_HINT_VOL_SLIDE: + case DIV_CMD_C64_FINE_DUTY: + case DIV_CMD_C64_FINE_CUTOFF: + w->writeS(c.value); + break; + case DIV_CMD_FM_FIXFREQ: + w->writeS((c.value<<12)|(c.value2&0x7ff)); + break; + case DIV_CMD_NES_SWEEP: + w->writeC((c.value?8:0)|(c.value2&0x77)); + break; + default: + logW("unimplemented command %s!",cmdName[c.cmd]); + break; + } +} + SafeWriter* DivEngine::saveCommand(bool binary) { - logI("implement! %d",binary); stop(); repeatPattern=false; setOrder(0); @@ -252,36 +375,43 @@ SafeWriter* DivEngine::saveCommand(bool binary) { w->init(); // write header - w->writeText("# Furnace Command Stream\n\n"); + if (binary) { + w->write("FCS",4); + } else { + w->writeText("# Furnace Command Stream\n\n"); - w->writeText("[Information]\n"); - w->writeText(fmt::sprintf("name: %s\n",song.name)); - w->writeText(fmt::sprintf("author: %s\n",song.author)); - w->writeText(fmt::sprintf("category: %s\n",song.category)); - w->writeText(fmt::sprintf("system: %s\n",song.systemName)); + w->writeText("[Information]\n"); + w->writeText(fmt::sprintf("name: %s\n",song.name)); + w->writeText(fmt::sprintf("author: %s\n",song.author)); + w->writeText(fmt::sprintf("category: %s\n",song.category)); + w->writeText(fmt::sprintf("system: %s\n",song.systemName)); - w->writeText("\n"); + w->writeText("\n"); - w->writeText("[SubSongInformation]\n"); - w->writeText(fmt::sprintf("name: %s\n",curSubSong->name)); - w->writeText(fmt::sprintf("tickRate: %f\n",curSubSong->hz)); + w->writeText("[SubSongInformation]\n"); + w->writeText(fmt::sprintf("name: %s\n",curSubSong->name)); + w->writeText(fmt::sprintf("tickRate: %f\n",curSubSong->hz)); - w->writeText("\n"); + w->writeText("\n"); - w->writeText("[SysDefinition]\n"); - // TODO + w->writeText("[SysDefinition]\n"); + // TODO - w->writeText("\n"); + w->writeText("\n"); + } // play the song ourselves bool done=false; playSub(false); - w->writeText("[Stream]\n"); + if (!binary) { + w->writeText("[Stream]\n"); + } int tick=0; bool oldCmdStreamEnabled=cmdStreamEnabled; cmdStreamEnabled=true; double curDivider=divider; + int lastTick=0; while (!done) { if (nextTick(false,true) || !playing) { done=true; @@ -290,11 +420,13 @@ SafeWriter* DivEngine::saveCommand(bool binary) { bool wroteTick=false; if (curDivider!=divider) { curDivider=divider; - if (!wroteTick) { - wroteTick=true; - w->writeText(fmt::sprintf(">> TICK %d\n",tick)); + WRITE_TICK; + if (binary) { + w->writeC(0xfb); + w->writeI((int)(curDivider*65536)); + } else { + w->writeText(fmt::sprintf(">> SET_RATE %f\n",curDivider)); } - w->writeText(fmt::sprintf(">> SET_RATE %f\n",curDivider)); } for (DivCommand& i: cmdStream) { switch (i.cmd) { @@ -314,11 +446,13 @@ SafeWriter* DivEngine::saveCommand(bool binary) { case DIV_CMD_PRE_NOTE: break; default: - if (!wroteTick) { - wroteTick=true; - w->writeText(fmt::sprintf(">> TICK %d\n",tick)); + WRITE_TICK; + if (binary) { + w->writeC(i.chan); + writePackedCommandValues(w,i); + } else { + w->writeText(fmt::sprintf(" %d: %s %d %d\n",i.chan,cmdName[i.cmd],i.value,i.value2)); } - w->writeText(fmt::sprintf(" %d: %s %d %d\n",i.chan,cmdName[i.cmd],i.value,i.value2)); break; } } @@ -327,10 +461,14 @@ SafeWriter* DivEngine::saveCommand(bool binary) { } cmdStreamEnabled=oldCmdStreamEnabled; - if (!playing) { - w->writeText(">> END\n"); + if (binary) { + w->writeC(0xff); } else { - w->writeText(">> LOOP 0\n"); + if (!playing) { + w->writeText(">> END\n"); + } else { + w->writeText(">> LOOP 0\n"); + } } remainingLoops=-1; diff --git a/src/main.cpp b/src/main.cpp index 6e0173aba..39c9e6ca2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,6 +64,7 @@ bool consoleMode=true; #endif bool displayEngineFailError=false; +bool cmdOutBinary=false; std::vector params; @@ -115,6 +116,11 @@ TAParamResult pConsole(String val) { return TA_PARAM_SUCCESS; } +TAParamResult pBinary(String val) { + cmdOutBinary=true; + return TA_PARAM_SUCCESS; +} + TAParamResult pLogLevel(String val) { if (val=="trace") { logLevel=LOGLEVEL_TRACE; @@ -273,6 +279,7 @@ void initParams() { params.push_back(TAParam("o","output",true,pOutput,"","output audio to file")); params.push_back(TAParam("O","vgmout",true,pVGMOut,"","output .vgm data")); params.push_back(TAParam("C","cmdout",true,pCmdOut,"","output command stream")); + params.push_back(TAParam("b","binary",false,pBinary,"","set command stream output format to binary")); params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)")); params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (pattern by default)")); params.push_back(TAParam("c","console",false,pConsole,"","enable console mode")); @@ -454,7 +461,7 @@ int main(int argc, char** argv) { } if (outName!="" || vgmOutName!="" || cmdOutName!="") { if (cmdOutName!="") { - SafeWriter* w=e.saveCommand(false); + SafeWriter* w=e.saveCommand(cmdOutBinary); if (w!=NULL) { FILE* f=fopen(cmdOutName.c_str(),"wb"); if (f!=NULL) { From 049ab065449d4237734ff6fb2214fe09482d255f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 4 Aug 2022 23:37:28 -0500 Subject: [PATCH 131/515] PCE: add option to pick A/non-A revision of chip --- src/engine/platform/pce.cpp | 13 +++++++++++-- src/gui/sysConf.cpp | 7 +++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index a61b61836..d46e012ce 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -569,6 +569,12 @@ void DivPlatformPCE::setFlags(unsigned int flags) { for (int i=0; i<6; i++) { oscBuf[i]->rate=rate; } + + if (pce!=NULL) { + delete pce; + pce=NULL; + } + pce=new PCE_PSG(tempL,tempR,(flags&4)?PCE_PSG::REVISION_HUC6280A:PCE_PSG::REVISION_HUC6280); } void DivPlatformPCE::poke(unsigned int addr, unsigned short val) { @@ -587,8 +593,8 @@ int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate, unsigned int f isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } + pce=NULL; setFlags(flags); - pce=new PCE_PSG(tempL,tempR,PCE_PSG::REVISION_HUC6280A); reset(); return 6; } @@ -597,7 +603,10 @@ void DivPlatformPCE::quit() { for (int i=0; i<6; i++) { delete oscBuf[i]; } - delete pce; + if (pce!=NULL) { + delete pce; + pce=NULL; + } } DivPlatformPCE::~DivPlatformPCE() { diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 7c624f309..4cc1784a6 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -118,6 +118,13 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::Checkbox("Disable anti-click",&antiClick)) { copyOfFlags=(flags&(~8))|(antiClick<<3); } + ImGui::Text("Chip revision:"); + if (ImGui::RadioButton("HuC6280 (original)",(flags&4)==0)) { + copyOfFlags=(flags&(~4))|0; + } + if (ImGui::RadioButton("HuC6280A (SuperGrafx)",(flags&4)==4)) { + copyOfFlags=(flags&(~4))|4; + } break; } case DIV_SYSTEM_SOUND_UNIT: { From 827904d46e1999d421fd0b9917ce0266bef07fcf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 5 Aug 2022 00:05:36 -0500 Subject: [PATCH 132/515] what happens if I force arm64 on macOS CI? --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e060924f..ed4710879 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -201,7 +201,7 @@ jobs: elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') elif [ '${{ runner.os }}' == 'macOS' ]; then - CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') + CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"' '-DCMAKE_OSX_ARCHITECTURES=arm64') fi cmake \ From a0968aed0719a032c131b24ce583abaaa2e25e00 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 5 Aug 2022 03:27:35 -0500 Subject: [PATCH 133/515] GUI: fix text/binary command stream outs being swa --- src/gui/gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 28edd9e32..c1cd7f076 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3544,7 +3544,7 @@ bool FurnaceGUI::loop() { if (i>='A' && i<='Z') i+='a'-'A'; } bool isBinary=true; - if ((lowerCase.size()<4 || lowerCase.rfind(".txt")!=lowerCase.size()-4)) { + if ((lowerCase.size()<4 || lowerCase.rfind(".bin")!=lowerCase.size()-4)) { isBinary=false; } From 1d30febff8497b2bfdc99c81591914de3480b2af Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 5 Aug 2022 15:39:13 -0500 Subject: [PATCH 134/515] oh yeah --- .github/workflows/build.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed4710879..5ee82f0da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,8 @@ jobs: - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } - { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } - { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } - - { name: 'macOS', os: macos-latest } + - { name: 'macOS x86_64', os: macos-latest, arch: x86_64 } + - { name: 'macOS ARM', os: macos-latest, arch: arm64 } - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false @@ -201,7 +202,11 @@ jobs: elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') elif [ '${{ runner.os }}' == 'macOS' ]; then - CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"' '-DCMAKE_OSX_ARCHITECTURES=arm64') + if [ '${{ matrix.config.arch }}' == 'arm64' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="11.0"' '-DCMAKE_OSX_ARCHITECTURES=arm64') + else + CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') + fi fi cmake \ From 3e70ed6d3eb22d42c51e030f367c5321796124bd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 5 Aug 2022 17:22:07 -0500 Subject: [PATCH 135/515] CI: fix artifact conflict --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5ee82f0da..da0cfbfae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,7 +77,7 @@ jobs: package_name="${package_name}-${{ matrix.config.arch }}" package_ext="" # Directory, uploading will automatically zip it elif [ '${{ runner.os }}' == 'macOS' ]; then - package_name="${package_name}-macOS" + package_name="${package_name}-macOS-${{ matrix.config.arch }}" package_ext=".dmg" else package_name="${package_name}-Linux" From 6ec9cceb091dbd70966f099510f72d4be0db662e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 00:34:28 -0500 Subject: [PATCH 136/515] PCE: remove some sample playback clicking --- src/engine/platform/pce.cpp | 9 ++++++++- src/engine/platform/pce.h | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index d46e012ce..757cff159 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -133,6 +133,10 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) } void DivPlatformPCE::updateWave(int ch) { + if (chan[ch].pcm) { + chan[ch].deferredWaveUpdate=true; + return; + } chWrite(ch,0x04,0x5f); chWrite(ch,0x04,0x1f); for (int i=0; i<32; i++) { @@ -142,6 +146,9 @@ void DivPlatformPCE::updateWave(int ch) { if (chan[ch].active) { chWrite(ch,0x04,0x80|chan[ch].outVol); } + if (chan[ch].deferredWaveUpdate) { + chan[ch].deferredWaveUpdate=false; + } } // TODO: in octave 6 the noise table changes to a tonal one @@ -227,7 +234,7 @@ void DivPlatformPCE::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].active) { - if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) { + if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) || chan[i].deferredWaveUpdate) { updateWave(i); } } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 22a24ddf8..17e191d44 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -33,7 +33,7 @@ class DivPlatformPCE: public DivDispatch { unsigned int dacPos; int dacSample, ins; unsigned char pan; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac, deferredWaveUpdate; signed char vol, outVol, wave; DivMacroInt std; DivWaveSynth ws; @@ -64,6 +64,7 @@ class DivPlatformPCE: public DivDispatch { noise(false), pcm(false), furnaceDac(false), + deferredWaveUpdate(false), vol(31), outVol(31), wave(-1) {} From 8a7d352ec6071c3d7f150953ba81f23c3b249f1d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 00:38:24 -0500 Subject: [PATCH 137/515] PCE: fix phase reset macro when anti-click is on --- src/engine/platform/pce.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 757cff159..5d9a0de88 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -233,6 +233,10 @@ void DivPlatformPCE::tick(bool sysTick) { } chan[i].freqChanged=true; } + if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) { + chan[i].antiClickWavePos=0; + chan[i].antiClickPeriodCount=0; + } if (chan[i].active) { if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) || chan[i].deferredWaveUpdate) { updateWave(i); From 0946d2388301cd59407d448a1e16686fe76a72e9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 00:39:09 -0500 Subject: [PATCH 138/515] Game Boy: fix phase reset macro when anti-click is --- src/engine/platform/gb.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 4d10d7d22..4067e9f17 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -220,6 +220,10 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; + if (i==2) { + antiClickWavePos=0; + antiClickPeriodCount=0; + } } } if (i==2) { From 5534f55f7aabb7814c65693972558a5062de61cc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 04:04:18 -0500 Subject: [PATCH 139/515] dev104 - add "is sample" flag to Sound Unit ins --- papers/format.md | 3 +++ src/engine/engine.h | 4 ++-- src/engine/instrument.cpp | 10 ++++++++++ src/engine/instrument.h | 9 +++++++++ src/engine/platform/su.cpp | 6 +++--- src/gui/insEdit.cpp | 24 +++++++++++++++--------- 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/papers/format.md b/papers/format.md index ca8092a5a..97e22a4e5 100644 --- a/papers/format.md +++ b/papers/format.md @@ -810,6 +810,9 @@ size | description 1 | vib depth 1 | am depth 23 | reserved + --- | **Sound Unit data** (>=104) + 1 | use sample + 1 | switch roles of phase reset timer and frequency ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index 6f969efc9..256b0c96d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev103" -#define DIV_ENGINE_VERSION 103 +#define DIV_VERSION "dev104" +#define DIV_ENGINE_VERSION 104 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index a76588561..4d274e18c 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -528,6 +528,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(0); } + // Sound Unit + w->writeC(su.useSample); + w->writeC(su.switchRoles); + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); @@ -1075,6 +1079,12 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int k=0; k<23; k++) reader.readC(); } + // Sound Unit + if (version>=104) { + su.useSample=reader.readC(); + su.switchRoles=reader.readC(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 18bf2c5f7..1c25988e4 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -437,6 +437,14 @@ struct DivInstrumentWaveSynth { param4(0) {} }; +struct DivInstrumentSoundUnit { + bool useSample; + bool switchRoles; + DivInstrumentSoundUnit(): + useSample(false), + switchRoles(false) {} +}; + struct DivInstrument { String name; bool mode; @@ -450,6 +458,7 @@ struct DivInstrument { DivInstrumentFDS fds; DivInstrumentMultiPCM multipcm; DivInstrumentWaveSynth ws; + DivInstrumentSoundUnit su; /** * save the instrument to a SafeWriter. diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 2d1a38932..4320798ab 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -256,12 +256,12 @@ 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 (chan[c.chan].pcm && ins->type!=DIV_INS_AMIGA) { - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA); + if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->su.useSample)) { + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); writeControl(c.chan); writeControlUpper(c.chan); } - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA); + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index f991b9e2a..8e405251e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3093,13 +3093,17 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest)); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_AMIGA) if (ImGui::BeginTabItem("Sample")) { + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SU) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { String sName; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { sName="none selected"; } else { sName=e->song.sample[ins->amiga.initSample]->name; } + if (ins->type==DIV_INS_SU) { + P(ImGui::Checkbox("Use sample",&ins->su.useSample)); + P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles)); + } if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { String id; for (int i=0; isong.sampleLen; i++) { @@ -3110,14 +3114,16 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndCombo(); } - P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); - if (ins->amiga.useWave) { - int len=ins->amiga.waveLen+1; - if (ImGui::InputInt("Width",&len,2,16)) { - if (len<2) len=2; - if (len>256) len=256; - ins->amiga.waveLen=(len&(~1))-1; - PARAMETER + if (ins->type==DIV_INS_AMIGA) { + P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); + if (ins->amiga.useWave) { + int len=ins->amiga.waveLen+1; + if (ImGui::InputInt("Width",&len,2,16)) { + if (len<2) len=2; + if (len>256) len=256; + ins->amiga.waveLen=(len&(~1))-1; + PARAMETER + } } } ImGui::BeginDisabled(ins->amiga.useWave); From a84129621937389d444cf09fe61544df8194a627 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Sat, 6 Aug 2022 17:50:15 +0200 Subject: [PATCH 140/515] Y8950: PCM -> ADPCM also where the f is my write access --- src/engine/sysDef.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 740854071..c5541baa3 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1850,8 +1850,8 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_Y8950]=new DivSysDef( "Yamaha Y8950", NULL, 0xb2, 0, 10, true, false, 0x151, false, "like OPL but with an ADPCM channel.", - {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "PCM"}, - {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "PCM"}, + {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "ADPCM"}, + {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, {}, @@ -1862,8 +1862,8 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef( "Yamaha Y8950 with drums", NULL, 0xb3, 0, 12, true, false, 0x151, false, "the Y8950 chip, in drums mode.", - {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "PCM"}, - {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"}, + {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "ADPCM"}, + {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_NULL}, From f03123fd75a0543efc5d6af3c9709eeea342748f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 16:22:57 -0500 Subject: [PATCH 141/515] SoundUnit: implement missing input line emulation --- src/engine/platform/sound/su.cpp | 65 ++++++++++++++++++++++++++++++-- src/engine/platform/sound/su.h | 8 +++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/sound/su.cpp b/src/engine/platform/sound/su.cpp index 0dd6dcdc7..a2fd76534 100644 --- a/src/engine/platform/sound/su.cpp +++ b/src/engine/platform/sound/su.cpp @@ -5,9 +5,22 @@ #define minval(a,b) (((a)<(b))?(a):(b)) #define maxval(a,b) (((a)>(b))?(a):(b)) +#define FILVOL chan[4].special1C +#define ILCTRL chan[4].special1D +#define ILSIZE chan[5].special1C +#define FIL1 chan[5].special1D +#define IL1 chan[6].special1C +#define IL2 chan[6].special1D +#define IL0 chan[7].special1C +#define MVOL chan[7].special1D + void SoundUnit::NextSample(short* l, short* r) { + // run channels for (int i=0; i<8; i++) { - if (chan[i].vol==0 && !chan[i].flags.swvol) {fns[i]=0; continue;} + if (chan[i].vol==0 && !chan[i].flags.swvol) { + fns[i]=0; + continue; + } if (chan[i].flags.pcm) { ns[i]=pcm[chan[i].pcmpos]; } else switch (chan[i].flags.shape) { @@ -48,7 +61,6 @@ void SoundUnit::NextSample(short* l, short* r) { pcmdec[i]-=32768; if (chan[i].pcmpos>2; tnsR=(nsR[0]+nsR[1]+nsR[2]+nsR[3]+nsR[4]+nsR[5]+nsR[6]+nsR[7])>>2; - + + // write input lines to sample memory + if (ILSIZE&64) { + if (++ilBufPeriod>=((1+(FIL1>>4))<<2)) { + ilBufPeriod=0; + unsigned short ilLowerBound=pcmSize-((1+(ILSIZE&63))<<7); + if (ilBufPos>4); + if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; + break; + case 1: + ilFeedback0=ilFeedback1=pcm[ilBufPos]; + pcm[ilBufPos]=IL1+((pcm[ilBufPos]*(FIL1&15))>>4); + if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; + break; + case 2: + ilFeedback0=ilFeedback1=pcm[ilBufPos]; + pcm[ilBufPos]=IL2+((pcm[ilBufPos]*(FIL1&15))>>4); + if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; + break; + case 3: + ilFeedback0=pcm[ilBufPos]; + pcm[ilBufPos]=IL1+((pcm[ilBufPos]*(FIL1&15))>>4); + if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; + ilFeedback1=pcm[ilBufPos]; + pcm[ilBufPos]=IL2+((pcm[ilBufPos]*(FIL1&15))>>4); + if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; + break; + } + } + if (ILSIZE&128) { + tnsL+=ilFeedback1*(signed char)FILVOL; + tnsR+=ilFeedback0*(signed char)FILVOL; + } else { + tnsL+=ilFeedback0*(signed char)FILVOL; + tnsR+=ilFeedback1*(signed char)FILVOL; + } + } + *l=minval(32767,maxval(-32767,tnsL)); *r=minval(32767,maxval(-32767,tnsR)); } @@ -272,6 +327,10 @@ void SoundUnit::Reset() { } tnsL=0; tnsR=0; + ilBufPos=0; + ilBufPeriod=0; + ilFeedback0=0; + ilFeedback1=0; memset(chan,0,sizeof(SUChannel)*8); } diff --git a/src/engine/platform/sound/su.h b/src/engine/platform/sound/su.h index 3b125f030..0ee843481 100644 --- a/src/engine/platform/sound/su.h +++ b/src/engine/platform/sound/su.h @@ -20,6 +20,10 @@ class SoundUnit { int nshigh[8]; int nsband[8]; int tnsL, tnsR; + unsigned char ilBufPeriod; + unsigned short ilBufPos; + signed char ilFeedback0; + signed char ilFeedback1; unsigned short oldfreq[8]; unsigned short oldflags[8]; unsigned int pcmSize; @@ -80,11 +84,13 @@ class SoundUnit { unsigned char dir: 1; unsigned char bound; } swcut; - unsigned short wc; + unsigned char special1C; + unsigned char special1D; unsigned short restimer; } chan[8]; signed char pcm[65536]; bool muted[8]; + void SetIL0(unsigned char addr); void Write(unsigned char addr, unsigned char data); void NextSample(short* l, short* r); inline int GetSample(int ch) { From 6934a499c10da650bf8cb67c70dc98d38f71194d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 18:23:11 -0500 Subject: [PATCH 142/515] SoundUnit: actually finish it --- src/engine/platform/sound/su.cpp | 43 +++++++++++++++++++++++-------- src/engine/platform/su.cpp | 16 +++++++++++- src/engine/platform/su.h | 3 +++ src/gui/sysConf.cpp | 44 +++++++++++++++++++++++++++++--- 4 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/engine/platform/sound/su.cpp b/src/engine/platform/sound/su.cpp index a2fd76534..6637bfa7d 100644 --- a/src/engine/platform/sound/su.cpp +++ b/src/engine/platform/sound/su.cpp @@ -238,44 +238,65 @@ void SoundUnit::NextSample(short* l, short* r) { 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; + IL1=minval(32767,maxval(-32767,tnsL))>>8; + IL2=minval(32767,maxval(-32767,tnsR))>>8; + // write input lines to sample memory if (ILSIZE&64) { if (++ilBufPeriod>=((1+(FIL1>>4))<<2)) { ilBufPeriod=0; unsigned short ilLowerBound=pcmSize-((1+(ILSIZE&63))<<7); + short next; if (ilBufPos>4); + next=((signed char)IL0)+((pcm[ilBufPos]*(FIL1&15))>>4); + if (next<-128) next=-128; + if (next>127) next=127; + pcm[ilBufPos]=next; if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; break; case 1: ilFeedback0=ilFeedback1=pcm[ilBufPos]; - pcm[ilBufPos]=IL1+((pcm[ilBufPos]*(FIL1&15))>>4); + next=((signed char)IL1)+((pcm[ilBufPos]*(FIL1&15))>>4); + if (next<-128) next=-128; + if (next>127) next=127; + pcm[ilBufPos]=next; if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; break; case 2: ilFeedback0=ilFeedback1=pcm[ilBufPos]; - pcm[ilBufPos]=IL2+((pcm[ilBufPos]*(FIL1&15))>>4); + next=((signed char)IL2)+((pcm[ilBufPos]*(FIL1&15))>>4); + if (next<-128) next=-128; + if (next>127) next=127; + pcm[ilBufPos]=next; if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; break; case 3: ilFeedback0=pcm[ilBufPos]; - pcm[ilBufPos]=IL1+((pcm[ilBufPos]*(FIL1&15))>>4); + next=((signed char)IL1)+((pcm[ilBufPos]*(FIL1&15))>>4); + if (next<-128) next=-128; + if (next>127) next=127; + pcm[ilBufPos]=next; if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; ilFeedback1=pcm[ilBufPos]; - pcm[ilBufPos]=IL2+((pcm[ilBufPos]*(FIL1&15))>>4); + next=((signed char)IL2)+((pcm[ilBufPos]*(FIL1&15))>>4); + if (next<-128) next=-128; + if (next>127) next=127; + pcm[ilBufPos]=next; if (++ilBufPos>=pcmSize) ilBufPos=ilLowerBound; break; } } - if (ILSIZE&128) { - tnsL+=ilFeedback1*(signed char)FILVOL; - tnsR+=ilFeedback0*(signed char)FILVOL; - } else { - tnsL+=ilFeedback0*(signed char)FILVOL; - tnsR+=ilFeedback1*(signed char)FILVOL; + if (ILCTRL&4) { + if (ILSIZE&128) { + tnsL+=ilFeedback1*(signed char)FILVOL; + tnsR+=ilFeedback0*(signed char)FILVOL; + } else { + tnsL+=ilFeedback0*(signed char)FILVOL; + tnsR+=ilFeedback1*(signed char)FILVOL; + } } } diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 4320798ab..6c6b0b329 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -529,6 +529,16 @@ void DivPlatformSoundUnit::reset() { lfoMode=0; lfoSpeed=255; delay=500; + + // set initial IL status + ilCtrl=initIlCtrl; + ilSize=initIlSize; + fil1=initFil1; + echoVol=initEchoVol; + rWrite(0x9c,echoVol); + rWrite(0x9d,ilCtrl); + rWrite(0xbc,ilSize); + rWrite(0xbd,fil1); } bool DivPlatformSoundUnit::isStereo() { @@ -555,6 +565,10 @@ void DivPlatformSoundUnit::setFlags(unsigned int flags) { for (int i=0; i<8; i++) { oscBuf[i]->rate=rate; } + initIlCtrl=3|(flags&4); + initIlSize=((flags>>8)&63)|((flags&4)?0x40:0)|((flags&8)?0x80:0); + initFil1=flags>>16; + initEchoVol=flags>>24; sampleMemSize=flags&16; @@ -575,7 +589,7 @@ const void* DivPlatformSoundUnit::getSampleMem(int index) { } size_t DivPlatformSoundUnit::getSampleMemCapacity(int index) { - return (index==0)?(sampleMemSize?65536:8192):0; + return (index==0)?((sampleMemSize?65536:8192)-((initIlSize&64)?((1+(initIlSize&63))<<7):0)):0; } size_t DivPlatformSoundUnit::getSampleMemUsage(int index) { diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index e882c398e..9972599d4 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -97,6 +97,9 @@ class DivPlatformSoundUnit: public DivDispatch { std::queue writes; unsigned char lastPan; bool sampleMemSize; + unsigned char ilCtrl, ilSize, fil1; + unsigned char initIlCtrl, initIlSize, initFil1; + signed char echoVol, initEchoVol; int cycles, curChan, delay; short tempL; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 4cc1784a6..3259f00c0 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -129,11 +129,11 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } case DIV_SYSTEM_SOUND_UNIT: { ImGui::Text("CPU rate:"); - if (ImGui::RadioButton("6.18MHz (NTSC)",(flags&15)==0)) { - copyOfFlags=(flags&(~15))|0; + if (ImGui::RadioButton("6.18MHz (NTSC)",(flags&3)==0)) { + copyOfFlags=(flags&(~3))|0; } - if (ImGui::RadioButton("5.95MHz (PAL)",(flags&15)==1)) { - copyOfFlags=(flags&(~15))|1; + if (ImGui::RadioButton("5.95MHz (PAL)",(flags&3)==1)) { + copyOfFlags=(flags&(~3))|1; } ImGui::Text("Chip revision (sample memory):"); if (ImGui::RadioButton("A/B/E (8K)",(flags&16)==0)) { @@ -142,6 +142,42 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("D/F (64K)",(flags&16)==16)) { copyOfFlags=(flags&(~16))|16; } + bool echo=flags&4; + if (ImGui::Checkbox("Enable echo",&echo)) { + copyOfFlags=(flags&(~4))|(echo<<2); + } + bool flipEcho=flags&8; + if (ImGui::Checkbox("Swap echo channels",&flipEcho)) { + copyOfFlags=(flags&(~8))|(flipEcho<<3); + } + ImGui::Text("Echo delay:"); + int echoBufSize=(flags&0x3f00)>>8; + if (CWSliderInt("##EchoBufSize",&echoBufSize,0,63)) { + if (echoBufSize<0) echoBufSize=0; + if (echoBufSize>63) echoBufSize=63; + copyOfFlags=(flags&~0x3f00)|(echoBufSize<<8); + } rightClickable + ImGui::Text("Echo resolution:"); + int echoResolution=(flags&0xf00000)>>20; + if (CWSliderInt("##EchoResolution",&echoResolution,0,15)) { + if (echoResolution<0) echoResolution=0; + if (echoResolution>15) echoResolution=15; + copyOfFlags=(flags&(~0xf00000))|(echoResolution<<20); + } rightClickable + ImGui::Text("Echo feedback:"); + int echoFeedback=(flags&0xf0000)>>16; + if (CWSliderInt("##EchoFeedback",&echoFeedback,0,15)) { + if (echoFeedback<0) echoFeedback=0; + if (echoFeedback>15) echoFeedback=15; + copyOfFlags=(flags&(~0xf0000))|(echoFeedback<<16); + } rightClickable + ImGui::Text("Echo volume:"); + int echoVolume=(signed char)((flags&0xff000000)>>24); + if (CWSliderInt("##EchoVolume",&echoVolume,-128,127)) { + if (echoVolume<-128) echoVolume=-128; + if (echoVolume>127) echoVolume=127; + copyOfFlags=(flags&(~0xff000000))|(((unsigned char)echoVolume)<<24); + } rightClickable break; } case DIV_SYSTEM_GB: { From f439bd2234b2d02de7b961bbbe31e01eb4c7ccf3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 19:22:00 -0500 Subject: [PATCH 143/515] CI: Cross-Linux-armhf trial, part 1 --- .github/workflows/build.yml | 48 ++++++++++++++++++++++++++------- scripts/Cross-Linux-armhf.cmake | 15 +++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 scripts/Cross-Linux-armhf.cmake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da0cfbfae..f3132f1d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,8 @@ jobs: - { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } - { name: 'macOS x86_64', os: macos-latest, arch: x86_64 } - { name: 'macOS ARM', os: macos-latest, arch: arm64 } - - { name: 'Ubuntu', os: ubuntu-18.04 } + - { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 } + - { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf } fail-fast: false name: ${{ matrix.config.name }} @@ -80,7 +81,7 @@ jobs: package_name="${package_name}-macOS-${{ matrix.config.arch }}" package_ext=".dmg" else - package_name="${package_name}-Linux" + package_name="${package_name}-Linux-${{ matrix.config.arch }}" package_ext=".AppImage" fi @@ -117,8 +118,8 @@ jobs: mingw-w64 \ mingw-w64-tools - - name: Install Dependencies [Ubuntu] - if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + - name: Install Dependencies [Linux x86_64] + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }} run: | sudo apt update sudo apt install \ @@ -132,8 +133,29 @@ jobs: wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" chmod +x appimagetool-x86_64.AppImage + - name: Install Dependencies [Linux armhf] + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'armhf' }} + run: | + sudo sed -ri "s/^deb /deb [arch=amd64] /" /etc/apt/sources.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic main universe" | sudo tee -a /etc/apt/sources.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main universe" | sudo tee -a /etc/apt/sources.list + sudo apt update + sudo dpkg --add-architecture armhf + sudo apt install \ + crossbuild-essential-armhf \ + libsdl2-dev:armhf \ + libfmt-dev:armhf \ + librtmidi-dev:armhf \ + libsndfile1-dev:armhf \ + zlib1g-dev:armhf \ + libjack-jackd2-dev:armhf \ + appstream + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-armhf" + chmod +x appimagetool-x86_64.AppImage + - name: Configure (System Libraries) - if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }} run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() @@ -164,7 +186,7 @@ jobs: "${CMAKE_EXTRA_ARGS[@]}" - name: Build (System Libraries) - if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }} run: | cmake \ --build ${PWD}/build \ @@ -172,14 +194,14 @@ jobs: --parallel ${{ steps.build-cores.outputs.amount }} - name: Install (System Libraries) - if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }} run: | cmake \ --install ${PWD}/build \ --config ${{ env.BUILD_TYPE }} - name: Cleanup (System Libraries) - if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }} run: | rm -rf build/ target/ @@ -207,6 +229,8 @@ jobs: else CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') fi + elif [ '${{ runner.os }}' == 'Linux' && '${{ matrix.config.arch }}' == 'armhf' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-Linux-armhf.cmake') fi cmake \ @@ -260,7 +284,7 @@ jobs: mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }} popd - - name: Package [Ubuntu] + - name: Package [Linux] if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | #if [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then @@ -278,7 +302,11 @@ jobs: cp -v ../../res/AppRun ./ popd - ../appimagetool-x86_64.AppImage furnace.AppDir + if [ '${{ matrix.config.arch }}' == 'armhf' ]; then + ../appimagetool-x86_64.AppImage --runtime-file=../runtime-armhf furnace.AppDir + else + ../appimagetool-x86_64.AppImage furnace.AppDir + fi mv Furnace-*.AppImage ../${{ steps.package-identify.outputs.filename }} popd diff --git a/scripts/Cross-Linux-armhf.cmake b/scripts/Cross-Linux-armhf.cmake new file mode 100644 index 000000000..969be4da9 --- /dev/null +++ b/scripts/Cross-Linux-armhf.cmake @@ -0,0 +1,15 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) + +set(TARGET_PREFIX arm-linux-gnueabihf) + +set(CMAKE_C_COMPILER ${TARGET_PREFIX}-gcc) +set(CMAKE_CXX_COMPILER ${TARGET_PREFIX}-g++) +set(PKG_CONFIG_EXECUTABLE ${TARGET_PREFIX}-pkg-config) + +set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX}) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) From dc5fd54544e468630f8b22aff0a5050024b77fc2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 19:35:06 -0500 Subject: [PATCH 144/515] CI: Cross-Linux-armhf trial, part 2 --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3132f1d4..042162533 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -139,17 +139,18 @@ jobs: sudo sed -ri "s/^deb /deb [arch=amd64] /" /etc/apt/sources.list echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic main universe" | sudo tee -a /etc/apt/sources.list echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main universe" | sudo tee -a /etc/apt/sources.list - sudo apt update sudo dpkg --add-architecture armhf + sudo apt update sudo apt install \ crossbuild-essential-armhf \ + appstream + sudo apt install \ libsdl2-dev:armhf \ libfmt-dev:armhf \ librtmidi-dev:armhf \ libsndfile1-dev:armhf \ zlib1g-dev:armhf \ - libjack-jackd2-dev:armhf \ - appstream + libjack-jackd2-dev:armhf wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-armhf" chmod +x appimagetool-x86_64.AppImage From 6594fe41237099ef139a47bad6907737844891fe Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 19:39:07 -0500 Subject: [PATCH 145/515] CI: Cross-Linux-armhf trial, part 3 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 042162533..6994383d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -230,7 +230,7 @@ jobs: else CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') fi - elif [ '${{ runner.os }}' == 'Linux' && '${{ matrix.config.arch }}' == 'armhf' ]; then + elif [ '${{ runner.os }}' == 'Linux' ] && [ '${{ matrix.config.arch }}' == 'armhf' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-Linux-armhf.cmake') fi From 8f03763107c1c9ad1baf01099a9c1572c5574256 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 19:53:29 -0500 Subject: [PATCH 146/515] CI: Cross-Linux-armhf trial, part 4 --- scripts/Cross-Linux-armhf.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Cross-Linux-armhf.cmake b/scripts/Cross-Linux-armhf.cmake index 969be4da9..0134be4af 100644 --- a/scripts/Cross-Linux-armhf.cmake +++ b/scripts/Cross-Linux-armhf.cmake @@ -12,4 +12,4 @@ set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) From 3c82e0abd4db40c7ff498e8518e86b40e192e7f1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 19:59:38 -0500 Subject: [PATCH 147/515] CI: Cross-Linux-armhf trial, part 5 --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6994383d0..3bccc91fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -150,10 +150,12 @@ jobs: librtmidi-dev:armhf \ libsndfile1-dev:armhf \ zlib1g-dev:armhf \ + cmake:armhf \ libjack-jackd2-dev:armhf wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-armhf" chmod +x appimagetool-x86_64.AppImage + ls /usr/arm-linux-gnueabihf/lib - name: Configure (System Libraries) if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' && matrix.config.arch == 'x86_64' }} From 2c1390c0a11f75d01f126b7bbd748e9c474f97f5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 21:29:33 -0500 Subject: [PATCH 148/515] CI: Cross-Linux-armhf trial, part 6 --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3bccc91fa..6d356bedb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -150,7 +150,6 @@ jobs: librtmidi-dev:armhf \ libsndfile1-dev:armhf \ zlib1g-dev:armhf \ - cmake:armhf \ libjack-jackd2-dev:armhf wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-armhf" From c4db8d514143f8aa13c9abdfe68209d0b7b52924 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 21:47:26 -0500 Subject: [PATCH 149/515] CI: Cross-Linux-armhf trial, part 7 --- scripts/Cross-Linux-armhf.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/Cross-Linux-armhf.cmake b/scripts/Cross-Linux-armhf.cmake index 0134be4af..fb494efc2 100644 --- a/scripts/Cross-Linux-armhf.cmake +++ b/scripts/Cross-Linux-armhf.cmake @@ -13,3 +13,5 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) + +set(CMAKE_SYSTEM_LIBRARY_PATH "/usr/lib/${TARGET_PREFIX};/usr/${TARGET_PREFIX}/lib") From 29d84f0affe7897a29f2f6b87cf8b262caf6efff Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 22:01:14 -0500 Subject: [PATCH 150/515] CI: Cross-Linux-armhf trial, part 8 --- scripts/Cross-Linux-armhf.cmake | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/Cross-Linux-armhf.cmake b/scripts/Cross-Linux-armhf.cmake index fb494efc2..122e2c264 100644 --- a/scripts/Cross-Linux-armhf.cmake +++ b/scripts/Cross-Linux-armhf.cmake @@ -7,11 +7,9 @@ set(CMAKE_C_COMPILER ${TARGET_PREFIX}-gcc) set(CMAKE_CXX_COMPILER ${TARGET_PREFIX}-g++) set(PKG_CONFIG_EXECUTABLE ${TARGET_PREFIX}-pkg-config) -set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX}) +set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX} /usr/lib/${TARGET_PREFIX}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) - -set(CMAKE_SYSTEM_LIBRARY_PATH "/usr/lib/${TARGET_PREFIX};/usr/${TARGET_PREFIX}/lib") From e2e0fd62a8610b73696f343901acaa88f05f4273 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 22:05:16 -0500 Subject: [PATCH 151/515] CI: Cross-Linux-armhf trial, part 9 --- scripts/Cross-Linux-armhf.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Cross-Linux-armhf.cmake b/scripts/Cross-Linux-armhf.cmake index 122e2c264..3e490ae12 100644 --- a/scripts/Cross-Linux-armhf.cmake +++ b/scripts/Cross-Linux-armhf.cmake @@ -11,5 +11,5 @@ set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX} /usr/lib/${TARGET_PREFIX}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) From 42a0ee13b87f37028d5b5b44a4ba22b7546d0f16 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 22:26:18 -0500 Subject: [PATCH 152/515] add two demo songs by psdominator and LVintageNerd --- demos/Bullet_Hell.fur | Bin 0 -> 60233 bytes demos/home_wfl_opl3.fur | Bin 0 -> 6367 bytes src/gui/about.cpp | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 demos/Bullet_Hell.fur create mode 100644 demos/home_wfl_opl3.fur diff --git a/demos/Bullet_Hell.fur b/demos/Bullet_Hell.fur new file mode 100644 index 0000000000000000000000000000000000000000..48c50f674d7d8a4c9cfbb2f632a1d1de602a617e GIT binary patch literal 60233 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

@Jkl=4Ns}LO9Yo9Q>HcR&Vv2yWz%NN& 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 VX2l>Ya^e5)ZZ<-~86)pg{s(PBp(X$T literal 0 HcmV?d00001 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 00d899f81..e65413fce 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -80,10 +80,12 @@ const char* aboutLine[]={ "Laggy", "LovelyA72", "LunaMoth", + "LVintageNerd", "Mahbod Karamoozian", "Miker", "nicco1690", "NikonTeen", + "psdominator", "SuperJet Spade", "TheDuccinator", "theloredev", From 17dba66fa0ba5e7e49a4acea2092c38e87b71e54 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 22:52:39 -0500 Subject: [PATCH 153/515] MMC5: finally fix PCM linear pitch mode issues --- src/engine/platform/mmc5.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index bafbda3fb..2154e855f 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -171,7 +171,7 @@ void DivPlatformMMC5::tick(bool sysTick) { // PCM if (chan[2].freqChanged) { - chan[2].freq=parent->calcFreq(chan[2].baseFreq,chan[2].pitch,false); + chan[2].freq=parent->calcFreq(chan[2].baseFreq,chan[2].pitch,false,0,chan[2].pitch2,1,1); if (chan[2].furnaceDac) { double off=1.0; if (dacSample>=0 && dacSamplesong.sampleLen) { @@ -201,7 +201,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { } dacPos=0; dacPeriod=0; - chan[c.chan].baseFreq=parent->song.tuning*pow(2.0f,((float)(c.value+3)/12.0f)); + chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; @@ -282,7 +282,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_PERIODIC(c.value2); + int destFreq=(c.chan==2)?(parent->calcBaseFreq(1,1,c.value2,false)):(NOTE_PERIODIC(c.value2)); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -315,7 +315,11 @@ int DivPlatformMMC5::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); + if (c.chan==2) { + chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)),false); + } else { + chan[c.chan].baseFreq=NOTE_PERIODIC(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; From 47ea8132b2a0e74719a76155b1cf5727ead4b683 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Aug 2022 23:05:54 -0500 Subject: [PATCH 154/515] QSound: limit max frequency to $EFFF it appears $F000 and beyond cause glitches (#256) --- src/engine/platform/qsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index faeaf6a9d..6bc88dbf0 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -358,7 +358,7 @@ void DivPlatformQSound::tick(bool sysTick) { } } chan[i].freq=off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,440.0,4096.0); - if (chan[i].freq>0xffff) chan[i].freq=0xffff; + if (chan[i].freq>0xefff) chan[i].freq=0xefff; if (chan[i].keyOn) { rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank); rWrite(q1_reg_map[Q1V_END][i], qsound_end); From 9f8c96d45bea71aac19b4ded40e616d0f60039a3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 00:03:27 -0500 Subject: [PATCH 155/515] dev105 - prepare for Game Boy hardware sequences issue #27 --- papers/format.md | 33 +++++++++++++++++++++++++++++++++ src/engine/engine.h | 4 ++-- src/engine/instrument.cpp | 16 ++++++++++++++++ src/engine/instrument.h | 11 +++++++++-- src/engine/platform/gb.h | 7 ++++++- 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/papers/format.md b/papers/format.md index 97e22a4e5..263955022 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 105: Furance dev105 +- 104: Furnace dev104 - 103: Furnace dev103 - 102: Furnace 0.6pre1 (dev102) - 101: Furnace 0.6pre1 (dev101) @@ -813,6 +815,37 @@ size | description --- | **Sound Unit data** (>=104) 1 | use sample 1 | switch roles of phase reset timer and frequency + --- | **Game Boy envelope sequence** (>=105) + 1 | length + ??? | hardware sequence data + | size is length*3: + | 1 byte: command + | - 0: set envelope + | - 1: set sweep + | - 2: wait + | - 3: wait for release + | - 4: loop + | - 5: loop until release + | 2 bytes: data + | - for set envelope: + | - 1 byte: parameter + | - bit 4-7: volume + | - bit 3: direction + | - bit 0-2: length + | - 1 byte: sound length + | - for set sweep: + | - 1 byte: parameter + | - bit 4-6: length + | - bit 3: direction + | - bit 0-2: shift + | - 1 byte: nothing + | - for wait: + | - 1 byte: length (in ticks) + | - 1 byte: nothing + | - for wait for release: + | - 2 bytes: nothing + | - for loop/loop until release: + | - 2 bytes: position ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index 256b0c96d..f54224233 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev104" -#define DIV_ENGINE_VERSION 104 +#define DIV_VERSION "dev105" +#define DIV_ENGINE_VERSION 105 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 4d274e18c..37c6a9b2a 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -532,6 +532,13 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(su.useSample); w->writeC(su.switchRoles); + // GB hardware sequence + w->writeC(gb.hwSeqLen); + for (int i=0; gb.hwSeqLen; i++) { + w->writeC(gb.hwSeq[i].cmd); + w->writeS(gb.hwSeq[i].data); + } + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); @@ -1085,6 +1092,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { su.switchRoles=reader.readC(); } + // GB hardware sequence + if (version>=105) { + gb.hwSeqLen=reader.readC(); + for (int i=0; i Date: Sun, 7 Aug 2022 00:22:03 -0500 Subject: [PATCH 156/515] Game Boy: make channel state independent of instru --- src/engine/platform/gb.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 4067e9f17..a239ea15b 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -187,9 +187,8 @@ void DivPlatformGB::tick(bool sysTick) { } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; - DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB); if (i!=2) { - rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); + rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(chan[i].soundLen&63))); } else { if (parent->song.waveDutyIsVol) { rWrite(16+i*5+2,gbVolMap[(chan[i].std.duty.val&3)<<2]); @@ -241,7 +240,6 @@ void DivPlatformGB::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB); if (i==3) { // noise int ntPos=chan[i].baseFreq; if (ntPos<0) ntPos=0; @@ -257,8 +255,8 @@ void DivPlatformGB::tick(bool sysTick) { rWrite(16+i*5,0x80); rWrite(16+i*5+2,gbVolMap[chan[i].vol]); } else { - rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); - rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3)); + rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(chan[i].soundLen&63))); + rWrite(16+i*5+2,((chan[i].vol<<4))|(chan[i].envLen&7)|((chan[i].envDir&1)<<3)); } } if (chan[i].keyOff) { @@ -270,10 +268,10 @@ void DivPlatformGB::tick(bool sysTick) { } if (i==3) { // noise rWrite(16+i*5+3,(chan[i].freq&0xff)|(chan[i].duty?8:0)); - rWrite(16+i*5+4,((chan[i].keyOn||chan[i].keyOff)?0x80:0x00)|((ins->gb.soundLen<64)<<6)); + rWrite(16+i*5+4,((chan[i].keyOn||chan[i].keyOff)?0x80:0x00)|((chan[i].soundLen<64)<<6)); } else { rWrite(16+i*5+3,(2048-chan[i].freq)&0xff); - rWrite(16+i*5+4,(((2048-chan[i].freq)>>8)&7)|((chan[i].keyOn||chan[i].keyOff)?0x80:0x00)|((ins->gb.soundLen<63)<<6)); + rWrite(16+i*5+4,(((2048-chan[i].freq)>>8)&7)|((chan[i].keyOn||chan[i].keyOff)?0x80:0x00)|((chan[i].soundLen<63)<<6)); } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; @@ -309,6 +307,11 @@ int DivPlatformGB::dispatch(DivCommand c) { ws.changeWave1(chan[c.chan].wave); } ws.init(ins,32,15,chan[c.chan].insChanged); + } else if (chan[c.chan].insChanged) { + chan[c.chan].envVol=ins->gb.envVol; + chan[c.chan].envLen=ins->gb.envLen; + chan[c.chan].envDir=ins->gb.envDir; + chan[c.chan].soundLen=ins->gb.soundLen; } chan[c.chan].insChanged=false; break; @@ -328,9 +331,13 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].insChanged=true; if (c.chan!=2) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB); - chan[c.chan].vol=ins->gb.envVol; + chan[c.chan].envVol=ins->gb.envVol; + chan[c.chan].envLen=ins->gb.envLen; + chan[c.chan].envDir=ins->gb.envDir; + chan[c.chan].soundLen=ins->gb.soundLen; + chan[c.chan].vol=chan[c.chan].envVol; if (parent->song.gbInsAffectsEnvelope) { - rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3)); + rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(chan[c.chan].envLen&7)|((chan[c.chan].envDir&1)<<3)); } } } From 7dad9098b60e69a2fc195b28b8813c2adc7ad6d5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 00:37:35 -0500 Subject: [PATCH 157/515] Game Boy: fix wave channel --- src/engine/platform/gb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index a239ea15b..2ec9bfdf9 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -307,7 +307,8 @@ int DivPlatformGB::dispatch(DivCommand c) { ws.changeWave1(chan[c.chan].wave); } ws.init(ins,32,15,chan[c.chan].insChanged); - } else if (chan[c.chan].insChanged) { + } + if (chan[c.chan].insChanged) { chan[c.chan].envVol=ins->gb.envVol; chan[c.chan].envLen=ins->gb.envLen; chan[c.chan].envDir=ins->gb.envDir; From 1721e1d03e5a164e2a688e8213ee50d4e398166d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 00:40:26 -0500 Subject: [PATCH 158/515] Game Boy: re-enable wave corruption bug emulation --- src/engine/platform/sound/gb/apu.c | 8 ++++---- src/engine/platform/sound/gb/gb.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/sound/gb/apu.c b/src/engine/platform/sound/gb/apu.c index 4c473997f..8836ddd29 100644 --- a/src/engine/platform/sound/gb/apu.c +++ b/src/engine/platform/sound/gb/apu.c @@ -1180,11 +1180,11 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) if ((value & 0x80)) { /* DMG bug: wave RAM gets corrupted if the channel is retriggerred 1 cycle before the APU reads from it. */ - /*if (!CGB && + if (!CGB && gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.sample_countdown == 0 && gb->apu.wave_channel.enable) { - unsigned offset = ((gb->apu.wave_channel.current_sample_index + 1) >> 1) & 0xF;*/ + unsigned offset = ((gb->apu.wave_channel.current_sample_index + 1) >> 1) & 0xF; /* This glitch varies between models and even specific instances: DMG-B: Most of them behave as emulated. A few behave differently. @@ -1193,7 +1193,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) Additionally, I believe DMGs, including those we behave differently than emulated, are all deterministic. */ - /*if (offset < 4) { + if (offset < 4) { gb->io_registers[GB_IO_WAV_START] = gb->io_registers[GB_IO_WAV_START + offset]; gb->apu.wave_channel.wave_form[0] = gb->apu.wave_channel.wave_form[offset / 2]; gb->apu.wave_channel.wave_form[1] = gb->apu.wave_channel.wave_form[offset / 2 + 1]; @@ -1206,7 +1206,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) gb->apu.wave_channel.wave_form + (offset & ~3) * 2, 8); } - }*/ + } if (!gb->apu.is_active[GB_WAVE]) { gb->apu.is_active[GB_WAVE] = true; update_sample(gb, GB_WAVE, diff --git a/src/engine/platform/sound/gb/gb.h b/src/engine/platform/sound/gb/gb.h index ac817395f..ca3650852 100644 --- a/src/engine/platform/sound/gb/gb.h +++ b/src/engine/platform/sound/gb/gb.h @@ -16,7 +16,7 @@ extern "C" { #define GB_STRUCT_VERSION 13 -#define CGB 0 +#define CGB (gb->model&GB_MODEL_CGB_FAMILY) #define GB_MODEL_FAMILY_MASK 0xF00 #define GB_MODEL_DMG_FAMILY 0x000 From 45196daf95ef5feeb5fec4116664f099243dc086 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 01:32:28 -0500 Subject: [PATCH 159/515] Game Boy: fix serious typo --- src/engine/instrument.cpp | 2 +- src/engine/instrument.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 37c6a9b2a..b1afc3953 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -534,7 +534,7 @@ void DivInstrument::putInsData(SafeWriter* w) { // GB hardware sequence w->writeC(gb.hwSeqLen); - for (int i=0; gb.hwSeqLen; i++) { + for (int i=0; iwriteC(gb.hwSeq[i].cmd); w->writeS(gb.hwSeq[i].data); } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 33e2856b2..eddf9f79e 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -262,6 +262,16 @@ struct DivInstrumentSTD { struct DivInstrumentGB { unsigned char envVol, envDir, envLen, soundLen, hwSeqLen; + enum HWSeqCommands: unsigned char { + DIV_GB_HWCMD_ENVELOPE=0, + DIV_GB_HWCMD_SWEEP, + DIV_GB_HWCMD_WAIT, + DIV_GB_HWCMD_WAIT_REL, + DIV_GB_HWCMD_LOOP, + DIV_GB_HWCMD_LOOP_REL, + + DIV_GB_HWCMD_MAX + }; struct HWSeqCommand { unsigned char cmd; unsigned short data; From 800f08b0fdaac548091d3ef5745e915f1dc24d0a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 06:06:14 -0500 Subject: [PATCH 160/515] Game Boy: hardware sequences, part 1 still not working! just the UI for it --- src/gui/insEdit.cpp | 155 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8e405251e..e0c18b6c1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -284,6 +284,15 @@ const char* dualWSEffects[9]={ "Phase Modulation" }; +const char* gbHWSeqCmdTypes[6]={ + "Envelope", + "Sweep", + "Wait", + "Wait for Release", + "Loop", + "Loop until Release" +}; + const char* macroAbsoluteMode="Fixed"; const char* macroRelativeMode="Relative"; const char* macroQSoundMode="QSound"; @@ -2974,6 +2983,152 @@ void FurnaceGUI::drawInsEdit() { } drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale)); + + if (ImGui::BeginChild("HWSeq",ImGui::GetContentRegionAvail(),true,ImGuiWindowFlags_MenuBar)) { + ImGui::BeginMenuBar(); + ImGui::Text("Hardware Sequence"); + ImGui::EndMenuBar(); + + if (ins->gb.hwSeqLen>0) if (ImGui::BeginTable("HWSeqList",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + int curFrame=0; + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Tick"); + ImGui::TableNextColumn(); + ImGui::Text("Command"); + for (int i=0; igb.hwSeqLen; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d (#%d)",curFrame,i); + ImGui::TableNextColumn(); + ImGui::PushID(i); + if (ins->gb.hwSeq[i].cmd>=DivInstrumentGB::DIV_GB_HWCMD_MAX) { + ins->gb.hwSeq[i].cmd=0; + } + int cmd=ins->gb.hwSeq[i].cmd; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::Combo("##HWSeqCmd",&cmd,gbHWSeqCmdTypes,DivInstrumentGB::DIV_GB_HWCMD_MAX)) { + if (ins->gb.hwSeq[i].cmd!=cmd) { + ins->gb.hwSeq[i].cmd=cmd; + ins->gb.hwSeq[i].data=0; + } + } + bool somethingChanged=false; + switch (ins->gb.hwSeq[i].cmd) { + case DivInstrumentGB::DIV_GB_HWCMD_ENVELOPE: { + int hwsVol=(ins->gb.hwSeq[i].data&0xf0)>>4; + bool hwsDir=ins->gb.hwSeq[i].data&8; + int hwsLen=ins->gb.hwSeq[i].data&7; + int hwsSoundLen=ins->gb.hwSeq[i].data>>8; + + if (CWSliderInt("Volume",&hwsVol,0,15)) { + somethingChanged=true; + } + if (CWSliderInt("Env Length",&hwsLen,0,7)) { + somethingChanged=true; + } + if (CWSliderInt("Sound Length",&hwsSoundLen,0,64,hwsSoundLen>63?"Infinity":"%d")) { + somethingChanged=true; + } + if (ImGui::RadioButton("Up",hwsDir)) { PARAMETER + hwsDir=true; + somethingChanged=true; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Down",!hwsDir)) { PARAMETER + hwsDir=false; + somethingChanged=true; + } + + if (somethingChanged) { + ins->gb.hwSeq[i].data=(hwsLen&7)|(hwsDir?8:0)|(hwsVol<<4)|(hwsSoundLen<<8); + PARAMETER; + } + break; + } + case DivInstrumentGB::DIV_GB_HWCMD_SWEEP: { + int hwsShift=ins->gb.hwSeq[i].data&7; + int hwsSpeed=(ins->gb.hwSeq[i].data&0x70)>>4; + bool hwsDir=ins->gb.hwSeq[i].data&8; + + if (CWSliderInt("Shift",&hwsShift,0,7)) { + somethingChanged=true; + } + if (CWSliderInt("Speed",&hwsSpeed,0,7)) { + somethingChanged=true; + } + + if (ImGui::RadioButton("Up",hwsDir)) { PARAMETER + hwsDir=true; + somethingChanged=true; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Down",!hwsDir)) { PARAMETER + hwsDir=false; + somethingChanged=true; + } + + if (somethingChanged) { + ins->gb.hwSeq[i].data=(hwsShift&7)|(hwsDir?8:0)|(hwsSpeed<<4); + PARAMETER; + } + break; + } + case DivInstrumentGB::DIV_GB_HWCMD_WAIT: { + int len=ins->gb.hwSeq[i].data+1; + curFrame+=ins->gb.hwSeq[i].data+1; + + if (ImGui::InputInt("Ticks",&len)) { + if (len<1) len=1; + if (len>255) len=256; + somethingChanged=true; + } + + if (somethingChanged) { + ins->gb.hwSeq[i].data=len-1; + PARAMETER; + } + break; + } + case DivInstrumentGB::DIV_GB_HWCMD_WAIT_REL: + curFrame++; + break; + case DivInstrumentGB::DIV_GB_HWCMD_LOOP: + case DivInstrumentGB::DIV_GB_HWCMD_LOOP_REL: { + int pos=ins->gb.hwSeq[i].data; + + if (ImGui::InputInt("Position",&pos)) { + if (pos<0) pos=0; + if (pos>(ins->gb.hwSeqLen-1)) pos=(ins->gb.hwSeqLen-1); + somethingChanged=true; + } + + if (somethingChanged) { + ins->gb.hwSeq[i].data=pos; + PARAMETER; + } + break; + } + default: + break; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + + if (ImGui::Button(ICON_FA_PLUS "##HWCmdAdd")) { + if (ins->gb.hwSeqLen<255) { + ins->gb.hwSeq[ins->gb.hwSeqLen].cmd=0; + ins->gb.hwSeq[ins->gb.hwSeqLen].data=0; + ins->gb.hwSeqLen++; + } + } + + ImGui::EndChild(); + } ImGui::EndTabItem(); } if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) { From 829db187df2a70c13a700dc3eb98e3a222c82435 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 06:24:48 -0500 Subject: [PATCH 161/515] Y8950: fix ADPCM per-chan osc I think --- src/engine/platform/opl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 36dd2c66b..a32777c33 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -293,7 +293,7 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_ if (!isMuted[adpcmChan]) { os[0]-=aOut.data[0]>>3; os[1]-=aOut.data[0]>>3; - oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]+=aOut.data[0]; + oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=aOut.data[0]; } else { oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=0; } From f80488d9b0905fe90b12aa2f18b45f0f959ed173 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 17:32:39 -0500 Subject: [PATCH 162/515] minimize allocations in nextBuf --- src/engine/engine.h | 6 +++++- src/engine/playback.cpp | 39 ++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index f54224233..001ea1941 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -164,7 +164,7 @@ struct DivNoteEvent { struct DivDispatchContainer { DivDispatch* dispatch; blip_buffer_t* bb[2]; - size_t bbInLen; + size_t bbInLen, runtotal, runLeft, runPos, lastAvail; int temp[2], prevSample[2]; short* bbIn[2]; short* bbOut[2]; @@ -182,6 +182,10 @@ struct DivDispatchContainer { dispatch(NULL), bb{NULL,NULL}, bbInLen(0), + runtotal(0), + runLeft(0), + runPos(0), + lastAvail(0), temp{0,0}, prevSample{0,0}, bbIn{NULL,NULL}, diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ee9115fd8..00ae942ee 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1308,25 +1308,22 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } // logic starts here - size_t runtotal[32]; - size_t runLeft[32]; - size_t runPos[32]; - size_t lastAvail[32]; for (int i=0; i0) { - disCont[i].flush(lastAvail[i]); + disCont[i].lastAvail=blip_samples_avail(disCont[i].bb[0]); + if (disCont[i].lastAvail>0) { + disCont[i].flush(disCont[i].lastAvail); } - runtotal[i]=blip_clocks_needed(disCont[i].bb[0],size-lastAvail[i]); - if (runtotal[i]>disCont[i].bbInLen) { + disCont[i].runtotal=blip_clocks_needed(disCont[i].bb[0],size-disCont[i].lastAvail); + if (disCont[i].runtotal>disCont[i].bbInLen) { + logV("growing dispatch %d bbIn to %d",i,disCont[i].runtotal+256); delete[] disCont[i].bbIn[0]; delete[] disCont[i].bbIn[1]; - disCont[i].bbIn[0]=new short[runtotal[i]+256]; - disCont[i].bbIn[1]=new short[runtotal[i]+256]; - disCont[i].bbInLen=runtotal[i]+256; + disCont[i].bbIn[0]=new short[disCont[i].runtotal+256]; + disCont[i].bbIn[1]=new short[disCont[i].runtotal+256]; + disCont[i].bbInLen=disCont[i].runtotal+256; } - runLeft[i]=runtotal[i]; - runPos[i]=0; + disCont[i].runLeft=disCont[i].runtotal; + disCont[i].runPos=0; } if (metroTickLen>MASTER_CLOCK_PREC); for (int i=0; i Date: Sun, 7 Aug 2022 17:37:07 -0500 Subject: [PATCH 163/515] fix possible crash when closing Furnace --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index fd94e521a..bf55d9d6e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3339,6 +3339,7 @@ bool DivEngine::initAudioBackend() { bool DivEngine::deinitAudioBackend() { if (output!=NULL) { + output->quit(); if (output->midiIn) { if (output->midiIn->isDeviceOpen()) { logI("closing MIDI input."); @@ -3352,7 +3353,6 @@ bool DivEngine::deinitAudioBackend() { } } output->quitMidi(); - output->quit(); delete output; output=NULL; //audioEngine=DIV_AUDIO_NULL; From 1c92d23d27965a230de25328a373ce811a312f33 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 7 Aug 2022 17:40:01 -0500 Subject: [PATCH 164/515] commands view now only displays useful commands --- src/engine/playback.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 00ae942ee..3ba4f1417 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -211,7 +211,27 @@ const char* formatNote(unsigned char note, unsigned char octave) { int DivEngine::dispatchCmd(DivCommand c) { if (view==DIV_STATUS_COMMANDS) { - if (!skipping) printf("%8d | %d: %s(%d, %d)\n",totalTicksR,c.chan,cmdName[c.cmd],c.value,c.value2); + if (!skipping) { + switch (c.cmd) { + // strip away hinted/useless commands + case DIV_ALWAYS_SET_VOLUME: + break; + case DIV_CMD_GET_VOLUME: + break; + case DIV_CMD_VOLUME: + break; + case DIV_CMD_NOTE_PORTA: + break; + case DIV_CMD_LEGATO: + break; + case DIV_CMD_PITCH: + break; + case DIV_CMD_PRE_NOTE: + break; + default: + printf("%8d | %d: %s(%d, %d)\n",totalTicksR,c.chan,cmdName[c.cmd],c.value,c.value2); + } + } } totalCmds++; if (cmdStreamEnabled && cmdStream.size()<2000) { From 2af4992e9b785d4944c766317ea077b5533af027 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 8 Aug 2022 00:25:05 -0500 Subject: [PATCH 165/515] JACK: fix crash when changing buffer size --- src/audio/jack.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/audio/jack.cpp b/src/audio/jack.cpp index 6e7b7bf1f..f9502cf4f 100644 --- a/src/audio/jack.cpp +++ b/src/audio/jack.cpp @@ -52,17 +52,30 @@ void TAAudioJACK::onBufferSize(jack_nframes_t bufsize) { } void TAAudioJACK::onProcess(jack_nframes_t nframes) { - if (audioProcCallback!=NULL) { - if (midiIn!=NULL) midiIn->gather(); - audioProcCallback(audioProcCallbackUser,inBufs,outBufs,desc.inChans,desc.outChans,desc.bufsize); - } for (int i=0; idesc.bufsize) { + delete[] inBufs[i]; + inBufs[i]=new float[nframes]; + } + memcpy(iInBufs[i],inBufs[i],nframes*sizeof(float)); + } + for (int i=0; idesc.bufsize) { + delete[] outBufs[i]; + outBufs[i]=new float[nframes]; + } + } + if (audioProcCallback!=NULL) { + if (midiIn!=NULL) midiIn->gather(); + audioProcCallback(audioProcCallbackUser,inBufs,outBufs,desc.inChans,desc.outChans,nframes); } for (int i=0; i Date: Tue, 9 Aug 2022 14:53:31 -0500 Subject: [PATCH 166/515] i guess to anybody who bothers reading the contents of this commit: who cares? you promised me C163 would become the name but nobody has bothered to call it C163 for an entire week. there's no point on pushing a dead idea forward! --- papers/doc/7-systems/README.md | 2 +- papers/doc/7-systems/n163.md | 22 +--------------------- src/engine/platform/gb.h | 5 ++++- src/gui/about.cpp | 2 +- src/gui/guiConst.cpp | 2 +- src/gui/presets.cpp | 4 ++-- src/gui/settings.cpp | 3 +-- 7 files changed, 11 insertions(+), 29 deletions(-) diff --git a/papers/doc/7-systems/README.md b/papers/doc/7-systems/README.md index e4b6cf5b9..c4dc6d493 100644 --- a/papers/doc/7-systems/README.md +++ b/papers/doc/7-systems/README.md @@ -26,7 +26,7 @@ this is a list of systems that Furnace supports, including each system's effects - [Seta/Allumer X1-010](x1-010.md) - [WonderSwan](wonderswan.md) - [Bubble System WSG](bubblesystem.md) -- [Namco C163](n163.md) +- [Namco 163](n163.md) - [Namco WSG](namco.md) - [Yamaha OPL](opl.md) - [PC Speaker](pcspkr.md) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index d3ece830f..3c2f389f9 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,24 +1,4 @@ -# - ANNOUNCEMENT - - -Start calling it C163! The TRUE name of the chip! - -The line will be consistent with your help: -- Namco C15 -- Namco C30 -- Namco C140 -- **Namco C163** -- Namco C219 -- Namco C352 - -The C names are official as indicated by: - -- MAME -- VGMPlay -- Korg × Bandai Namco (from Kamata info page) - -C stands for Custom! Call it C163! - -# Namco 163 (also called Namco C163, 106, 160 or 129) +# Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 128 byte of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consumes 8 bytes for each channel. You must avoid conflict with channel register area and waveform for avoid broken channel playback. diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index d4f6ca536..58cce8805 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -32,6 +32,7 @@ class DivPlatformGB: public DivDispatch { bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta; signed char vol, outVol, wave; unsigned char envVol, envDir, envLen, soundLen; + unsigned short hwSeqPos, hwSeqDelay; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -59,7 +60,9 @@ class DivPlatformGB: public DivDispatch { envVol(0), envDir(0), envLen(0), - soundLen(0) {} + soundLen(0), + hwSeqPos(0), + hwSeqDelay(0) {} }; Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; diff --git a/src/gui/about.cpp b/src/gui/about.cpp index e65413fce..587aba84d 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -135,7 +135,7 @@ const char* aboutLine[]={ "VICE VIC-20 sound core by Rami Rasanen and viznut", "VERA sound core by Frank van den Hoef", "K005289 emulator by cam900", - "Namco C163 emulator by cam900", + "Namco 163 emulator by cam900", "Seta X1-010 emulator by cam900", "Konami VRC6 emulator by cam900", "Konami SCC emulator by cam900", diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 6c0bb891b..59c917ae0 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -97,7 +97,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "FM (OPL)", "FDS", "Virtual Boy", - "Namco C163", + "Namco 163", "Konami SCC/Bubble System WSG", "FM (OPZ)", "POKEY", diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index f8e7a522c..571cda441 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -409,7 +409,7 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "Namco C163", { + "Namco 163", { DIV_SYSTEM_N163, 64, 0, 0, 0 } @@ -617,7 +617,7 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "Famicom with Namco C163", { + "Famicom with Namco 163", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_N163, 64, 0, 112, 0 diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 2ad3ef23c..73e9d2333 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1201,7 +1201,7 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); - ImGui::Text("N163/C163 chip name"); + ImGui::Text("Namco 163 chip name"); ImGui::SameLine(); ImGui::InputTextWithHint("##C163Name",DIV_C163_DEFAULT_NAME,&settings.c163Name); @@ -2028,7 +2028,6 @@ void FurnaceGUI::syncSettings() { settings.audioDevice=e->getConfString("audioDevice",""); settings.midiInDevice=e->getConfString("midiInDevice",""); settings.midiOutDevice=e->getConfString("midiOutDevice",""); - // I'm sorry, but the C163 education program has failed... settings.c163Name=e->getConfString("c163Name",DIV_C163_DEFAULT_NAME); settings.audioQuality=e->getConfInt("audioQuality",0); settings.audioBufSize=e->getConfInt("audioBufSize",1024); From 28698beaf3cad3abb11c77c84da28acf7354921d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 01:55:44 -0500 Subject: [PATCH 167/515] dev106 - Game Boy: implement hw seq and prepare for software envelope maybe --- TODO.md | 1 - papers/format.md | 6 +++- src/engine/engine.h | 4 +-- src/engine/instrument.cpp | 10 +++++++ src/engine/instrument.h | 5 +++- src/engine/platform/gb.cpp | 57 +++++++++++++++++++++++++++++++++++++- src/engine/platform/gb.h | 6 ++-- src/gui/insEdit.cpp | 17 ++++++++---- 8 files changed, 93 insertions(+), 13 deletions(-) diff --git a/TODO.md b/TODO.md index 46773705a..13f31300e 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1.5-0.6pre2 -- Game Boy envelope macro/sequence - volume commands should work on Game Boy - ability to customize `OFF`, `===` and `REL` - stereo separation control for AY diff --git a/papers/format.md b/papers/format.md index 263955022..1a8cd7219 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,7 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: -- 105: Furance dev105 +- 106: Furnace dev106 +- 105: Furnace dev105 - 104: Furnace dev104 - 103: Furnace dev103 - 102: Furnace 0.6pre1 (dev102) @@ -846,6 +847,9 @@ size | description | - 2 bytes: nothing | - for loop/loop until release: | - 2 bytes: position + --- | **Game Boy extra flags** (>=106) + 1 | use software envelope + 1 | always init hard env on new note ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index 001ea1941..483ebcf0d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev105" -#define DIV_ENGINE_VERSION 105 +#define DIV_VERSION "dev106" +#define DIV_ENGINE_VERSION 106 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index b1afc3953..555d7d17f 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -539,6 +539,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeS(gb.hwSeq[i].data); } + // GB additional flags + w->writeC(gb.softEnv); + w->writeC(gb.alwaysInit); + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); @@ -1101,6 +1105,12 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { } } + // GB additional flags + if (version>=106) { + gb.softEnv=reader.readC(); + gb.alwaysInit=reader.readC(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index eddf9f79e..df7a6b361 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -262,6 +262,7 @@ struct DivInstrumentSTD { struct DivInstrumentGB { unsigned char envVol, envDir, envLen, soundLen, hwSeqLen; + bool softEnv, alwaysInit; enum HWSeqCommands: unsigned char { DIV_GB_HWCMD_ENVELOPE=0, DIV_GB_HWCMD_SWEEP, @@ -281,7 +282,9 @@ struct DivInstrumentGB { envDir(0), envLen(2), soundLen(64), - hwSeqLen(0) { + hwSeqLen(0), + softEnv(false), + alwaysInit(false) { memset(hwSeq,0,256*sizeof(int)); } }; diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 2ec9bfdf9..5b7393ef3 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -233,12 +233,61 @@ void DivPlatformGB::tick(bool sysTick) { } } } + // run hardware sequence + if (chan[i].active) { + if (--chan[i].hwSeqDelay<=0) { + chan[i].hwSeqDelay=0; + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB); + int hwSeqCount=0; + while (chan[i].hwSeqPosgb.hwSeqLen && hwSeqCount<4) { + bool leave=false; + unsigned short data=ins->gb.hwSeq[chan[i].hwSeqPos].data; + switch (ins->gb.hwSeq[chan[i].hwSeqPos].cmd) { + case DivInstrumentGB::DIV_GB_HWCMD_ENVELOPE: + chan[i].envLen=data&7; + chan[i].envDir=(data&8)?1:0; + chan[i].envVol=(data>>4)&15; + chan[i].soundLen=data>>8; + chan[i].keyOn=true; + break; + case DivInstrumentGB::DIV_GB_HWCMD_SWEEP: + chan[i].sweep=data; + chan[i].sweepChanged=true; + break; + case DivInstrumentGB::DIV_GB_HWCMD_WAIT: + chan[i].hwSeqDelay=data+1; + leave=true; + break; + case DivInstrumentGB::DIV_GB_HWCMD_WAIT_REL: + if (!chan[i].released) { + chan[i].hwSeqPos--; + leave=true; + } + break; + case DivInstrumentGB::DIV_GB_HWCMD_LOOP: + chan[i].hwSeqPos=data-1; + break; + case DivInstrumentGB::DIV_GB_HWCMD_LOOP_REL: + if (!chan[i].released) { + chan[i].hwSeqPos=data-1; + } + break; + } + + chan[i].hwSeqPos++; + if (leave) break; + hwSeqCount++; + } + } + } + if (chan[i].sweepChanged) { chan[i].sweepChanged=false; if (i==0) { rWrite(16+i*5,chan[i].sweep); } } + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (i==3) { // noise int ntPos=chan[i].baseFreq; @@ -300,6 +349,9 @@ int DivPlatformGB::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; + chan[c.chan].hwSeqPos=0; + chan[c.chan].hwSeqDelay=0; + chan[c.chan].released=false; chan[c.chan].macroInit(ins); if (c.chan==2) { if (chan[c.chan].wave<0) { @@ -308,7 +360,7 @@ int DivPlatformGB::dispatch(DivCommand c) { } ws.init(ins,32,15,chan[c.chan].insChanged); } - if (chan[c.chan].insChanged) { + if (chan[c.chan].insChanged || ins->gb.alwaysInit) { chan[c.chan].envVol=ins->gb.envVol; chan[c.chan].envLen=ins->gb.envLen; chan[c.chan].envDir=ins->gb.envDir; @@ -320,11 +372,14 @@ int DivPlatformGB::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; + chan[c.chan].hwSeqPos=0; + chan[c.chan].hwSeqDelay=0; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: chan[c.chan].std.release(); + chan[c.chan].released=true; break; case DIV_CMD_INSTRUMENT: if (chan[c.chan].ins!=c.value || c.value2==1) { diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 58cce8805..a4432f1e7 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -29,10 +29,11 @@ class DivPlatformGB: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, ins; unsigned char duty, sweep; - bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta; + bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released; signed char vol, outVol, wave; unsigned char envVol, envDir, envLen, soundLen; - unsigned short hwSeqPos, hwSeqDelay; + unsigned short hwSeqPos; + short hwSeqDelay; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -54,6 +55,7 @@ class DivPlatformGB: public DivDispatch { keyOn(false), keyOff(false), inPorta(false), + released(false), vol(15), outVol(15), wave(-1), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index e0c18b6c1..ce9406ba1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2965,6 +2965,10 @@ void FurnaceGUI::drawInsEdit() { } } if (ins->type==DIV_INS_GB) if (ImGui::BeginTabItem("Game Boy")) { + P(ImGui::Checkbox("Use software envelope",&ins->gb.softEnv)); + P(ImGui::Checkbox("Initialize envelope on every note",&ins->gb.alwaysInit)); + + ImGui::BeginDisabled(ins->gb.softEnv); P(CWSliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable P(CWSliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable @@ -3060,13 +3064,13 @@ void FurnaceGUI::drawInsEdit() { somethingChanged=true; } - if (ImGui::RadioButton("Up",hwsDir)) { PARAMETER - hwsDir=true; + if (ImGui::RadioButton("Up",!hwsDir)) { PARAMETER + hwsDir=false; somethingChanged=true; } ImGui::SameLine(); - if (ImGui::RadioButton("Down",!hwsDir)) { PARAMETER - hwsDir=false; + if (ImGui::RadioButton("Down",hwsDir)) { PARAMETER + hwsDir=true; somethingChanged=true; } @@ -3128,6 +3132,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndChild(); + ImGui::EndDisabled(); } ImGui::EndTabItem(); } @@ -3689,8 +3694,10 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { volMax=127; } - if (ins->type==DIV_INS_GB) { + if (ins->type==DIV_INS_GB && !ins->gb.softEnv) { volMax=0; + } else { + volMax=15; } if (ins->type==DIV_INS_PET || ins->type==DIV_INS_BEEPER) { volMax=1; From df10b6cc5952926e4a1c81dcd87fc58d0b074392 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 14:16:26 -0500 Subject: [PATCH 168/515] Game Boy: hardware sequences, part 3 the previous commit was part 2 --- src/gui/insEdit.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ce9406ba1..0d90e3733 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2993,15 +2993,18 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Hardware Sequence"); ImGui::EndMenuBar(); - if (ins->gb.hwSeqLen>0) if (ImGui::BeginTable("HWSeqList",2)) { + if (ins->gb.hwSeqLen>0) if (ImGui::BeginTable("HWSeqList",3)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); int curFrame=0; ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::Text("Tick"); ImGui::TableNextColumn(); ImGui::Text("Command"); + ImGui::TableNextColumn(); + ImGui::Text("Move/Remove"); for (int i=0; igb.hwSeqLen; i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -3119,6 +3122,46 @@ void FurnaceGUI::drawInsEdit() { break; } ImGui::PopID(); + ImGui::TableNextColumn(); + ImGui::PushID(i+512); + if (ImGui::Button(ICON_FA_CHEVRON_UP "##HWCmdUp")) { + if (i>0) { + e->lockEngine([ins,i]() { + ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; + ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i-1].cmd; + ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; + + ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; + ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i-1].data; + ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; + }); + } + MARK_MODIFIED; + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_CHEVRON_DOWN "##HWCmdDown")) { + if (igb.hwSeqLen-1) { + e->lockEngine([ins,i]() { + ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; + ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i-1].cmd; + ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; + + ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; + ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i-1].data; + ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; + }); + } + MARK_MODIFIED; + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_TIMES "##HWCmdDel")) { + for (int j=i; jgb.hwSeqLen-1; j++) { + ins->gb.hwSeq[j].cmd=ins->gb.hwSeq[j+1].cmd; + ins->gb.hwSeq[j].data=ins->gb.hwSeq[j+1].data; + } + ins->gb.hwSeqLen--; + } + ImGui::PopID(); } ImGui::EndTable(); } From 6bcb3063a59f40df4cfbe3d350c67d57b016ad71 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 15:41:52 -0500 Subject: [PATCH 169/515] add OPZ disclaimer in docs --- papers/doc/7-systems/opz.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/papers/doc/7-systems/opz.md b/papers/doc/7-systems/opz.md index 61e931394..c7952a55b 100644 --- a/papers/doc/7-systems/opz.md +++ b/papers/doc/7-systems/opz.md @@ -1,5 +1,7 @@ # Yamaha OPZ (YM2414) +**disclaimer: despite the name, this has nothing to do with teenage engineering's OP-Z synth!** + this is the YM2151's little-known successor, used in the Yamaha TX81Z and a few other Yamaha synthesizers. oh, and the Korg Z3 too. it adds these features on top of the YM2151: From bccecc4c07ba59eee23507590ba627e720795588 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 16:27:29 -0500 Subject: [PATCH 170/515] Game Boy: software envelopes, part 1 --- src/engine/fileOps.cpp | 5 +++-- src/engine/platform/gb.cpp | 41 ++++++++++++++++++++++++++------------ src/engine/platform/gb.h | 3 ++- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 8dcd55d22..db2305c65 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -590,7 +590,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { logD("GB data: vol %d dir %d len %d sl %d",ins->gb.envVol,ins->gb.envDir,ins->gb.envLen,ins->gb.soundLen); } else if (ds.system[0]==DIV_SYSTEM_GB) { - // try to convert macro to envelope + // set software envelope flag + ins->gb.softEnv=true; + // try to convert macro to envelope in case the user decides to switch to them if (ins->std.volMacro.len>0) { ins->gb.envVol=ins->std.volMacro.val[0]; if (ins->std.volMacro.val[0]std.volMacro.val[1]) { @@ -600,7 +602,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->gb.soundLen=ins->std.volMacro.len*2; } } - addWarning("Game Boy volume macros converted to envelopes. may not be perfect!"); } } diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 5b7393ef3..aa95d6cbd 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -160,6 +160,16 @@ void DivPlatformGB::tick(bool sysTick) { for (int i=0; i<4; i++) { chan[i].std.next(); + if (chan[i].softEnv) { + if (chan[i].std.vol.had) { + chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); + if (chan[i].outVol<0) chan[i].outVol=0; + + // temporary until zombie mode is implemented + chan[i].vol=chan[i].outVol; + chan[i].keyOn=true; + } + } if (chan[i].std.arp.had) { if (i==3) { // noise if (chan[i].std.arp.mode) { @@ -189,7 +199,7 @@ void DivPlatformGB::tick(bool sysTick) { chan[i].duty=chan[i].std.duty.val; if (i!=2) { rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(chan[i].soundLen&63))); - } else { + } else if (!chan[i].softEnv) { if (parent->song.waveDutyIsVol) { rWrite(16+i*5+2,gbVolMap[(chan[i].std.duty.val&3)<<2]); } @@ -244,11 +254,13 @@ void DivPlatformGB::tick(bool sysTick) { unsigned short data=ins->gb.hwSeq[chan[i].hwSeqPos].data; switch (ins->gb.hwSeq[chan[i].hwSeqPos].cmd) { case DivInstrumentGB::DIV_GB_HWCMD_ENVELOPE: - chan[i].envLen=data&7; - chan[i].envDir=(data&8)?1:0; - chan[i].envVol=(data>>4)&15; - chan[i].soundLen=data>>8; - chan[i].keyOn=true; + if (!chan[i].softEnv) { + chan[i].envLen=data&7; + chan[i].envDir=(data&8)?1:0; + chan[i].envVol=(data>>4)&15; + chan[i].soundLen=data>>8; + chan[i].keyOn=true; + } break; case DivInstrumentGB::DIV_GB_HWCMD_SWEEP: chan[i].sweep=data; @@ -352,6 +364,7 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].hwSeqPos=0; chan[c.chan].hwSeqDelay=0; chan[c.chan].released=false; + chan[c.chan].softEnv=ins->gb.softEnv; chan[c.chan].macroInit(ins); if (c.chan==2) { if (chan[c.chan].wave<0) { @@ -387,13 +400,15 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].insChanged=true; if (c.chan!=2) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB); - chan[c.chan].envVol=ins->gb.envVol; - chan[c.chan].envLen=ins->gb.envLen; - chan[c.chan].envDir=ins->gb.envDir; - chan[c.chan].soundLen=ins->gb.soundLen; - chan[c.chan].vol=chan[c.chan].envVol; - if (parent->song.gbInsAffectsEnvelope) { - rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(chan[c.chan].envLen&7)|((chan[c.chan].envDir&1)<<3)); + if (!ins->gb.softEnv) { + chan[c.chan].envVol=ins->gb.envVol; + chan[c.chan].envLen=ins->gb.envLen; + chan[c.chan].envDir=ins->gb.envDir; + chan[c.chan].soundLen=ins->gb.soundLen; + chan[c.chan].vol=chan[c.chan].envVol; + if (parent->song.gbInsAffectsEnvelope) { + rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(chan[c.chan].envLen&7)|((chan[c.chan].envDir&1)<<3)); + } } } } diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index a4432f1e7..082f33ba9 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -29,7 +29,7 @@ class DivPlatformGB: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, ins; unsigned char duty, sweep; - bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released; + bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released, softEnv; signed char vol, outVol, wave; unsigned char envVol, envDir, envLen, soundLen; unsigned short hwSeqPos; @@ -56,6 +56,7 @@ class DivPlatformGB: public DivDispatch { keyOff(false), inPorta(false), released(false), + softEnv(false), vol(15), outVol(15), wave(-1), From 4b18d0920bbde8e0887beab27c302a24026bcfd0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 17:02:45 -0500 Subject: [PATCH 171/515] Game Boy: software envelopes, part 2 --- src/engine/platform/gb.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index aa95d6cbd..875304023 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -166,7 +166,10 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].outVol<0) chan[i].outVol=0; // temporary until zombie mode is implemented - chan[i].vol=chan[i].outVol; + chan[i].envLen=0; + chan[i].envDir=0; + chan[i].envVol=chan[i].outVol; + chan[i].soundLen=64; chan[i].keyOn=true; } } @@ -314,10 +317,10 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].keyOn) { if (i==2) { // wave rWrite(16+i*5,0x80); - rWrite(16+i*5+2,gbVolMap[chan[i].vol]); + rWrite(16+i*5+2,gbVolMap[chan[i].outVol]); } else { rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(chan[i].soundLen&63))); - rWrite(16+i*5+2,((chan[i].vol<<4))|(chan[i].envLen&7)|((chan[i].envDir&1)<<3)); + rWrite(16+i*5+2,((chan[i].envVol<<4))|(chan[i].envLen&7)|((chan[i].envDir&1)<<3)); } } if (chan[i].keyOff) { @@ -406,6 +409,7 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].envDir=ins->gb.envDir; chan[c.chan].soundLen=ins->gb.soundLen; chan[c.chan].vol=chan[c.chan].envVol; + chan[c.chan].outVol=chan[c.chan].vol; if (parent->song.gbInsAffectsEnvelope) { rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(chan[c.chan].envLen&7)|((chan[c.chan].envDir&1)<<3)); } @@ -415,8 +419,9 @@ int DivPlatformGB::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: chan[c.chan].vol=c.value; + chan[c.chan].outVol=c.value; if (c.chan==2) { - rWrite(16+c.chan*5+2,gbVolMap[chan[c.chan].vol]); + rWrite(16+c.chan*5+2,gbVolMap[chan[c.chan].outVol]); } break; case DIV_CMD_GET_VOLUME: From 51db06298bfcdbcb4e197407e00d6510e2585d43 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 23:53:47 -0500 Subject: [PATCH 172/515] Game Boy: fix volume regression --- src/engine/platform/gb.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 875304023..abbb19336 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -423,6 +423,9 @@ int DivPlatformGB::dispatch(DivCommand c) { if (c.chan==2) { rWrite(16+c.chan*5+2,gbVolMap[chan[c.chan].outVol]); } + if (!chan[c.chan].softEnv) { + chan[c.chan].envVol=chan[c.chan].vol; + } break; case DIV_CMD_GET_VOLUME: return chan[c.chan].vol; From 92f40774e4c87675a659c931cb74001bafc9ef01 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 10 Aug 2022 23:56:25 -0500 Subject: [PATCH 173/515] Game Boy: I hate your artificial limitations fixes a DefleMask demo module --- src/engine/platform/gb.cpp | 4 ++++ src/engine/platform/gb.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index abbb19336..31ce24240 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -573,6 +573,10 @@ void DivPlatformGB::reset() { antiClickWavePos=0; } +int DivPlatformGB::getPortaFloor(int ch) { + return 24; +} + bool DivPlatformGB::isStereo() { return true; } diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 082f33ba9..e4b8568b1 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -94,6 +94,7 @@ class DivPlatformGB: public DivDispatch { void forceIns(); void tick(bool sysTick=true); void muteChannel(int ch, bool mute); + int getPortaFloor(int ch); bool isStereo(); void notifyInsChange(int ins); void notifyWaveChange(int wave); From 340052cf0a50f6a848d5c545df4ada5a6c077283 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 00:46:15 -0500 Subject: [PATCH 174/515] Game Boy: add chip revision flag --- src/engine/platform/gb.cpp | 35 ++++++++++++++++++++++++++++++----- src/engine/platform/gb.h | 9 +++++++++ src/gui/sysConf.cpp | 13 +++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 31ce24240..39ccaf56c 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -21,8 +21,8 @@ #include "../engine.h" #include -#define rWrite(a,v) if (!skipRegisterWrites) {GB_apu_write(gb,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } -#define immWrite(a,v) {GB_apu_write(gb,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } +#define immWrite(a,v) {writes.emplace(a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } #define CHIP_DIVIDER 16 @@ -84,6 +84,12 @@ const char* DivPlatformGB::getEffectName(unsigned char effect) { void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; iapu_output.final_sample.left; bufR[i]=gb->apu_output.final_sample.right; @@ -97,8 +103,8 @@ void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) void DivPlatformGB::updateWave() { rWrite(0x1a,0); for (int i=0; i<16; i++) { - int nibble1=15-ws.output[((i<<1)+antiClickWavePos)&31]; - int nibble2=15-ws.output[((1+(i<<1))+antiClickWavePos)&31]; + int nibble1=15-ws.output[((i<<1)+antiClickWavePos-1)&31]; + int nibble2=15-ws.output[((1+(i<<1))+antiClickWavePos-1)&31]; rWrite(0x30+i,(nibble1<<4)|nibble2); } antiClickWavePos&=31; @@ -559,7 +565,7 @@ void DivPlatformGB::reset() { } memset(gb,0,sizeof(GB_gameboy_t)); memset(regPool,0,128); - gb->model=GB_MODEL_DMG_B; + gb->model=model; GB_apu_init(gb); GB_set_sample_rate(gb,rate); // enable all channels @@ -581,6 +587,10 @@ bool DivPlatformGB::isStereo() { return true; } +bool DivPlatformGB::getDCOffRequired() { + return (model==GB_MODEL_AGB); +} + void DivPlatformGB::notifyInsChange(int ins) { for (int i=0; i<4; i++) { if (chan[i].ins==ins) { @@ -613,6 +623,20 @@ void DivPlatformGB::poke(std::vector& wlist) { void DivPlatformGB::setFlags(unsigned int flags) { antiClickEnabled=!(flags&8); + switch (flags&3) { + case 0: + model=GB_MODEL_DMG_B; + break; + case 1: + model=GB_MODEL_CGB_C; + break; + case 2: + model=GB_MODEL_CGB_E; + break; + case 3: + model=GB_MODEL_AGB; + break; + } } int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -626,6 +650,7 @@ int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, unsigned int fl parent=p; dumpWrites=false; skipRegisterWrites=false; + model=GB_MODEL_DMG_B; gb=new GB_gameboy_t; setFlags(flags); reset(); diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index e4b8568b1..ce582979f 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -24,6 +24,7 @@ #include "../macroInt.h" #include "../waveSynth.h" #include "sound/gb/gb.h" +#include class DivPlatformGB: public DivDispatch { struct Channel { @@ -73,10 +74,17 @@ class DivPlatformGB: public DivDispatch { bool antiClickEnabled; unsigned char lastPan; DivWaveSynth ws; + struct QueuedWrite { + unsigned char addr; + unsigned char val; + QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {} + }; + std::queue writes; int antiClickPeriodCount, antiClickWavePos; GB_gameboy_t* gb; + GB_model_t model; unsigned char regPool[128]; unsigned char procMute(); @@ -96,6 +104,7 @@ class DivPlatformGB: public DivDispatch { void muteChannel(int ch, bool mute); int getPortaFloor(int ch); bool isStereo(); + bool getDCOffRequired(); void notifyInsChange(int ins); void notifyWaveChange(int wave); void notifyInsDeletion(void* ins); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 3259f00c0..484490348 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -185,6 +185,19 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::Checkbox("Disable anti-click",&antiClick)) { copyOfFlags=(flags&(~8))|(antiClick<<3); } + ImGui::Text("Chip revision:"); + if (ImGui::RadioButton("Original (DMG)",(flags&7)==0)) { + copyOfFlags=(flags&(~7))|0; + } + if (ImGui::RadioButton("Game Boy Color (rev C)",(flags&7)==1)) { + copyOfFlags=(flags&(~7))|1; + } + if (ImGui::RadioButton("Game Boy Color (rev E)",(flags&7)==2)) { + copyOfFlags=(flags&(~7))|2; + } + if (ImGui::RadioButton("Game Boy Advance",(flags&7)==3)) { + copyOfFlags=(flags&(~7))|3; + } break; } case DIV_SYSTEM_OPLL: From d30f9bc8a02f80d337ba6239b7d1a38d8152c96b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 01:24:53 -0500 Subject: [PATCH 175/515] Game Boy: software envelopes, part 3 zombie mode --- src/engine/platform/gb.cpp | 29 +++++++++++++++++++++++++---- src/engine/platform/gb.h | 6 ++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 39ccaf56c..2fad226ae 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -171,12 +171,13 @@ void DivPlatformGB::tick(bool sysTick) { chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); if (chan[i].outVol<0) chan[i].outVol=0; - // temporary until zombie mode is implemented chan[i].envLen=0; - chan[i].envDir=0; + chan[i].envDir=1; chan[i].envVol=chan[i].outVol; chan[i].soundLen=64; - chan[i].keyOn=true; + + if (!chan[i].keyOn) chan[i].killIt=true; + chan[i].freqChanged=true; } } if (chan[i].std.arp.had) { @@ -327,6 +328,7 @@ void DivPlatformGB::tick(bool sysTick) { } else { rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(chan[i].soundLen&63))); rWrite(16+i*5+2,((chan[i].envVol<<4))|(chan[i].envLen&7)|((chan[i].envDir&1)<<3)); + chan[i].lastKill=chan[i].envVol; } } if (chan[i].keyOff) { @@ -346,6 +348,25 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; chan[i].freqChanged=false; + + if (chan[i].killIt) { + if (i!=2) { + //rWrite(16+i*5+2,8); + int killDelta=chan[i].lastKill-chan[i].outVol+1; + if (killDelta<0) killDelta+=16; + chan[i].lastKill=chan[i].outVol; + + if (killDelta!=1) { + rWrite(16+i*5+2,((chan[i].envVol<<4))|8); + for (int j=0; jgb.alwaysInit) { + if ((chan[c.chan].insChanged || ins->gb.alwaysInit) && !chan[c.chan].softEnv) { chan[c.chan].envVol=ins->gb.envVol; chan[c.chan].envLen=ins->gb.envLen; chan[c.chan].envDir=ins->gb.envDir; diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index ce582979f..9498317bd 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -30,8 +30,8 @@ class DivPlatformGB: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, ins; unsigned char duty, sweep; - bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released, softEnv; - signed char vol, outVol, wave; + bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released, softEnv, killIt; + signed char vol, outVol, wave, lastKill; unsigned char envVol, envDir, envLen, soundLen; unsigned short hwSeqPos; short hwSeqDelay; @@ -58,9 +58,11 @@ class DivPlatformGB: public DivDispatch { inPorta(false), released(false), softEnv(false), + killIt(false), vol(15), outVol(15), wave(-1), + lastKill(0), envVol(0), envDir(0), envLen(0), From 7e7a5a8e3037cdf0415a1db3adb512ad04a4fc9e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 01:34:18 -0500 Subject: [PATCH 176/515] Game Boy: software envelopes, part 4 fixes --- src/engine/platform/gb.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 2fad226ae..3797d5bca 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -171,13 +171,17 @@ void DivPlatformGB::tick(bool sysTick) { chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); if (chan[i].outVol<0) chan[i].outVol=0; - chan[i].envLen=0; - chan[i].envDir=1; - chan[i].envVol=chan[i].outVol; - chan[i].soundLen=64; + if (i==2) { + rWrite(16+i*5+2,gbVolMap[chan[i].outVol]); + } else { + chan[i].envLen=0; + chan[i].envDir=1; + chan[i].envVol=chan[i].outVol; + chan[i].soundLen=64; - if (!chan[i].keyOn) chan[i].killIt=true; - chan[i].freqChanged=true; + if (!chan[i].keyOn) chan[i].killIt=true; + chan[i].freqChanged=true; + } } } if (chan[i].std.arp.had) { @@ -452,6 +456,10 @@ int DivPlatformGB::dispatch(DivCommand c) { } if (!chan[c.chan].softEnv) { chan[c.chan].envVol=chan[c.chan].vol; + } else if (c.chan!=2) { + chan[c.chan].envVol=chan[c.chan].vol; + if (!chan[c.chan].keyOn) chan[c.chan].killIt=true; + chan[c.chan].freqChanged=true; } break; case DIV_CMD_GET_VOLUME: From ed98df91d284b0c9d37515ac54d80c6fa8eb7ee4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 02:05:05 -0500 Subject: [PATCH 177/515] turn on proper noise layout by default --- src/engine/song.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/song.h b/src/engine/song.h index 8375fc561..8b7eaa59f 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -562,7 +562,7 @@ struct DivSong { linearPitch(2), pitchSlideSpeed(4), loopModality(0), - properNoiseLayout(false), + properNoiseLayout(true), waveDutyIsVol(false), resetMacroOnPorta(false), legacyVolumeSlides(false), From 762b3b292845cea80acbdb8b22c1bef2bc2a1ce5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 02:08:24 -0500 Subject: [PATCH 178/515] PCE: per-chan osc DAC mode overflow fix --- src/engine/platform/pce.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 5d9a0de88..3fc7a05bd 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -115,7 +115,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) pce->ResetTS(0); for (int i=0; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1])<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP((pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1])<<1,-32768,32767); } tempL[0]=(tempL[0]>>1)+(tempL[0]>>2); From 81482c2f2be021b58f605c49060500e9646c6613 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 04:50:16 -0500 Subject: [PATCH 179/515] QSound: SAMPLE LOOP BUG DEBUG BEGIN --- src/engine/platform/qsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 6bc88dbf0..ca6a794cd 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -365,7 +365,7 @@ void DivPlatformQSound::tick(bool sysTick) { rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); rWrite(q1_reg_map[Q1V_START][i], qsound_addr); rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); - //logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); + logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume if (!chan[i].std.vol.had) { rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4); From 0528f4e7bde0d04609d37ed0d6a3f9205de7f2d8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 05:04:35 -0500 Subject: [PATCH 180/515] Game Boy: possibly fix wave soft env --- src/engine/platform/gb.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 3797d5bca..0a8b624c9 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -173,6 +173,7 @@ void DivPlatformGB::tick(bool sysTick) { if (i==2) { rWrite(16+i*5+2,gbVolMap[chan[i].outVol]); + chan[i].soundLen=64; } else { chan[i].envLen=0; chan[i].envDir=1; @@ -413,6 +414,9 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].envDir=ins->gb.envDir; chan[c.chan].soundLen=ins->gb.soundLen; } + if (c.chan==2 && chan[c.chan].softEnv) { + chan[c.chan].soundLen=64; + } chan[c.chan].insChanged=false; break; } From 01d1556fb496675927a8c4b1fd5e1ee694b792e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 05:38:31 -0500 Subject: [PATCH 181/515] GUI: rename "system" to "chip" "system" made sense when Furnace was a .dmf tracker and had compound setups like Genesis (YM2612+SN) however, it doesn't make too much sense now when compared to "chip" --- src/gui/debug.cpp | 2 +- src/gui/debugWindow.cpp | 4 ++-- src/gui/gui.cpp | 22 +++++++++++----------- src/gui/settings.cpp | 11 +++-------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index f1c974e8b..5ae596bcd 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -334,7 +334,7 @@ void putDispatchChan(void* data, int chanNum, int type) { break; } default: - ImGui::Text("Unknown system! Help!"); + ImGui::Text("Unimplemented chip! Help!"); break; } } diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 6ad2ddddf..8fe02b116 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -297,7 +297,7 @@ void FurnaceGUI::drawDebug() { } if (ImGui::TreeNode("Playground")) { if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0; - if (ImGui::BeginCombo("System",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) { + if (ImGui::BeginCombo("Chip",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) { for (int i=0; isong.systemLen; i++) { if (ImGui::Selectable(fmt::sprintf("%d. %s",i+1,e->getSystemName(e->song.system[i])).c_str())) { pgSys=i; @@ -358,7 +358,7 @@ void FurnaceGUI::drawDebug() { if (ImGui::TreeNode("Register Cheatsheet")) { const char** sheet=e->getRegisterSheet(pgSys); if (sheet==NULL) { - ImGui::Text("no cheatsheet available for this system."); + ImGui::Text("no cheatsheet available for this chip."); } else { if (ImGui::BeginTable("RegisterSheet",2,ImGuiTableFlags_SizingFixedSame)) { ImGui::TableNextRow(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c1cd7f076..8ee6c60b9 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1879,7 +1879,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { #define sysAddOption(x) \ if (ImGui::MenuItem(getSystemName(x))) { \ if (!e->addSystem(x)) { \ - showError("cannot add system! ("+e->getLastError()+")"); \ + showError("cannot add chip! ("+e->getLastError()+")"); \ } \ updateWindowTitle(); \ } @@ -2887,7 +2887,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("one file")) { openFileDialog(GUI_FILE_EXPORT_AUDIO_ONE); } - if (ImGui::MenuItem("multiple files (one per system)")) { + if (ImGui::MenuItem("multiple files (one per chip)")) { openFileDialog(GUI_FILE_EXPORT_AUDIO_PER_SYS); } if (ImGui::MenuItem("multiple files (one per channel)")) { @@ -2928,7 +2928,7 @@ bool FurnaceGUI::loop() { "pattern indexes are ordered as they appear in the song." ); } - ImGui::Text("systems to export:"); + ImGui::Text("chips to export:"); bool hasOneAtLeast=false; for (int i=0; isong.systemLen; i++) { int minVersion=e->minVGMVersion(e->song.system[i]); @@ -2937,17 +2937,17 @@ bool FurnaceGUI::loop() { ImGui::EndDisabled(); if (minVersion>vgmExportVersion) { if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { - ImGui::SetTooltip("this system is only available in VGM %d.%.2x and higher!",minVersion>>8,minVersion&0xff); + ImGui::SetTooltip("this chip is only available in VGM %d.%.2x and higher!",minVersion>>8,minVersion&0xff); } } else if (minVersion==0) { if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { - ImGui::SetTooltip("this system is not supported by the VGM format!"); + ImGui::SetTooltip("this chip is not supported by the VGM format!"); } } else { if (willExport[i]) hasOneAtLeast=true; } } - ImGui::Text("select the systems you wish to export,"); + ImGui::Text("select the chip you wish to export,"); ImGui::Text("but only up to %d of each type.",(vgmExportVersion>=0x151)?2:1); if (hasOneAtLeast) { if (ImGui::MenuItem("click to export")) { @@ -2972,14 +2972,14 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } ImGui::Separator(); - if (ImGui::BeginMenu("add system...")) { + if (ImGui::BeginMenu("add chip...")) { for (int j=0; availableSystems[j]; j++) { if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue; sysAddOption((DivSystem)availableSystems[j]); } ImGui::EndMenu(); } - if (ImGui::BeginMenu("configure system...")) { + if (ImGui::BeginMenu("configure chip...")) { for (int i=0; isong.systemLen; i++) { if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSP%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true); @@ -2988,7 +2988,7 @@ bool FurnaceGUI::loop() { } ImGui::EndMenu(); } - if (ImGui::BeginMenu("change system...")) { + if (ImGui::BeginMenu("change chip...")) { ImGui::Checkbox("Preserve channel positions",&preserveChanPos); for (int i=0; isong.systemLen; i++) { if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { @@ -3001,12 +3001,12 @@ bool FurnaceGUI::loop() { } ImGui::EndMenu(); } - if (ImGui::BeginMenu("remove system...")) { + if (ImGui::BeginMenu("remove chip...")) { ImGui::Checkbox("Preserve channel positions",&preserveChanPos); for (int i=0; isong.systemLen; i++) { if (ImGui::MenuItem(fmt::sprintf("%d. %s##_SYSR%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { if (!e->removeSystem(i,preserveChanPos)) { - showError("cannot remove system! ("+e->getLastError()+")"); + showError("cannot remove chip! ("+e->getLastError()+")"); } } } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 73e9d2333..37d4bfecf 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -468,7 +468,7 @@ void FurnaceGUI::drawSettings() { } bool restartOnFlagChangeB=settings.restartOnFlagChange; - if (ImGui::Checkbox("Restart song when changing system properties",&restartOnFlagChangeB)) { + if (ImGui::Checkbox("Restart song when changing chip properties",&restartOnFlagChangeB)) { settings.restartOnFlagChange=restartOnFlagChangeB; } @@ -1232,11 +1232,6 @@ void FurnaceGUI::drawSettings() { } ImGui::EndDisabled(); - bool chipNamesB=settings.chipNames; - if (ImGui::Checkbox("Use chip names instead of system names",&chipNamesB)) { - settings.chipNames=chipNamesB; - } - bool oplStandardWaveNamesB=settings.oplStandardWaveNames; if (ImGui::Checkbox("Use standard OPL waveform names",&oplStandardWaveNamesB)) { settings.oplStandardWaveNames=oplStandardWaveNamesB; @@ -1567,8 +1562,8 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SONG,"Song effect"); UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_TIME,"Time effect"); UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SPEED,"Speed effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,"Primary system effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"Secondary system effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,"Primary specific effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"Secondary specific effect"); UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_MISC,"Miscellaneous"); UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output"); ImGui::TreePop(); From d44f5f0b2b91897250d8c2e750b7796a49003de8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 11 Aug 2022 22:21:54 +0900 Subject: [PATCH 182/515] Prepare for backward and bi-directional loop --- src/engine/engine.cpp | 20 ++++- src/engine/engine.h | 6 +- src/engine/fileOps.cpp | 8 +- src/engine/platform/amiga.cpp | 10 +-- src/engine/platform/genesis.cpp | 12 +-- src/engine/platform/lynx.cpp | 6 +- src/engine/platform/mmc5.cpp | 8 +- src/engine/platform/nes.cpp | 8 +- src/engine/platform/pce.cpp | 8 +- src/engine/platform/pcmdac.cpp | 10 +-- src/engine/platform/qsound.cpp | 7 +- src/engine/platform/rf5c68.cpp | 4 +- src/engine/platform/segapcm.cpp | 22 ++--- src/engine/platform/su.cpp | 6 +- src/engine/platform/swan.cpp | 8 +- src/engine/platform/vera.cpp | 8 +- src/engine/platform/vrc6.cpp | 8 +- src/engine/platform/zxbeeper.cpp | 4 +- src/engine/playback.cpp | 108 ++++++++++++++++++++--- src/engine/sample.cpp | 146 +++++++++++++++++++++++++------ src/engine/sample.h | 46 +++++++++- src/engine/vgmOps.cpp | 16 ++-- src/gui/debugWindow.cpp | 7 +- src/gui/doAction.cpp | 3 + src/gui/guiConst.cpp | 6 ++ src/gui/guiConst.h | 1 + src/gui/sampleEdit.cpp | 45 ++++++++++ 27 files changed, 418 insertions(+), 123 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bf55d9d6e..3f24d5a24 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -974,6 +974,7 @@ void DivEngine::renderSamplesP() { void DivEngine::renderSamples() { sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; // step 1: render samples for (int i=0; inotifyPlaybackStop(); } @@ -1914,9 +1918,11 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) { BUSY_BEGIN; sPreview.pBegin=pStart; sPreview.pEnd=pEnd; + sPreview.dir=false; if (sample<0 || sample>=(int)song.sample.size()) { sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; return; } @@ -1932,6 +1938,7 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) { sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0; sPreview.sample=sample; sPreview.wave=-1; + sPreview.dir=false; BUSY_END; } @@ -1939,6 +1946,7 @@ void DivEngine::stopSamplePreview() { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; } @@ -1947,6 +1955,7 @@ void DivEngine::previewWave(int wave, int note) { if (wave<0 || wave>=(int)song.wave.size()) { sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; return; } @@ -1962,6 +1971,7 @@ void DivEngine::previewWave(int wave, int note) { sPreview.pos=0; sPreview.sample=-1; sPreview.wave=wave; + sPreview.dir=false; BUSY_END; } @@ -1969,6 +1979,7 @@ void DivEngine::stopWavePreview() { BUSY_BEGIN; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; } @@ -2382,6 +2393,7 @@ int DivEngine::addSample() { song.sampleLen=sampleCount+1; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; saveLock.unlock(); renderSamples(); BUSY_END; @@ -2601,13 +2613,16 @@ int DivEngine::addSampleFromFile(const char* path) { inst.detune = inst.detune - 100; short pitch = ((0x3c-inst.basenote)*100) + inst.detune; sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); - if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD) + if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) { + sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD); sample->loopStart=inst.loops[0].start; sample->loopEnd=inst.loops[0].end; if(inst.loops[0].end < (unsigned int)sampleCount) sampleCount=inst.loops[0].end; } + else + sample->loop=false; } if (sample->centerRate<4000) sample->centerRate=4000; @@ -2627,6 +2642,7 @@ void DivEngine::delSample(int index) { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; saveLock.lock(); if (index>=0 && index<(int)song.sample.size()) { delete song.sample[index]; @@ -2843,6 +2859,7 @@ bool DivEngine::moveSampleUp(int which) { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; DivSample* prev=song.sample[which]; saveLock.lock(); song.sample[which]=song.sample[which-1]; @@ -2882,6 +2899,7 @@ bool DivEngine::moveSampleDown(int which) { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; DivSample* prev=song.sample[which]; saveLock.lock(); song.sample[which]=song.sample[which+1]; diff --git a/src/engine/engine.h b/src/engine/engine.h index 001ea1941..6d49d710a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -353,14 +353,16 @@ class DivEngine { struct SamplePreview { int sample; int wave; - unsigned int pos; + int pos; int pBegin, pEnd; + bool dir; SamplePreview(): sample(-1), wave(-1), pos(0), pBegin(-1), - pEnd(-1) {} + pEnd(-1), + dir(false) {} } sPreview; short vibTable[64]; diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 8dcd55d22..76cff9df8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1669,6 +1669,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { sample->loopStart=reader.readI(); sample->loopEnd=reader.readI(); + sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); for (int i=0; i<4; i++) { reader.readI(); @@ -1694,6 +1695,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version>=19) { sample->loopStart=reader.readI(); + sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); } else { reader.readI(); } @@ -1948,6 +1950,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { if (loopLen>=2) { sample->loopStart=loopStart; sample->loopEnd=loopEnd; + sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); } sample->init(slen); ds.sample.push_back(sample); @@ -2485,6 +2488,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } s->loopStart=sample[i].loopStart*2; s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; + s->loop=(s->loopStart>=0)&&(s->loopEnd>=0); reader.read(s->data8,sample[i].len); ds.sample.push_back(s); } @@ -3586,8 +3590,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(0); // reserved w->writeC(0); w->writeC(0); - w->writeI(sample->loopStart); - w->writeI(sample->loopEnd); + w->writeI(sample->loop?sample->loopStart:-1); + w->writeI(sample->loop?sample->loopEnd:-1); for (int i=0; i<4; i++) { w->writeI(0xffffffff); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 1b0075307..eec6f66c7 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -110,13 +110,13 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } } else { DivSample* s=parent->getSample(chan[i].sample); - if (s->samples>0) { - if (chan[i].audPossamples) { + if (s->getEndPosition()>0) { + if (chan[i].audPos<(unsigned int)s->getEndPosition()) { writeAudDat(s->data8[chan[i].audPos++]); } - if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) { - chan[i].audPos=s->loopStart; - } else if (chan[i].audPos>=MIN(131071,s->samples)) { + if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) { + chan[i].audPos=s->getLoopStartPosition(); + } else if (chan[i].audPos>=MIN(131071,(unsigned int)s->getEndPosition())) { chan[i].sample=-1; } } else { diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index b6dbb8d12..d3c1e6c36 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -154,9 +154,9 @@ void DivPlatformGenesis::processDAC() { if (s->samples>0) { while (chan[i].dacPeriod>=(chipClock/576)) { ++chan[i].dacPos; - if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=s->getEndPosition())) { - chan[i].dacPos=s->loopStart; - } else if (chan[i].dacPos>=s->samples) { + if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition())) { + chan[i].dacPos=s->getLoopStartPosition(); + } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { chan[i].dacSample=-1; chan[i].dacPeriod=0; break; @@ -200,9 +200,9 @@ void DivPlatformGenesis::processDAC() { } } chan[5].dacPos++; - if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=s->getEndPosition())) { - chan[5].dacPos=s->loopStart; - } else if (chan[5].dacPos>=s->samples) { + if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->getLoopEndPosition())) { + chan[5].dacPos=s->getLoopStartPosition(); + } else if (chan[5].dacPos>=(unsigned int)s->getEndPosition()) { chan[5].dacSample=-1; if (parent->song.brokenDACMode) { rWrite(0x2b,0); diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 7c349e5a5..836ce3155 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -158,9 +158,9 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7); } - if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) { - chan[i].samplePos=s->loopStart; - } else if (chan[i].samplePos>=(int)s->samples) { + if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) { + chan[i].samplePos=s->getLoopStartPosition(); + } else if (chan[i].samplePos>=s->getEndPosition()) { chan[i].sample=-1; } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 2154e855f..40e2f5c17 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -58,14 +58,14 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; if (dacPeriod>=rate) { DivSample* s=parent->getSample(dacSample); - if (s->samples>0) { + if (s->getEndPosition()>0) { if (!isMuted[2]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } dacPos++; - if (s->isLoopable() && dacPos>=s->getEndPosition()) { - dacPos=s->loopStart; - } else if (dacPos>=s->samples) { + if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { + dacPos=s->getLoopStartPosition(); + } else if (dacPos>=(unsigned int)s->getEndPosition()) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index bd1be94a8..d835e3852 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -97,7 +97,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { dacPeriod+=dacRate; \ if (dacPeriod>=rate) { \ DivSample* s=parent->getSample(dacSample); \ - if (s->samples>0) { \ + if (s->getEndPosition()>0) { \ if (!isMuted[4]) { \ unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \ if (dacAntiClickOn && dacAntiClickisLoopable() && dacPos>=s->getEndPosition()) { \ - dacPos=s->loopStart; \ - } else if (dacPos>=s->samples) { \ + if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { \ + dacPos=s->getLoopStartPosition(); \ + } else if (dacPos>=(unsigned int)s->getEndPosition()) { \ dacSample=-1; \ } \ dacPeriod-=rate; \ diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 5d9a0de88..d71e19146 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -82,7 +82,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>rate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { chan[i].dacSample=-1; continue; } @@ -90,9 +90,9 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x04,0xdf); chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) { - chan[i].dacPos=s->loopStart; - } else if (chan[i].dacPos>=s->samples) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { + chan[i].dacPos=s->getLoopStartPosition(); + } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { chan[i].dacSample=-1; } chan[i].dacPeriod-=rate; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 213cb85a3..67a533b1b 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -49,13 +49,13 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l output=(chan.ws.output[chan.audPos]^0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); - if (s->samples>0) { - if (s->isLoopable() && chan.audPos>=s->getEndPosition()) { - chan.audPos=s->loopStart; - } else if (chan.audPos>=s->samples) { + if (s->getEndPosition()>0) { + if (s->isLoopable() && chan.audPos>=(unsigned int)s->getLoopEndPosition()) { + chan.audPos=s->getLoopStartPosition(); + } else if (chan.audPos>=(unsigned int)s->getEndPosition()) { chan.sample=-1; } - if (chan.audPossamples) { + if (chan.audPos<(unsigned int)s->getEndPosition()) { output=s->data16[chan.audPos]; } } else { diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 6bc88dbf0..04696f2cf 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -301,16 +301,17 @@ void DivPlatformQSound::tick(bool sysTick) { qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_addr = s->offQSound & 0xffff; - int length = s->getEndPosition(); + int loopStart=s->getLoopStartPosition(); + int length = s->getLoopEndPosition(); if (length > 65536 - 16) { length = 65536 - 16; } - if (s->loopStart == -1 || s->loopStart >= length) { + if (loopStart == -1 || loopStart >= length) { qsound_end = s->offQSound + length + 15; qsound_loop = 15; } else { qsound_end = s->offQSound + length; - qsound_loop = length - s->loopStart; + qsound_loop = length - loopStart; } } if (chan[i].std.arp.had) { diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index e4a39d44e..5b829c348 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -143,7 +143,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { start=start+MIN(chan[i].audPos,s->length8); } if (s->isLoopable()) { - loop=start+s->loopStart; + loop=start+s->getLoopStartPosition(); } start=MIN(start,getSampleMemCapacity()-31); loop=MIN(loop,getSampleMemCapacity()-31); @@ -393,7 +393,7 @@ void DivPlatformRF5C68::renderSamples() { size_t memPos=0; for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; - int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT); + int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT); int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length); if (actualLength>0) { s->offRF5C68=memPos; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index d66fcce0b..6a63f823b 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -45,7 +45,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t for (int i=0; i<16; i++) { if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].pcm.sample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { chan[i].pcm.sample=-1; oscBuf[i]->data[oscBuf[i]->needle++]=0; continue; @@ -56,9 +56,9 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); } chan[i].pcm.pos+=chan[i].pcm.freq; - if (s->isLoopable() && chan[i].pcm.pos>=(s->getEndPosition()<<8)) { - chan[i].pcm.pos=s->loopStart<<8; - } else if (chan[i].pcm.pos>=(s->samples<<8)) { + if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->getLoopEndPosition()<<8)) { + chan[i].pcm.pos=s->getLoopStartPosition()<<8; + } else if (chan[i].pcm.pos>=((unsigned int)s->getEndPosition()<<8)) { chan[i].pcm.sample=-1; } } else { @@ -200,16 +200,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); if (actualLength>0xfeff) actualLength=0xfeff; addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (s->loopStart<0 || s->loopStart>=actualLength) { + if (loopStart<0 || loopStart>=actualLength) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { - int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; addWrite(0x10004+(c.chan<<3),loopPos&0xff); addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); @@ -233,16 +234,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].furnacePCM=false; if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); if (actualLength>65536) actualLength=65536; addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (s->loopStart<0 || s->loopStart>=actualLength) { + if (loopStart<0 || loopStart>=actualLength) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { - int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; addWrite(0x10004+(c.chan<<3),loopPos&0xff); addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 6c6b0b329..a212c65fe 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -220,7 +220,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note)); if (sample!=NULL) { - unsigned int sampleEnd=sample->offSU+(sample->getEndPosition()); + unsigned int sampleEnd=sample->offSU+(sample->getLoopEndPosition()); unsigned int off=sample->offSU+chan[i].hasOffset; chan[i].hasOffset=0; if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1; @@ -229,7 +229,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chWrite(i,0x0c,sampleEnd&0xff); chWrite(i,0x0d,sampleEnd>>8); if (sample->isLoopable()) { - unsigned int sampleLoop=sample->offSU+sample->loopStart; + unsigned int sampleLoop=sample->offSU+sample->getLoopStartPosition(); if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1; chWrite(i,0x0e,sampleLoop&0xff); chWrite(i,0x0f,sampleLoop>>8); @@ -603,7 +603,7 @@ void DivPlatformSoundUnit::renderSamples() { for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; if (s->data8==NULL) continue; - int paddedLen=s->samples; + int paddedLen=s->getEndPosition(); if (memPos>=getSampleMemCapacity(0)) { logW("out of PCM memory for sample %d!",i); break; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index b6da23271..5110d7e15 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -78,14 +78,14 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; while (dacPeriod>rate) { DivSample* s=parent->getSample(dacSample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { dacSample=-1; continue; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (s->isLoopable() && dacPos>=s->getEndPosition()) { - dacPos=s->loopStart; - } else if (dacPos>=s->samples) { + if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { + dacPos=s->getLoopStartPosition(); + } else if (dacPos>=(unsigned int)s->getEndPosition()) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 6376cc19e..301091bfc 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -70,7 +70,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len size_t pos=start; DivSample* s=parent->getSample(chan[16].pcm.sample); while (len>0) { - if (s->samples>0) { + if (s->getEndPosition()>0) { while (pcm_is_fifo_almost_empty(pcm)) { short tmp_l=0; short tmp_r=0; @@ -96,9 +96,9 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len rWritePCMData(tmp_r&0xff); } chan[16].pcm.pos++; - if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) { - chan[16].pcm.pos=s->loopStart; - } else if (chan[16].pcm.pos>=s->samples) { + if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->getLoopEndPosition()) { + chan[16].pcm.pos=s->getLoopStartPosition(); + } else if (chan[16].pcm.pos>=(unsigned int)s->getEndPosition()) { chan[16].pcm.sample=-1; break; } diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 8a34d9252..fa81afb91 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -66,7 +66,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>rate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { chan[i].dacSample=-1; chWrite(i,0,0); continue; @@ -77,9 +77,9 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chWrite(i,0,0x80|chan[i].dacOut); } chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) { - chan[i].dacPos=s->loopStart; - } else if (chan[i].dacPos>=s->samples) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { + chan[i].dacPos=s->getLoopStartPosition(); + } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { chan[i].dacSample=-1; chWrite(i,0,0); } diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 01702dc5d..dbe21de62 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -46,9 +46,9 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t if (curSample>=0 && curSamplesong.sampleLen) { if (--curSamplePeriod<0) { DivSample* s=parent->getSample(curSample); - if (s->samples>0) { + if (s->getEndPosition()>0) { sampleOut=(s->data8[curSamplePos++]>0); - if (curSamplePos>=s->samples) curSample=-1; + if (curSamplePos>=(unsigned int)s->getEndPosition()) curSample=-1; // 256 bits if (curSamplePos>2047) curSample=-1; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 3ba4f1417..d3fa252d6 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -760,6 +760,7 @@ void DivEngine::processRow(int i, bool afterDelay) { sPreview.sample=-1; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; break; } } @@ -1268,26 +1269,109 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi DivSample* s=song.sample[sPreview.sample]; for (size_t i=0; i=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { + if (sPreview.pos>=(int)s->samples || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { samp_temp=0; } else { - samp_temp=s->data16[sPreview.pos++]; + samp_temp=s->data16[sPreview.pos]; + if (sPreview.dir) { + sPreview.pos--; + } + else { + sPreview.pos++; + } } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); samp_prevSample=samp_temp; - if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) { - sPreview.pos=s->loopStart; + if (sPreview.dir) { // backward + if (sPreview.posgetLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.posisLoopable() && sPreview.posgetLoopEndPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + default: + break; + } + } + } + } else { // forward + if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + default: + break; + } + } } } } - - if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) { - sPreview.pos=s->loopStart; - } else if (sPreview.pos>=s->samples) { - sPreview.sample=-1; + if (sPreview.dir) { // backward + if (sPreview.pos<=s->getLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) { + if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + default: + break; + } + } else if (sPreview.pos<0) { + sPreview.sample=-1; + } + } + } else { // forward + if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + default: + break; + } + } else if (sPreview.pos>=s->getEndPosition()) { + sPreview.sample=-1; + } } } } else if (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()) { @@ -1298,7 +1382,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else { samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192; } - if (++sPreview.pos>=(unsigned int)wave->len) { + if (++sPreview.pos>=wave->len) { sPreview.pos=0; } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 60eb35bb2..5697176cd 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -39,57 +39,143 @@ DivSampleHistory::~DivSampleHistory() { } bool DivSample::isLoopable() { - return (loopStart>=0 && loopStartloopStart && loopEnd<=(int)samples); + return loop && ((loopStart>=0 && loopStartloopStart && loopEnd<=(int)samples)); } -unsigned int DivSample::getEndPosition(DivSampleDepth depth) { - int end=loopEnd; - unsigned int len=samples; +int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) { + if ((length==0) || (offset==length)) { + int off=offset; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + off=(offset+7)/8; + break; + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + off=(offset+7)/8; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_A: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_B: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_8BIT: + off=offset; + break; + case DIV_SAMPLE_DEPTH_BRR: + off=9*((offset+15)/16); + break; + case DIV_SAMPLE_DEPTH_VOX: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_16BIT: + off=offset*2; + break; + default: + break; + } + return off; + } else { + int off=offset; + int len=length; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + off=(offset+7)/8; + len=(length+7)/8; + break; + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + off=(offset+7)/8; + len=(length+7)/8; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_A: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_B: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_8BIT: + off=offset; + len=length; + break; + case DIV_SAMPLE_DEPTH_BRR: + off=9*((offset+15)/16); + len=9*((length+15)/16); + break; + case DIV_SAMPLE_DEPTH_VOX: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_16BIT: + off=offset*2; + len=length*2; + break; + default: + break; + } + return isLoopable()?off:len; + } +} + +int DivSample::getLoopStartPosition(DivSampleDepth depth) { + return getSampleOffset(loopStart,0,depth); +} + +int DivSample::getLoopEndPosition(DivSampleDepth depth) { + return getSampleOffset(loopEnd,samples,depth); +} + +int DivSample::getEndPosition(DivSampleDepth depth) { + int off=samples; switch (depth) { case DIV_SAMPLE_DEPTH_1BIT: - end=(loopEnd+7)/8; - len=length1; + off=length1; break; case DIV_SAMPLE_DEPTH_1BIT_DPCM: - end=(loopEnd+7)/8; - len=lengthDPCM; + off=lengthDPCM; break; case DIV_SAMPLE_DEPTH_YMZ_ADPCM: - end=(loopEnd+1)/2; - len=lengthZ; + off=lengthZ; break; case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: - end=(loopEnd+1)/2; - len=lengthQSoundA; + off=lengthQSoundA; break; case DIV_SAMPLE_DEPTH_ADPCM_A: - end=(loopEnd+1)/2; - len=lengthA; + off=lengthA; break; case DIV_SAMPLE_DEPTH_ADPCM_B: - end=(loopEnd+1)/2; - len=lengthB; + off=lengthB; break; case DIV_SAMPLE_DEPTH_8BIT: - end=loopEnd; - len=length8; + off=length8; break; case DIV_SAMPLE_DEPTH_BRR: - end=9*((loopEnd+15)/16); - len=lengthBRR; + off=lengthBRR; break; case DIV_SAMPLE_DEPTH_VOX: - end=(loopEnd+1)/2; - len=lengthVOX; + off=lengthVOX; break; case DIV_SAMPLE_DEPTH_16BIT: - end=loopEnd*2; - len=length16; + off=length16; break; default: break; } - return isLoopable()?end:len; + return off; } void DivSample::setSampleCount(unsigned int count) { @@ -138,7 +224,7 @@ bool DivSample::save(const char* path) { if(isLoopable()) { inst.loop_count = 1; - inst.loops[0].mode = SF_LOOP_FORWARD; + inst.loops[0].mode = (int)loopMode+SF_LOOP_FORWARD; inst.loops[0].start = loopStart; inst.loops[0].end = loopEnd; } @@ -895,9 +981,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { duplicate=new unsigned char[getCurBufLen()]; memcpy(duplicate,getCurBuf(),getCurBufLen()); } - h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd); + h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,loopMode); } else { - h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd); + h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,loopMode); } if (!doNotPush) { while (!redoHist.empty()) { @@ -928,7 +1014,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { rate=h->rate; \ centerRate=h->centerRate; \ loopStart=h->loopStart; \ - loopEnd=h->loopEnd; + loopEnd=h->loopEnd; \ + loop=h->loop; \ + loopMode=h->loopMode; int DivSample::undo() { diff --git a/src/engine/sample.h b/src/engine/sample.h index 103bcaa27..05c97ac83 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -25,6 +25,13 @@ #include "../ta-utils.h" #include +enum DivSampleLoopMode: unsigned char { + DIV_SAMPLE_LOOP_FORWARD=0, + DIV_SAMPLE_LOOP_BACKWARD, + DIV_SAMPLE_LOOP_PINGPONG, + DIV_SAMPLE_LOOP_MAX // boundary for loop mode +}; + enum DivSampleDepth: unsigned char { DIV_SAMPLE_DEPTH_1BIT=0, DIV_SAMPLE_DEPTH_1BIT_DPCM=1, @@ -53,8 +60,10 @@ struct DivSampleHistory { unsigned int length, samples; DivSampleDepth depth; int rate, centerRate, loopStart, loopEnd; + bool loop; + DivSampleLoopMode loopMode; bool hasSample; - DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le): + DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm): data((unsigned char*)d), length(l), samples(s), @@ -63,8 +72,10 @@ struct DivSampleHistory { centerRate(cr), loopStart(ls), loopEnd(le), + loop(lp), + loopMode(lm), hasSample(true) {} - DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le): + DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm): data(NULL), length(0), samples(0), @@ -73,6 +84,8 @@ struct DivSampleHistory { centerRate(cr), loopStart(ls), loopEnd(le), + loop(lp), + loopMode(lm), hasSample(false) {} ~DivSampleHistory(); }; @@ -92,6 +105,13 @@ struct DivSample { // - 10: VOX ADPCM // - 16: 16-bit PCM DivSampleDepth depth; + bool loop; + // valid values are: + // - 0: No loop + // - 1: Forward loop + // - 2: Backward loop + // - 3: Pingpong loop + DivSampleLoopMode loopMode; // these are the new data structures. signed char* data8; // 8 @@ -120,11 +140,29 @@ struct DivSample { */ bool isLoopable(); + /** + * get sample start position + * @return the samples start position. + */ + int getLoopStartPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + + /** + * get sample loop end position + * @return the samples loop end position. + */ + int getLoopEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + /** * get sample end position * @return the samples end position. */ - unsigned int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + + /** + * get sample offset + * @return the sample offset. + */ + int getSampleOffset(int offset, int length, DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); /** * @warning DO NOT USE - internal functions @@ -253,6 +291,8 @@ struct DivSample { loopEnd(-1), loopOffP(0), depth(DIV_SAMPLE_DEPTH_16BIT), + loop(false), + loopMode(DIV_SAMPLE_LOOP_FORWARD), data8(NULL), data16(NULL), data1(NULL), diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 15de0156f..51948f27f 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -511,7 +511,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(0x95); w->writeC(streamID); w->writeS(write.val); // sample number - w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags + w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags if (sample->isLoopable() && !sampleDir[streamID]) { loopTimer[streamID]=sample->length8; loopSample[streamID]=write.val; @@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p size_t memPos=0; for (int i=0; igetEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff); + unsigned int alignedSize=(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff); if (alignedSize>65536) alignedSize=65536; if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) { memPos=(memPos+0xffff)&0xff0000; @@ -1559,9 +1559,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p sample->offSegaPCM=memPos; unsigned int readPos=0; for (unsigned int j=0; j=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (readPos>=sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { if (sample->isLoopable()) { - readPos=sample->loopStart; + readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); } else { pcmMem[memPos++]=0x80; @@ -1572,7 +1572,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p readPos++; if (memPos>=16777216) break; } - sample->loopOffP=readPos-sample->loopStart; + sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); if (memPos>=16777216) break; } @@ -1897,12 +1897,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p if (loopSample[nextToTouch]loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { w->writeC(0x93); w->writeC(nextToTouch); - w->writeI(sample->off8+sample->loopStart); + w->writeI(sample->off8+sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)); w->writeC(0x81); - w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart); + w->writeI(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)); } } loopSample[nextToTouch]=-1; diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 6ad2ddddf..58dfac399 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -157,10 +157,11 @@ void FurnaceGUI::drawDebug() { ImGui::Text("loopStart: %d",sample->loopStart); ImGui::Text("loopEnd: %d", sample->loopEnd); ImGui::Text("loopOffP: %d",sample->loopOffP); - if (sampleDepths[sample->depth]!=NULL) { - ImGui::Text("depth: %d (%s)",(unsigned char)sample->depth,sampleDepths[sample->depth]); + ImGui::Text(sample->loop?"loop: Enabled":"loop: Disabled"); + if (sampleLoopModes[sample->loopMode]!=NULL) { + ImGui::Text("loopMode: %d (%s)",(unsigned char)sample->loopMode,sampleLoopModes[sample->loopMode]); } else { - ImGui::Text("depth: %d ()",(unsigned char)sample->depth); + ImGui::Text("loopMode: %d ()",(unsigned char)sample->loopMode); } ImGui::Text("length8: %d",sample->length8); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index ca640d627..48780dcc2 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -710,6 +710,8 @@ void FurnaceGUI::doAction(int what) { sample->name=prevSample->name; sample->loopStart=prevSample->loopStart; sample->loopEnd=prevSample->loopEnd; + sample->loop=prevSample->loop; + sample->loopMode=prevSample->loopMode; sample->depth=prevSample->depth; if (sample->init(prevSample->samples)) { if (prevSample->getCurBuf()!=NULL) { @@ -1264,6 +1266,7 @@ void FurnaceGUI::doAction(int what) { sample->loopStart=start; sample->loopEnd=end; + sample->loop=true; updateSampleTex=true; e->renderSamples(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 59c917ae0..da86ce86a 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -116,6 +116,12 @@ const char* insTypes[DIV_INS_MAX+1]={ NULL }; +const char* sampleLoopModes[DIV_SAMPLE_LOOP_MAX]={ + "Forward", + "Backward", + "Ping pong" +}; + const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={ "1-bit PCM", "1-bit DPCM", diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index a6df68f62..d6824efb8 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -40,6 +40,7 @@ extern const char* noteNames[180]; extern const char* noteNamesG[180]; extern const char* pitchLabel[11]; extern const char* insTypes[]; +extern const char* sampleLoopModes[]; extern const char* sampleDepths[]; extern const char* resampleStrats[]; extern const int availableSystems[]; diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index e9b5cfb35..ff3072109 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -46,6 +46,12 @@ void FurnaceGUI::drawSampleEdit() { sampleType=sampleDepths[sample->depth]; } } + String loopType="Invalid"; + if (sample->loopModeloopMode]!=NULL) { + loopType=sampleLoopModes[sample->loopMode]; + } + } if (!settings.sampleLayout) { ImGui::Text("Name"); ImGui::SameLine(); @@ -96,9 +102,11 @@ void FurnaceGUI::drawSampleEdit() { bool doLoop=(sample->isLoopable()); if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { + sample->loop=true; sample->loopStart=0; sample->loopEnd=sample->samples; } else { + sample->loop=false; sample->loopStart=-1; sample->loopEnd=sample->samples; } @@ -107,6 +115,23 @@ void FurnaceGUI::drawSampleEdit() { if (doLoop) { ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::Text("Loop Mode"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##SampleLoopMode",loopType.c_str())) { + for (int i=0; iprepareUndo(true); + sample->loopMode=(DivSampleLoopMode)i; + e->renderSamplesP(); + updateSampleTex=true; + MARK_MODIFIED; + } + } + ImGui::EndCombo(); + } + ImGui::TableNextColumn(); ImGui::Text("Loop Start"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -631,15 +656,35 @@ void FurnaceGUI::drawSampleEdit() { bool doLoop=(sample->isLoopable()); if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { + sample->loop=true; sample->loopStart=0; sample->loopEnd=sample->samples; } else { + sample->loop=false; sample->loopStart=-1; sample->loopEnd=sample->samples; } updateSampleTex=true; } if (doLoop) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Loop Mode"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##SampleLoopMode",loopType.c_str())) { + for (int i=0; iprepareUndo(true); + sample->loopMode=(DivSampleLoopMode)i; + e->renderSamplesP(); + updateSampleTex=true; + MARK_MODIFIED; + } + } + ImGui::EndCombo(); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Loop Start"); From 00ae5b4142589d37d5e038e1b8afc287561b0d37 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 11:30:45 -0500 Subject: [PATCH 183/515] GUI: fix volume macro always being 15 issue #629 --- src/gui/insEdit.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 0d90e3733..55094252f 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3737,10 +3737,12 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { volMax=127; } - if (ins->type==DIV_INS_GB && !ins->gb.softEnv) { - volMax=0; - } else { - volMax=15; + if (ins->type==DIV_INS_GB) { + if (ins->gb.softEnv) { + volMax=15; + } else { + volMax=0; + } } if (ins->type==DIV_INS_PET || ins->type==DIV_INS_BEEPER) { volMax=1; From b156336216a7f55c04dcc67cbf3c1cfd39bec2bc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 11 Aug 2022 14:27:33 -0500 Subject: [PATCH 184/515] GUI: fix Game Boy ins edit crashes --- src/gui/insEdit.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 55094252f..1c29c5d9b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3173,10 +3173,9 @@ void FurnaceGUI::drawInsEdit() { ins->gb.hwSeqLen++; } } - - ImGui::EndChild(); - ImGui::EndDisabled(); } + ImGui::EndChild(); + ImGui::EndDisabled(); ImGui::EndTabItem(); } if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) { From 39feda54acb0a75d32dfe7c1e6e4da6e178fb9c5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 12 Aug 2022 04:11:17 -0500 Subject: [PATCH 185/515] OPZ: volume macro should go to 127 --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1c29c5d9b..d4e76611f 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3733,7 +3733,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { volMax=64; } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ) { volMax=127; } if (ins->type==DIV_INS_GB) { From 2743c60cf3f6021b6271af9eb9afc9c250bd535a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 12 Aug 2022 23:09:34 -0500 Subject: [PATCH 186/515] Game Boy: fix wave channel auto-enable on wave cha --- src/engine/platform/gb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 0a8b624c9..a7b310935 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -636,7 +636,7 @@ void DivPlatformGB::notifyWaveChange(int wave) { if (chan[2].wave==wave) { ws.changeWave1(wave); updateWave(); - if (!chan[2].keyOff) chan[2].keyOn=true; + if (!chan[2].keyOff && chan[2].active) chan[2].keyOn=true; } } From 5506b87b4073bc4e22772c5c7606b472ce4e7dcd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 02:48:34 -0500 Subject: [PATCH 187/515] update sample doc --- papers/doc/6-sample/README.md | 72 ++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/papers/doc/6-sample/README.md b/papers/doc/6-sample/README.md index 0c038fdb9..035a58cc6 100644 --- a/papers/doc/6-sample/README.md +++ b/papers/doc/6-sample/README.md @@ -4,29 +4,54 @@ In the context of Furnace, a sound sample (usually just referred to as a sample) In Furnace, these samples can be generated by importing a .wav (think of it as an higher quality MP3) file. -## supported systems +## supported chips -As of Furnace 0.6, the following sound chips have sample support: - - NES/Ricoh 2A03 (with DPCM support and only on channel 5) - - Sega Genesis/YM2612 (channel 6 only; but only if there exists a `1701` effect that gets played on or before a trigger for a sample, or if you are using an instrument with Sample type) - - PC Engine/TurboGrafx 16/Huc6280 (same conditions as above) - - Amiga/Paula (on all channels) - - Arcade/SEGA PCM (same as above) - - Neo Geo/Neo Geo CD (on the last 7 channels (6 if you are using Neo Geo CD) only and can be resampled the same way as above) - - Seta/Allumer X1-010 (same as YM2612) - - Atari Lynx - - MSM6258 and MSM6295 - - YMU759/MA-2 (last channel only) - - QSound - - ZX Spectrum 48k - - RF5C68 - - WonderSwan - - Tildearrow Sound Unit - - VERA (last channel only) - - Y8590 (last channel only) - - And a few more that I've forgotten to mention. +as of Furnace 0.6, the following sound chips have sample support: -Furnace also has a feature where you can make an Amiga formarted instrument on the YM2612 and Huc6280 to resample a sample you have in the module. +- NES/Ricoh 2A03 (with DPCM support and only on channel 5) +- Sega Genesis/YM2612 (channel 6 only) +- PC Engine/TurboGrafx-16/HuC6280 +- Amiga/Paula +- SegaPCM +- Neo Geo/Neo Geo CD/YM2610 (ADPCM channels only) +- Seta/Allumer X1-010 +- Atari Lynx +- MSM6258 and MSM6295 +- YMU759/MA-2 (last channel only) +- QSound +- ZX Spectrum 48k (1-bit) +- RF5C68 +- WonderSwan +- tildearrow Sound Unit +- VERA (last channel only) +- Y8950 (last channel only) +- a few more that I've forgotten to mention + +## compatible sample mode + +effect `17xx` enables/disables compatible sample mode whether supported (e.g. on Sega Genesis or PC Engine). + +in this mode, samples are mapped to notes in an octave from C to B, allowing you to use up to 12 samples. +if you need to use more samples, you may change the sample bank using effect `EBxx`. + +use of this mode is discouraged in favor of Sample type instruments. + +## notes + +due to limitations in some of those sound chips, some restrictions exist: + +- Amiga: sample lengths and loop will be set to an even number, and your sample can't be longer than 131070. +- NES: if on DPCM mode, only a limited selection of frequencies is available, and loop position isn't supported (only entire sample). +- SegaPCM: your sample can't be longer than 65535, and the maximum frequency is 31.25KHz. +- QSound: your sample can't be longer than 65535, and the loop length shall not be greater than 32767. +- Neo Geo (ADPCM-A): no looping supported. your samples will play at ~18.5KHz. +- Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is ~55KHz. +- YM2608: the maximum frequency is ~55KHz. +- MSM6258/MSM6295: no arbitrary frequency. +- ZX Spectrum Beeper: your sample can't be longer than 2048. +- Seta/Allumer X1-010: frequency resolution is terrible in the lower end. your sample can't be longer than 131072. + +furthermore, many of these chips have a limited amount of sample memory. check memory usage in window > statistics. # the sample editor @@ -34,11 +59,12 @@ You can actually tweak your samples in Furnace's sample editor, which can be acc In there, you can modify certain data pertaining to your sample, such as the: - volume of the sample in percentage, where 100% is the current level of the sample (note that you can distort it if you put it too high) - - the sample rate, from 0Hz (no sample movement) to 65535Hz (65.5kHz). + - the sample rate. - what frequencies to filter, along with filter level/sweep and resonance options (much like the C64) - and many more. The changes you make will be applied as soon as you've committed them to your sample, but they can be undoed and redoed, just like text. # tips -If you have a sample you wanna use that is about 44100 or anything over 32000Hz, downsample the sample to 32000Hz so that the pitch of the sample in Furnace stays like the original audio file. You can do this in Audacity by going to the bottom left of the screen (If you see "Project Rate (Hz)" you are there), change the project rate to 32000Hz and save the file to wav in Audacity using "File -> Export -> Export as WAV". + +if you have a sample you wanna use that is about 44100 or anything over 32000Hz, downsample the sample to 32000Hz so that the pitch of the sample in Furnace stays like the original audio file, From 4707eb7002d07747a6bfc3d9d0397a4ce0faa6e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 04:07:50 -0500 Subject: [PATCH 188/515] update Namco 163 doc --- papers/doc/4-instrument/n163.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/4-instrument/n163.md b/papers/doc/4-instrument/n163.md index 0bd914453..ca4dd2e7c 100644 --- a/papers/doc/4-instrument/n163.md +++ b/papers/doc/4-instrument/n163.md @@ -2,7 +2,7 @@ Namco 163 instrument editor consists of two tabs: one controlling various parameters for waveform initialize and macro tab containing 10 macros. -## N163 +## Namco 163 - [Initial Waveform] - Determines the initial waveform for playing. - [Initial Waveform position in RAM] - Determines the initial waveform position will be load to RAM. - [Initial Waveform length in RAM] - Determines the initial waveform length will be load to RAM. From ce2d322e474911440cc4ca8544b27db91a55e235 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 04:17:32 -0500 Subject: [PATCH 189/515] GUI: add replace for wave/sample and prepare for raw sample import --- src/engine/engine.cpp | 112 +++++++++++++++++++++---------------- src/engine/engine.h | 17 ++++-- src/gui/dataList.cpp | 19 +++++++ src/gui/doAction.cpp | 12 ++++ src/gui/gui.cpp | 126 +++++++++++++++++++++++++++++++++++++++--- src/gui/gui.h | 12 +++- src/gui/guiConst.cpp | 4 ++ src/gui/waveEdit.cpp | 3 +- 8 files changed, 242 insertions(+), 63 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bf55d9d6e..9b2696c17 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2196,7 +2196,10 @@ void DivEngine::delInstrument(int index) { } int DivEngine::addWave() { - if (song.wave.size()>=256) return -1; + if (song.wave.size()>=256) { + lastError="too many wavetables!"; + return -1; + } BUSY_BEGIN; saveLock.lock(); DivWavetable* wave=new DivWavetable; @@ -2208,50 +2211,62 @@ int DivEngine::addWave() { return waveCount; } -bool DivEngine::addWaveFromFile(const char* path, bool addRaw) { +int DivEngine::addWavePtr(DivWavetable* which) { if (song.wave.size()>=256) { lastError="too many wavetables!"; - return false; + delete which; + return -1; } + BUSY_BEGIN; + saveLock.lock(); + int waveCount=(int)song.wave.size(); + song.wave.push_back(which); + song.waveLen=waveCount+1; + saveLock.unlock(); + BUSY_END; + return song.waveLen; +} + +DivWavetable* DivEngine::waveFromFile(const char* path, bool addRaw) { FILE* f=ps_fopen(path,"rb"); if (f==NULL) { lastError=fmt::sprintf("%s",strerror(errno)); - return false; + return NULL; } unsigned char* buf; ssize_t len; if (fseek(f,0,SEEK_END)!=0) { fclose(f); lastError=fmt::sprintf("could not seek to end: %s",strerror(errno)); - return false; + return NULL; } len=ftell(f); if (len<0) { fclose(f); lastError=fmt::sprintf("could not determine file size: %s",strerror(errno)); - return false; + return NULL; } if (len==(SIZE_MAX>>1)) { fclose(f); lastError="file size is invalid!"; - return false; + return NULL; } if (len==0) { fclose(f); lastError="file is empty"; - return false; + return NULL; } if (fseek(f,0,SEEK_SET)!=0) { fclose(f); lastError=fmt::sprintf("could not seek to beginning: %s",strerror(errno)); - return false; + return NULL; } buf=new unsigned char[len]; if (fread(buf,1,len,f)!=(size_t)len) { logW("did not read entire wavetable file buffer!"); delete[] buf; lastError=fmt::sprintf("could not read entire file: %s",strerror(errno)); - return false; + return NULL; } fclose(f); @@ -2279,7 +2294,7 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) { lastError="invalid wavetable header/data!"; delete wave; delete[] buf; - return false; + return NULL; } } else { try { @@ -2320,7 +2335,7 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) { } else { delete wave; delete[] buf; - return false; + return NULL; } } } catch (EndOfFileException& e) { @@ -2338,7 +2353,7 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) { } else { delete wave; delete[] buf; - return false; + return NULL; } } } @@ -2346,17 +2361,10 @@ bool DivEngine::addWaveFromFile(const char* path, bool addRaw) { delete wave; delete[] buf; lastError="premature end of file"; - return false; + return NULL; } - BUSY_BEGIN; - saveLock.lock(); - int waveCount=(int)song.wave.size(); - song.wave.push_back(wave); - song.waveLen=waveCount+1; - saveLock.unlock(); - BUSY_END; - return true; + return wave; } void DivEngine::delWave(int index) { @@ -2372,7 +2380,10 @@ void DivEngine::delWave(int index) { } int DivEngine::addSample() { - if (song.sample.size()>=256) return -1; + if (song.sample.size()>=256) { + lastError="too many samples!"; + return -1; + } BUSY_BEGIN; saveLock.lock(); DivSample* sample=new DivSample; @@ -2388,11 +2399,28 @@ int DivEngine::addSample() { return sampleCount; } -int DivEngine::addSampleFromFile(const char* path) { +int DivEngine::addSamplePtr(DivSample* which) { if (song.sample.size()>=256) { lastError="too many samples!"; + delete which; return -1; } + int sampleCount=(int)song.sample.size(); + BUSY_BEGIN; + saveLock.lock(); + song.sample.push_back(which); + song.sampleLen=sampleCount+1; + saveLock.unlock(); + renderSamples(); + BUSY_END; + return sampleCount; +} + +DivSample* DivEngine::sampleFromFile(const char* path) { + if (song.sample.size()>=256) { + lastError="too many samples!"; + return NULL; + } BUSY_BEGIN; warnings=""; @@ -2425,7 +2453,6 @@ int DivEngine::addSampleFromFile(const char* path) { if (extS==".dmc") { // read as .dmc size_t len=0; DivSample* sample=new DivSample; - int sampleCount=(int)song.sample.size(); sample->name=stripPath; FILE* f=ps_fopen(path,"rb"); @@ -2433,7 +2460,7 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; lastError=fmt::sprintf("could not open file! (%s)",strerror(errno)); delete sample; - return -1; + return NULL; } if (fseek(f,0,SEEK_END)<0) { @@ -2441,7 +2468,7 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno)); delete sample; - return -1; + return NULL; } len=ftell(f); @@ -2451,7 +2478,7 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; lastError="file is empty!"; delete sample; - return -1; + return NULL; } if (len==(SIZE_MAX>>1)) { @@ -2459,7 +2486,7 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; lastError="file is invalid!"; delete sample; - return -1; + return NULL; } if (fseek(f,0,SEEK_SET)<0) { @@ -2467,7 +2494,7 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno)); delete sample; - return -1; + return NULL; } sample->rate=33144; @@ -2480,22 +2507,16 @@ int DivEngine::addSampleFromFile(const char* path) { BUSY_END; lastError=fmt::sprintf("could not read file! (%s)",strerror(errno)); delete sample; - return -1; + return NULL; } - - saveLock.lock(); - song.sample.push_back(sample); - song.sampleLen=sampleCount+1; - saveLock.unlock(); - renderSamples(); BUSY_END; - return sampleCount; + return sample; } } #ifndef HAVE_SNDFILE lastError="Furnace was not compiled with libsndfile!"; - return -1; + return NULL; #else SF_INFO si; SFWrapper sfWrap; @@ -2507,15 +2528,15 @@ int DivEngine::addSampleFromFile(const char* path) { if (err==SF_ERR_SYSTEM) { lastError=fmt::sprintf("could not open file! (%s %s)",sf_error_number(err),strerror(errno)); } else { - lastError=fmt::sprintf("could not open file! (%s)",sf_error_number(err)); + lastError=fmt::sprintf("could not open file! (%s)\nif this is raw sample data, you may import it by right-clicking the Load Sample icon and selecting \"import raw\".",sf_error_number(err)); } - return -1; + return NULL; } if (si.frames>16777215) { lastError="this sample is too big! max sample size is 16777215."; sfWrap.doClose(); BUSY_END; - return -1; + return NULL; } void* buf=NULL; sf_count_t sampleLen=sizeof(short); @@ -2613,13 +2634,8 @@ int DivEngine::addSampleFromFile(const char* path) { if (sample->centerRate<4000) sample->centerRate=4000; if (sample->centerRate>64000) sample->centerRate=64000; sfWrap.doClose(); - saveLock.lock(); - song.sample.push_back(sample); - song.sampleLen=sampleCount+1; - saveLock.unlock(); - renderSamples(); BUSY_END; - return sampleCount; + return sample; #endif } diff --git a/src/engine/engine.h b/src/engine/engine.h index 483ebcf0d..a03c92432 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -706,8 +706,11 @@ class DivEngine { // add wavetable int addWave(); - // add wavetable from file - bool addWaveFromFile(const char* path, bool loadRaw=true); + // add wavetable from pointer + int addWavePtr(DivWavetable* which); + + // get wavetable from file + DivWavetable* waveFromFile(const char* path, bool loadRaw=true); // delete wavetable void delWave(int index); @@ -715,8 +718,14 @@ class DivEngine { // add sample int addSample(); - // add sample from file - int addSampleFromFile(const char* path); + // add sample from pointer + int addSamplePtr(DivSample* which); + + // get sample from file + DivSample* sampleFromFile(const char* path); + + // get raw sample + DivSample* sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian); // delete sample void delSample(int index); diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 3a536951f..10dda6aaf 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -420,6 +420,12 @@ void FurnaceGUI::drawWaveList() { if (ImGui::Button(ICON_FA_FOLDER_OPEN "##WaveLoad")) { doAction(GUI_ACTION_WAVE_LIST_OPEN); } + if (ImGui::BeginPopupContextItem("WaveOpenOpt")) { + if (ImGui::MenuItem("replace...")) { + doAction((curWave>=0 && curWave<(int)e->song.wave.size())?GUI_ACTION_WAVE_LIST_OPEN_REPLACE:GUI_ACTION_WAVE_LIST_OPEN); + } + ImGui::EndPopup(); + } ImGui::SameLine(); if (ImGui::Button(ICON_FA_FLOPPY_O "##WaveSave")) { doAction(GUI_ACTION_WAVE_LIST_SAVE); @@ -470,6 +476,19 @@ void FurnaceGUI::drawSampleList() { if (ImGui::Button(ICON_FA_FOLDER_OPEN "##SampleLoad")) { doAction(GUI_ACTION_SAMPLE_LIST_OPEN); } + if (ImGui::BeginPopupContextItem("SampleOpenOpt")) { + if (ImGui::MenuItem("replace...")) { + doAction((curSample>=0 && curSample<(int)e->song.sample.size())?GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE:GUI_ACTION_SAMPLE_LIST_OPEN); + } + ImGui::Separator(); + if (ImGui::MenuItem("import raw...")) { + doAction(GUI_ACTION_SAMPLE_LIST_OPEN_RAW); + } + if (ImGui::MenuItem("import raw (replace)...")) { + doAction((curSample>=0 && curSample<(int)e->song.sample.size())?GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE_RAW:GUI_ACTION_SAMPLE_LIST_OPEN_RAW); + } + ImGui::EndPopup(); + } ImGui::SameLine(); if (ImGui::Button(ICON_FA_FLOPPY_O "##SampleSave")) { doAction(GUI_ACTION_SAMPLE_LIST_SAVE); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index ca640d627..931de26dc 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -648,6 +648,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WAVE_LIST_OPEN: openFileDialog(GUI_FILE_WAVE_OPEN); break; + case GUI_ACTION_WAVE_LIST_OPEN_REPLACE: + openFileDialog(GUI_FILE_WAVE_OPEN_REPLACE); + break; case GUI_ACTION_WAVE_LIST_SAVE: if (curWave>=0 && curWave<(int)e->song.wave.size()) openFileDialog(GUI_FILE_WAVE_SAVE); break; @@ -728,6 +731,15 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_LIST_OPEN: openFileDialog(GUI_FILE_SAMPLE_OPEN); break; + case GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE: + openFileDialog(GUI_FILE_SAMPLE_OPEN_REPLACE); + break; + case GUI_ACTION_SAMPLE_LIST_OPEN_RAW: + openFileDialog(GUI_FILE_SAMPLE_OPEN_RAW); + break; + case GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE_RAW: + openFileDialog(GUI_FILE_SAMPLE_OPEN_REPLACE_RAW); + break; case GUI_ACTION_SAMPLE_LIST_SAVE: if (curSample>=0 && curSample<(int)e->song.sample.size()) openFileDialog(GUI_FILE_SAMPLE_SAVE); break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 8ee6c60b9..022dfe83f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1320,6 +1320,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { ); break; case GUI_FILE_WAVE_OPEN: + case GUI_FILE_WAVE_OPEN_REPLACE: if (!dirExists(workingDirWave)) workingDirWave=getHomeDir(); hasOpened=fileDialog->openLoad( "Load Wavetable", @@ -1341,6 +1342,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { ); break; case GUI_FILE_SAMPLE_OPEN: + case GUI_FILE_SAMPLE_OPEN_REPLACE: if (!dirExists(workingDirSample)) workingDirSample=getHomeDir(); hasOpened=fileDialog->openLoad( "Load Sample", @@ -1351,6 +1353,17 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { dpiScale ); break; + case GUI_FILE_SAMPLE_OPEN_RAW: + case GUI_FILE_SAMPLE_OPEN_REPLACE_RAW: + if (!dirExists(workingDirSample)) workingDirSample=getHomeDir(); + hasOpened=fileDialog->openLoad( + "Load Raw Sample", + {"all files", ".*"}, + ".*", + workingDirSample, + dpiScale + ); + break; case GUI_FILE_SAMPLE_SAVE: if (!dirExists(workingDirSample)) workingDirSample=getHomeDir(); hasOpened=fileDialog->openSave( @@ -2630,6 +2643,8 @@ bool FurnaceGUI::loop() { case SDL_DROPFILE: if (ev.drop.file!=NULL) { std::vector instruments=e->instrumentFromFile(ev.drop.file); + DivWavetable* droppedWave=NULL; + DivSample* droppedSample=NULL;; if (!instruments.empty()) { if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); @@ -2639,10 +2654,12 @@ bool FurnaceGUI::loop() { } nextWindow=GUI_WINDOW_INS_LIST; MARK_MODIFIED; - } else if (e->addWaveFromFile(ev.drop.file,false)) { + } else if ((droppedWave=e->waveFromFile(ev.drop.file,false))!=NULL) { + e->addWavePtr(droppedWave); nextWindow=GUI_WINDOW_WAVE_LIST; MARK_MODIFIED; - } else if (e->addSampleFromFile(ev.drop.file)!=-1) { + } else if ((droppedSample=e->sampleFromFile(ev.drop.file))!=NULL) { + e->addSamplePtr(droppedSample); nextWindow=GUI_WINDOW_SAMPLE_LIST; MARK_MODIFIED; } else if (modified) { @@ -3269,10 +3286,14 @@ bool FurnaceGUI::loop() { workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR; break; case GUI_FILE_WAVE_OPEN: + case GUI_FILE_WAVE_OPEN_REPLACE: case GUI_FILE_WAVE_SAVE: workingDirWave=fileDialog->getPath()+DIR_SEPARATOR_STR; break; case GUI_FILE_SAMPLE_OPEN: + case GUI_FILE_SAMPLE_OPEN_RAW: + case GUI_FILE_SAMPLE_OPEN_REPLACE: + case GUI_FILE_SAMPLE_OPEN_REPLACE_RAW: case GUI_FILE_SAMPLE_SAVE: workingDirSample=fileDialog->getPath()+DIR_SEPARATOR_STR; break; @@ -3438,13 +3459,45 @@ bool FurnaceGUI::loop() { e->song.wave[curWave]->save(copyOfName.c_str()); } break; - case GUI_FILE_SAMPLE_OPEN: - if (e->addSampleFromFile(copyOfName.c_str())==-1) { + case GUI_FILE_SAMPLE_OPEN: { + DivSample* s=e->sampleFromFile(copyOfName.c_str()); + if (s==NULL) { showError(e->getLastError()); } else { - MARK_MODIFIED; + if (e->addSamplePtr(s)==-1) { + showError(e->getLastError()); + } else { + MARK_MODIFIED; + } } break; + } + case GUI_FILE_SAMPLE_OPEN_REPLACE: { + DivSample* s=e->sampleFromFile(copyOfName.c_str()); + if (s==NULL) { + showError(e->getLastError()); + } else { + if (curSample>=0 && curSample<(int)e->song.sample.size()) { + e->lockEngine([this,s]() { + // if it crashes here please tell me... + DivSample* oldSample=e->song.sample[curSample]; + e->song.sample[curSample]=s; + delete oldSample; + e->renderSamples(); + MARK_MODIFIED; + }); + } else { + showError("...but you haven't selected a sample!"); + delete s; + } + } + break; + } + case GUI_FILE_SAMPLE_OPEN_RAW: + case GUI_FILE_SAMPLE_OPEN_REPLACE_RAW: + pendingRawSample=copyOfName; + displayPendingRawSample=true; + break; case GUI_FILE_SAMPLE_SAVE: if (curSample>=0 && curSample<(int)e->song.sample.size()) { e->song.sample[curSample]->save(copyOfName.c_str()); @@ -3508,13 +3561,36 @@ bool FurnaceGUI::loop() { } break; } - case GUI_FILE_WAVE_OPEN: - if (!e->addWaveFromFile(copyOfName.c_str())) { + case GUI_FILE_WAVE_OPEN: { + DivWavetable* wave=e->waveFromFile(copyOfName.c_str()); + if (wave==NULL) { showError("cannot load wavetable! ("+e->getLastError()+")"); } else { - MARK_MODIFIED; + if (e->addWavePtr(wave)==-1) { + showError("cannot load wavetable! ("+e->getLastError()+")"); + } else { + MARK_MODIFIED; + } } break; + } + case GUI_FILE_WAVE_OPEN_REPLACE: { + DivWavetable* wave=e->waveFromFile(copyOfName.c_str()); + if (wave==NULL) { + showError("cannot load wavetable! ("+e->getLastError()+")"); + } else { + if (curWave>=0 && curWave<(int)e->song.wave.size()) { + e->lockEngine([this,wave]() { + *e->song.wave[curWave]=*wave; + MARK_MODIFIED; + }); + } else { + showError("...but you haven't selected a wavetable!"); + } + delete wave; + } + break; + } case GUI_FILE_EXPORT_VGM: { SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints); if (w!=NULL) { @@ -3641,6 +3717,11 @@ bool FurnaceGUI::loop() { ImGui::OpenPopup("Select Instrument"); } + if (displayPendingRawSample) { + displayPendingRawSample=false; + ImGui::OpenPopup("Import Raw Sample"); + } + if (displayExporting) { displayExporting=false; ImGui::OpenPopup("Rendering..."); @@ -4071,6 +4152,34 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } + bool doRespond=false; + if (ImGui::BeginPopupModal("Import Raw Sample",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("Work In Progress - sorry"); + if (ImGui::Button("Oh... really?")) { + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Why are you so hostile? I'm just trying to import a raw sample.")) { + doRespond=true; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + if (doRespond) { + doRespond=false; + ImGui::OpenPopup("Fatal Alert"); + } + + if (ImGui::BeginPopupModal("Fatal Alert",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("Well, I'd rather you didn't. So, good night."); + if (ImGui::Button("Fine")) { + abort(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + layoutTimeEnd=SDL_GetPerformanceCounter(); // backup trigger @@ -4521,6 +4630,7 @@ FurnaceGUI::FurnaceGUI(): noteInputPoly(true), displayPendingIns(false), pendingInsSingle(false), + displayPendingRawSample(false), vgmExportVersion(0x171), drawHalt(10), macroPointSize(16), diff --git a/src/gui/gui.h b/src/gui/gui.h index 0ce4afaee..3b148924e 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -259,8 +259,12 @@ enum FurnaceGUIFileDialogs { GUI_FILE_INS_OPEN_REPLACE, GUI_FILE_INS_SAVE, GUI_FILE_WAVE_OPEN, + GUI_FILE_WAVE_OPEN_REPLACE, GUI_FILE_WAVE_SAVE, GUI_FILE_SAMPLE_OPEN, + GUI_FILE_SAMPLE_OPEN_RAW, + GUI_FILE_SAMPLE_OPEN_REPLACE, + GUI_FILE_SAMPLE_OPEN_REPLACE_RAW, GUI_FILE_SAMPLE_SAVE, GUI_FILE_EXPORT_AUDIO_ONE, GUI_FILE_EXPORT_AUDIO_PER_SYS, @@ -451,6 +455,7 @@ enum FurnaceGUIActions { GUI_ACTION_WAVE_LIST_ADD, GUI_ACTION_WAVE_LIST_DUPLICATE, GUI_ACTION_WAVE_LIST_OPEN, + GUI_ACTION_WAVE_LIST_OPEN_REPLACE, GUI_ACTION_WAVE_LIST_SAVE, GUI_ACTION_WAVE_LIST_MOVE_UP, GUI_ACTION_WAVE_LIST_MOVE_DOWN, @@ -464,6 +469,9 @@ enum FurnaceGUIActions { GUI_ACTION_SAMPLE_LIST_ADD, GUI_ACTION_SAMPLE_LIST_DUPLICATE, GUI_ACTION_SAMPLE_LIST_OPEN, + GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE, + GUI_ACTION_SAMPLE_LIST_OPEN_RAW, + GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE_RAW, GUI_ACTION_SAMPLE_LIST_SAVE, GUI_ACTION_SAMPLE_LIST_MOVE_UP, GUI_ACTION_SAMPLE_LIST_MOVE_DOWN, @@ -958,13 +966,15 @@ class FurnaceGUI { bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; - bool displayPendingIns, pendingInsSingle; + bool displayPendingIns, pendingInsSingle, displayPendingRawSample; bool willExport[32]; int vgmExportVersion; int drawHalt; int macroPointSize; int waveEditStyle; + String pendingRawSample; + ImGuiWindowFlags globalWinFlags; FurnaceGUIFileDialogs curFileDialog; diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 59c917ae0..5fabb1c72 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -581,6 +581,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WAVE_LIST_ADD", "Add", SDLK_INSERT), D("WAVE_LIST_DUPLICATE", "Duplicate", FURKMOD_CMD|SDLK_d), D("WAVE_LIST_OPEN", "Open", 0), + D("WAVE_LIST_OPEN_REPLACE", "Open (replace current)", 0), D("WAVE_LIST_SAVE", "Save", 0), D("WAVE_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP), D("WAVE_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN), @@ -594,6 +595,9 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("SAMPLE_LIST_ADD", "Add", SDLK_INSERT), D("SAMPLE_LIST_DUPLICATE", "Duplicate", FURKMOD_CMD|SDLK_d), D("SAMPLE_LIST_OPEN", "Open", 0), + D("SAMPLE_LIST_OPEN_REPLACE", "Open (replace current)", 0), + D("SAMPLE_LIST_OPEN_RAW", "Import raw data", 0), + D("SAMPLE_LIST_OPEN_REPLACE_RAW", "Import raw data (replace current)", 0), D("SAMPLE_LIST_SAVE", "Save", 0), D("SAMPLE_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP), D("SAMPLE_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN), diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index ac06bcb7c..7e453ef58 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -131,9 +131,8 @@ void FurnaceGUI::drawWaveEdit() { if (curWave>=(int)e->song.wave.size()) curWave=e->song.wave.size()-1; } ImGui::SameLine(); - // TODO: load replace if (ImGui::Button(ICON_FA_FOLDER_OPEN "##WELoad")) { - doAction(GUI_ACTION_WAVE_LIST_OPEN); + doAction(GUI_ACTION_WAVE_LIST_OPEN_REPLACE); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_FLOPPY_O "##WESave")) { From 91f9352eafbc516e97100950cac47636f81f316c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 05:50:36 -0500 Subject: [PATCH 190/515] implement raw sample import untested --- src/engine/engine.cpp | 166 ++++++++++++++++++++++++++++++++++++++++++ src/gui/gui.cpp | 56 +++++++++----- src/gui/gui.h | 2 + 3 files changed, 205 insertions(+), 19 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 9b2696c17..ffe2d6aa3 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2639,6 +2639,172 @@ DivSample* DivEngine::sampleFromFile(const char* path) { #endif } +DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian) { + if (song.sample.size()>=256) { + lastError="too many samples!"; + return NULL; + } + if (channels<1) { + lastError="invalid channel count"; + return NULL; + } + if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) { + if (channels!=1) { + lastError="channel count has to be 1 for non-8/16-bit format"; + return NULL; + } + } + BUSY_BEGIN; + warnings=""; + + const char* pathRedux=strrchr(path,DIR_SEPARATOR); + if (pathRedux==NULL) { + pathRedux=path; + } else { + pathRedux++; + } + String stripPath; + const char* pathReduxEnd=strrchr(pathRedux,'.'); + if (pathReduxEnd==NULL) { + stripPath=pathRedux; + } else { + for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) { + stripPath+=*i; + } + } + + size_t len=0; + size_t lenDivided=0; + DivSample* sample=new DivSample; + sample->name=stripPath; + + FILE* f=ps_fopen(path,"rb"); + if (f==NULL) { + BUSY_END; + lastError=fmt::sprintf("could not open file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + if (fseek(f,0,SEEK_END)<0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + len=ftell(f); + + if (len==0) { + fclose(f); + BUSY_END; + lastError="file is empty!"; + delete sample; + return NULL; + } + + if (len==(SIZE_MAX>>1)) { + fclose(f); + BUSY_END; + lastError="file is invalid!"; + delete sample; + return NULL; + } + + if (fseek(f,0,SEEK_SET)<0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + lenDivided=len/channels; + + unsigned int samples=lenDivided; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + samples=lenDivided*8; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + case DIV_SAMPLE_DEPTH_ADPCM_A: + case DIV_SAMPLE_DEPTH_ADPCM_B: + case DIV_SAMPLE_DEPTH_VOX: + samples=lenDivided*2; + break; + case DIV_SAMPLE_DEPTH_8BIT: + samples=lenDivided; + break; + case DIV_SAMPLE_DEPTH_BRR: + samples=16*((lenDivided+8)/9); + break; + case DIV_SAMPLE_DEPTH_16BIT: + samples=(lenDivided+1)/2; + break; + default: + break; + } + + if (samples>16777215) { + fclose(f); + BUSY_END; + lastError="this sample is too big! max sample size is 16777215."; + delete sample; + return NULL; + } + + sample->rate=32000; + sample->centerRate=32000; + sample->depth=depth; + sample->init(samples); + + unsigned char* buf=new unsigned char[len]; + if (fread(buf,1,len,f)==0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not read file! (%s)",strerror(errno)); + delete[] buf; + delete sample; + return NULL; + } + + fclose(f); + + // import sample + size_t pos=0; + if (depth==DIV_SAMPLE_DEPTH_16BIT) { + for (unsigned int i=0; i=len) break; + accum+=((short*)buf)[pos>>1]; + pos+=2; + } + accum/=channels; + sample->data16[i]=accum; + } + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { + for (unsigned int i=0; i=len) break; + accum+=(signed char)buf[pos++]; + } + accum/=channels; + sample->data8[i]=accum; + } + } else { + memcpy(sample->getCurBuf(),buf,len); + } + delete[] buf; + + BUSY_END; + return sample; +} + void DivEngine::delSample(int index) { BUSY_BEGIN; sPreview.sample=-1; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 022dfe83f..4d01f60ff 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4152,29 +4152,47 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } - bool doRespond=false; if (ImGui::BeginPopupModal("Import Raw Sample",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Work In Progress - sorry"); - if (ImGui::Button("Oh... really?")) { + ImGui::Text("Data type:"); + for (int i=0; isampleFromFileRaw(pendingRawSample.c_str(),(DivSampleDepth)pendingRawSampleDepth,pendingRawSampleChannels,pendingRawSampleBigEndian); + if (s==NULL) { + showError(e->getLastError()); + } else { + if (e->addSamplePtr(s)==-1) { + showError(e->getLastError()); + } else { + MARK_MODIFIED; + } + } ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("Why are you so hostile? I'm just trying to import a raw sample.")) { - doRespond=true; - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - - if (doRespond) { - doRespond=false; - ImGui::OpenPopup("Fatal Alert"); - } - - if (ImGui::BeginPopupModal("Fatal Alert",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Well, I'd rather you didn't. So, good night."); - if (ImGui::Button("Fine")) { - abort(); + if (ImGui::Button("Cancel")) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); diff --git a/src/gui/gui.h b/src/gui/gui.h index 3b148924e..e178efc9d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -974,6 +974,8 @@ class FurnaceGUI { int waveEditStyle; String pendingRawSample; + int pendingRawSampleDepth, pendingRawSampleChannels; + bool pendingRawSampleBigEndian; ImGuiWindowFlags globalWinFlags; From 041a76ad816159436ea309bf44a5e437bc8488f1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 06:25:11 -0500 Subject: [PATCH 191/515] raw sample import fixes --- src/engine/engine.cpp | 10 +++++++--- src/engine/engine.h | 2 +- src/gui/gui.cpp | 7 ++++++- src/gui/gui.h | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index ffe2d6aa3..4c51f367f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2639,7 +2639,7 @@ DivSample* DivEngine::sampleFromFile(const char* path) { #endif } -DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian) { +DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign) { if (song.sample.size()>=256) { lastError="too many samples!"; return NULL; @@ -2780,7 +2780,11 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int accum=0; for (int j=0; j=len) break; - accum+=((short*)buf)[pos>>1]; + if (bigEndian) { + accum+=(short)(((short)((buf[pos]<<8)|buf[pos+1]))^(unsign?0x8000:0)); + } else { + accum+=(short)(((short)(buf[pos]|(buf[pos+1]<<8)))^(unsign?0x8000:0)); + } pos+=2; } accum/=channels; @@ -2791,7 +2795,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int accum=0; for (int j=0; j=len) break; - accum+=(signed char)buf[pos++]; + accum+=(signed char)(buf[pos++]^(unsign?0x80:0)); } accum/=channels; sample->data8[i]=accum; diff --git a/src/engine/engine.h b/src/engine/engine.h index a03c92432..3a73d7d24 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -725,7 +725,7 @@ class DivEngine { DivSample* sampleFromFile(const char* path); // get raw sample - DivSample* sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian); + DivSample* sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign); // delete sample void delSample(int index); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4d01f60ff..0ed0ffbe1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4172,6 +4172,7 @@ bool FurnaceGUI::loop() { if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels)) { } ImGui::Text("(will be mixed down to mono)"); + ImGui::Checkbox("Unsigned",&pendingRawSampleUnsigned); ImGui::EndDisabled(); ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT); @@ -4179,7 +4180,7 @@ bool FurnaceGUI::loop() { ImGui::EndDisabled(); if (ImGui::Button("OK")) { - DivSample* s=e->sampleFromFileRaw(pendingRawSample.c_str(),(DivSampleDepth)pendingRawSampleDepth,pendingRawSampleChannels,pendingRawSampleBigEndian); + DivSample* s=e->sampleFromFileRaw(pendingRawSample.c_str(),(DivSampleDepth)pendingRawSampleDepth,pendingRawSampleChannels,pendingRawSampleBigEndian,pendingRawSampleUnsigned); if (s==NULL) { showError(e->getLastError()); } else { @@ -4653,6 +4654,10 @@ FurnaceGUI::FurnaceGUI(): drawHalt(10), macroPointSize(16), waveEditStyle(0), + pendingRawSampleDepth(8), + pendingRawSampleChannels(1), + pendingRawSampleUnsigned(false), + pendingRawSampleBigEndian(false), globalWinFlags(0), curFileDialog(GUI_FILE_OPEN), warnAction(GUI_WARN_OPEN), diff --git a/src/gui/gui.h b/src/gui/gui.h index e178efc9d..ff6dd93bb 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -975,7 +975,7 @@ class FurnaceGUI { String pendingRawSample; int pendingRawSampleDepth, pendingRawSampleChannels; - bool pendingRawSampleBigEndian; + bool pendingRawSampleUnsigned, pendingRawSampleBigEndian; ImGuiWindowFlags globalWinFlags; From 02fb5abc021c241e34606790ba1591fdbd6c49db Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 15:43:13 -0500 Subject: [PATCH 192/515] add ability to save ins/wave as .dmp/.dmw also saving wavetables as raw data --- src/engine/instrument.cpp | 145 ++++++++++++++++++++++++++++++++++++++ src/engine/instrument.h | 7 ++ src/engine/wavetable.cpp | 62 ++++++++++++++++ src/engine/wavetable.h | 16 ++++- src/gui/gui.cpp | 61 +++++++++++++--- 5 files changed, 282 insertions(+), 9 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 555d7d17f..2836e6f95 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -1150,3 +1150,148 @@ bool DivInstrument::save(const char* path) { w->finish(); return true; } + +bool DivInstrument::saveDMP(const char* path) { + SafeWriter* w=new SafeWriter(); + w->init(); + + // write version + w->writeC(11); + + // guess the system + switch (type) { + case DIV_INS_FM: + // we can't tell between Genesis, Neo Geo and Arcade ins type yet + w->writeC(0x02); + w->writeC(1); + break; + case DIV_INS_STD: + // we can't tell between SMS and NES ins type yet + w->writeC(0x03); + w->writeC(0); + break; + case DIV_INS_GB: + w->writeC(0x04); + w->writeC(0); + break; + case DIV_INS_C64: + w->writeC(0x07); + w->writeC(0); + break; + case DIV_INS_PCE: + w->writeC(0x06); + w->writeC(0); + break; + case DIV_INS_OPLL: + // ??? + w->writeC(0x13); + w->writeC(1); + break; + case DIV_INS_OPZ: + // data will be lost + w->writeC(0x08); + w->writeC(1); + break; + case DIV_INS_FDS: + // ??? + w->writeC(0x06); + w->writeC(0); + break; + default: + // not supported by .dmp + w->finish(); + return false; + } + + if (type==DIV_INS_FM || type==DIV_INS_OPLL || type==DIV_INS_OPZ) { + w->writeC(fm.fms); + w->writeC(fm.fb); + w->writeC(fm.alg); + w->writeC(fm.ams); + + // TODO: OPLL params + for (int i=0; i<4; i++) { + DivInstrumentFM::Operator& op=fm.op[i]; + w->writeC(op.mult); + w->writeC(op.tl); + w->writeC(op.ar); + w->writeC(op.dr); + w->writeC(op.sl); + w->writeC(op.rr); + w->writeC(op.am); + w->writeC(op.rs); + w->writeC(op.dt|(op.dt2<<4)); + w->writeC(op.d2r); + w->writeC(op.ssgEnv); + } + } else { + if (type!=DIV_INS_GB) { + w->writeC(std.volMacro.len); + for (int i=0; iwriteI(std.volMacro.val[i]); + } + if (std.volMacro.len>0) w->writeC(std.volMacro.loop); + } + + w->writeC(std.arpMacro.len); + for (int i=0; iwriteI(std.arpMacro.val[i]+12); + } + if (std.arpMacro.len>0) w->writeC(std.arpMacro.loop); + w->writeC(std.arpMacro.mode); + + w->writeC(std.dutyMacro.len); + for (int i=0; iwriteI(std.dutyMacro.val[i]+12); + } + if (std.dutyMacro.len>0) w->writeC(std.dutyMacro.loop); + + w->writeC(std.waveMacro.len); + for (int i=0; iwriteI(std.waveMacro.val[i]+12); + } + if (std.waveMacro.len>0) w->writeC(std.waveMacro.loop); + + if (type==DIV_INS_C64) { + w->writeC(c64.triOn); + w->writeC(c64.sawOn); + w->writeC(c64.pulseOn); + w->writeC(c64.noiseOn); + w->writeC(c64.a); + w->writeC(c64.d); + w->writeC(c64.s); + w->writeC(c64.r); + w->writeC((c64.duty*100)/4095); + w->writeC(c64.ringMod); + w->writeC(c64.oscSync); + w->writeC(c64.toFilter); + w->writeC(c64.volIsCutoff); + w->writeC(c64.initFilter); + w->writeC(c64.res); + w->writeC((c64.cut*100)/2047); + w->writeC(c64.hp); + w->writeC(c64.lp); + w->writeC(c64.bp); + w->writeC(c64.ch3off); + } + if (type==DIV_INS_GB) { + w->writeC(gb.envVol); + w->writeC(gb.envDir); + w->writeC(gb.envLen); + w->writeC(gb.soundLen); + } + } + + FILE* outFile=ps_fopen(path,"wb"); + if (outFile==NULL) { + logE("could not save instrument: %s!",strerror(errno)); + w->finish(); + return false; + } + if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { + logW("did not write entire instrument!"); + } + fclose(outFile); + w->finish(); + return true; +} diff --git a/src/engine/instrument.h b/src/engine/instrument.h index df7a6b361..9f49a627a 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -500,6 +500,13 @@ struct DivInstrument { * @return whether it was successful. */ bool save(const char* path); + + /** + * save this instrument to a file in .dmp format. + * @param path file path. + * @return whether it was successful. + */ + bool saveDMP(const char* path); DivInstrument(): name(""), type(DIV_INS_FM) { diff --git a/src/engine/wavetable.cpp b/src/engine/wavetable.cpp index 953400ee1..0b13497ef 100644 --- a/src/engine/wavetable.cpp +++ b/src/engine/wavetable.cpp @@ -92,3 +92,65 @@ bool DivWavetable::save(const char* path) { w->finish(); return true; } + +bool DivWavetable::saveDMW(const char* path) { + SafeWriter* w=new SafeWriter(); + w->init(); + + // write width + w->writeI(len); + + // check height + w->writeC(max); + if (max==255) { + // write as new format (because 0xff means that) + w->writeC(1); // format version + w->writeC(max); // actual height + + // waveform data + for (int i=0; iwriteI(data[i]&0xff); + } + } else { + // write as old format + for (int i=0; iwriteC(data[i]); + } + } + + FILE* outFile=ps_fopen(path,"wb"); + if (outFile==NULL) { + logE("could not save wavetable: %s!",strerror(errno)); + w->finish(); + return false; + } + if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { + logW("did not write entire wavetable!"); + } + fclose(outFile); + w->finish(); + return true; +} + +bool DivWavetable::saveRaw(const char* path) { + SafeWriter* w=new SafeWriter(); + w->init(); + + // waveform data + for (int i=0; iwriteC(data[i]); + } + + FILE* outFile=ps_fopen(path,"wb"); + if (outFile==NULL) { + logE("could not save wavetable: %s!",strerror(errno)); + w->finish(); + return false; + } + if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { + logW("did not write entire wavetable!"); + } + fclose(outFile); + w->finish(); + return true; +} diff --git a/src/engine/wavetable.h b/src/engine/wavetable.h index 616b048cf..0f518ab53 100644 --- a/src/engine/wavetable.h +++ b/src/engine/wavetable.h @@ -46,6 +46,20 @@ struct DivWavetable { * @return whether it was successful. */ bool save(const char* path); + + /** + * save this wavetable to a file in .dmw format. + * @param path file path. + * @return whether it was successful. + */ + bool saveDMW(const char* path); + + /** + * save this wavetable to a file in raw format. + * @param path file path. + * @return whether it was successful. + */ + bool saveRaw(const char* path); DivWavetable(): len(32), min(0), @@ -56,4 +70,4 @@ struct DivWavetable { } }; -#endif \ No newline at end of file +#endif diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0ed0ffbe1..f065dfe34 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1313,8 +1313,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); hasOpened=fileDialog->openSave( "Save Instrument", - {"Furnace instrument", "*.fui"}, - "Furnace instrument{.fui}", + {"Furnace instrument", "*.fui", + "DefleMask preset", "*.dmp"}, + "Furnace instrument{.fui},DefleMask preset{.dmp}", workingDirIns, dpiScale ); @@ -1335,8 +1336,10 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirWave)) workingDirWave=getHomeDir(); hasOpened=fileDialog->openSave( "Save Wavetable", - {"Furnace wavetable", ".fuw"}, - "Furnace wavetable{.fuw}", + {"Furnace wavetable", ".fuw", + "DefleMask wavetable", ".dmw", + "raw data", ".raw"}, + "Furnace wavetable{.fuw},DefleMask wavetable{.dmw},raw data{.raw}", workingDirWave, dpiScale ); @@ -1921,6 +1924,15 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { fileName+=fallback; \ } +#define checkExtensionTriple(x,y,z,fallback) \ + String lowerCase=fileName; \ + for (char& i: lowerCase) { \ + if (i>='A' && i<='Z') i+='a'-'A'; \ + } \ + if (lowerCase.size()<4 || (lowerCase.rfind(x)!=lowerCase.size()-4 && lowerCase.rfind(y)!=lowerCase.size()-4 && lowerCase.rfind(z)!=lowerCase.size()-4)) { \ + fileName+=fallback; \ + } + #define drawOpMask(m) \ ImGui::PushFont(patFont); \ ImGui::PushID("om_" #m); \ @@ -3365,10 +3377,21 @@ bool FurnaceGUI::loop() { checkExtension(".wav"); } if (curFileDialog==GUI_FILE_INS_SAVE) { - checkExtension(".fui"); + // we can't tell whether the user chose .fui or .dmp in the system file picker + const char* fallbackExt=(settings.sysFileDialog || ImGuiFileDialog::Instance()->GetCurrentFilter()=="Furnace instrument")?".fui":".dmp"; + checkExtensionDual(".fui",".dmp",fallbackExt); } if (curFileDialog==GUI_FILE_WAVE_SAVE) { - checkExtension(".fuw"); + // same thing here + const char* fallbackExt=".fuw"; + if (!settings.sysFileDialog) { + if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="raw data") { + fallbackExt=".raw"; + } else if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="DefleMask wavetable") { + fallbackExt=".dmw"; + } + } + checkExtensionTriple(".fuw",".dmw",".raw",fallbackExt); } if (curFileDialog==GUI_FILE_EXPORT_VGM) { checkExtension(".vgm"); @@ -3451,12 +3474,34 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_INS_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { - e->song.ins[curIns]->save(copyOfName.c_str()); + String lowerCase=fileName; + for (char& i: lowerCase) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + if ((lowerCase.size()<4 || lowerCase.rfind(".dmp")!=lowerCase.size()-4)) { + e->song.ins[curIns]->save(copyOfName.c_str()); + } else { + if (!e->song.ins[curIns]->saveDMP(copyOfName.c_str())) { + showError("error while saving instrument! make sure your instrument is compatible."); + } + } } break; case GUI_FILE_WAVE_SAVE: if (curWave>=0 && curWave<(int)e->song.wave.size()) { - e->song.wave[curWave]->save(copyOfName.c_str()); + String lowerCase=fileName; + for (char& i: lowerCase) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + if (lowerCase.size()<4) { + e->song.wave[curWave]->save(copyOfName.c_str()); + } else if (lowerCase.rfind(".dmw")==lowerCase.size()-4) { + e->song.wave[curWave]->saveDMW(copyOfName.c_str()); + } else if (lowerCase.rfind(".raw")==lowerCase.size()-4) { + e->song.wave[curWave]->saveRaw(copyOfName.c_str()); + } else { + e->song.wave[curWave]->save(copyOfName.c_str()); + } } break; case GUI_FILE_SAMPLE_OPEN: { From ee16d20047ee44ac606c9dd4e2908a77524590be Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 15:53:47 -0500 Subject: [PATCH 193/515] add demo song by brickblock369 --- demos/Egyptian_Rule.fur | Bin 0 -> 11774 bytes src/gui/about.cpp | 1 + src/gui/gui.cpp | 1 + 3 files changed, 2 insertions(+) create mode 100644 demos/Egyptian_Rule.fur diff --git a/demos/Egyptian_Rule.fur b/demos/Egyptian_Rule.fur new file mode 100644 index 0000000000000000000000000000000000000000..1715906ec3376d6ee757af34530ff6832ee34c02 GIT binary patch literal 11774 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 literal 0 HcmV?d00001 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 587aba84d..ae0792aef 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -67,6 +67,7 @@ const char* aboutLine[]={ "AURORA*FIELDS", "BlueElectric05", "breakthetargets", + "brickblock369", "CaptainMalware", "DeMOSic", "DevEd", diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f065dfe34..add68d769 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1267,6 +1267,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { hasOpened=fileDialog->openLoad( "Load Instrument", // TODO supply loadable formats in a dynamic, scalable, "DRY" way. + // thank the author of IGFD for making things impossible {"all compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.opli *.opni *.y12 *.bnk *.ff *.gyb *.opm *.wopl *.wopn", "Furnace instrument", "*.fui", "DefleMask preset", "*.dmp", From bb5cee4a662c3cd54fa4b3e4739cd55cc0186ab0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 18:00:29 -0500 Subject: [PATCH 194/515] GUI: add pattern label customization settings --- src/gui/editing.cpp | 2 +- src/gui/findReplace.cpp | 24 ++++++++++++------------ src/gui/gui.cpp | 20 ++++++++++++++++---- src/gui/gui.h | 19 ++++++++++++++++++- src/gui/pattern.cpp | 26 +++++++++++++------------- src/gui/settings.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/utfutils.cpp | 8 ++++---- src/utfutils.h | 2 ++ 8 files changed, 106 insertions(+), 35 deletions(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 9bd827951..21b1a72eb 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -24,7 +24,7 @@ #include "actionUtil.h" -const char* noteNameNormal(short note, short octave) { +const char* FurnaceGUI::noteNameNormal(short note, short octave) { if (note==100) { // note cut return "OFF"; } else if (note==101) { // note off and envelope release diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 559d7f7ff..428fce5a4 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -593,11 +593,11 @@ void FurnaceGUI::drawFindReplace() { i.note=0; } if (i.note==130) { - snprintf(tempID,1024,"REL"); + snprintf(tempID,1024,"%s##MREL",macroRelLabel); } else if (i.note==129) { - snprintf(tempID,1024,"==="); + snprintf(tempID,1024,"%s##NREL",noteRelLabel); } else if (i.note==128) { - snprintf(tempID,1024,"OFF"); + snprintf(tempID,1024,"%s##NOFF",noteOffLabel); } else if (i.note>=-60 && i.note<120) { snprintf(tempID,1024,"%s",noteNames[i.note+60]); } else { @@ -613,13 +613,13 @@ void FurnaceGUI::drawFindReplace() { } } if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) { - if (ImGui::Selectable("OFF",i.note==128)) { + if (ImGui::Selectable(noteOffLabel,i.note==128)) { i.note=128; } - if (ImGui::Selectable("===",i.note==129)) { + if (ImGui::Selectable(noteRelLabel,i.note==129)) { i.note=129; } - if (ImGui::Selectable("REL",i.note==130)) { + if (ImGui::Selectable(macroRelLabel,i.note==130)) { i.note=130; } } @@ -916,11 +916,11 @@ void FurnaceGUI::drawFindReplace() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) { if (queryReplaceNote==130) { - snprintf(tempID,1024,"REL"); + snprintf(tempID,1024,"%s##MREL",macroRelLabel); } else if (queryReplaceNote==129) { - snprintf(tempID,1024,"==="); + snprintf(tempID,1024,"%s##NREL",noteRelLabel); } else if (queryReplaceNote==128) { - snprintf(tempID,1024,"OFF"); + snprintf(tempID,1024,"%s##NOFF",noteOffLabel); } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { snprintf(tempID,1024,"%s",noteNames[queryReplaceNote+60]); } else { @@ -934,13 +934,13 @@ void FurnaceGUI::drawFindReplace() { queryReplaceNote=j-60; } } - if (ImGui::Selectable("OFF",queryReplaceNote==128)) { + if (ImGui::Selectable(noteOffLabel,queryReplaceNote==128)) { queryReplaceNote=128; } - if (ImGui::Selectable("===",queryReplaceNote==129)) { + if (ImGui::Selectable(noteRelLabel,queryReplaceNote==129)) { queryReplaceNote=129; } - if (ImGui::Selectable("REL",queryReplaceNote==130)) { + if (ImGui::Selectable(macroRelLabel,queryReplaceNote==130)) { queryReplaceNote=130; } ImGui::EndCombo(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index add68d769..66649cbae 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -84,13 +84,13 @@ void FurnaceGUI::bindEngine(DivEngine* eng) { const char* FurnaceGUI::noteName(short note, short octave) { if (note==100) { - return "OFF"; + return noteOffLabel; } else if (note==101) { // note off and envelope release - return "==="; + return noteRelLabel; } else if (note==102) { // envelope release only - return "REL"; + return macroRelLabel; } else if (octave==0 && note==0) { - return "..."; + return emptyLabel; } else if (note==0 && octave!=0) { return "BUG"; } @@ -5067,4 +5067,16 @@ FurnaceGUI::FurnaceGUI(): memset(queryReplaceEffectValDo,0,sizeof(bool)*8); chanOscGrad.bgColor=ImVec4(0.0f,0.0f,0.0f,1.0f); + + memset(noteOffLabel,0,32); + memset(noteRelLabel,0,32); + memset(macroRelLabel,0,32); + memset(emptyLabel,0,32); + memset(emptyLabel2,0,32); + + strncat(noteOffLabel,"OFF",32); + strncat(noteRelLabel,"===",32); + strncat(macroRelLabel,"REL",32); + strncat(emptyLabel,"...",32); + strncat(emptyLabel2,"..",32); } diff --git a/src/gui/gui.h b/src/gui/gui.h index ff6dd93bb..1c7355060 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1017,6 +1017,12 @@ class FurnaceGUI { ImU32 sysCmd1Grad[256]; ImU32 sysCmd2Grad[256]; + char noteOffLabel[32]; + char noteRelLabel[32]; + char macroRelLabel[32]; + char emptyLabel[32]; + char emptyLabel2[32]; + struct Settings { int mainFontSize, patFontSize, iconSize; int audioEngine; @@ -1119,6 +1125,11 @@ class FurnaceGUI { String midiOutDevice; String c163Name; String initialSysName; + String noteOffLabel; + String noteRelLabel; + String macroRelLabel; + String emptyLabel; + String emptyLabel2; std::vector initialSys; Settings(): @@ -1224,7 +1235,12 @@ class FurnaceGUI { midiInDevice(""), midiOutDevice(""), c163Name(""), - initialSysName("Sega Genesis/Mega Drive") {} + initialSysName("Sega Genesis/Mega Drive"), + noteOffLabel("OFF"), + noteRelLabel("==="), + macroRelLabel("REL"), + emptyLabel("..."), + emptyLabel2("..") {} } settings; char finalLayoutPath[4096]; @@ -1657,6 +1673,7 @@ class FurnaceGUI { public: void showWarning(String what, FurnaceGUIWarnings type); void showError(String what); + const char* noteNameNormal(short note, short octave); const char* noteName(short note, short octave); bool decodeNote(const char* what, short& note, short& octave); void bindEngine(DivEngine* eng); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index b7940a9e8..153944797 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -56,7 +56,7 @@ void FurnaceGUI::popPartBlend() { // draw a pattern row inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel) { - static char id[32]; + static char id[64]; bool selectedRow=(i>=sel1.y && i<=sel2.y && !inhibitSel); ImGui::TableNextRow(0,lineHeight); ImGui::TableNextColumn(); @@ -114,9 +114,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int ImGui::PushStyleColor(ImGuiCol_Text,rowIndexColor); if (settings.patRowsBase==1) { - snprintf(id,31," %.2X ##PR_%d",i,i); + snprintf(id,63," %.2X ##PR_%d",i,i); } else { - snprintf(id,31,"%3d ##PR_%d",i,i); + snprintf(id,63,"%3d ##PR_%d",i,i); } ImGui::Selectable(id,false,ImGuiSelectableFlags_NoPadWithHalfSpacing,fourChars); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) { @@ -151,7 +151,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int bool cursorVol=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==2 && curWindowLast==GUI_WINDOW_PATTERN); // note - sprintf(id,"%s##PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j); + snprintf(id,63,"%.31s##PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j); if (pat->data[i][0]==0 && pat->data[i][1]==0) { ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); } else { @@ -182,7 +182,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int // instrument if (pat->data[i][2]==-1) { ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); - sprintf(id,"..##PI_%d_%d",i,j); + snprintf(id,63,"%.31s##PI_%d_%d",emptyLabel2,i,j); } else { if (pat->data[i][2]<0 || pat->data[i][2]>=e->song.insLen) { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS_ERROR]); @@ -194,7 +194,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]); } } - sprintf(id,"%.2X##PI_%d_%d",pat->data[i][2],i,j); + snprintf(id,63,"%.2X##PI_%d_%d",pat->data[i][2],i,j); } ImGui::SameLine(0.0f,0.0f); if (cursorIns) { @@ -221,13 +221,13 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int if (e->curSubSong->chanCollapse[j]<2) { // volume if (pat->data[i][3]==-1) { - sprintf(id,"..##PV_%d_%d",i,j); + snprintf(id,63,"%.31s##PV_%d_%d",emptyLabel2,i,j); ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); } else { int volColor=(pat->data[i][3]*127)/chanVolMax; if (volColor>127) volColor=127; if (volColor<0) volColor=0; - sprintf(id,"%.2X##PV_%d_%d",pat->data[i][3],i,j); + snprintf(id,63,"%.2X##PV_%d_%d",pat->data[i][3],i,j); ImGui::PushStyleColor(ImGuiCol_Text,volColors[volColor]); } ImGui::SameLine(0.0f,0.0f); @@ -263,15 +263,15 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int // effect if (pat->data[i][index]==-1) { - sprintf(id,"..##PE%d_%d_%d",k,i,j); + snprintf(id,63,"%.31s##PE%d_%d_%d",emptyLabel2,k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); } else { if (pat->data[i][index]>0xff) { - sprintf(id,"??##PE%d_%d_%d",k,i,j); + snprintf(id,63,"??##PE%d_%d_%d",k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); } else { const unsigned char data=pat->data[i][index]; - sprintf(id,"%.2X##PE%d_%d_%d",data,k,i,j); + snprintf(id,63,"%.2X##PE%d_%d_%d",data,k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]); } } @@ -297,9 +297,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int // effect value if (pat->data[i][index+1]==-1) { - sprintf(id,"..##PF%d_%d_%d",k,i,j); + snprintf(id,63,"%.31s##PF%d_%d_%d",emptyLabel2,k,i,j); } else { - sprintf(id,"%.2X##PF%d_%d_%d",pat->data[i][index+1],k,i,j); + snprintf(id,63,"%.2X##PF%d_%d_%d",pat->data[i][index+1],k,i,j); } ImGui::SameLine(0.0f,0.0f); if (cursorEffectVal) { diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 37d4bfecf..6c300d0a4 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -21,6 +21,7 @@ #include "fonts.h" #include "../ta-log.h" #include "../fileutils.h" +#include "../utfutils.h" #include "util.h" #include "guiConst.h" #include "intConst.h" @@ -1081,6 +1082,15 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); + ImGui::Text("Pattern view labels:"); + ImGui::InputTextWithHint("Note off (3-char)","OFF",&settings.noteOffLabel); + ImGui::InputTextWithHint("Note release (3-char)","===",&settings.noteRelLabel); + ImGui::InputTextWithHint("Macro release (3-char)","REL",&settings.macroRelLabel); + ImGui::InputTextWithHint("Empty field (3-char)","...",&settings.emptyLabel); + ImGui::InputTextWithHint("Empty field (2-char)","..",&settings.emptyLabel2); + + ImGui::Separator(); + ImGui::Text("Orders row number format:"); if (ImGui::RadioButton("Decimal##orbD",settings.orderRowsBase==0)) { settings.orderRowsBase=0; @@ -2118,6 +2128,11 @@ void FurnaceGUI::syncSettings() { settings.noThreadedInput=e->getConfInt("noThreadedInput",0); settings.initialSysName=e->getConfString("initialSysName",""); settings.clampSamples=e->getConfInt("clampSamples",0); + settings.noteOffLabel=e->getConfString("noteOffLabel","OFF"); + settings.noteRelLabel=e->getConfString("noteRelLabel","==="); + settings.macroRelLabel=e->getConfString("macroRelLabel","REL"); + settings.emptyLabel=e->getConfString("emptyLabel","..."); + settings.emptyLabel2=e->getConfString("emptyLabel2",".."); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2345,6 +2360,11 @@ void FurnaceGUI::commitSettings() { e->setConf("unsignedDetune",settings.unsignedDetune); e->setConf("noThreadedInput",settings.noThreadedInput); e->setConf("clampSamples",settings.clampSamples); + e->setConf("noteOffLabel",settings.noteOffLabel); + e->setConf("noteRelLabel",settings.noteRelLabel); + e->setConf("macroRelLabel",settings.macroRelLabel); + e->setConf("emptyLabel",settings.emptyLabel); + e->setConf("emptyLabel2",settings.emptyLabel2); // colors for (int i=0; i=0.5f) dpiScale=settings.dpiScale; // colors diff --git a/src/utfutils.cpp b/src/utfutils.cpp index c99528986..4c727777b 100644 --- a/src/utfutils.cpp +++ b/src/utfutils.cpp @@ -19,7 +19,7 @@ #include "utfutils.h" -int decodeUTF8(const unsigned char* data, char& len) { +int decodeUTF8(const unsigned char* data, signed char& len) { int ret=0xfffd; if (data[0]<0x80) { ret=data[0]; @@ -66,7 +66,7 @@ int decodeUTF8(const unsigned char* data, char& len) { size_t utf8len(const char* s) { size_t p=0; size_t r=0; - char cl; + signed char cl; while (s[p]!=0) { r++; decodeUTF8((const unsigned char*)&s[p],cl); @@ -76,7 +76,7 @@ size_t utf8len(const char* s) { } char utf8csize(const unsigned char* c) { - char ret; + signed char ret; decodeUTF8(c,ret); return ret; } @@ -84,7 +84,7 @@ char utf8csize(const unsigned char* c) { WString utf8To16(const char* s) { WString ret; int ch, p; - char chs; + signed char chs; p=0; while (s[p]!=0) { ch=decodeUTF8((const unsigned char*)&s[p],chs); diff --git a/src/utfutils.h b/src/utfutils.h index 087913a43..76c894708 100644 --- a/src/utfutils.h +++ b/src/utfutils.h @@ -21,6 +21,8 @@ #define _UTFUTILS_H #include "ta-utils.h" +int decodeUTF8(const unsigned char* data, signed char& len); + size_t utf8len(const char* s); size_t utf8clen(const char* s); size_t utf8pos(const char* s, size_t inpos); From 774a949ccaebbbd7ddc82f46abf168efb2e203ed Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 13 Aug 2022 18:16:24 -0500 Subject: [PATCH 195/515] GUI: fix labels being empty --- src/gui/gui.cpp | 10 +++++----- src/gui/settings.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 66649cbae..2b4367c91 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5074,9 +5074,9 @@ FurnaceGUI::FurnaceGUI(): memset(emptyLabel,0,32); memset(emptyLabel2,0,32); - strncat(noteOffLabel,"OFF",32); - strncat(noteRelLabel,"===",32); - strncat(macroRelLabel,"REL",32); - strncat(emptyLabel,"...",32); - strncat(emptyLabel2,"..",32); + strncpy(noteOffLabel,"OFF",32); + strncpy(noteRelLabel,"===",32); + strncpy(macroRelLabel,"REL",32); + strncpy(emptyLabel,"...",32); + strncpy(emptyLabel2,"..",32); } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 6c300d0a4..ee35fd86c 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2781,7 +2781,7 @@ void setupLabel(const char* lStr, char* label, int len) { memset(label,0,32); for (int i=0, p=0; i Date: Sat, 13 Aug 2022 22:50:11 -0400 Subject: [PATCH 196/515] Add demo song --- ...m Follin - Silver Surfer - Stage Music 1.fur | Bin 0 -> 22904 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/[TSU] Tim Follin - Silver Surfer - Stage Music 1.fur diff --git a/demos/[TSU] Tim Follin - Silver Surfer - Stage Music 1.fur b/demos/[TSU] Tim Follin - Silver Surfer - Stage Music 1.fur new file mode 100644 index 0000000000000000000000000000000000000000..bbe6a3c778e5706ecfdb4f577b359a705c347ed0 GIT binary patch literal 22904 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 Date: Sun, 14 Aug 2022 16:09:31 +1000 Subject: [PATCH 197/515] Reported bug - 2nd 2op pair did not read ALG and FB registers to instrument patch --- src/engine/fileOpsIns.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 54e0eefc6..62c3a1d8a 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -733,6 +733,8 @@ void DivEngine::loadOPLI(SafeReader& reader, std::vector& ret, S ins = new DivInstrument; ins->type = DIV_INS_OPL; ins->name = fmt::sprintf("%s (2)", insName); + ins->fm.alg = (feedConnect2nd & 0x1); + ins->fm.fb = ((feedConnect2nd >> 1) & 0xF); for (int i : {1,0}) { readOpliOp(reader, ins->fm.op[i]); } @@ -1498,6 +1500,8 @@ void DivEngine::loadWOPL(SafeReader& reader, std::vector& ret, S ins = new DivInstrument; ins->type = DIV_INS_OPL; ins->name = fmt::sprintf("%s (2)", insName); + ins->fm.alg = (feedConnect2nd & 0x1); + ins->fm.fb = ((feedConnect2nd >> 1) & 0xF); for (int i : {1,0}) { patchSum += readWoplOp(reader, ins->fm.op[i]); } From 2b6160b76fc7ea524c839c2d9d6030bf5a08937d Mon Sep 17 00:00:00 2001 From: SirForte <67491162+SirForte@users.noreply.github.com> Date: Sun, 14 Aug 2022 08:32:48 -0500 Subject: [PATCH 198/515] The only thing i'm proud of --- demos/BONUS. Sonic 2 Boss.fur | Bin 0 -> 17308 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/BONUS. Sonic 2 Boss.fur diff --git a/demos/BONUS. Sonic 2 Boss.fur b/demos/BONUS. Sonic 2 Boss.fur new file mode 100644 index 0000000000000000000000000000000000000000..8f5263f79c9f3ac8d34fdc79f6cf53f131f947d1 GIT binary patch literal 17308 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

#Mb2)^I^j*G*qT zuIQ10*nV@tG~eXYdEY!GugRJaEzh8X<`l1@YRZ0#&wKFI`RVbK?lWBI0}vgt=lGfWE!Q$hv_ z_Soy3c;ZJ$rNedMk}FetcFh7Jcw{IYs;2*5z5&0p2Q`B1V9!ytIdm*M@>5XVD<%g$2~^#8bE`t0AziIC_> z{FnVb-t-TsMl-ShDER9BDKcLF{UEDH{m=8Cy8~aI0-VOz?E8O<59J&t^#9tESit?y zK>t(WDv}V8`M-k53=x__gZod=WA;30xC5lX|Df~G-~Vq41vqiTvJKb5|1yN{x&6m3 zffedMV0JuXEifRsMM?g{DsTC}DatWLcBg3#82(q>|HmW#SH)?F5|a6tJWkYquw?Au z$NwLX_-_gx(mufzmN$IIaX2ZaeonM`59=S`O~BqAmn+P-kgrQAP*eyL!2THp{VhbG zQ1Jxw%^>cJ3SL-7{a>zh9Z8O8bML^@T zpdX~8eQM}`W%?ES{4@FhH!&Utu~R|ZMS~OQgwP6^%gNWer?DrX@!Q-+P#pu+EGT_n z_5!r_;&uL?!&}ULu%ra_(p*UTV)r|6qy?1sPo^0O7;E+WiG5BZ=ho4p=1}DBaVLSy z_tzJ{%H0P9Ye3NX7YU%<&!Xy$blpP%m(=$Mz?G^-$G>Nn1*ryyJr}gkr5YWmbJwVb9O!%(137k$f3?0XT7ZBp=p9zj9%Z7eVFY(b(Q)RJ*zyC6vs7~v5Dk% z)%w$(q8t6wpIhz$bjUOdQp>FQ5|oB>W&&hz%fM-5XKw!F(HQ^J#M!($n@PW|Bkv#v zGCLoF|N0)H!Ds8+ zIdKl@XzzhLuKXpqAgn-jfZ!CrE!p%X1uC}-$sL-fdEkFg;zICC>PTp~6s+#)*eN=- zx|-|w*FH%6!*+)GIZgjx&2O>fg9r~ERhO-R?NliqSV{363a2kMRdDkq{#9F7WLxGg z!N%E_yteKEq$5nU2Rg{o-R?WjgzsO##rOdp2nFTL?@$*V3Bm+XE#E(TnTs&Fg-Jm` zz{4GQed+%beks---#$)+7``EOL_mdXCkF`C9v{0g-}?WH_0L4HS4|zF48dgxVRvk- z4ZlavpqT3A$k-SJHEqL}j8-<45FH_k#uv{l4fp>@(5&{*pr%daF7p4Y%l`39is6Fl zzyEIF8RkVdD*8{3A61SyAi@OrlaBZwZv*BA|Nqg*suplqTBQG5JkvjAa^uV&UsrBGYtpZV4haDkIn6a_dyAFJxcns3Wf*tD{@*1G!^fw+fR;f;=-(HtnCN9~z;qO@R3inJD~-g-GG-+DX# zN1dM6fD|!;FyvDAM2z8r>u5c03CtRyUBtpOn=)bf|LuuGUJWnuH;}VW`2z=z1>CW`eGv6*em&0$0UWxsm+_Hel_~~gbZ%}dX^Wp2^B&UY?!VjLm z`X|bnn04A?O~ju{(R^W_C+eSsf9A_pcKq2c39K%@f{d?)@*? zm*3_8_UV6I{+oyYyY2S>GUq}WAJK^mbNX23b2A=&FSK*&3xmx|jBo!cUTVJRzkc}q z7yoa~c=7+)rJeVF?N?GfQ&W00Mx_P4VtroZWFlVD_1q&LSU1C>B!V9p{=eQYyc5N> zAA`s<36HaZ9ulay44sL{@#+eZXfYYR!$k!Ub08 NaEbr_7yI=D008b-jFSKW literal 0 HcmV?d00001 From 9f9ee6153e39904b2060029745d65c8a091c4e4c Mon Sep 17 00:00:00 2001 From: SirForte <67491162+SirForte@users.noreply.github.com> Date: Sun, 14 Aug 2022 08:33:21 -0500 Subject: [PATCH 199/515] old crappy demo song --- ..._thing_the_Metallix_fear_is_you_Forte....fur | Bin 59895 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 demos/The_only_thing_the_Metallix_fear_is_you_Forte....fur diff --git a/demos/The_only_thing_the_Metallix_fear_is_you_Forte....fur b/demos/The_only_thing_the_Metallix_fear_is_you_Forte....fur deleted file mode 100644 index 123381d8dc27c50307fcc76664ca1fc82d92b8dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59895 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 From 1b10c547e38daebb1951c7fa2eadeead6d15c069 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 14 Aug 2022 14:19:30 -0500 Subject: [PATCH 200/515] SoundUnit: implement switch roles flag --- src/engine/platform/su.cpp | 48 ++++++++++++++++++++++++++++---------- src/engine/platform/su.h | 4 +++- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 6c6b0b329..ef06e4bf6 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -26,6 +26,7 @@ #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_DIVIDER 8 #define CHIP_FREQBASE 524288 const char** DivPlatformSoundUnit::getRegisterSheet() { @@ -98,6 +99,13 @@ const char* DivPlatformSoundUnit::getEffectName(unsigned char effect) { return NULL; } +double DivPlatformSoundUnit::NOTE_SU(int ch, int note) { + if (chan[ch].switchRoles) { + return NOTE_PERIODIC(note); + } + return NOTE_FREQUENCY(note); +} + void DivPlatformSoundUnit::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h0); - chWrite(i,0x1e,chan[i].syncTimer&0xff); - chWrite(i,0x1f,chan[i].syncTimer>>8); + if (chan[i].switchRoles) { + chWrite(i,0x00,chan[i].syncTimer&0xff); + chWrite(i,0x01,chan[i].syncTimer>>8); + } else { + chWrite(i,0x1e,chan[i].syncTimer&0xff); + chWrite(i,0x1f,chan[i].syncTimer>>8); + } writeControlUpper(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,2,chan[i].pitch2,chipClock,CHIP_FREQBASE); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].switchRoles,2,chan[i].pitch2,chipClock,chan[i].switchRoles?CHIP_DIVIDER:CHIP_FREQBASE); if (chan[i].pcm) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); // TODO: sample map? @@ -213,8 +226,13 @@ void DivPlatformSoundUnit::tick(bool sysTick) { } if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; - chWrite(i,0x00,chan[i].freq&0xff); - chWrite(i,0x01,chan[i].freq>>8); + if (chan[i].switchRoles) { + chWrite(i,0x1e,chan[i].freq&0xff); + chWrite(i,0x1f,chan[i].freq>>8); + } else { + chWrite(i,0x00,chan[i].freq&0xff); + chWrite(i,0x01,chan[i].freq>>8); + } if (chan[i].keyOn) { if (chan[i].pcm) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); @@ -256,6 +274,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU); + chan[c.chan].switchRoles=ins->su.switchRoles; if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->su.useSample)) { chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); writeControl(c.chan); @@ -263,7 +282,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { } chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -421,7 +440,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { } break; case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_FREQUENCY(c.value2); + int destFreq=NOTE_SU(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:(1+(chan[c.chan].baseFreq>>9))); @@ -453,7 +472,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { chan[c.chan].keyOn=true; 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].baseFreq=NOTE_SU(c.chan,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; @@ -461,7 +480,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU)); } - if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_SU(c.chan,chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: @@ -485,6 +504,11 @@ void DivPlatformSoundUnit::forceIns() { for (int i=0; i<8; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; + + // restore channel attributes + chWrite(i,0x03,chan[i].pan); + writeControl(i); + writeControlUpper(i); } } diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 9972599d4..2392624f6 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -31,7 +31,7 @@ class DivPlatformSoundUnit: public DivDispatch { int ins, cutoff, baseCutoff, res, control, hasOffset; signed char pan; unsigned char duty; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, phaseReset, filterPhaseReset; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, phaseReset, filterPhaseReset, switchRoles; bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep; unsigned short freqSweepP, volSweepP, cutSweepP; unsigned char freqSweepB, volSweepB, cutSweepB; @@ -67,6 +67,7 @@ class DivPlatformSoundUnit: public DivDispatch { pcm(false), phaseReset(false), filterPhaseReset(false), + switchRoles(false), pcmLoop(false), timerSync(false), freqSweep(false), @@ -108,6 +109,7 @@ class DivPlatformSoundUnit: public DivDispatch { SoundUnit* su; size_t sampleMemLen; unsigned char regPool[128]; + double NOTE_SU(int ch, int note); void writeControl(int ch); void writeControlUpper(int ch); From cb4417824d383a9041d3476317d52ba915f6de0c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 14 Aug 2022 14:26:55 -0500 Subject: [PATCH 201/515] YMZ280B: restore panning in forceIns --- src/engine/platform/ymz280b.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index b690d30cb..0543a815c 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -332,6 +332,8 @@ void DivPlatformYMZ280B::forceIns() { chan[i].insChanged=true; chan[i].freqChanged=true; chan[i].sample=-1; + + rWrite(0x03+i*4,chan[i].panning); } } From 9b6730607e2ae72ba5f32614d663badb90445fdd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 14 Aug 2022 19:17:03 -0500 Subject: [PATCH 202/515] OPL: finally fix the carnival night zone bug TODO: RUN TEST SUITE! --- src/engine/platform/opl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index a32777c33..8b76db213 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -872,6 +872,13 @@ int DivPlatformOPL::dispatch(DivCommand c) { int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2; chan[c.chan].fourOp=(ops==4); if (chan[c.chan].fourOp) { + /* + if (chan[c.chan+1].active) { + chan[c.chan+1].keyOff=true; + chan[c.chan+1].keyOn=false; + chan[c.chan+1].active=false; + }*/ + chan[c.chan+1].insChanged=true; chan[c.chan+1].macroInit(NULL); } update4OpMask=true; From f8b3c089a4386c8f40f7f80670956cf72edb919c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 14 Aug 2022 23:07:19 -0500 Subject: [PATCH 203/515] Game Boy: fix volume column --- src/engine/platform/gb.cpp | 11 ++++++++++- src/engine/platform/gb.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index a7b310935..9680d0ff9 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -373,6 +373,8 @@ void DivPlatformGB::tick(bool sysTick) { chan[i].killIt=false; } } + + chan[i].soManyHacksToMakeItDefleCompatible=false; } } @@ -409,10 +411,16 @@ int DivPlatformGB::dispatch(DivCommand c) { ws.init(ins,32,15,chan[c.chan].insChanged); } if ((chan[c.chan].insChanged || ins->gb.alwaysInit) && !chan[c.chan].softEnv) { - chan[c.chan].envVol=ins->gb.envVol; + if (!chan[c.chan].soManyHacksToMakeItDefleCompatible) { + chan[c.chan].envVol=ins->gb.envVol; + } chan[c.chan].envLen=ins->gb.envLen; chan[c.chan].envDir=ins->gb.envDir; chan[c.chan].soundLen=ins->gb.soundLen; + if (!chan[c.chan].soManyHacksToMakeItDefleCompatible) { + chan[c.chan].vol=chan[c.chan].envVol; + chan[c.chan].outVol=chan[c.chan].envVol; + } } if (c.chan==2 && chan[c.chan].softEnv) { chan[c.chan].soundLen=64; @@ -460,6 +468,7 @@ int DivPlatformGB::dispatch(DivCommand c) { } if (!chan[c.chan].softEnv) { chan[c.chan].envVol=chan[c.chan].vol; + chan[c.chan].soManyHacksToMakeItDefleCompatible=true; } else if (c.chan!=2) { chan[c.chan].envVol=chan[c.chan].vol; if (!chan[c.chan].keyOn) chan[c.chan].killIt=true; diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 9498317bd..00dcca036 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -31,6 +31,7 @@ class DivPlatformGB: public DivDispatch { int freq, baseFreq, pitch, pitch2, note, ins; unsigned char duty, sweep; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, released, softEnv, killIt; + bool soManyHacksToMakeItDefleCompatible; signed char vol, outVol, wave, lastKill; unsigned char envVol, envDir, envLen, soundLen; unsigned short hwSeqPos; @@ -59,6 +60,7 @@ class DivPlatformGB: public DivDispatch { released(false), softEnv(false), killIt(false), + soManyHacksToMakeItDefleCompatible(false), vol(15), outVol(15), wave(-1), From 23276211f5dfb037e1d487e696324e8b473b93dc Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 15 Aug 2022 13:25:31 +0900 Subject: [PATCH 204/515] Fix incorrect info on ES5506 --- src/engine/sysDef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index c5541baa3..73964089a 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1840,7 +1840,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( "Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false, - "a sample chip used in the Gravis Ultrasound, popular in the PC (DOS) demoscene.", + "a sample chip used in the Ensoniq's unique transwave synthesizers, \nand SoundScape series PC ISA soundcards...\nthat's just yet another (partially)SB compatible one with emulated OPL3 and MIDI ROMpler.", {"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", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, From a8d3803efcb98243f44cf493ccb29cc15b2ffbb6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 14 Aug 2022 23:28:15 -0500 Subject: [PATCH 205/515] Game Boy: now fix wave channel volume column --- src/engine/platform/gb.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 9680d0ff9..27d2ff839 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -84,7 +84,7 @@ const char* DivPlatformGB::getEffectName(unsigned char effect) { void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; igb.alwaysInit) && !chan[c.chan].softEnv) { - if (!chan[c.chan].soManyHacksToMakeItDefleCompatible) { + if (!chan[c.chan].soManyHacksToMakeItDefleCompatible && c.chan!=2) { chan[c.chan].envVol=ins->gb.envVol; } chan[c.chan].envLen=ins->gb.envLen; chan[c.chan].envDir=ins->gb.envDir; chan[c.chan].soundLen=ins->gb.soundLen; - if (!chan[c.chan].soManyHacksToMakeItDefleCompatible) { + if (!chan[c.chan].soManyHacksToMakeItDefleCompatible && c.chan!=2) { chan[c.chan].vol=chan[c.chan].envVol; chan[c.chan].outVol=chan[c.chan].envVol; } From a34c9806cb847ff6ec91a186095b52cbf63680c9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 14 Aug 2022 23:30:36 -0500 Subject: [PATCH 206/515] Game Boy: whoops --- src/engine/platform/gb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 27d2ff839..b6a00c0f1 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -84,7 +84,7 @@ const char* DivPlatformGB::getEffectName(unsigned char effect) { void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i Date: Sun, 14 Aug 2022 23:34:57 -0500 Subject: [PATCH 207/515] fix system definition for ES5506 - again --- src/engine/sysDef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 73964089a..e3c356cf7 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1840,7 +1840,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( "Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false, - "a sample chip used in the Ensoniq's unique transwave synthesizers, \nand SoundScape series PC ISA soundcards...\nthat's just yet another (partially)SB compatible one with emulated OPL3 and MIDI ROMpler.", + "a sample chip used in the Ensoniq's unique TransWave synthesizers, and SoundScape series PC ISA soundcards (which are yet another (partially) Sound Blaster compatible ones with emulated OPL3 and MIDI ROMpler).", {"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", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, From 15b42945323fa3f591f48c95dec8003b0ef77111 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 02:01:08 -0500 Subject: [PATCH 208/515] FC loader: fix wave, sample and freq seq loading --- src/engine/fileOps.cpp | 64 +++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index db2305c65..c5084252d 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2272,8 +2272,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { unsigned int patPtr, freqMacroPtr, volMacroPtr, samplePtr, wavePtr; unsigned int seqLen, patLen, freqMacroLen, volMacroLen, sampleLen; - unsigned char waveLen[40]; - unsigned char waveLoopLen[40]; + unsigned char waveLen[80]; + //unsigned char waveLoopLen[40]; struct FCSequence { unsigned char pat[4]; @@ -2363,24 +2363,24 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { wavePtr=0; } - logD("patPtr: %d",patPtr); + logD("patPtr: %x",patPtr); logD("patLen: %d",patLen); - logD("freqMacroPtr: %d",freqMacroPtr); + logD("freqMacroPtr: %x",freqMacroPtr); logD("freqMacroLen: %d",freqMacroLen); - logD("volMacroPtr: %d",volMacroPtr); + logD("volMacroPtr: %x",volMacroPtr); logD("volMacroLen: %d",volMacroLen); - logD("samplePtr: %d",samplePtr); + logD("samplePtr: %x",samplePtr); if (isFC14) { - logD("wavePtr: %d",wavePtr); + logD("wavePtr: %x",wavePtr); } else { logD("sampleLen: %d",sampleLen); } // sample info - logD("samples:"); + logD("samples: (%x)",reader.tell()); for (int i=0; i<10; i++) { - sample[i].loopLen=reader.readS_BE(); sample[i].len=reader.readS_BE(); + sample[i].loopLen=reader.readS_BE(); sample[i].loopStart=reader.readS_BE(); logD("- %d: %d (%d, %d)",i,sample[i].len,sample[i].loopStart,sample[i].loopLen); @@ -2389,11 +2389,10 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { // wavetable lengths if (isFC14) { logD("wavetables:"); - for (int i=0; i<40; i++) { - waveLen[i]=reader.readC(); - waveLoopLen[i]=reader.readC(); + for (int i=0; i<80; i++) { + waveLen[i]=(unsigned char)reader.readC(); - logD("- %d: %.4x (%.4x)",i,waveLen[i],waveLoopLen[i]); + logD("- %d: %.4x",i,waveLen[i]); } } @@ -2482,11 +2481,12 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { DivSample* s=new DivSample; s->depth=DIV_SAMPLE_DEPTH_8BIT; if (sample[i].len>0) { - s->init(sample[i].len); + s->init(sample[i].len*2); } + s->name=fmt::sprintf("Sample %d",i+1); s->loopStart=sample[i].loopStart*2; s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; - reader.read(s->data8,sample[i].len); + reader.read(s->data8,sample[i].len*2); ds.sample.push_back(s); } ds.sampleLen=(int)ds.sample.size(); @@ -2500,11 +2500,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { return false; } logD("reading wavetables..."); - for (int i=0; i<40; i++) { + for (int i=0; i<80; i++) { DivWavetable* w=new DivWavetable; w->min=0; w->max=255; - w->len=MIN(256,waveLoopLen[i]*2); + w->len=MIN(256,waveLen[i]*2); for (int i=0; i<256; i++) { w->data[i]=128; @@ -2513,13 +2513,14 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (waveLen[i]>0) { signed char* waveArray=new signed char[waveLen[i]*2]; reader.read(waveArray,waveLen[i]*2); - int howMany=MIN(waveLen[i]*2,waveLoopLen[i]*2); + int howMany=waveLen[i]*2; if (howMany>256) howMany=256; for (int i=0; idata[i]=waveArray[i]+128; } delete[] waveArray; } else { + logV("empty wave %d",i); w->len=32; for (int i=0; i<32; i++) { w->data[i]=(i*255)/31; @@ -2600,9 +2601,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } } else { - p->data[k][2]=fp.val[k]&0x3f; + p->data[k][2]=(fp.val[k]+seq[i].offsetIns[j])&0x3f; } } + } else if (fp.note[k]>0) { + p->data[k][2]=seq[i].offsetIns[j]; } } } @@ -2627,6 +2630,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { signed char loopMap[64]; memset(loopMap,-1,64); + signed char loopMapFreq[64]; + memset(loopMapFreq,-1,64); + // volume sequence ins->std.volMacro.len=0; for (int j=5; j<64; j++) { @@ -2678,7 +2684,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (freqMacrostd.arpMacro.len; if (fm.val[j]==0xe1) { + if (ins->std.arpMacro.mode) { + ins->std.arpMacro.loop=(signed int)ins->std.arpMacro.len-1; + } break; } else if (fm.val[j]==0xe2 || fm.val[j]==0xe4) { if (++j>=64) break; @@ -2692,11 +2702,12 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.waveMacro.val[ins->std.waveMacro.len]=wave-10; ins->std.waveMacro.open=true; lastVal=wave; - if (++ins->std.waveMacro.len>=128) break; if (++ins->std.arpMacro.len>=128) break; } } else if (fm.val[j]==0xe0) { - logV("unhandled loop!"); + if (++j>=64) break; + ins->std.arpMacro.loop=loopMapFreq[fm.val[j]&63]; + break; } else if (fm.val[j]==0xe3) { logV("unhandled vibrato!"); } else if (fm.val[j]==0xe8) { @@ -2708,9 +2719,18 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } else if (fm.val[j]==0xea) { logV("unhandled pitch!"); } else { - ins->std.arpMacro.val[ins->std.arpMacro.len]=(signed char)fm.val[j]; + if (fm.val[j]>0x80) { + ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j]-0x80+24; + ins->std.arpMacro.mode=1; // TODO: variable fixed/relative mode + } else { + ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j]; + } + if (lastVal>=10) { + ins->std.waveMacro.val[ins->std.waveMacro.len]=lastVal-10; + } ins->std.arpMacro.open=true; if (++ins->std.arpMacro.len>=128) break; + if (++ins->std.waveMacro.len>=128) break; } } } From 4663534fa3565a49ab8c3acf6098d0dd06efa9ea Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 03:18:54 -0500 Subject: [PATCH 209/515] FC loader: preset waveforms, vibrato and stuff --- src/engine/fileOps.cpp | 189 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 14 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index c5084252d..2ac810c69 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2262,6 +2262,95 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { return success; } +unsigned char fcXORTriangle[32]={ + 0xc0, 0xc0, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0x00, 0xf8, 0xf0, 0xe8, 0xe0, 0xd8, 0xd0, 0xc8, + 0xc0, 0xb8, 0xb0, 0xa8, 0xa0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8 +}; + +unsigned char fcCustom1[32]={ + 0x45, 0x45, 0x79, 0x7d, 0x7a, 0x77, 0x70, 0x66, 0x61, 0x58, 0x53, 0x4d, 0x2c, 0x20, 0x18, 0x12, + 0x04, 0xdb, 0xd3, 0xcd, 0xc6, 0xbc, 0xb5, 0xae, 0xa8, 0xa3, 0x9d, 0x99, 0x93, 0x8e, 0x8b, 0x8a +}; + +unsigned char fcCustom2[32]={ + 0x45, 0x45, 0x79, 0x7d, 0x7a, 0x77, 0x70, 0x66, 0x5b, 0x4b, 0x43, 0x37, 0x2c, 0x20, 0x18, 0x12, + 0x04, 0xf8, 0xe8, 0xdb, 0xcf, 0xc6, 0xbe, 0xb0, 0xa8, 0xa4, 0x9e, 0x9a, 0x95, 0x94, 0x8d, 0x83 +}; + +unsigned char fcTinyTriangle[16]={ + 0x00, 0x00, 0x40, 0x60, 0x7f, 0x60, 0x40, 0x20, 0x00, 0xe0, 0xc0, 0xa0, 0x80, 0xa0, 0xc0, 0xe0 +}; + +void generateFCPresetWave(int index, DivWavetable* wave) { + wave->max=255; + wave->len=32; + + switch (index) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // XOR triangle + for (int i=0; i<32; i++) { + wave->data[i]=(unsigned char)((fcXORTriangle[i]^0x80)^(((index+15)data[i]=(index>i)?0x01:0xff; + } + break; + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + // tiny pulse + for (int i=0; i<32; i++) { + wave->data[i]=((index-0x18)>(i&15))?0x01:0xff; + } + break; + case 0x28: + case 0x2e: + // saw + for (int i=0; i<32; i++) { + wave->data[i]=i<<3; + } + break; + case 0x29: + case 0x2f: + // tiny saw + for (int i=0; i<32; i++) { + wave->data[i]=(i<<4)&0xff; + } + break; + case 0x2a: + // custom 1 + for (int i=0; i<32; i++) { + wave->data[i]=fcCustom1[i]^0x80; + } + break; + case 0x2b: + // custom 2 + for (int i=0; i<32; i++) { + wave->data[i]=fcCustom2[i]^0x80; + } + break; + case 0x2c: case 0x2d: + // tiny triangle + for (int i=0; i<32; i++) { + wave->data[i]=fcTinyTriangle[i&15]^0x80; + } + break; + default: + for (int i=0; i<32; i++) { + wave->data[i]=i; + } + break; + } +} + bool DivEngine::loadFC(unsigned char* file, size_t len) { struct InvalidHeaderException {}; bool success=false; @@ -2301,10 +2390,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { DivSong ds; ds.tuning=436.0; ds.version=DIV_VERSION_FC; - //ds.linearPitch=0; + ds.linearPitch=0; + ds.pitchMacroIsLinear=false; //ds.noSlidesOnFirstTick=true; //ds.rowResetsArpPos=true; - //ds.ignoreJumpAtEnd=false; + ds.ignoreJumpAtEnd=false; // load here if (!reader.seek(0,SEEK_SET)) { @@ -2521,12 +2611,16 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { delete[] waveArray; } else { logV("empty wave %d",i); - w->len=32; - for (int i=0; i<32; i++) { - w->data[i]=(i*255)/31; - } + generateFCPresetWave(i,w); } + ds.wave.push_back(w); + } + } else { + // generate preset waves + for (int i=0; i<48; i++) { + DivWavetable* w=new DivWavetable; + generateFCPresetWave(i,w); ds.wave.push_back(w); } } @@ -2542,6 +2636,14 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ds.subsong[0]->speed1=3; ds.subsong[0]->speed2=3; + int lastIns[4]; + int lastNote[4]; + signed char lastTranspose[4]; + + memset(lastIns,-1,4*sizeof(int)); + memset(lastNote,-1,4*sizeof(int)); + memset(lastTranspose,0,4); + for (unsigned int i=0; iorders.ord[j][i]=i; @@ -2559,6 +2661,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { for (int k=0; k<32; k++) { FCPattern& fp=pat[seq[i].pat[j]]; if (fp.note[k]>0 && fp.note[k]<0x49) { + lastNote[j]=fp.note[k]; short note=(fp.note[k]+seq[i].transpose[j])%12; short octave=2+((fp.note[k]+seq[i].transpose[j])/12); if (fp.note[k]>=0x3d) octave-=6; @@ -2574,6 +2677,27 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { p->data[k][4]=2; p->data[k][5]=0; } + } else if (fp.note[k]==0x49) { + if (k>0) { + p->data[k-1][4]=0x0d; + p->data[k-1][5]=0; + } + } else if (k==0 && lastTranspose[j]!=seq[i].transpose[j]) { + p->data[0][2]=lastIns[j]; + p->data[0][4]=0x03; + p->data[0][5]=0xff; + lastTranspose[j]=seq[i].transpose[j]; + + short note=(lastNote[j]+seq[i].transpose[j])%12; + short octave=2+((lastNote[j]+seq[i].transpose[j])/12); + if (lastNote[j]>=0x3d) octave-=6; + if (note==0) { + note=12; + octave--; + } + octave&=0xff; + p->data[k][0]=note; + p->data[k][1]=octave; } if (fp.val[k]) { if (ignoreNext) { @@ -2602,10 +2726,12 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } else { p->data[k][2]=(fp.val[k]+seq[i].offsetIns[j])&0x3f; + lastIns[j]=p->data[k][2]; } } - } else if (fp.note[k]>0) { + } else if (fp.note[k]>0 && fp.note[k]<0x49) { p->data[k][2]=seq[i].offsetIns[j]; + lastIns[j]=p->data[k][2]; } } } @@ -2619,11 +2745,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->type=DIV_INS_AMIGA; ins->name=fmt::sprintf("Instrument %d",i); ins->amiga.useWave=true; - //unsigned char seqSpeed=m.val[0]; + unsigned char seqSpeed=m.val[0]; unsigned char freqMacro=m.val[1]; - //unsigned char vibSpeed=m.val[2]; - //unsigned char vibDepth=m.val[3]; - //unsigned char vibDelay=m.val[4]; + unsigned char vibSpeed=m.val[2]; + unsigned char vibDepth=m.val[3]; + unsigned char vibDelay=m.val[4]; unsigned char lastVal=m.val[5]; @@ -2633,6 +2759,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { signed char loopMapFreq[64]; memset(loopMapFreq,-1,64); + signed char loopMapWave[64]; + memset(loopMapWave,-1,64); + // volume sequence ins->std.volMacro.len=0; for (int j=5; j<64; j++) { @@ -2672,9 +2801,13 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (++ins->std.volMacro.len>=128) break; } } else { - ins->std.volMacro.val[ins->std.volMacro.len]=m.val[j]; - lastVal=m.val[j]; - if (++ins->std.volMacro.len>=128) break; + // TODO: replace with upcoming macro speed + for (int k=0; kstd.volMacro.val[ins->std.volMacro.len]=m.val[j]; + lastVal=m.val[j]; + if (++ins->std.volMacro.len>=128) break; + } + if (ins->std.volMacro.len>=128) break; } } @@ -2685,6 +2818,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { FCMacro& fm=freqMacros[freqMacro]; for (int j=0; j<64; j++) { loopMapFreq[j]=ins->std.arpMacro.len; + loopMapWave[j]=ins->std.waveMacro.len; if (fm.val[j]==0xe1) { if (ins->std.arpMacro.mode) { ins->std.arpMacro.loop=(signed int)ins->std.arpMacro.len-1; @@ -2707,6 +2841,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } else if (fm.val[j]==0xe0) { if (++j>=64) break; ins->std.arpMacro.loop=loopMapFreq[fm.val[j]&63]; + ins->std.waveMacro.loop=loopMapWave[fm.val[j]&63]; break; } else if (fm.val[j]==0xe3) { logV("unhandled vibrato!"); @@ -2735,6 +2870,32 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } + // vibrato + for (int j=0; j<=vibDelay; j++) { + ins->std.pitchMacro.val[ins->std.pitchMacro.len]=0; + if (++ins->std.pitchMacro.len>=128) break; + } + int vibPos=0; + ins->std.pitchMacro.loop=ins->std.pitchMacro.len; + do { + vibPos+=vibSpeed; + if (vibPos>vibDepth) vibPos=vibDepth; + ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*4; + if (++ins->std.pitchMacro.len>=128) break; + } while (vibPosstd.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*4; + if (++ins->std.pitchMacro.len>=128) break; + } while (vibPos>-vibDepth); + do { + vibPos+=vibSpeed; + if (vibPos>0) vibPos=0; + ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*4; + if (++ins->std.pitchMacro.len>=128) break; + } while (vibPos<0); + ds.ins.push_back(ins); } ds.insLen=(int)ds.ins.size(); From bef8cf5f5f374bdb811932523a180aa75274ac55 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 03:32:27 -0500 Subject: [PATCH 210/515] FC loader: sample loop point and more fixes --- src/engine/fileOps.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 2ac810c69..a9b0bcfc8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2470,8 +2470,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { logD("samples: (%x)",reader.tell()); for (int i=0; i<10; i++) { sample[i].len=reader.readS_BE(); - sample[i].loopLen=reader.readS_BE(); sample[i].loopStart=reader.readS_BE(); + sample[i].loopLen=reader.readS_BE(); logD("- %d: %d (%d, %d)",i,sample[i].len,sample[i].loopStart,sample[i].loopLen); } @@ -2574,8 +2574,10 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { s->init(sample[i].len*2); } s->name=fmt::sprintf("Sample %d",i+1); - s->loopStart=sample[i].loopStart*2; - s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; + if (sample[i].loopLen>1) { + s->loopStart=sample[i].loopStart; + s->loopEnd=sample[i].loopStart+(sample[i].loopLen*2); + } reader.read(s->data8,sample[i].len*2); ds.sample.push_back(s); } @@ -2703,7 +2705,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (ignoreNext) { ignoreNext=false; } else { - if (fp.val[k]&0xe0) { + if (fp.val[k]==0xf0) { + p->data[k][0]=100; + p->data[k][1]=0; + p->data[k][2]=-1; + } else if (fp.val[k]&0xe0) { if (fp.val[k]&0x40) { p->data[k][4]=2; p->data[k][5]=0; @@ -2780,6 +2786,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.volMacro.val[ins->std.volMacro.len]=lastVal; if (++ins->std.volMacro.len>=128) break; } + if (ins->std.volMacro.len>=128) break; } else if (m.val[j]==0xe9 || m.val[j]==0xea) { // volume slide if (++j>=64) break; signed char slideStep=m.val[j]; @@ -2870,6 +2877,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } + // waveform width + if (lastVal>=10 && (unsigned int)(lastVal-10)amiga.waveLen=ds.wave[lastVal-10]->len-1; + } + // vibrato for (int j=0; j<=vibDelay; j++) { ins->std.pitchMacro.val[ins->std.pitchMacro.len]=0; From 206b3af12a7e7aed2f814871fd8d1dc22a1b6188 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 03:40:04 -0500 Subject: [PATCH 211/515] FC loader: aaaaaaand more fixes --- src/engine/fileOps.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index a9b0bcfc8..4b7f78785 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2390,10 +2390,11 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { DivSong ds; ds.tuning=436.0; ds.version=DIV_VERSION_FC; - ds.linearPitch=0; - ds.pitchMacroIsLinear=false; + //ds.linearPitch=0; + //ds.pitchMacroIsLinear=false; //ds.noSlidesOnFirstTick=true; //ds.rowResetsArpPos=true; + ds.pitchSlideSpeed=8; ds.ignoreJumpAtEnd=false; // load here @@ -2843,7 +2844,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.waveMacro.val[ins->std.waveMacro.len]=wave-10; ins->std.waveMacro.open=true; lastVal=wave; - if (++ins->std.arpMacro.len>=128) break; + //if (++ins->std.arpMacro.len>=128) break; } } else if (fm.val[j]==0xe0) { if (++j>=64) break; @@ -2892,19 +2893,19 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { do { vibPos+=vibSpeed; if (vibPos>vibDepth) vibPos=vibDepth; - ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*4; + ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; if (++ins->std.pitchMacro.len>=128) break; } while (vibPosstd.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*4; + ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; if (++ins->std.pitchMacro.len>=128) break; } while (vibPos>-vibDepth); do { vibPos+=vibSpeed; if (vibPos>0) vibPos=0; - ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*4; + ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; if (++ins->std.pitchMacro.len>=128) break; } while (vibPos<0); From 20c5e14f266a4deaf1fd15864d3c8a511078a05a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 04:22:14 -0500 Subject: [PATCH 212/515] FC loader: the final fixes for this night --- src/engine/fileOps.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 4b7f78785..845ee98bd 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2642,10 +2642,12 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { int lastIns[4]; int lastNote[4]; signed char lastTranspose[4]; + bool isSliding[4]; memset(lastIns,-1,4*sizeof(int)); memset(lastNote,-1,4*sizeof(int)); memset(lastTranspose,0,4); + memset(isSliding,0,4*sizeof(bool)); for (unsigned int i=0; idata[k][0]=note; p->data[k][1]=octave; - if (isSliding) { - isSliding=false; + if (isSliding[j]) { + isSliding[j]=false; p->data[k][4]=2; p->data[k][5]=0; } @@ -2714,9 +2715,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (fp.val[k]&0x40) { p->data[k][4]=2; p->data[k][5]=0; - isSliding=false; + isSliding[j]=false; } else if (fp.val[k]&0x80) { - isSliding=true; + isSliding[j]=true; if (k<31) { if (fp.val[k+1]&0x20) { p->data[k][4]=2; @@ -2856,7 +2857,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } else if (fm.val[j]==0xe8) { logV("unhandled sustain!"); } else if (fm.val[j]==0xe7) { - logV("unhandled newseq!"); + if (++j>=64) break; + fm=freqMacros[MIN(fm.val[j],freqMacros.size()-1)]; + j=0; } else if (fm.val[j]==0xe9) { logV("unhandled pack!"); } else if (fm.val[j]==0xea) { From 2fb00e76149be685f4490cb4e6439949faa813df Mon Sep 17 00:00:00 2001 From: Eris Lund <38136789+0x5066@users.noreply.github.com> Date: Mon, 15 Aug 2022 20:37:21 +0200 Subject: [PATCH 213/515] Add files via upload --- .../government funding breakcore-ish remix.fur | Bin 0 -> 417084 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/government funding breakcore-ish remix.fur diff --git a/demos/government funding breakcore-ish remix.fur b/demos/government funding breakcore-ish remix.fur new file mode 100644 index 0000000000000000000000000000000000000000..5659ca1a1a930c347249e700da26b6bf5be42bfe GIT binary patch literal 417084 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

yZB1y%9oUOX> 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

SbKxOT%qU&}-j5jq3;5;z8=YzyB|O{4 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 z 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

dJS3K6f7_(_vm#dV3je+DA;ou*vV6z6JW2rW6V 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

Y-376yk^et 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

p9OPfR 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 z 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�aE4*N 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 Date: Mon, 15 Aug 2022 21:46:36 -0500 Subject: [PATCH 215/515] PET: fix missing pitch macro --- src/engine/platform/pet.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 493436271..dc524e45f 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -133,8 +133,14 @@ void DivPlatformPET::tick(bool sysTick) { } } if (chan.std.pitch.had) { - chan.freqChanged=true; + if (chan.std.pitch.mode) { + chan.pitch2+=chan.std.pitch.val; + CLAMP_VAR(chan.pitch2,-32768,32767); + } else { + chan.pitch2=chan.std.pitch.val; } + chan.freqChanged=true; + } if (chan.freqChanged || chan.keyOn || chan.keyOff) { chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.pitch2,chipClock,CHIP_DIVIDER)-2; if (chan.freq>65535) chan.freq=65535; From 474dfa2587c7bfa178a7b3c9199d84cd05cec449 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 22:36:26 -0500 Subject: [PATCH 216/515] Game Boy: fix bug involving hw sweep and zombie --- src/engine/platform/gb.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index b6a00c0f1..c29329b95 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -181,7 +181,6 @@ void DivPlatformGB::tick(bool sysTick) { chan[i].soundLen=64; if (!chan[i].keyOn) chan[i].killIt=true; - chan[i].freqChanged=true; } } } @@ -353,25 +352,24 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; chan[i].freqChanged=false; + } + if (chan[i].killIt) { + if (i!=2) { + //rWrite(16+i*5+2,8); + int killDelta=chan[i].lastKill-chan[i].outVol+1; + if (killDelta<0) killDelta+=16; + chan[i].lastKill=chan[i].outVol; - if (chan[i].killIt) { - if (i!=2) { - //rWrite(16+i*5+2,8); - int killDelta=chan[i].lastKill-chan[i].outVol+1; - if (killDelta<0) killDelta+=16; - chan[i].lastKill=chan[i].outVol; - - if (killDelta!=1) { - rWrite(16+i*5+2,((chan[i].envVol<<4))|8); - for (int j=0; j Date: Mon, 15 Aug 2022 22:40:04 -0500 Subject: [PATCH 217/515] allow rates down to 1Hz --- src/engine/playback.cpp | 6 +++--- src/gui/songInfo.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 3ba4f1417..3dbc6b5fb 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -604,7 +604,7 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xc0: case 0xc1: case 0xc2: case 0xc3: // set Hz divider=(double)(((effect&0x3)<<8)|effectVal); - if (divider<10) divider=10; + if (divider<1) divider=1; cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider; clockDrift=0; subticks=0; @@ -695,7 +695,7 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xf0: // set Hz by tempo divider=(double)effectVal*2.0/5.0; - if (divider<10) divider=10; + if (divider<1) divider=1; cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider; clockDrift=0; subticks=0; @@ -959,7 +959,7 @@ void DivEngine::nextRow() { bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { bool ret=false; - if (divider<10) divider=10; + if (divider<1) divider=1; if (lowLatency && !skipping && !inhibitLowLat) { tickMult=1000/divider; diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 7f7e026ed..44982abaf 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -195,7 +195,7 @@ void FurnaceGUI::drawSongInfo() { float setHz=tempoView?e->curSubSong->hz*2.5:e->curSubSong->hz; if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { MARK_MODIFIED if (tempoView) setHz/=2.5; - if (setHz<10) setHz=10; + if (setHz<1) setHz=1; if (setHz>999) setHz=999; e->setSongRate(setHz,setHz<52); } From 51cc36532e223b4aefa82b8c74b1d21ac13d4e70 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 22:44:55 -0500 Subject: [PATCH 218/515] fix documentation regarding ZX beeper samples --- papers/doc/6-sample/README.md | 2 +- papers/doc/7-systems/zxbeep.md | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/papers/doc/6-sample/README.md b/papers/doc/6-sample/README.md index 035a58cc6..59613da27 100644 --- a/papers/doc/6-sample/README.md +++ b/papers/doc/6-sample/README.md @@ -48,7 +48,7 @@ due to limitations in some of those sound chips, some restrictions exist: - Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is ~55KHz. - YM2608: the maximum frequency is ~55KHz. - MSM6258/MSM6295: no arbitrary frequency. -- ZX Spectrum Beeper: your sample can't be longer than 2048. +- ZX Spectrum Beeper: your sample can't be longer than 2048, and it always plays at ~55KHz. - Seta/Allumer X1-010: frequency resolution is terrible in the lower end. your sample can't be longer than 131072. furthermore, many of these chips have a limited amount of sample memory. check memory usage in window > statistics. diff --git a/papers/doc/7-systems/zxbeep.md b/papers/doc/7-systems/zxbeep.md index 1c6cd74f3..9e25284bf 100644 --- a/papers/doc/7-systems/zxbeep.md +++ b/papers/doc/7-systems/zxbeep.md @@ -2,9 +2,12 @@ Rather than having a dedicated sound synthesizer, early ZX Spectrum models had one piezo beeper, controlled by Z80 CPU and ULA chip. It's capabilities should be on par with an IBM PC speaker... right? -Not really - very soon talented programmers found out ways to output much more than one square wave channel. A lot of ZX beeper routines do exist, as of 0.6pre1 Furnace supports only one - Follin-like engine with 6 channels of narrow pulse wave and click drums. +Not really - very soon talented programmers found out ways to output much more than one square wave channel. A lot of ZX beeper routines do exist, but as of 0.6pre1 Furnace supports only one - Follin-like engine with 6 channels of narrow pulse wave and click drums. # effects -- `12xx`: set pulse width -- `17xx`: trigger overlay drums. +- `12xx`: set pulse width. +- `17xx`: trigger overlay drum. + - `xx` is the sample number. + - overlay drums are 1-bit and always play at 55930Hz (NTSC) or 55420Hz (PAL). + - the maximum length is 2048! \ No newline at end of file From 77109c3832ab750f38ee088a8cb4768772e0eddf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 22:54:31 -0500 Subject: [PATCH 219/515] fix instrument move/del screwing up sub-songs --- src/engine/engine.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 4c51f367f..68c492219 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2181,11 +2181,13 @@ void DivEngine::delInstrument(int index) { song.ins.erase(song.ins.begin()+index); song.insLen=song.ins.size(); for (int i=0; ipatLen; k++) { - if (curPat[i].data[j]->data[k][2]>index) { - curPat[i].data[j]->data[k][2]--; + for (size_t j=0; jpat[i].data[k]==NULL) continue; + for (int l=0; lpatLen; l++) { + if (song.subsong[j]->pat[i].data[k]->data[l][2]>index) { + song.subsong[j]->pat[i].data[k]->data[l][2]--; + } } } } @@ -2986,13 +2988,15 @@ void DivEngine::moveOrderDown() { void DivEngine::exchangeIns(int one, int two) { for (int i=0; ipatLen; k++) { - if (curPat[i].data[j]->data[k][2]==one) { - curPat[i].data[j]->data[k][2]=two; - } else if (curPat[i].data[j]->data[k][2]==two) { - curPat[i].data[j]->data[k][2]=one; + for (size_t j=0; jpat[i].data[k]==NULL) continue; + for (int l=0; lpatLen; l++) { + if (song.subsong[j]->pat[i].data[k]->data[l][2]==one) { + song.subsong[j]->pat[i].data[k]->data[l][2]=two; + } else if (song.subsong[j]->pat[i].data[k]->data[l][2]==two) { + song.subsong[j]->pat[i].data[k]->data[l][2]=one; + } } } } From 8734005b2302492c4e7a1e3b1b086578245ebbd6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 15 Aug 2022 23:20:26 -0500 Subject: [PATCH 220/515] SoundUnit: fix switch roles mode --- src/engine/platform/su.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index ef06e4bf6..8cd6d3abc 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -26,7 +26,7 @@ #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_DIVIDER 8 +#define CHIP_DIVIDER 2 #define CHIP_FREQBASE 524288 const char** DivPlatformSoundUnit::getRegisterSheet() { From fcb8fba77be923856a47d94b807b8764893070ef Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 02:07:57 -0500 Subject: [PATCH 221/515] GUI: fix particle commands --- src/gui/pattern.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 153944797..254c53bed 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -701,6 +701,15 @@ void FurnaceGUI::drawPattern() { if (i.cmd==DIV_CMD_SAMPLE_BANK) continue; if (i.cmd==DIV_CMD_GET_VOLUME) continue; if (i.cmd==DIV_ALWAYS_SET_VOLUME) continue; + if (i.cmd==DIV_CMD_HINT_VOLUME || + i.cmd==DIV_CMD_HINT_PORTA || + i.cmd==DIV_CMD_HINT_LEGATO || + i.cmd==DIV_CMD_HINT_VOL_SLIDE || + i.cmd==DIV_CMD_HINT_ARPEGGIO || + i.cmd==DIV_CMD_HINT_PITCH || + i.cmd==DIV_CMD_HINT_VIBRATO || + i.cmd==DIV_CMD_HINT_VIBRATO_RANGE || + i.cmd==DIV_CMD_HINT_VIBRATO_SHAPE) continue; float width=patChanX[i.chan+1]-patChanX[i.chan]; float speedX=0.0f; From 976e1933091f078c73a333bacb0e97410cb9231d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 02:08:10 -0500 Subject: [PATCH 222/515] SoundUnit: add 1-bit PDM rev emulation --- src/engine/platform/sound/su.cpp | 42 +++++++++++++++++++++++++++++--- src/engine/platform/sound/su.h | 4 ++- src/engine/platform/su.cpp | 2 +- src/gui/sysConf.cpp | 13 +++++++--- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/sound/su.cpp b/src/engine/platform/sound/su.cpp index 6637bfa7d..a87205457 100644 --- a/src/engine/platform/sound/su.cpp +++ b/src/engine/platform/sound/su.cpp @@ -300,12 +300,46 @@ void SoundUnit::NextSample(short* l, short* r) { } } - *l=minval(32767,maxval(-32767,tnsL)); - *r=minval(32767,maxval(-32767,tnsR)); + if (dsOut) { + tnsL=minval(32767,maxval(-32767,tnsL<<1)); + tnsR=minval(32767,maxval(-32767,tnsR<<1)); + + short accumL=0; + short accumR=0; + + for (int i=0; i<4; i++) { + if ((tnsL>>8)==0 && dsCounterL>0) dsCounterL=0; + dsCounterL+=tnsL>>8; + if (dsCounterL>=0) { + accumL+=4095; + dsCounterL-=127; + } else { + accumL+=-4095; + dsCounterL+=127; + } + + if ((tnsR>>8)==0 && dsCounterR>0) dsCounterR=0; + dsCounterR+=tnsR>>8; + if (dsCounterR>=0) { + accumR+=4095; + dsCounterR-=127; + } else { + accumR+=-4095; + dsCounterR+=127; + } + } + + *l=accumL; + *r=accumR; + } else { + *l=minval(32767,maxval(-32767,tnsL)); + *r=minval(32767,maxval(-32767,tnsR)); + } } -void SoundUnit::Init(int sampleMemSize) { +void SoundUnit::Init(int sampleMemSize, bool dsOutMode) { pcmSize=sampleMemSize; + dsOut=dsOutMode; Reset(); memset(pcm,0,pcmSize); for (int i=0; i<256; i++) { @@ -346,6 +380,8 @@ void SoundUnit::Reset() { oldflags[i]=0; pcmdec[i]=0; } + dsCounterL=0; + dsCounterR=0; tnsL=0; tnsR=0; ilBufPos=0; diff --git a/src/engine/platform/sound/su.h b/src/engine/platform/sound/su.h index 0ee843481..546acfc9c 100644 --- a/src/engine/platform/sound/su.h +++ b/src/engine/platform/sound/su.h @@ -27,6 +27,8 @@ class SoundUnit { unsigned short oldfreq[8]; unsigned short oldflags[8]; unsigned int pcmSize; + bool dsOut; + short dsCounterL, dsCounterR; public: unsigned short resetfreq[8]; unsigned short voldcycles[8]; @@ -99,7 +101,7 @@ class SoundUnit { if (ret>32767) ret=32767; return ret; } - void Init(int sampleMemSize=8192); + void Init(int sampleMemSize=8192, bool dsOutMode=false); void Reset(); SoundUnit(); }; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 8cd6d3abc..afcdba242 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -596,7 +596,7 @@ void DivPlatformSoundUnit::setFlags(unsigned int flags) { sampleMemSize=flags&16; - su->Init(sampleMemSize?65536:8192); + su->Init(sampleMemSize?65536:8192,flags&32); renderSamples(); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 484490348..a6bbcb921 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -135,13 +135,20 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("5.95MHz (PAL)",(flags&3)==1)) { copyOfFlags=(flags&(~3))|1; } - ImGui::Text("Chip revision (sample memory):"); - if (ImGui::RadioButton("A/B/E (8K)",(flags&16)==0)) { + ImGui::Text("Sample memory:"); + if (ImGui::RadioButton("8K (rev A/B/E)",(flags&16)==0)) { copyOfFlags=(flags&(~16))|0; } - if (ImGui::RadioButton("D/F (64K)",(flags&16)==16)) { + if (ImGui::RadioButton("64K (rev D/F)",(flags&16)==16)) { copyOfFlags=(flags&(~16))|16; } + ImGui::Text("DAC resolution"); + if (ImGui::RadioButton("16-bit (rev A/B/D/F)",(flags&32)==0)) { + copyOfFlags=(flags&(~32))|0; + } + if (ImGui::RadioButton("1-bit PDM (rev C/E)",(flags&32)==32)) { + copyOfFlags=(flags&(~32))|32; + } bool echo=flags&4; if (ImGui::Checkbox("Enable echo",&echo)) { copyOfFlags=(flags&(~4))|(echo<<2); From edddff8431b0d8254e36f9df4fccb6fddb0ac057 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 03:19:16 -0500 Subject: [PATCH 223/515] prepare for pattern optimization --- src/engine/fileOps.cpp | 4 ++ src/engine/pattern.cpp | 114 ++++++++++++++--------------------------- src/engine/pattern.h | 23 ++++++--- src/engine/song.cpp | 29 +++++++++++ src/engine/song.h | 2 + 5 files changed, 89 insertions(+), 83 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 845ee98bd..7cdcd5c8e 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2916,6 +2916,10 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } ds.insLen=(int)ds.ins.size(); + // optimize + ds.subsong[0]->optimizePatterns(); + ds.subsong[0]->rearrangePatterns(); + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); diff --git a/src/engine/pattern.cpp b/src/engine/pattern.cpp index 0a561376b..77255e084 100644 --- a/src/engine/pattern.cpp +++ b/src/engine/pattern.cpp @@ -18,6 +18,7 @@ */ #include "engine.h" +#include "../ta-log.h" static DivPattern emptyPat; @@ -40,6 +41,44 @@ DivPattern* DivChannelData::getPattern(int index, bool create) { return data[index]; } +std::vector> DivChannelData::optimize() { + std::vector> ret; + for (int i=0; i<256; i++) { + if (data[i]!=NULL) { + // compare + for (int j=0; j<256; j++) { + if (j==i) continue; + if (data[j]==NULL) continue; + if (memcmp(data[i]->data,data[j]->data,256*32*sizeof(short))==0) { + delete data[j]; + data[j]=NULL; + logV("%d == %d",i,j); + ret.push_back(std::pair(j,i)); + } + } + } + } + return ret; +} + +std::vector> DivChannelData::rearrange() { + std::vector> ret; + for (int i=0; i<256; i++) { + if (data[i]==NULL) { + for (int j=i; j<256; j++) { + if (data[j]!=NULL) { + data[i]=data[j]; + data[j]=NULL; + logV("%d -> %d",j,i); + ret.push_back(std::pair(j,i)); + if (++i>=256) break; + } + } + } + } + return ret; +} + void DivChannelData::wipePatterns() { for (int i=0; i<256; i++) { if (data[i]!=NULL) { @@ -54,81 +93,6 @@ void DivPattern::copyOn(DivPattern* dest) { memcpy(dest->data,data,sizeof(data)); } -SafeReader* DivPattern::compile(int len, int fxRows) { - SafeWriter w; - w.init(); - short lastNote, lastOctave, lastInstr, lastVolume, lastEffect[8], lastEffectVal[8]; - unsigned char rows=0; - - lastNote=0; - lastOctave=0; - lastInstr=-1; - lastVolume=-1; - memset(lastEffect,-1,8*sizeof(short)); - memset(lastEffectVal,-1,8*sizeof(short)); - - for (int i=0; i struct DivPattern { String name; @@ -28,14 +29,6 @@ struct DivPattern { * @param dest the destination pattern. */ void copyOn(DivPattern* dest); - - /** - * don't use yet! - * @param len the pattern length - * @param fxRows number of effect ...columns - * @return a SafeReader. - */ - SafeReader* compile(int len=256, int fxRows=1); DivPattern(); }; @@ -59,6 +52,20 @@ struct DivChannelData { */ DivPattern* getPattern(int index, bool create); + /** + * optimize pattern data. + * not thread-safe! use a mutex! + * @return a list of From -> To pairs + */ + std::vector> optimize(); + + /** + * re-arrange NULLs. + * not thread-safe! use a mutex! + * @return a list of From -> To pairs + */ + std::vector> rearrange(); + /** * destroy all patterns on this DivChannelData. */ diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 216a1bc4d..1adb33ebb 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -18,6 +18,7 @@ */ #include "song.h" +#include "../ta-log.h" void DivSubSong::clearData() { for (int i=0; i> clearOuts=pat[i].optimize(); + for (auto& j: clearOuts) { + for (int k=0; k<256; k++) { + if (orders.ord[i][k]==j.first) { + orders.ord[i][k]=j.second; + } + } + } + } +} + +void DivSubSong::rearrangePatterns() { + for (int i=0; i> clearOuts=pat[i].rearrange(); + for (auto& j: clearOuts) { + for (int k=0; k<256; k++) { + if (orders.ord[i][k]==j.first) { + orders.ord[i][k]=j.second; + } + } + } + } +} + void DivSong::clearSongData() { for (DivSubSong* i: subsong) { i->clearData(); diff --git a/src/engine/song.h b/src/engine/song.h index 8b7eaa59f..de422a24a 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -138,6 +138,8 @@ struct DivSubSong { String chanShortName[DIV_MAX_CHANS]; void clearData(); + void optimizePatterns(); + void rearrangePatterns(); DivSubSong(): hilightA(4), From d1c5a4725bbb5b919eed2fa32c94b859dd173fad Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 03:42:17 -0500 Subject: [PATCH 224/515] add option to save unused patterns closes #106 also prepare for the pattern manager window --- CMakeLists.txt | 1 + src/engine/fileOps.cpp | 30 +++++++++++++++++++++--------- src/gui/doAction.cpp | 6 ++++++ src/gui/gui.cpp | 5 +++++ src/gui/gui.h | 7 ++++++- src/gui/guiConst.cpp | 1 + src/gui/patManager.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/gui/settings.cpp | 8 ++++++++ 8 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 src/gui/patManager.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e468d4073..732cb623f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -531,6 +531,7 @@ src/gui/midiMap.cpp src/gui/newSong.cpp src/gui/orders.cpp src/gui/osc.cpp +src/gui/patManager.cpp src/gui/pattern.cpp src/gui/piano.cpp src/gui/presets.cpp diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 7cdcd5c8e..589ca6a58 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -3515,15 +3515,27 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { // high short is channel // low short is pattern number std::vector patsToWrite; - bool alreadyAdded[256]; - for (int i=0; iordersLen; k++) { - if (alreadyAdded[subs->orders.ord[i][k]]) continue; - patsToWrite.push_back(PatToWrite(j,i,subs->orders.ord[i][k])); - alreadyAdded[subs->orders.ord[i][k]]=true; + if (getConfInt("saveUnusedPatterns",0)==1) { + for (int i=0; ipat[i].data[k]==NULL) continue; + patsToWrite.push_back(PatToWrite(j,i,k)); + } + } + } + } else { + bool alreadyAdded[256]; + for (int i=0; iordersLen; k++) { + if (alreadyAdded[subs->orders.ord[i][k]]) continue; + patsToWrite.push_back(PatToWrite(j,i,subs->orders.ord[i][k])); + alreadyAdded[subs->orders.ord[i][k]]=true; + } } } } diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 931de26dc..5c840df4e 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -238,6 +238,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_CHANNELS: nextWindow=GUI_WINDOW_CHANNELS; break; + case GUI_ACTION_WINDOW_PAT_MANAGER: + nextWindow=GUI_WINDOW_PAT_MANAGER; + break; case GUI_ACTION_WINDOW_REGISTER_VIEW: nextWindow=GUI_WINDOW_REGISTER_VIEW; break; @@ -322,6 +325,9 @@ void FurnaceGUI::doAction(int what) { case GUI_WINDOW_CHANNELS: channelsOpen=false; break; + case GUI_WINDOW_PAT_MANAGER: + patManagerOpen=false; + break; case GUI_WINDOW_REGISTER_VIEW: regViewOpen=false; break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2b4367c91..4a6f3f39a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3107,6 +3107,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("pattern",BIND_FOR(GUI_ACTION_WINDOW_PATTERN),patternOpen)) patternOpen=!patternOpen; if (ImGui::MenuItem("mixer",BIND_FOR(GUI_ACTION_WINDOW_MIXER),mixerOpen)) mixerOpen=!mixerOpen; if (ImGui::MenuItem("channels",BIND_FOR(GUI_ACTION_WINDOW_CHANNELS),channelsOpen)) channelsOpen=!channelsOpen; + if (ImGui::MenuItem("pattern manager",BIND_FOR(GUI_ACTION_WINDOW_PAT_MANAGER),patManagerOpen)) patManagerOpen=!patManagerOpen; if (ImGui::MenuItem("compatibility flags",BIND_FOR(GUI_ACTION_WINDOW_COMPAT_FLAGS),compatFlagsOpen)) compatFlagsOpen=!compatFlagsOpen; if (ImGui::MenuItem("song comments",BIND_FOR(GUI_ACTION_WINDOW_NOTES),notesOpen)) notesOpen=!notesOpen; ImGui::Separator(); @@ -3241,6 +3242,7 @@ bool FurnaceGUI::loop() { drawPiano(); drawNotes(); drawChannels(); + drawPatManager(); drawRegView(); drawLog(); drawEffectList(); @@ -4361,6 +4363,7 @@ bool FurnaceGUI::init() { pianoOpen=e->getConfBool("pianoOpen",false); notesOpen=e->getConfBool("notesOpen",false); channelsOpen=e->getConfBool("channelsOpen",false); + patManagerOpen=e->getConfBool("patManagerOpen",false); regViewOpen=e->getConfBool("regViewOpen",false); logOpen=e->getConfBool("logOpen",false); effectListOpen=e->getConfBool("effectListOpen",false); @@ -4603,6 +4606,7 @@ bool FurnaceGUI::finish() { e->setConf("pianoOpen",pianoOpen); e->setConf("notesOpen",notesOpen); e->setConf("channelsOpen",channelsOpen); + e->setConf("patManagerOpen",patManagerOpen); e->setConf("regViewOpen",regViewOpen); e->setConf("logOpen",logOpen); e->setConf("effectListOpen",effectListOpen); @@ -4782,6 +4786,7 @@ FurnaceGUI::FurnaceGUI(): subSongsOpen(true), findOpen(false), spoilerOpen(false), + patManagerOpen(false), selecting(false), selectingFull(false), dragging(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 1c7355060..785c63f97 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -242,6 +242,7 @@ enum FurnaceGUIWindows { GUI_WINDOW_PIANO, GUI_WINDOW_NOTES, GUI_WINDOW_CHANNELS, + GUI_WINDOW_PAT_MANAGER, GUI_WINDOW_REGISTER_VIEW, GUI_WINDOW_LOG, GUI_WINDOW_EFFECT_LIST, @@ -361,6 +362,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_PIANO, GUI_ACTION_WINDOW_NOTES, GUI_ACTION_WINDOW_CHANNELS, + GUI_ACTION_WINDOW_PAT_MANAGER, GUI_ACTION_WINDOW_REGISTER_VIEW, GUI_ACTION_WINDOW_LOG, GUI_ACTION_WINDOW_EFFECT_LIST, @@ -1117,6 +1119,7 @@ class FurnaceGUI { int unsignedDetune; int noThreadedInput; int clampSamples; + int saveUnusedPatterns; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1228,6 +1231,7 @@ class FurnaceGUI { unsignedDetune(0), noThreadedInput(0), clampSamples(0), + saveUnusedPatterns(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -1257,7 +1261,7 @@ class FurnaceGUI { bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; - bool subSongsOpen, findOpen, spoilerOpen; + bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen; SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; @@ -1566,6 +1570,7 @@ class FurnaceGUI { void drawPiano(); void drawNotes(); void drawChannels(); + void drawPatManager(); void drawRegView(); void drawAbout(); void drawSettings(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 5fabb1c72..ea2edf279 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -487,6 +487,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_PIANO", "Piano", 0), D("WINDOW_NOTES", "Song Comments", 0), D("WINDOW_CHANNELS", "Channels", 0), + D("WINDOW_PAT_MANAGER", "Pattern Manager", 0), D("WINDOW_REGISTER_VIEW", "Register View", 0), D("WINDOW_LOG", "Log Viewer", 0), D("EFFECT_LIST", "Effect List", 0), diff --git a/src/gui/patManager.cpp b/src/gui/patManager.cpp new file mode 100644 index 000000000..16fdc345c --- /dev/null +++ b/src/gui/patManager.cpp @@ -0,0 +1,37 @@ +/** + * 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 "gui.h" +#include "misc/cpp/imgui_stdlib.h" +#include "IconsFontAwesome4.h" +#include + +void FurnaceGUI::drawPatManager() { + if (nextWindow==GUI_WINDOW_PAT_MANAGER) { + patManagerOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!patManagerOpen) return; + if (ImGui::Begin("Pattern Manager",&patManagerOpen,globalWinFlags)) { + ImGui::Text("Hello World!"); + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PAT_MANAGER; + ImGui::End(); +} diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index ee35fd86c..3134d9e38 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -514,6 +514,11 @@ void FurnaceGUI::drawSettings() { settings.blankIns=blankInsB; } + bool saveUnusedPatternsB=settings.saveUnusedPatterns; + if (ImGui::Checkbox("Save unused patterns",&saveUnusedPatternsB)) { + settings.saveUnusedPatterns=saveUnusedPatternsB; + } + ImGui::Text("Note preview behavior:"); if (ImGui::RadioButton("Never##npb0",settings.notePreviewBehavior==0)) { settings.notePreviewBehavior=0; @@ -2133,6 +2138,7 @@ void FurnaceGUI::syncSettings() { settings.macroRelLabel=e->getConfString("macroRelLabel","REL"); settings.emptyLabel=e->getConfString("emptyLabel","..."); settings.emptyLabel2=e->getConfString("emptyLabel2",".."); + settings.saveUnusedPatterns=e->getConfInt("saveUnusedPatterns",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2221,6 +2227,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.unsignedDetune,0,1); clampSetting(settings.noThreadedInput,0,1); clampSetting(settings.clampSamples,0,1); + clampSetting(settings.saveUnusedPatterns,0,1); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2365,6 +2372,7 @@ void FurnaceGUI::commitSettings() { e->setConf("macroRelLabel",settings.macroRelLabel); e->setConf("emptyLabel",settings.emptyLabel); e->setConf("emptyLabel2",settings.emptyLabel2); + e->setConf("saveUnusedPatterns",settings.saveUnusedPatterns); // colors for (int i=0; i Date: Tue, 16 Aug 2022 04:19:00 -0500 Subject: [PATCH 225/515] GUI: pattern manager, part 1 --- src/gui/gui.h | 7 ++++ src/gui/guiConst.cpp | 7 ++++ src/gui/patManager.cpp | 74 +++++++++++++++++++++++++++++++++++++++++- src/gui/settings.cpp | 9 +++++ 4 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 785c63f97..2162ae1e9 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -200,6 +200,13 @@ enum FurnaceGUIColors { GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY, GUI_COLOR_PATTERN_EFFECT_MISC, + GUI_COLOR_PAT_MANAGER_NULL, + GUI_COLOR_PAT_MANAGER_USED, + GUI_COLOR_PAT_MANAGER_OVERUSED, + GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED, + GUI_COLOR_PAT_MANAGER_COMBO_BREAKER, + GUI_COLOR_PAT_MANAGER_UNUSED, + GUI_COLOR_PIANO_BACKGROUND, GUI_COLOR_PIANO_KEY_BOTTOM, GUI_COLOR_PIANO_KEY_TOP, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index ea2edf279..714e77709 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -812,6 +812,13 @@ 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_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)), + D(GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED,"",ImVec4(1.0f,0.5f,0.15f,1.0f)), + D(GUI_COLOR_PAT_MANAGER_COMBO_BREAKER,"",ImVec4(1.0f,0.15f,1.0f,1.0f)), + D(GUI_COLOR_PAT_MANAGER_UNUSED,"",ImVec4(1.0f,0.15f,0.15f,1.0f)), + D(GUI_COLOR_PIANO_BACKGROUND,"",ImVec4(0.0f,0.0f,0.0f,1.0f)), D(GUI_COLOR_PIANO_KEY_BOTTOM,"",ImVec4(1.0f,1.0f,1.0f,1.0f)), D(GUI_COLOR_PIANO_KEY_TOP,"",ImVec4(0.0f,0.0f,0.0f,1.0f)), diff --git a/src/gui/patManager.cpp b/src/gui/patManager.cpp index 16fdc345c..d597bd9c2 100644 --- a/src/gui/patManager.cpp +++ b/src/gui/patManager.cpp @@ -29,8 +29,80 @@ void FurnaceGUI::drawPatManager() { nextWindow=GUI_WINDOW_NOTHING; } if (!patManagerOpen) return; + char id[1024]; + unsigned char isUsed[256]; + bool isNull[256]; if (ImGui::Begin("Pattern Manager",&patManagerOpen,globalWinFlags)) { - ImGui::Text("Hello World!"); + ImGui::Text("Global Tasks"); + + if (ImGui::Button("De-duplicate patterns")) { + e->lockEngine([this]() { + e->curSubSong->optimizePatterns(); + }); + } + ImGui::SameLine(); + if (ImGui::Button("Re-arrange patterns")) { + e->lockEngine([this]() { + e->curSubSong->rearrangePatterns(); + }); + } + + for (int i=0; igetTotalChannelCount(); i++) { + memset(isUsed,0,256); + memset(isNull,0,256*sizeof(bool)); + for (int j=0; jcurSubSong->ordersLen; j++) { + isUsed[e->curSubSong->orders.ord[i][j]]++; + } + for (int j=0; j<256; j++) { + isNull[j]=(e->curSubSong->pat[i].data[j]==NULL); + } + ImGui::Text("%d. %s",i+1,e->getChannelName(i)); + ImGui::PushID(1000+i); + ImGui::PushFont(patFont); + if (ImGui::BeginTable("PatManTable",32)) { + for (int k=0; k<256; k++) { + if ((k&31)==0) ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + snprintf(id,1023,"%.2X",k); + if (isNull[k]) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_NULL]); + } else if (isUsed[k]>=e->curSubSong->ordersLen) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_COMBO_BREAKER]); + } else if (isUsed[k]>=0.7*(double)e->curSubSong->ordersLen) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED]); + } else if (isUsed[k]>=0.4*(double)e->curSubSong->ordersLen) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_OVERUSED]); + } else if (isUsed[k]) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_USED]); + } else { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_UNUSED]); + } + ImGui::Selectable(id,isUsed[k]); + if (ImGui::IsItemHovered()) { + ImGui::PushFont(mainFont); + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]); + if (isNull[k]) { + ImGui::SetTooltip("Pattern %.2X\n- not allocated",k); + } else { + ImGui::SetTooltip("Pattern %.2X\n- use count: %d (%.0f%%)\n\nright-click to erase",k,isUsed[k],100.0*(double)isUsed[k]/(double)e->curSubSong->ordersLen); + } + ImGui::PopStyleColor(); + ImGui::PopFont(); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + e->lockEngine([this,i,k]() { + delete e->curSubSong->pat[i].data[k]; + e->curSubSong->pat[i].data[k]=NULL; + }); + } + ImGui::PopStyleColor(); + } + ImGui::EndTable(); + } + ImGui::PopFont(); + ImGui::PopID(); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PAT_MANAGER; ImGui::End(); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 3134d9e38..f411dea5e 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1583,6 +1583,15 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output"); 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"); + UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_USED,"Used"); + UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_OVERUSED,"Overused"); + UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED,"Really overused"); + UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_COMBO_BREAKER,"Combo Breaker"); + ImGui::TreePop(); + } if (ImGui::TreeNode("Piano")) { UI_COLOR_CONFIG(GUI_COLOR_PIANO_BACKGROUND,"Background"); UI_COLOR_CONFIG(GUI_COLOR_PIANO_KEY_TOP,"Upper key"); From a8a6d8bc4e2fd793b99b0160426b439968c8bea8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 11:32:06 -0500 Subject: [PATCH 226/515] move --- ...usic 1.fur => Silver Surfer - Stage Music 1.fur} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename demos/{[TSU] Tim Follin - Silver Surfer - Stage Music 1.fur => Silver Surfer - Stage Music 1.fur} (100%) diff --git a/demos/[TSU] Tim Follin - Silver Surfer - Stage Music 1.fur b/demos/Silver Surfer - Stage Music 1.fur similarity index 100% rename from demos/[TSU] Tim Follin - Silver Surfer - Stage Music 1.fur rename to demos/Silver Surfer - Stage Music 1.fur From 159383aa40f1f5000ee144f8216520eeea7e39f9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 11:40:28 -0500 Subject: [PATCH 227/515] workaround for account limit issue --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d356bedb..ec8ed890b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,7 +130,7 @@ jobs: zlib1g-dev \ libjack-jackd2-dev \ appstream - wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" || wget "https://tildearrow.org/storage/furnace/ci/appimagetool-x86_64.AppImage" chmod +x appimagetool-x86_64.AppImage - name: Install Dependencies [Linux armhf] @@ -151,8 +151,8 @@ jobs: libsndfile1-dev:armhf \ zlib1g-dev:armhf \ libjack-jackd2-dev:armhf - wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" - wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-armhf" + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" || wget "https://tildearrow.org/storage/furnace/ci/appimagetool-x86_64.AppImage" + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-armhf" || wget "https://tildearrow.org/storage/furnace/ci/runtime-armhf" chmod +x appimagetool-x86_64.AppImage ls /usr/arm-linux-gnueabihf/lib From 793dad89ad625dd3fd287ff64bd4fdfb873013b5 Mon Sep 17 00:00:00 2001 From: Eris Lund <38136789+0x5066@users.noreply.github.com> Date: Tue, 16 Aug 2022 19:52:17 +0200 Subject: [PATCH 228/515] Completed the module --- ...government funding breakcore-ish remix.fur | Bin 417079 -> 417129 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/government funding breakcore-ish remix.fur b/demos/government funding breakcore-ish remix.fur index 5c3a47ce2df99d6c61cfe83503540c45567c0dbc..7acbabc49d88e3b43f27ef132f0edce99fbead61 100644 GIT binary patch delta 368330 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

  • ^rP(| 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
    cvK3wwR`EcWMzu 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 TiMT<3!aDxh`2+kf)3uWG%tS%U delta 368199 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 m*w6ki*w6kK@ZSJ-JNn`-7iug3 From 89eace24725ff48639329dcf4be28504b5838e58 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 16 Aug 2022 13:53:51 -0500 Subject: [PATCH 229/515] GUI: prepare for channel header customization opti ons --- src/gui/gui.h | 10 +++++ src/gui/settings.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/gui/gui.h b/src/gui/gui.h index 2162ae1e9..3e3401195 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1127,6 +1127,11 @@ class FurnaceGUI { int noThreadedInput; int clampSamples; int saveUnusedPatterns; + int channelColors; + int channelTextColors; + int channelStyle; + int channelVolStyle; + int channelFeedbackStyle; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1239,6 +1244,11 @@ class FurnaceGUI { noThreadedInput(0), clampSamples(0), saveUnusedPatterns(0), + channelColors(1), + channelTextColors(0), + channelStyle(0), + channelVolStyle(0), + channelFeedbackStyle(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index f411dea5e..03c32e655 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1222,6 +1222,79 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); + ImGui::Text("Channel colors:"); + if (ImGui::RadioButton("Single##CHC0",settings.channelColors==0)) { + settings.channelColors=0; + } + if (ImGui::RadioButton("Channel type##CHC1",settings.channelColors==1)) { + settings.channelColors=1; + } + if (ImGui::RadioButton("Instrument type##CHC2",settings.channelColors==2)) { + settings.channelColors=2; + } + + ImGui::Text("Channel name colors:"); + if (ImGui::RadioButton("Single##CTC0",settings.channelColors==0)) { + settings.channelColors=0; + } + if (ImGui::RadioButton("Channel type##CTC1",settings.channelColors==1)) { + settings.channelColors=1; + } + if (ImGui::RadioButton("Instrument type##CTC2",settings.channelColors==2)) { + settings.channelColors=2; + } + + ImGui::Text("Channel style:"); + if (ImGui::RadioButton("Classic##CHS0",settings.channelStyle==0)) { + settings.channelStyle=0; + } + if (ImGui::RadioButton("Line##CHS1",settings.channelStyle==1)) { + settings.channelStyle=1; + } + if (ImGui::RadioButton("Round##CHS2",settings.channelStyle==2)) { + settings.channelStyle=2; + } + if (ImGui::RadioButton("Split button##CHS3",settings.channelStyle==3)) { + settings.channelStyle=3; + } + if (ImGui::RadioButton("Square border##CH42",settings.channelStyle==4)) { + settings.channelStyle=4; + } + if (ImGui::RadioButton("Round border##CHS5",settings.channelStyle==5)) { + settings.channelStyle=5; + } + + ImGui::Text("Channel volume bar:"); + if (ImGui::RadioButton("None##CHV0",settings.channelVolStyle==0)) { + settings.channelVolStyle=0; + } + if (ImGui::RadioButton("Simple##CHV1",settings.channelVolStyle==1)) { + settings.channelVolStyle=1; + } + if (ImGui::RadioButton("Stereo##CHV2",settings.channelVolStyle==2)) { + settings.channelVolStyle=2; + } + if (ImGui::RadioButton("Real##CHV3",settings.channelVolStyle==3)) { + settings.channelVolStyle=3; + } + + ImGui::Text("Channel feedback style:"); + + if (ImGui::RadioButton("Off##CHF0",settings.channelFeedbackStyle==0)) { + settings.channelFeedbackStyle=0; + } + if (ImGui::RadioButton("Note##CHF1",settings.channelFeedbackStyle==1)) { + settings.channelFeedbackStyle=1; + } + if (ImGui::RadioButton("Volume##CHF2",settings.channelFeedbackStyle==2)) { + settings.channelFeedbackStyle=2; + } + if (ImGui::RadioButton("Active##CHF3",settings.channelFeedbackStyle==3)) { + settings.channelFeedbackStyle=3; + } + + ImGui::Separator(); + bool insEditColorizeB=settings.insEditColorize; if (ImGui::Checkbox("Colorize instrument editor using instrument type",&insEditColorizeB)) { settings.insEditColorize=insEditColorizeB; @@ -2148,6 +2221,11 @@ void FurnaceGUI::syncSettings() { settings.emptyLabel=e->getConfString("emptyLabel","..."); settings.emptyLabel2=e->getConfString("emptyLabel2",".."); settings.saveUnusedPatterns=e->getConfInt("saveUnusedPatterns",0); + settings.channelColors=e->getConfInt("channelColors",1); + settings.channelTextColors=e->getConfInt("channelTextColors",0); + settings.channelStyle=e->getConfInt("channelStyle",0); + settings.channelVolStyle=e->getConfInt("channelVolStyle",0); + settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2237,6 +2315,11 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.noThreadedInput,0,1); clampSetting(settings.clampSamples,0,1); clampSetting(settings.saveUnusedPatterns,0,1); + clampSetting(settings.channelColors,0,2); + clampSetting(settings.channelTextColors,0,2); + clampSetting(settings.channelStyle,0,5); + clampSetting(settings.channelVolStyle,0,3); + clampSetting(settings.channelFeedbackStyle,0,3); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2382,6 +2465,11 @@ void FurnaceGUI::commitSettings() { e->setConf("emptyLabel",settings.emptyLabel); e->setConf("emptyLabel2",settings.emptyLabel2); e->setConf("saveUnusedPatterns",settings.saveUnusedPatterns); + e->setConf("channelColors",settings.channelColors); + e->setConf("channelTextColors",settings.channelTextColors); + e->setConf("channelStyle",settings.channelStyle); + e->setConf("channelVolStyle",settings.channelVolStyle); + e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle); // colors for (int i=0; i Date: Wed, 17 Aug 2022 18:29:40 -0500 Subject: [PATCH 230/515] GUI: finally re-organize the GB env UI --- src/gui/insEdit.cpp | 68 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index d4e76611f..64e098909 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2969,24 +2969,60 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Initialize envelope on every note",&ins->gb.alwaysInit)); ImGui::BeginDisabled(ins->gb.softEnv); - P(CWSliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable - P(CWSliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable - P(CWSliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable - ImGui::Text("Envelope Direction:"); + if (ImGui::BeginTable("GBParams",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.6f); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.4f); - bool goesUp=ins->gb.envDir; - ImGui::SameLine(); - if (ImGui::RadioButton("Up",goesUp)) { PARAMETER - goesUp=true; - ins->gb.envDir=goesUp; - } - ImGui::SameLine(); - if (ImGui::RadioButton("Down",!goesUp)) { PARAMETER - goesUp=false; - ins->gb.envDir=goesUp; - } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::BeginTable("GBParamsI",2)) { + ImGui::TableSetupColumn("ci0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("ci1",ImGuiTableColumnFlags_WidthStretch); - drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale)); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Volume"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##GBVolume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Length"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##GBEnvLen",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Sound Length"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##GBSoundLen",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Direction"); + ImGui::TableNextColumn(); + bool goesUp=ins->gb.envDir; + if (ImGui::RadioButton("Up",goesUp)) { PARAMETER + goesUp=true; + ins->gb.envDir=goesUp; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Down",!goesUp)) { PARAMETER + goesUp=false; + ins->gb.envDir=goesUp; + } + + ImGui::EndTable(); + } + + ImGui::TableNextColumn(); + drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale)); + + ImGui::EndTable(); + } if (ImGui::BeginChild("HWSeq",ImGui::GetContentRegionAvail(),true,ImGuiWindowFlags_MenuBar)) { ImGui::BeginMenuBar(); From 4e7eb728db900693cbc545049af537e7420e5290 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 17 Aug 2022 18:37:16 -0500 Subject: [PATCH 231/515] GUI: fix moving GB HW seq step down --- src/gui/insEdit.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 64e098909..a306e366c 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3178,13 +3178,13 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Button(ICON_FA_CHEVRON_DOWN "##HWCmdDown")) { if (igb.hwSeqLen-1) { e->lockEngine([ins,i]() { - ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; - ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i-1].cmd; - ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd; + ins->gb.hwSeq[i+1].cmd^=ins->gb.hwSeq[i].cmd; + ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i+1].cmd; + ins->gb.hwSeq[i+1].cmd^=ins->gb.hwSeq[i].cmd; - ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; - ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i-1].data; - ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data; + ins->gb.hwSeq[i+1].data^=ins->gb.hwSeq[i].data; + ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i+1].data; + ins->gb.hwSeq[i+1].data^=ins->gb.hwSeq[i].data; }); } MARK_MODIFIED; From 7c42453422c101bd2704bef0d697bbc0bbdaf632 Mon Sep 17 00:00:00 2001 From: Natt Akuma <77432377+akumanatt@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:26:22 +0700 Subject: [PATCH 232/515] Rewrite per-system effect handling (#548) * Rewrite per-system effect handling * fix build * C64: fix fine cutoff regression * fix some more crashes Co-authored-by: tildearrow --- src/engine/dispatch.h | 7 - src/engine/engine.cpp | 11 +- src/engine/engine.h | 37 +- src/engine/platform/abstract.cpp | 4 - src/engine/platform/amiga.cpp | 15 - src/engine/platform/amiga.h | 1 - src/engine/platform/arcade.cpp | 105 --- src/engine/platform/arcade.h | 1 - src/engine/platform/ay.cpp | 36 - src/engine/platform/ay.h | 1 - src/engine/platform/ay8930.cpp | 48 -- src/engine/platform/ay8930.h | 1 - src/engine/platform/bubsyswsg.cpp | 9 - src/engine/platform/bubsyswsg.h | 1 - src/engine/platform/c64.cpp | 46 - src/engine/platform/c64.h | 1 - src/engine/platform/fds.cpp | 24 - src/engine/platform/fds.h | 1 - src/engine/platform/gb.cpp | 21 - src/engine/platform/gb.h | 1 - src/engine/platform/genesis.cpp | 102 --- src/engine/platform/genesis.h | 1 - src/engine/platform/lynx.cpp | 13 - src/engine/platform/lynx.h | 1 - src/engine/platform/mmc5.cpp | 9 - src/engine/platform/mmc5.h | 1 - src/engine/platform/msm6258.cpp | 12 - src/engine/platform/msm6258.h | 1 - src/engine/platform/msm6295.cpp | 9 - src/engine/platform/msm6295.h | 1 - src/engine/platform/n163.cpp | 45 - src/engine/platform/n163.h | 1 - src/engine/platform/namcowsg.cpp | 12 - src/engine/platform/namcowsg.h | 1 - src/engine/platform/nes.cpp | 21 - src/engine/platform/nes.h | 1 - src/engine/platform/opl.cpp | 92 -- src/engine/platform/opl.h | 1 - src/engine/platform/opll.cpp | 62 -- src/engine/platform/opll.h | 1 - src/engine/platform/pce.cpp | 21 - src/engine/platform/pce.h | 1 - src/engine/platform/pcspkr.cpp | 4 - src/engine/platform/pcspkr.h | 1 - src/engine/platform/pet.cpp | 9 - src/engine/platform/pet.h | 1 - src/engine/platform/qsound.cpp | 18 - src/engine/platform/qsound.h | 1 - src/engine/platform/rf5c68.cpp | 4 - src/engine/platform/rf5c68.h | 1 - src/engine/platform/saa.cpp | 15 - src/engine/platform/saa.h | 1 - src/engine/platform/scc.cpp | 9 - src/engine/platform/scc.h | 1 - src/engine/platform/segapcm.cpp | 9 - src/engine/platform/segapcm.h | 1 - src/engine/platform/sms.cpp | 9 - src/engine/platform/sms.h | 1 - src/engine/platform/su.cpp | 66 -- src/engine/platform/su.h | 1 - src/engine/platform/swan.cpp | 21 - src/engine/platform/swan.h | 1 - src/engine/platform/tia.cpp | 9 - src/engine/platform/tia.h | 1 - src/engine/platform/tx81z.cpp | 133 --- src/engine/platform/tx81z.h | 1 - src/engine/platform/vera.cpp | 12 - src/engine/platform/vera.h | 1 - src/engine/platform/vic20.cpp | 9 - src/engine/platform/vic20.h | 1 - src/engine/platform/vrc6.cpp | 12 - src/engine/platform/vrc6.h | 1 - src/engine/platform/x1_010.cpp | 33 - src/engine/platform/x1_010.h | 1 - src/engine/platform/ym2203.cpp | 117 --- src/engine/platform/ym2203.h | 1 - src/engine/platform/ym2608.cpp | 120 --- src/engine/platform/ym2608.h | 1 - src/engine/platform/ym2610.cpp | 120 --- src/engine/platform/ym2610.h | 1 - src/engine/platform/ym2610b.cpp | 120 --- src/engine/platform/ym2610b.h | 1 - src/engine/platform/ymz280b.cpp | 4 - src/engine/platform/ymz280b.h | 1 - src/engine/platform/zxbeeper.cpp | 12 - src/engine/platform/zxbeeper.h | 1 - src/engine/playback.cpp | 37 +- src/engine/sysDef.cpp | 1344 +++++++++-------------------- 88 files changed, 477 insertions(+), 2571 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index fb9be5800..2fde9addd 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -417,13 +417,6 @@ class DivDispatch { */ virtual bool getWantPreNote(); - /** - * get a description of a dispatch-specific effect. - * @param effect the effect. - * @return the description, or NULL if effect is invalid. - */ - virtual const char* getEffectName(unsigned char effect); - /** * set the chip flags. * @param flags the flags. see song.h for possible values. diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 68c492219..5fe2db695 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -124,8 +124,15 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul if ((effect&0xf0)==0x90) { return "9xxx: Set sample offset*256"; } else if (chan>=0 && changetEffectName(effect); - if (ret!=NULL) return ret; + DivSysDef* sysDef=sysDefs[sysOfChan[chan]]; + auto iter=sysDef->effectHandlers.find(effect); + if (iter!=sysDef->effectHandlers.end()) { + return iter->second.description; + } + iter=sysDef->postEffectHandlers.find(effect); + if (iter!=sysDef->postEffectHandlers.end()) { + return iter->second.description; + } } break; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 3a73d7d24..191414f5f 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #define addWarning(x) \ @@ -194,7 +195,29 @@ struct DivDispatchContainer { dcOffCompensation(false) {} }; -typedef std::function EffectProcess; +typedef int EffectValConversion(unsigned char,unsigned char); + +struct EffectHandler { + DivDispatchCmds dispatchCmd; + const char* description; + EffectValConversion* val; + EffectValConversion* val2; + EffectHandler( + DivDispatchCmds dispatchCmd_, + const char* description_, + EffectValConversion val_=NULL, + EffectValConversion val2_=NULL + ): + dispatchCmd(dispatchCmd_), + description(description_), + val(val_), + val2(val2_) {} +}; + +struct DivDoNotHandleEffect { +}; + +typedef std::unordered_map EffectHandlerMap; struct DivSysDef { const char* name; @@ -211,8 +234,8 @@ struct DivSysDef { // 0: primary // 1: alternate (usually PCM) DivInstrumentType chanInsType[DIV_MAX_CHANS][2]; - EffectProcess effectFunc; - EffectProcess postEffectFunc; + const EffectHandlerMap effectHandlers; + const EffectHandlerMap postEffectHandlers; DivSysDef( const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans, bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, const char* desc, @@ -221,8 +244,8 @@ struct DivSysDef { std::initializer_list chTypes, std::initializer_list chInsType1, std::initializer_list chInsType2={}, - EffectProcess fxHandler=[](int,unsigned char,unsigned char) -> bool {return false;}, - EffectProcess postFxHandler=[](int,unsigned char,unsigned char) -> bool {return false;}): + const EffectHandlerMap fxHandlers_={}, + const EffectHandlerMap postFxHandlers_={}): name(sysName), nameJ(sysNameJ), description(desc), @@ -233,8 +256,8 @@ struct DivSysDef { isSTD(isSTDChip), isCompound(compound), vgmVersion(vgmVer), - effectFunc(fxHandler), - postEffectFunc(postFxHandler) { + effectHandlers(fxHandlers_), + postEffectHandlers(postFxHandlers_) { memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*)); memset(chanShortNames,0,DIV_MAX_CHANS*sizeof(void*)); memset(chanTypes,0,DIV_MAX_CHANS*sizeof(int)); diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 5b732e7e9..358e54aa0 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -94,10 +94,6 @@ bool DivDispatch::getWantPreNote() { return false; } -const char* DivDispatch::getEffectName(unsigned char effect) { - return NULL; -} - void DivDispatch::setFlags(unsigned int flags) { } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 1b0075307..57c0e3e21 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -64,21 +64,6 @@ const char** DivPlatformAmiga::getRegisterSheet() { return regCheatSheetAmiga; } -const char* DivPlatformAmiga::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Toggle filter (0 disables; 1 enables)"; - break; - case 0x11: - return "11xx: Toggle AM with next channel"; - break; - case 0x12: - return "12xx: Toggle period modulation with next channel"; - break; - } - return NULL; -} - #define writeAudDat(x) \ chan[i].audDat=x; \ if (i<3 && chan[i].useV) { \ diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index e7372e63b..59617ec36 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -105,7 +105,6 @@ class DivPlatformAmiga: public DivDispatch { void notifyWaveChange(int wave); void notifyInsDeletion(void* ins); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); }; diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 41042cd5c..1f51dc9bd 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -50,111 +50,6 @@ const char** DivPlatformArcade::getRegisterSheet() { return regCheatSheetOPM; } -const char* DivPlatformArcade::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set noise frequency (xx: value; 0 disables noise)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x17: - return "17xx: Set LFO speed"; - break; - case 0x18: - return "18xx: Set LFO waveform (0 saw, 1 square, 2 triangle, 3 noise)"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x1e: - return "1Exx: Set AM depth (0 to 7F)"; - break; - case 0x1f: - return "1Fxx: Set PM depth (0 to 7F)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - } - return NULL; -} - void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) { static int o[2]; diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index daa883620..93aa490d0 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -115,7 +115,6 @@ class DivPlatformArcade: public DivPlatformOPM { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformArcade(); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 8df5bd4ce..1b24ac733 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -73,42 +73,6 @@ const char** DivPlatformAY8910::getRegisterSheet() { return intellivision?regCheatSheetAY8914:regCheatSheetAY; } -const char* DivPlatformAY8910::getEffectName(unsigned char effect) { - switch (effect) { - case 0x20: - return "20xx: Set channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"; - break; - case 0x21: - return "21xx: Set noise frequency (0 to 1F)"; - break; - case 0x22: - return "22xy: Set envelope mode (x: shape, y: enable for this channel)"; - break; - case 0x23: - return "23xx: Set envelope period low byte"; - break; - case 0x24: - return "24xx: Set envelope period high byte"; - break; - case 0x25: - return "25xx: Envelope slide up"; - break; - case 0x26: - return "26xx: Envelope slide down"; - break; - case 0x29: - return "29xy: Set auto-envelope (x: numerator; y: denominator)"; - break; - case 0x2e: - return "2Exx: Write to I/O port A"; - break; - case 0x2f: - return "2Fxx: Write to I/O port B"; - break; - } - return NULL; -} - void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) { if (ayBufLen& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8): diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 581ebb9e8..0fc9091f2 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -77,54 +77,6 @@ const char** DivPlatformAY8930::getRegisterSheet() { return regCheatSheetAY8930; } -const char* DivPlatformAY8930::getEffectName(unsigned char effect) { - switch (effect) { - case 0x12: - return "12xx: Set duty cycle (0 to 8)"; - break; - case 0x20: - return "20xx: Set channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"; - break; - case 0x21: - return "21xx: Set noise frequency (0 to 1F)"; - break; - case 0x22: - return "22xy: Set envelope mode (x: shape, y: enable for this channel)"; - break; - case 0x23: - return "23xx: Set envelope period low byte"; - break; - case 0x24: - return "24xx: Set envelope period high byte"; - break; - case 0x25: - return "25xx: Envelope slide up"; - break; - case 0x26: - return "26xx: Envelope slide down"; - break; - case 0x27: - return "27xx: Set noise AND mask"; - break; - case 0x28: - return "28xx: Set noise OR mask"; - break; - case 0x29: - return "29xy: Set auto-envelope (x: numerator; y: denominator)"; - break; - case 0x2d: - return "2Dxx: NOT TO BE EMPLOYED BY THE COMPOSER"; - break; - case 0x2e: - return "2Exx: Write to I/O port A"; - break; - case 0x2f: - return "2Fxx: Write to I/O port B"; - break; - } - return NULL; -} - void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) { if (ayBufLen& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); }; diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 5fe4462f4..fd00ebeeb 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -39,15 +39,6 @@ const char** DivPlatformBubSysWSG::getRegisterSheet() { return regCheatSheetBubSysWSG; } -const char* DivPlatformBubSysWSG::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - } - return NULL; -} - void DivPlatformBubSysWSG::acquire(short* bufL, short* bufR, size_t start, size_t len) { int chanOut=0; for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformBubSysWSG(); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 9049ffec4..dc0cd8a2d 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -62,52 +62,6 @@ const char** DivPlatformC64::getRegisterSheet() { return regCheatSheetSID; } -const char* DivPlatformC64::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set waveform (bit 0: triangle; bit 1: saw; bit 2: pulse; bit 3: noise)"; - break; - case 0x11: - return "11xx: Set coarse cutoff (not recommended; use 4xxx instead)"; - break; - case 0x12: - return "12xx: Set coarse pulse width (not recommended; use 3xxx instead)"; - break; - case 0x13: - return "13xx: Set resonance (0 to F)"; - break; - case 0x14: - return "14xx: Set filter mode (bit 0: low pass; bit 1: band pass; bit 2: high pass)"; - break; - case 0x15: - return "15xx: Set envelope reset time"; - break; - case 0x1a: - return "1Axx: Disable envelope reset for this channel (1 disables; 0 enables)"; - break; - case 0x1b: - return "1Bxy: Reset cutoff (x: on new note; y: now)"; - break; - case 0x1c: - return "1Cxy: Reset pulse width (x: on new note; y: now)"; - break; - case 0x1e: - return "1Exy: Change additional parameters"; - break; - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - return "3xxx: Set pulse width (0 to FFF)"; - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - return "4xxx: Set cutoff (0 to 7FF)"; - break; - } - return NULL; -} - void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) { int dcOff=sid.get_dc(0); for (size_t i=start; i& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void setChipModel(bool is6581); void quit(); diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index f9fc5b50b..fc4d3e775 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -55,30 +55,6 @@ const char** DivPlatformFDS::getRegisterSheet() { return regCheatSheetFDS; } -const char* DivPlatformFDS::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - case 0x11: - return "11xx: Set modulation depth"; - break; - case 0x12: - return "12xy: Set modulation speed high byte (x: enable; y: value)"; - break; - case 0x13: - return "13xx: Set modulation speed low byte"; - break; - case 0x14: - return "14xx: Set modulator position"; - break; - case 0x15: - return "15xx: Set modulator table to waveform"; - break; - } - return NULL; -} - void DivPlatformFDS::acquire_puNES(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformFDS(); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index c29329b95..ab603266c 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -61,27 +61,6 @@ const char** DivPlatformGB::getRegisterSheet() { return regCheatSheetGB; } -const char* DivPlatformGB::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - case 0x11: - return "11xx: Set noise length (0: long; 1: short)"; - break; - case 0x12: - return "12xx: Set duty cycle (0 to 3)"; - break; - case 0x13: - return "13xy: Setup sweep (x: time; y: shift)"; - break; - case 0x14: - return "14xx: Set sweep direction (0: up; 1: down)"; - break; - } - return NULL; -} - void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index b6dbb8d12..0260ea06c 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -27,108 +27,6 @@ #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) -const char* DivPlatformGenesis::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xy: Setup LFO (x: enable; y: speed)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x17: - return "17xx: Enable channel 6 DAC"; - break; - case 0x18: - return "18xx: Toggle extended channel 3 mode"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - case 0xdf: - return "DFxx: Set sample playback direction (0: normal; 1: reverse)"; - break; - } - return NULL; -} - void DivPlatformGenesis::processDAC() { if (softPCM) { softPCMTimer+=chipClock/576; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index c46a992d3..5e61fe678 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -144,7 +144,6 @@ class DivPlatformGenesis: public DivPlatformOPN { int getPortaFloor(int ch); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformGenesis(): diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 7c349e5a5..ead20590a 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -129,19 +129,6 @@ const char** DivPlatformLynx::getRegisterSheet() { return regCheatSheetLynx; } -const char* DivPlatformLynx::getEffectName(unsigned char effect) { - switch (effect) - { - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - return "3xxx: Load LFSR (0 to FFF)"; - break; - } - return NULL; -} - void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName( unsigned char effect ); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformLynx(); diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 2154e855f..b5bb5a9e8 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -43,15 +43,6 @@ const char** DivPlatformMMC5::getRegisterSheet() { return regCheatSheetMMC5; } -const char* DivPlatformMMC5::getEffectName(unsigned char effect) { - switch (effect) { - case 0x12: - return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"; - break; - } - return NULL; -} - void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformMMC5(); diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index dc81950ef..0ba3ae0b8 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -30,18 +30,6 @@ const char** DivPlatformMSM6258::getRegisterSheet() { return NULL; } -const char* DivPlatformMSM6258::getEffectName(unsigned char effect) { - switch (effect) { - case 0x20: - return "20xx: Set frequency divider (0-2)"; - break; - case 0x21: - return "21xx: Select clock rate (0: full; 1: half)"; - break; - } - return NULL; -} - void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t len) { short* outs[2]={ &msmOut, diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index cd975c8f8..f6a351b5e 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -109,7 +109,6 @@ class DivPlatformMSM6258: public DivDispatch { void poke(std::vector& wlist); void setFlags(unsigned int flags); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index); size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index fc5f9ea30..0a76a2c9b 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -30,15 +30,6 @@ const char** DivPlatformMSM6295::getRegisterSheet() { return NULL; } -const char* DivPlatformMSM6295::getEffectName(unsigned char effect) { - switch (effect) { - case 0x20: - return "20xx: Set chip output rate (0: clock/132; 1: clock/165)"; - break; - } - return NULL; -} - u8 DivPlatformMSM6295::read_byte(u32 address) { if (adpcmMem==NULL || address>=getSampleMemCapacity(0)) { return 0; diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index f01c1b233..0953bd33e 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -97,7 +97,6 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { virtual void poke(std::vector& wlist) override; virtual void setFlags(unsigned int flags) override; virtual const char** getRegisterSheet() override; - virtual const char* getEffectName(unsigned char effect) override; virtual const void* getSampleMem(int index) override; virtual size_t getSampleMemCapacity(int index) override; virtual size_t getSampleMemUsage(int index) override; diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index b20b460e0..52352dc62 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -108,51 +108,6 @@ const char** DivPlatformN163::getRegisterSheet() { return regCheatSheetN163; } -const char* DivPlatformN163::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Select waveform"; - break; - case 0x11: - return "11xx: Set waveform position in RAM (single nibble unit)"; - break; - case 0x12: - return "12xx: Set waveform length in RAM (04 to FC, 4 nibble unit)"; - break; - case 0x13: - return "130x: Change waveform update mode (0: off, bit 0: update now, bit 1: update when every waveform changes)"; - break; - case 0x14: - return "14xx: Select waveform for load to RAM"; - break; - case 0x15: - return "15xx: Set waveform position for load to RAM (single nibble unit)"; - break; - case 0x16: - return "16xx: Set waveform length for load to RAM (04 to FC, 4 nibble unit)"; - break; - case 0x17: - return "170x: Change waveform load mode (0: off, bit 0: load now, bit 1: load when every waveform changes)"; - break; - case 0x18: - return "180x: Change channel limits (0 to 7, x + 1)"; - break; - case 0x20: - return "20xx: (Global) Select waveform for load to RAM"; - break; - case 0x21: - return "21xx: (Global) Set waveform position for load to RAM (single nibble unit)"; - break; - case 0x22: - return "22xx: (Global) Set waveform length for load to RAM (04 to FC, 4 nibble unit)"; - break; - case 0x23: - return "230x: (Global) Change waveform load mode (0: off, bit 0: load now, bit 1: load when every waveform changes)"; - break; - } - return NULL; -} - void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformN163(); diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 00b127930..e88bb0ebf 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -151,18 +151,6 @@ const char** DivPlatformNamcoWSG::getRegisterSheet() { return regCheatSheetNamcoWSG; } -const char* DivPlatformNamcoWSG::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - case 0x11: - return "11xx: Toggle noise mode"; - break; - } - return NULL; -} - void DivPlatformNamcoWSG::acquire(short* bufL, short* bufR, size_t start, size_t len) { while (!writes.empty()) { QueuedWrite w=writes.front(); diff --git a/src/engine/platform/namcowsg.h b/src/engine/platform/namcowsg.h index 4ab81bdce..ede25e8e6 100644 --- a/src/engine/platform/namcowsg.h +++ b/src/engine/platform/namcowsg.h @@ -96,7 +96,6 @@ class DivPlatformNamcoWSG: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformNamcoWSG(); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index bd1be94a8..a55199d15 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -62,27 +62,6 @@ const char** DivPlatformNES::getRegisterSheet() { return regCheatSheetNES; } -const char* DivPlatformNES::getEffectName(unsigned char effect) { - switch (effect) { - case 0x11: - return "11xx: Write to delta modulation counter (0 to 7F)"; - break; - case 0x12: - return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"; - break; - case 0x13: - return "13xy: Sweep up (x: time; y: shift)"; - break; - case 0x14: - return "14xy: Sweep down (x: time; y: shift)"; - break; - case 0x18: - return "18xx: Select PCM/DPCM mode (0: PCM; 1: DPCM)"; - break; - } - return NULL; -} - void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { if (useNP) { nes1_NP->Write(addr,data); diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 35c51df74..c00003305 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -106,7 +106,6 @@ class DivPlatformNES: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index); size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 8b76db213..784bd08fa 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -152,98 +152,6 @@ const int orderedOpsL[4]={ #define ADDR_FREQH 0xb0 #define ADDR_LR_FB_ALG 0xc0 -const char* DivPlatformOPL::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set global AM depth (0: 1dB, 1: 4.8dB)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 3F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 3F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 3F lowest; 4-op only)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 3F lowest; 4-op only)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x17: - return "17xx: Set global vibrato depth (0: normal, 1: double)"; - break; - case 0x18: - if (properDrumsSys) { - return "18xx: Toggle drums mode (1: enabled; 0: disabled)"; - } - break; - case 0x19: - return "19xx: Set attack of all operators (0 to F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to F; 4-op only)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to F; 4-op only)"; - break; - case 0x2a: - return "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 3 in OPL2 and 0 to 7 in OPL3)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set vibrato (x: operator from 1 to 4 (0 for all ops); y: enabled)"; - break; - case 0x54: - return "54xy: Set key scale level (x: operator from 1 to 4 (0 for all ops); y: level from 0 to 3)"; - break; - case 0x55: - return "55xy: Set envelope sustain (x: operator from 1 to 4 (0 for all ops); y: enabled)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to F; 4-op only)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to F; 4-op only)"; - break; - case 0x5b: - return "5Bxy: Set whether key will scale envelope (x: operator from 1 to 4 (0 for all ops); y: enabled)"; - break; - } - return NULL; -} - void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) { static short o[2]; static int os[2]; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 3d6497367..e3b16679f 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -145,7 +145,6 @@ class DivPlatformOPL: public DivDispatch { int getPortaFloor(int ch); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index); size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 5c9611b43..e29f6e622 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -27,68 +27,6 @@ #define CHIP_FREQBASE 1180068 -const char* DivPlatformOPLL::getEffectName(unsigned char effect) { - switch (effect) { - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 3F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 2; y: multiplier)"; - break; - case 0x18: - if (properDrumsSys) { - return "18xx: Toggle drums mode (1: enabled; 0: disabled)"; - } - break; - case 0x19: - return "19xx: Set attack of all operators (0 to F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to F)"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 2 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 2 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 2 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set vibrato (x: operator from 1 to 2 (0 for all ops); y: enabled)"; - break; - case 0x54: - return "54xy: Set key scale level (x: operator from 1 to 2 (0 for all ops); y: level from 0 to 3)"; - break; - case 0x55: - return "55xy: Set envelope sustain (x: operator from 1 to 2 (0 for all ops); y: enabled)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to F)"; - break; - case 0x5b: - return "5Bxy: Set whether key will scale envelope (x: operator from 1 to 2 (0 for all ops); y: enabled)"; - break; - } - return NULL; -} - const unsigned char cycleMapOPLL[18]={ 8, 7, 6, 7, 8, 7, 8, 6, 0, 1, 2, 7, 8, 9, 3, 4, 5, 9 }; diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index dad660dea..21a77b4e6 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -122,7 +122,6 @@ class DivPlatformOPLL: public DivDispatch { int getPortaFloor(int ch); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformOPLL(); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 3fc7a05bd..1dcf24511 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -53,27 +53,6 @@ const char** DivPlatformPCE::getRegisterSheet() { return regCheatSheetPCE; } -const char* DivPlatformPCE::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - case 0x11: - return "11xx: Toggle noise mode"; - break; - case 0x12: - return "12xx: Setup LFO (0: disabled; 1: 1x depth; 2: 16x depth; 3: 256x depth)"; - break; - case 0x13: - return "13xx: Set LFO speed"; - break; - case 0x17: - return "17xx: Toggle PCM mode"; - break; - } - return NULL; -} - void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformPCE(); diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index d40a297ae..260f5bbd6 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -190,10 +190,6 @@ const char** DivPlatformPCSpeaker::getRegisterSheet() { return regCheatSheetPCSpeaker; } -const char* DivPlatformPCSpeaker::getEffectName(unsigned char effect) { - return NULL; -} - const float cut=0.05; const float reso=0.06; diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index cb6f070fe..ba6275c32 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -113,7 +113,6 @@ class DivPlatformPCSpeaker: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformPCSpeaker(); diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index dc524e45f..4e1c39a97 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -37,15 +37,6 @@ const char** DivPlatformPET::getRegisterSheet() { return regCheatSheet6522; } -const char* DivPlatformPET::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - } - return NULL; -} - // high-level emulation of 6522 shift register and driver software for now void DivPlatformPET::rWrite(unsigned int addr, unsigned char val) { bool hwSROutput=((regPool[11]>>2)&7)==4; diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index 06c7e736a..8de217790 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -80,7 +80,6 @@ class DivPlatformPET: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformPET(); diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index ca6a794cd..863c0e1fd 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -249,24 +249,6 @@ const char** DivPlatformQSound::getRegisterSheet() { return regCheatSheetQSound; } -const char* DivPlatformQSound::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set echo feedback level (00 to FF)"; - break; - case 0x11: - return "11xx: Set channel echo level (00 to FF)"; - break; - case 0x12: - return "12xx: Toggle QSound algorithm (0: disabled; 1: enabled)"; - break; - default: - if ((effect & 0xf0) == 0x30) { - return "3xxx: Set echo delay buffer length (000 to AA5)"; - } - } - return NULL; -} void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index = 0); size_t getSampleMemCapacity(int index = 0); size_t getSampleMemUsage(int index = 0); diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index e4a39d44e..e19b945b0 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -43,10 +43,6 @@ const char** DivPlatformRF5C68::getRegisterSheet() { return regCheatSheetRF5C68; } -const char* DivPlatformRF5C68::getEffectName(unsigned char effect) { - return NULL; -} - void DivPlatformRF5C68::chWrite(unsigned char ch, unsigned int addr, unsigned char val) { if (!skipRegisterWrites) { if (curChan!=ch) { diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 6946b4900..d82c926e6 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -92,7 +92,6 @@ class DivPlatformRF5C68: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index = 0); size_t getSampleMemCapacity(int index = 0); size_t getSampleMemUsage(int index = 0); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 103c3348f..a05a61d4f 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -56,21 +56,6 @@ const char** DivPlatformSAA1099::getRegisterSheet() { return regCheatSheetSAA; } -const char* DivPlatformSAA1099::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xy: Set channel mode (x: noise; y: tone)"; - break; - case 0x11: - return "11xx: Set noise frequency"; - break; - case 0x12: - return "12xx: Setup envelope (refer to docs for more information)"; - break; - } - return NULL; -} - void DivPlatformSAA1099::acquire_saaSound(short* bufL, short* bufR, size_t start, size_t len) { if (saaBufLen& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); }; diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index 485839bf1..a72257629 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -80,15 +80,6 @@ const char** DivPlatformSCC::getRegisterSheet() { return isPlus ? regCheatSheetSCCPlus : regCheatSheetSCC; } -const char* DivPlatformSCC::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - } - return NULL; -} - void DivPlatformSCC::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void setChipModel(bool isPlus); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index d66fcce0b..e406e293b 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -26,15 +26,6 @@ //#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} //#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } -const char* DivPlatformSegaPCM::getEffectName(unsigned char effect) { - switch (effect) { - case 0x20: - return "20xx: Set PCM frequency"; - break; - } - return NULL; -} - void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 6edc85302..0dd4b837a 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -114,7 +114,6 @@ class DivPlatformSegaPCM: public DivDispatch { bool isStereo(); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformSegaPCM(); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 3d11a5ac9..2988be2f8 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -38,15 +38,6 @@ const char** DivPlatformSMS::getRegisterSheet() { return stereo?regCheatSheetGG:regCheatSheetSN; } -const char* DivPlatformSMS::getEffectName(unsigned char effect) { - switch (effect) { - case 0x20: - return "20xy: Set noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)"; - break; - } - return NULL; -} - void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) { int oL=0; int oR=0; diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 35bb44bab..eef54da1e 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -101,7 +101,6 @@ class DivPlatformSMS: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); void setNuked(bool value); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index afcdba242..ca933650f 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -33,72 +33,6 @@ const char** DivPlatformSoundUnit::getRegisterSheet() { return NULL; } -const char* DivPlatformSoundUnit::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set waveform (0 to 7)"; - break; - case 0x12: - return "12xx: Set pulse width (0 to 7F)"; - break; - case 0x13: - return "13xx: Set resonance (0 to F)"; - break; - case 0x14: - return "14xx: Set filter mode (bit 0: ring mod; bit 1: low pass; bit 2: high pass; bit 3: band pass)"; - break; - case 0x15: - return "15xx: Set frequency sweep period low byte"; - break; - case 0x16: - return "16xx: Set frequency sweep period high byte"; - break; - case 0x17: - return "17xx: Set volume sweep period low byte"; - break; - case 0x18: - return "18xx: Set volume sweep period high byte"; - break; - case 0x19: - return "19xx: Set cutoff sweep period low byte"; - break; - case 0x1a: - return "1Axx: Set cutoff sweep period high byte"; - break; - case 0x1b: - return "1Bxx: Set frequency sweep boundary"; - break; - case 0x1c: - return "1Cxx: Set volume sweep boundary"; - break; - case 0x1d: - return "1Dxx: Set cutoff sweep boundary"; - break; - case 0x1e: - return "1Exx: Set phase reset period low byte"; - break; - case 0x1f: - return "1Fxx: Set phase reset period high byte"; - break; - case 0x20: - return "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)"; - break; - case 0x21: - return "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)"; - break; - case 0x22: - return "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)"; - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - return "4xxx: Set cutoff (0 to FFF)"; - break; - } - return NULL; -} - double DivPlatformSoundUnit::NOTE_SU(int ch, int note) { if (chan[ch].switchRoles) { return NOTE_PERIODIC(note); diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 2392624f6..d76d07227 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -133,7 +133,6 @@ class DivPlatformSoundUnit: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index); size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index b6da23271..cdab93d5c 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -50,27 +50,6 @@ const char** DivPlatformSwan::getRegisterSheet() { return regCheatSheetWS; } -const char* DivPlatformSwan::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - case 0x11: - return "11xx: Setup noise mode (0: disabled; 1-8: enabled/tap)"; - break; - case 0x12: - return "12xx: Setup sweep period (0: disabled; 1-20: enabled/period)"; - break; - case 0x13: - return "13xx: Set sweep amount"; - break; - case 0x17: - return "17xx: Toggle PCM mode"; - break; - } - return NULL; -} - void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformSwan(); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index ddb380844..bebc1ff2e 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -34,15 +34,6 @@ const char* regCheatSheetTIA[]={ NULL }; -const char* DivPlatformTIA::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Select shape (0 to F)"; - break; - } - return NULL; -} - const char** DivPlatformTIA::getRegisterSheet() { return regCheatSheetTIA; } diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index cabe91533..168175367 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -67,7 +67,6 @@ class DivPlatformTIA: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); }; diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 9d24e4db5..e6e38a128 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -55,139 +55,6 @@ const char** DivPlatformTX81Z::getRegisterSheet() { return regCheatSheetOPZ; } -const char* DivPlatformTX81Z::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set noise frequency (xx: value; 0 disables noise)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x17: - return "17xx: Set LFO speed"; - break; - case 0x18: - return "18xx: Set LFO waveform (0 saw, 1 square, 2 triangle, 3 noise)"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x1e: - return "1Exx: Set AM depth (0 to 7F)"; - break; - case 0x1f: - return "1Fxx: Set PM depth (0 to 7F)"; - break; - case 0x28: - return "28xy: Set reverb (x: operator from 1 to 4 (0 for all ops); y: reverb from 0 to 7)"; - break; - case 0x2a: - return "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 7)"; - break; - case 0x2b: - return "2Bxy: Set envelope generator shift (x: operator from 1 to 4 (0 for all ops); y: shift from 0 to 3)"; - break; - case 0x2c: - return "2Cxy: Set fine multiplier (x: operator from 1 to 4 (0 for all ops); y: fine)"; - break; - case 0x2f: - return "2Fxx: Toggle hard envelope reset on new notes"; - break; - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - return "3xyy: Set fixed frequency of operator 1 (x: octave from 0 to 7; y: frequency)"; - break; - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - return "3xyy: Set fixed frequency of operator 2 (x: octave from 8 to F; y: frequency)"; - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - return "4xyy: Set fixed frequency of operator 3 (x: octave from 0 to 7; y: frequency)"; - break; - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - return "4xyy: Set fixed frequency of operator 4 (x: octave from 8 to F; y: frequency)"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - } - return NULL; -} - void DivPlatformTX81Z::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index e867416cf..d1e427282 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -108,7 +108,6 @@ class DivPlatformTX81Z: public DivPlatformOPM { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformTX81Z(); diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 6376cc19e..e50bcd6ea 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -51,18 +51,6 @@ const char** DivPlatformVERA::getRegisterSheet() { return regCheatSheetVERA; } -const char* DivPlatformVERA::getEffectName(unsigned char effect) { - switch (effect) { - case 0x20: - return "20xx: Change waveform"; - break; - case 0x22: - return "22xx: Set duty cycle (0 to 3F)"; - break; - } - return NULL; -} - void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len) { // both PSG part and PCM part output a full 16-bit range, putting bufL/R // argument right into both could cause an overflow diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 612b4354b..53e766dcd 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -79,7 +79,6 @@ class DivPlatformVERA: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformVERA(); diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 771b87d1e..5c0bdf461 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -39,15 +39,6 @@ const char** DivPlatformVIC20::getRegisterSheet() { return regCheatSheetVIC; } -const char* DivPlatformVIC20::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - } - return NULL; -} - void DivPlatformVIC20::acquire(short* bufL, short* bufR, size_t start, size_t len) { const unsigned char loadFreq[3] = {0x7e, 0x7d, 0x7b}; const unsigned char wavePatterns[16] = { diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index d23f27be8..d4b56028c 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -82,7 +82,6 @@ class DivPlatformVIC20: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformVIC20(); diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 8a34d9252..9a7bcef0d 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -46,18 +46,6 @@ const char** DivPlatformVRC6::getRegisterSheet() { return regCheatSheetVRC6; } -const char* DivPlatformVRC6::getEffectName(unsigned char effect) { - switch (effect) { - case 0x12: - return "12xx: Set duty cycle (pulse: 0 to 7)"; - break; - case 0x17: - return "17xx: Toggle PCM mode (pulse channel)"; - break; - } - return NULL; -} - void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); DivPlatformVRC6() : vrc6(intf) {}; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index e2e360b1b..f6aa1c651 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -205,39 +205,6 @@ const char** DivPlatformX1_010::getRegisterSheet() { return regCheatSheetX1_010; } -const char* DivPlatformX1_010::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform"; - break; - case 0x11: - return "11xx: Change envelope shape"; - break; - case 0x17: - return "17xx: Toggle PCM mode"; - break; - case 0x20: - return "20xx: Set PCM frequency (1 to FF)"; - break; - case 0x22: - return "22xx: Set envelope mode (bit 0: enable, bit 1: one-shot, bit 2: split shape to L/R, bit 3/5: H.invert right/left, bit 4/6: V.invert right/left)"; - break; - case 0x23: - return "23xx: Set envelope period"; - break; - case 0x25: - return "25xx: Envelope slide up"; - break; - case 0x26: - return "26xx: Envelope slide down"; - break; - case 0x29: - return "29xy: Set auto-envelope (x: numerator; y: denominator)"; - break; - } - return NULL; -} - void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; htick(); diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 7a85b6336..178a89383 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -149,7 +149,6 @@ class DivPlatformX1_010: public DivDispatch { size_t getSampleMemUsage(int index = 0); void renderSamples(); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformX1_010(); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 83c93c58e..afb4f526c 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -156,123 +156,6 @@ const char** DivPlatformYM2203::getRegisterSheet() { return regCheatSheetYM2203; } -const char* DivPlatformYM2203::getEffectName(unsigned char effect) { - switch (effect) { - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x18: - return "18xx: Toggle extended channel 3 mode"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x20: - return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"; - break; - case 0x21: - return "21xx: Set SSG noise frequency (0 to 1F)"; - break; - case 0x22: - return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)"; - break; - case 0x23: - return "23xx: Set SSG envelope period low byte"; - break; - case 0x24: - return "24xx: Set SSG envelope period high byte"; - break; - case 0x25: - return "25xx: SSG envelope slide up"; - break; - case 0x26: - return "26xx: SSG envelope slide down"; - break; - case 0x29: - return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - } - return NULL; -} - void DivPlatformYM2203::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os; diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index d406e2f28..0395c9d0f 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -114,7 +114,6 @@ class DivPlatformYM2203: public DivPlatformOPN { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index c3cf52a06..9e76e6e3f 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -279,126 +279,6 @@ const char** DivPlatformYM2608::getRegisterSheet() { return regCheatSheetYM2608; } -const char* DivPlatformYM2608::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xy: Setup LFO (x: enable; y: speed)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x18: - return "18xx: Toggle extended channel 3 mode"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x20: - return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"; - break; - case 0x21: - return "21xx: Set SSG noise frequency (0 to 1F)"; - break; - case 0x22: - return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)"; - break; - case 0x23: - return "23xx: Set SSG envelope period low byte"; - break; - case 0x24: - return "24xx: Set SSG envelope period high byte"; - break; - case 0x25: - return "25xx: SSG envelope slide up"; - break; - case 0x26: - return "26xx: SSG envelope slide down"; - break; - case 0x29: - return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - } - return NULL; -} - double DivPlatformYM2608::NOTE_OPNB(int ch, int note) { if (ch>8) { // ADPCM-B return NOTE_ADPCMB(note); diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index ac38a8c08..7a471b8bf 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -127,7 +127,6 @@ class DivPlatformYM2608: public DivPlatformOPN { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index); size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 4e01b005c..920d9b144 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -318,126 +318,6 @@ const char** DivPlatformYM2610::getRegisterSheet() { return regCheatSheetYM2610; } -const char* DivPlatformYM2610::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xy: Setup LFO (x: enable; y: speed)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x18: - return "18xx: Toggle extended channel 3 mode"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x20: - return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"; - break; - case 0x21: - return "21xx: Set SSG noise frequency (0 to 1F)"; - break; - case 0x22: - return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)"; - break; - case 0x23: - return "23xx: Set SSG envelope period low byte"; - break; - case 0x24: - return "24xx: Set SSG envelope period high byte"; - break; - case 0x25: - return "25xx: SSG envelope slide up"; - break; - case 0x26: - return "26xx: SSG envelope slide down"; - break; - case 0x29: - return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - } - return NULL; -} - double DivPlatformYM2610::NOTE_OPNB(int ch, int note) { if (ch>6) { // ADPCM return NOTE_ADPCMB(note); diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index dde7ed105..5e22ed2a0 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -145,7 +145,6 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 1a1f7f0ae..039691e74 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -302,126 +302,6 @@ const char** DivPlatformYM2610B::getRegisterSheet() { return regCheatSheetYM2610B; } -const char* DivPlatformYM2610B::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xy: Setup LFO (x: enable; y: speed)"; - break; - case 0x11: - return "11xx: Set feedback (0 to 7)"; - break; - case 0x12: - return "12xx: Set level of operator 1 (0 highest, 7F lowest)"; - break; - case 0x13: - return "13xx: Set level of operator 2 (0 highest, 7F lowest)"; - break; - case 0x14: - return "14xx: Set level of operator 3 (0 highest, 7F lowest)"; - break; - case 0x15: - return "15xx: Set level of operator 4 (0 highest, 7F lowest)"; - break; - case 0x16: - return "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)"; - break; - case 0x18: - return "18xx: Toggle extended channel 3 mode"; - break; - case 0x19: - return "19xx: Set attack of all operators (0 to 1F)"; - break; - case 0x1a: - return "1Axx: Set attack of operator 1 (0 to 1F)"; - break; - case 0x1b: - return "1Bxx: Set attack of operator 2 (0 to 1F)"; - break; - case 0x1c: - return "1Cxx: Set attack of operator 3 (0 to 1F)"; - break; - case 0x1d: - return "1Dxx: Set attack of operator 4 (0 to 1F)"; - break; - case 0x20: - return "20xx: Set SSG channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"; - break; - case 0x21: - return "21xx: Set SSG noise frequency (0 to 1F)"; - break; - case 0x22: - return "22xy: Set SSG envelope mode (x: shape, y: enable for this channel)"; - break; - case 0x23: - return "23xx: Set SSG envelope period low byte"; - break; - case 0x24: - return "24xx: Set SSG envelope period high byte"; - break; - case 0x25: - return "25xx: SSG envelope slide up"; - break; - case 0x26: - return "26xx: SSG envelope slide down"; - break; - case 0x29: - return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; - break; - case 0x30: - return "30xx: Toggle hard envelope reset on new notes"; - break; - case 0x50: - return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)"; - break; - case 0x51: - return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)"; - break; - case 0x52: - return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)"; - break; - case 0x53: - return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)"; - break; - case 0x54: - return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)"; - break; - case 0x55: - return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)"; - break; - case 0x56: - return "56xx: Set decay of all operators (0 to 1F)"; - break; - case 0x57: - return "57xx: Set decay of operator 1 (0 to 1F)"; - break; - case 0x58: - return "58xx: Set decay of operator 2 (0 to 1F)"; - break; - case 0x59: - return "59xx: Set decay of operator 3 (0 to 1F)"; - break; - case 0x5a: - return "5Axx: Set decay of operator 4 (0 to 1F)"; - break; - case 0x5b: - return "5Bxx: Set decay 2 of all operators (0 to 1F)"; - break; - case 0x5c: - return "5Cxx: Set decay 2 of operator 1 (0 to 1F)"; - break; - case 0x5d: - return "5Dxx: Set decay 2 of operator 2 (0 to 1F)"; - break; - case 0x5e: - return "5Exx: Set decay 2 of operator 3 (0 to 1F)"; - break; - case 0x5f: - return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; - break; - } - return NULL; -} - double DivPlatformYM2610B::NOTE_OPNB(int ch, int note) { if (ch>8) { // ADPCM-B return NOTE_ADPCMB(note); diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index fefb06929..703f8dd4a 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -113,7 +113,6 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 0543a815c..ca1b225d2 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -60,10 +60,6 @@ const char** DivPlatformYMZ280B::getRegisterSheet() { return regCheatSheetYMZ280B; } -const char* DivPlatformYMZ280B::getEffectName(unsigned char effect) { - return NULL; -} - void DivPlatformYMZ280B::acquire(short* bufL, short* bufR, size_t start, size_t len) { short buf[16][256]; short *bufPtrs[16]={ diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index 0d254c088..6dbe2623c 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -91,7 +91,6 @@ class DivPlatformYMZ280B: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index = 0); size_t getSampleMemCapacity(int index = 0); size_t getSampleMemUsage(int index = 0); diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 01702dc5d..d83903094 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -27,18 +27,6 @@ const char** DivPlatformZXBeeper::getRegisterSheet() { return NULL; } -const char* DivPlatformZXBeeper::getEffectName(unsigned char effect) { - switch (effect) { - case 0x12: - return "12xx: Set pulse width"; - break; - case 0x17: - return "17xx: Trigger overlay drum"; - break; - } - return NULL; -} - void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t len) { bool o=false; for (size_t h=start; h& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); ~DivPlatformZXBeeper(); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 3dbc6b5fb..63203ab54 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -292,13 +292,39 @@ int DivEngine::dispatchCmd(DivCommand c) { } bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) { - if (sysDefs[sysOfChan[ch]]==NULL) return false; - return sysDefs[sysOfChan[ch]]->effectFunc(ch,effect,effectVal); + DivSysDef* sysDef=sysDefs[sysOfChan[ch]]; + if (sysDef==NULL) return false; + auto iter=sysDef->effectHandlers.find(effect); + if (iter==sysDef->effectHandlers.end()) return false; + EffectHandler handler=iter->second; + int val=0; + int val2=0; + try { + val=handler.val?handler.val(effect,effectVal):effectVal; + val2=handler.val2?handler.val2(effect,effectVal):0; + } catch (DivDoNotHandleEffect& e) { + return false; + } + // wouldn't this cause problems if it were to return 0? + return dispatchCmd(DivCommand(handler.dispatchCmd,ch,val,val2)); } bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) { - if (sysDefs[sysOfChan[ch]]==NULL) return false; - return sysDefs[sysOfChan[ch]]->postEffectFunc(ch,effect,effectVal); + DivSysDef* sysDef=sysDefs[sysOfChan[ch]]; + if (sysDef==NULL) return false; + auto iter=sysDef->postEffectHandlers.find(effect); + if (iter==sysDef->postEffectHandlers.end()) return false; + EffectHandler handler=iter->second; + int val=0; + int val2=0; + try { + val=handler.val?handler.val(effect,effectVal):effectVal; + val2=handler.val2?handler.val2(effect,effectVal):0; + } catch (DivDoNotHandleEffect& e) { + return true; + } + // wouldn't this cause problems if it were to return 0? + return dispatchCmd(DivCommand(handler.dispatchCmd,ch,val,val2)); } void DivEngine::processRow(int i, bool afterDelay) { @@ -609,9 +635,6 @@ void DivEngine::processRow(int i, bool afterDelay) { clockDrift=0; subticks=0; break; - case 0xdf: // set sample direction - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal)); - break; case 0xe0: // arp speed if (effectVal>0) { curSubSong->arpLen=effectVal; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index e3c356cf7..63cb6faca 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -360,390 +360,222 @@ int DivEngine::minVGMVersion(DivSystem which) { // {chanTypes, ...}, // {chanPreferInsType, ...}, // {chanPreferInsType2, ...}, (optional) -// [this](int ch, unsigned char effect, unsigned char effectVal) -> bool {}, (effect handler, optional) -// [this](int ch, unsigned char effect, unsigned char effectVal) -> bool {} (post effect handler, optional) +// {{effect, {DIV_CMD_xx, "Description"}}, ...}, (effect handler, optional) +// {{effect, {DIV_CMD_xx, "Description"}}, ...} (post effect handler, optional) // ); +template int constVal(unsigned char, unsigned char) { + return val; +}; + +int effectVal(unsigned char, unsigned char val) { + return val; +}; + +int negEffectVal(unsigned char, unsigned char val) { + return -(int)val; +}; + +template int effectValAnd(unsigned char, unsigned char val) { + return val&mask; +}; + +template int effectOpVal(unsigned char, unsigned char val) { + if ((val>>4)>maxOp) throw DivDoNotHandleEffect(); + return (val>>4)-1; +}; + +template int effectOpValNoZero(unsigned char, unsigned char val) { + if ((val>>4)<1 || (val>>4)>maxOp) throw DivDoNotHandleEffect(); + return (val>>4)-1; +}; + +template int effectValLong(unsigned char cmd, unsigned char val) { + return ((((unsigned int)cmd)&((1<<(bits-8))-1))<<8)|((unsigned int)val); +}; + void DivEngine::registerSystems() { logD("registering systems..."); - auto fmPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // LFO or noise mode - if (IS_OPM_LIKE) { - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - } else { - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); - } - break; - case 0x11: // FB - dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); - break; - case 0x12: // TL op1 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x7f)); - break; - case 0x13: // TL op2 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x7f)); - break; - case 0x14: // TL op3 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,2,effectVal&0x7f)); - break; - case 0x15: // TL op4 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,3,effectVal&0x7f)); - break; - case 0x16: // MULT - if ((effectVal>>4)>0 && (effectVal>>4)<5) { - dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); - } - break; - case 0x17: // arcade LFO - if (IS_OPM_LIKE) { - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); - } - break; - case 0x18: // EXT or LFO waveform - if (IS_OPM_LIKE) { - dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal)); - } else { - dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); - } - break; - case 0x19: // AR global - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31)); - break; - case 0x1a: // AR op1 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&31)); - break; - case 0x1b: // AR op2 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&31)); - break; - case 0x1c: // AR op3 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,2,effectVal&31)); - break; - case 0x1d: // AR op4 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&31)); - break; - case 0x1e: // UNOFFICIAL: Arcade AM depth - dispatchCmd(DivCommand(DIV_CMD_FM_AM_DEPTH,ch,effectVal&127)); - break; - case 0x1f: // UNOFFICIAL: Arcade PM depth - dispatchCmd(DivCommand(DIV_CMD_FM_PM_DEPTH,ch,effectVal&127)); - break; - case 0x20: // Neo Geo PSG mode - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - } - break; - case 0x21: // Neo Geo PSG noise freq - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - } - break; - case 0x22: // UNOFFICIAL: Neo Geo PSG envelope enable - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); - } - break; - case 0x23: // UNOFFICIAL: Neo Geo PSG envelope period low - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); - } - break; - case 0x24: // UNOFFICIAL: Neo Geo PSG envelope period high - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); - } - break; - case 0x25: // UNOFFICIAL: Neo Geo PSG envelope slide up - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal)); - } - break; - case 0x26: // UNOFFICIAL: Neo Geo PSG envelope slide down - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal)); - } - break; - case 0x29: // auto-envelope - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); - } - break; - // fixed frequency effects on OPZ - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - if (sysOfChan[ch]==DIV_SYSTEM_OPZ) { - dispatchCmd(DivCommand(DIV_CMD_FM_FIXFREQ,ch,0,((effect&7)<<8)|effectVal)); - } - break; - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - if (sysOfChan[ch]==DIV_SYSTEM_OPZ) { - dispatchCmd(DivCommand(DIV_CMD_FM_FIXFREQ,ch,1,((effect&7)<<8)|effectVal)); - } - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - if (sysOfChan[ch]==DIV_SYSTEM_OPZ) { - dispatchCmd(DivCommand(DIV_CMD_FM_FIXFREQ,ch,2,((effect&7)<<8)|effectVal)); - } - break; - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - if (sysOfChan[ch]==DIV_SYSTEM_OPZ) { - dispatchCmd(DivCommand(DIV_CMD_FM_FIXFREQ,ch,3,((effect&7)<<8)|effectVal)); - } - break; - // extra FM effects here - OP_EFFECT_SINGLE(0x50,DIV_CMD_FM_AM,4,1); - OP_EFFECT_SINGLE(0x51,DIV_CMD_FM_SL,4,15); - OP_EFFECT_SINGLE(0x52,DIV_CMD_FM_RR,4,15); - OP_EFFECT_SINGLE(0x53,DIV_CMD_FM_DT,4,7); - OP_EFFECT_SINGLE(0x54,DIV_CMD_FM_RS,4,3); - OP_EFFECT_SINGLE(0x55,DIV_CMD_FM_SSG,4,(IS_OPM_LIKE?3:15)); + // Common effect handler maps - OP_EFFECT_MULTI(0x56,DIV_CMD_FM_DR,-1,31); - OP_EFFECT_MULTI(0x57,DIV_CMD_FM_DR,0,31); - OP_EFFECT_MULTI(0x58,DIV_CMD_FM_DR,1,31); - OP_EFFECT_MULTI(0x59,DIV_CMD_FM_DR,2,31); - OP_EFFECT_MULTI(0x5a,DIV_CMD_FM_DR,3,31); - - OP_EFFECT_MULTI(0x5b,DIV_CMD_FM_D2R,-1,31); - OP_EFFECT_MULTI(0x5c,DIV_CMD_FM_D2R,0,31); - OP_EFFECT_MULTI(0x5d,DIV_CMD_FM_D2R,1,31); - OP_EFFECT_MULTI(0x5e,DIV_CMD_FM_D2R,2,31); - OP_EFFECT_MULTI(0x5f,DIV_CMD_FM_D2R,3,31); - - OP_EFFECT_SINGLE(0x28,DIV_CMD_FM_REV,4,7); - OP_EFFECT_SINGLE(0x2a,DIV_CMD_FM_WS,4,7); - OP_EFFECT_SINGLE(0x2b,DIV_CMD_FM_EG_SHIFT,4,3); - OP_EFFECT_SINGLE(0x2c,DIV_CMD_FM_FINE,4,15); - default: - return false; - } - return true; + EffectHandlerMap ayPostEffectHandlerMap={ + {0x20, {DIV_CMD_STD_NOISE_MODE, "20xx: Set channel mode (bit 0: square; bit 1: noise; bit 2: envelope)"}}, + {0x21, {DIV_CMD_STD_NOISE_FREQ, "21xx: Set noise frequency (0 to 1F)"}}, + {0x22, {DIV_CMD_AY_ENVELOPE_SET, "22xy: Set envelope mode (x: shape, y: enable for this channel)"}}, + {0x23, {DIV_CMD_AY_ENVELOPE_LOW, "23xx: Set envelope period low byte"}}, + {0x24, {DIV_CMD_AY_ENVELOPE_HIGH, "24xx: Set envelope period high byte"}}, + {0x25, {DIV_CMD_AY_ENVELOPE_SLIDE, "25xx: Envelope slide up", negEffectVal}}, + {0x26, {DIV_CMD_AY_ENVELOPE_SLIDE, "26xx: Envelope slide down"}}, + {0x29, {DIV_CMD_AY_AUTO_ENVELOPE, "29xy: Set auto-envelope (x: numerator; y: denominator)"}}, + {0x2e, {DIV_CMD_AY_IO_WRITE, "2Exx: Write to I/O port A", constVal<0>, effectVal}}, + {0x2f, {DIV_CMD_AY_IO_WRITE, "2Fxx: Write to I/O port B", constVal<1>, effectVal}}, }; - auto fmOPLLPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x11: // FB - dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); - break; - case 0x12: // TL op1 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x3f)); - break; - case 0x13: // TL op2 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x0f)); - break; - case 0x16: // MULT - if ((effectVal>>4)>0 && (effectVal>>4)<3) { - dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); - } - break; - case 0x19: // AR global - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31)); - break; - case 0x1a: // AR op1 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&31)); - break; - case 0x1b: // AR op2 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&31)); - break; + EffectHandlerMap ay8930PostEffectHandlerMap(ayPostEffectHandlerMap); + ay8930PostEffectHandlerMap.insert({ + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle (0 to 8)", + [](unsigned char, unsigned char val) -> int { return 0x10+(val&15); }}}, + {0x27, {DIV_CMD_AY_NOISE_MASK_AND, "27xx: Set noise AND mask"}}, + {0x28, {DIV_CMD_AY_NOISE_MASK_OR, "28xx: Set noise OR mask"}}, + {0x2d, {DIV_CMD_AY_IO_WRITE, "2Dxx: NOT TO BE EMPLOYED BY THE COMPOSER", constVal<255>, effectVal}}, + }); - // extra FM effects here - OP_EFFECT_SINGLE(0x50,DIV_CMD_FM_AM,2,1); - OP_EFFECT_SINGLE(0x51,DIV_CMD_FM_SL,2,15); - OP_EFFECT_SINGLE(0x52,DIV_CMD_FM_RR,2,15); - OP_EFFECT_SINGLE(0x53,DIV_CMD_FM_VIB,2,1); - OP_EFFECT_SINGLE(0x54,DIV_CMD_FM_RS,2,3); - OP_EFFECT_SINGLE(0x55,DIV_CMD_FM_SUS,2,1); - - OP_EFFECT_MULTI(0x56,DIV_CMD_FM_DR,-1,15); - OP_EFFECT_MULTI(0x57,DIV_CMD_FM_DR,0,15); - OP_EFFECT_MULTI(0x58,DIV_CMD_FM_DR,1,15); - - OP_EFFECT_SINGLE(0x5b,DIV_CMD_FM_KSR,2,1); - default: - return false; - } - return true; + EffectHandlerMap fmEffectHandlerMap={ + {0x30, {DIV_CMD_FM_HARD_RESET, "30xx: Toggle hard envelope reset on new notes"}}, }; - auto fmOPLPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // DAM - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal&1)); - break; - case 0x11: // FB - dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); - break; - case 0x12: // TL op1 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x3f)); - break; - case 0x13: // TL op2 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x3f)); - break; - case 0x14: // TL op3 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,2,effectVal&0x3f)); - break; - case 0x15: // TL op4 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,3,effectVal&0x3f)); - break; - case 0x16: // MULT - if ((effectVal>>4)>0 && (effectVal>>4)<5) { - dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); - } - break; - case 0x17: // DVB - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,2+(effectVal&1))); - break; - case 0x19: // AR global - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&15)); - break; - case 0x1a: // AR op1 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&15)); - break; - case 0x1b: // AR op2 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&15)); - break; - case 0x1c: // AR op3 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,2,effectVal&15)); - break; - case 0x1d: // AR op4 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&15)); - break; - - // extra FM effects here - OP_EFFECT_SINGLE(0x50,DIV_CMD_FM_AM,4,1); - OP_EFFECT_SINGLE(0x51,DIV_CMD_FM_SL,4,15); - OP_EFFECT_SINGLE(0x52,DIV_CMD_FM_RR,4,15); - OP_EFFECT_SINGLE(0x53,DIV_CMD_FM_VIB,4,1); - OP_EFFECT_SINGLE(0x54,DIV_CMD_FM_RS,4,3); - OP_EFFECT_SINGLE(0x55,DIV_CMD_FM_SUS,4,1); + EffectHandlerMap fmOPN2EffectHandlerMap(fmEffectHandlerMap); + fmOPN2EffectHandlerMap.insert({ + {0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode"}}, + {0xdf, {DIV_CMD_SAMPLE_DIR, "DFxx: Set sample playback direction (0: normal; 1: reverse)"}}, + }); - OP_EFFECT_MULTI(0x56,DIV_CMD_FM_DR,-1,15); - OP_EFFECT_MULTI(0x57,DIV_CMD_FM_DR,0,15); - OP_EFFECT_MULTI(0x58,DIV_CMD_FM_DR,1,15); - OP_EFFECT_MULTI(0x59,DIV_CMD_FM_DR,2,15); - OP_EFFECT_MULTI(0x5a,DIV_CMD_FM_DR,3,15); + EffectHandlerMap fmOPLDrumsEffectHandlerMap(fmEffectHandlerMap); + fmOPLDrumsEffectHandlerMap.insert({ + {0x18, {DIV_CMD_FM_EXTCH, "18xx: Toggle drums mode (1: enabled; 0: disabled)"}}, + }); - OP_EFFECT_SINGLE(0x5b,DIV_CMD_FM_KSR,4,1); - OP_EFFECT_SINGLE(0x2a,DIV_CMD_FM_WS,4,7); - - default: - return false; - } - return true; + EffectHandlerMap fmOPNPostEffectHandlerMap={ + {0x11, {DIV_CMD_FM_FB, "11xx: Set feedback (0 to 7)"}}, + {0x12, {DIV_CMD_FM_TL, "12xx: Set level of operator 1 (0 highest, 7F lowest)", constVal<0>, effectVal}}, + {0x13, {DIV_CMD_FM_TL, "13xx: Set level of operator 2 (0 highest, 7F lowest)", constVal<1>, effectVal}}, + {0x14, {DIV_CMD_FM_TL, "14xx: Set level of operator 3 (0 highest, 7F lowest)", constVal<2>, effectVal}}, + {0x15, {DIV_CMD_FM_TL, "15xx: Set level of operator 4 (0 highest, 7F lowest)", constVal<3>, effectVal}}, + {0x16, {DIV_CMD_FM_MULT, "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)", effectOpValNoZero<4>, effectValAnd<15>}}, + {0x19, {DIV_CMD_FM_AR, "19xx: Set attack of all operators (0 to 1F)", constVal<-1>, effectValAnd<31>}}, + {0x1a, {DIV_CMD_FM_AR, "1Axx: Set attack of operator 1 (0 to 1F)", constVal<0>, effectValAnd<31>}}, + {0x1b, {DIV_CMD_FM_AR, "1Bxx: Set attack of operator 2 (0 to 1F)", constVal<1>, effectValAnd<31>}}, + {0x1c, {DIV_CMD_FM_AR, "1Cxx: Set attack of operator 3 (0 to 1F)", constVal<2>, effectValAnd<31>}}, + {0x1d, {DIV_CMD_FM_AR, "1Dxx: Set attack of operator 4 (0 to 1F)", constVal<3>, effectValAnd<31>}}, + {0x50, {DIV_CMD_FM_AM, "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)", effectOpVal<4>, effectValAnd<1>}}, + {0x51, {DIV_CMD_FM_SL, "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)", effectOpVal<4>, effectValAnd<15>}}, + {0x52, {DIV_CMD_FM_RR, "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)", effectOpVal<4>, effectValAnd<15>}}, + {0x53, {DIV_CMD_FM_DT, "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)", effectOpVal<4>, effectValAnd<7>}}, + {0x54, {DIV_CMD_FM_RS, "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)", effectOpVal<4>, effectValAnd<3>}}, + {0x56, {DIV_CMD_FM_DR, "56xx: Set decay of all operators (0 to 1F)", constVal<-1>, effectValAnd<31>}}, + {0x57, {DIV_CMD_FM_DR, "57xx: Set decay of operator 1 (0 to 1F)", constVal<0>, effectValAnd<31>}}, + {0x58, {DIV_CMD_FM_DR, "58xx: Set decay of operator 2 (0 to 1F)", constVal<1>, effectValAnd<31>}}, + {0x59, {DIV_CMD_FM_DR, "59xx: Set decay of operator 3 (0 to 1F)", constVal<2>, effectValAnd<31>}}, + {0x5a, {DIV_CMD_FM_DR, "5Axx: Set decay of operator 4 (0 to 1F)", constVal<3>, effectValAnd<31>}}, + {0x5b, {DIV_CMD_FM_D2R, "5Bxx: Set decay 2 of all operators (0 to 1F)", constVal<-1>, effectValAnd<31>}}, + {0x5c, {DIV_CMD_FM_D2R, "5Cxx: Set decay 2 of operator 1 (0 to 1F)", constVal<0>, effectValAnd<31>}}, + {0x5d, {DIV_CMD_FM_D2R, "5Dxx: Set decay 2 of operator 2 (0 to 1F)", constVal<1>, effectValAnd<31>}}, + {0x5e, {DIV_CMD_FM_D2R, "5Exx: Set decay 2 of operator 3 (0 to 1F)", constVal<2>, effectValAnd<31>}}, + {0x5f, {DIV_CMD_FM_D2R, "5Fxx: Set decay 2 of operator 4 (0 to 1F)", constVal<3>, effectValAnd<31>}}, }; - auto c64PostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // cutoff - dispatchCmd(DivCommand(DIV_CMD_C64_CUTOFF,ch,effectVal)); - break; - case 0x12: // duty - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // resonance - dispatchCmd(DivCommand(DIV_CMD_C64_RESONANCE,ch,effectVal)); - break; - case 0x14: // filter mode - dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_MODE,ch,effectVal)); - break; - case 0x15: // reset time - dispatchCmd(DivCommand(DIV_CMD_C64_RESET_TIME,ch,effectVal)); - break; - case 0x1a: // reset mask - dispatchCmd(DivCommand(DIV_CMD_C64_RESET_MASK,ch,effectVal)); - break; - case 0x1b: // cutoff reset - dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_RESET,ch,effectVal)); - break; - case 0x1c: // duty reset - dispatchCmd(DivCommand(DIV_CMD_C64_DUTY_RESET,ch,effectVal)); - break; - case 0x1e: // extended - dispatchCmd(DivCommand(DIV_CMD_C64_EXTENDED,ch,effectVal)); - break; - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: // fine duty - dispatchCmd(DivCommand(DIV_CMD_C64_FINE_DUTY,ch,((effect&0x0f)<<8)|effectVal)); - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: // fine cutoff - dispatchCmd(DivCommand(DIV_CMD_C64_FINE_CUTOFF,ch,((effect&0x07)<<8)|effectVal)); - break; - default: - return false; - } - return true; + EffectHandlerMap fmOPMPostEffectHandlerMap(fmOPNPostEffectHandlerMap); + fmOPMPostEffectHandlerMap.insert({ + {0x10, {DIV_CMD_STD_NOISE_FREQ, "10xx: Set noise frequency (xx: value; 0 disables noise)"}}, + {0x17, {DIV_CMD_FM_LFO, "17xx: Set LFO speed"}}, + {0x18, {DIV_CMD_FM_LFO_WAVE, "18xx: Set LFO waveform (0 saw, 1 square, 2 triangle, 3 noise)"}}, + {0x1e, {DIV_CMD_FM_AM_DEPTH, "1Exx: Set AM depth (0 to 7F)", effectValAnd<127>}}, + {0x1f, {DIV_CMD_FM_PM_DEPTH, "1Fxx: Set PM depth (0 to 7F)", effectValAnd<127>}}, + {0x55, {DIV_CMD_FM_SSG, "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)", effectOpVal<4>, effectValAnd<3>}}, + }); + + EffectHandlerMap fmOPZPostEffectHandlerMap(fmOPMPostEffectHandlerMap); + fmOPZPostEffectHandlerMap.insert({ + {0x28, {DIV_CMD_FM_REV, "28xy: Set reverb (x: operator from 1 to 4 (0 for all ops); y: reverb from 0 to 7)", effectOpVal<4>, effectValAnd<7>}}, + {0x2a, {DIV_CMD_FM_WS, "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 7)", effectOpVal<4>, effectValAnd<7>}}, + {0x2b, {DIV_CMD_FM_EG_SHIFT, "2Bxy: Set envelope generator shift (x: operator from 1 to 4 (0 for all ops); y: shift from 0 to 3)", effectOpVal<4>, effectValAnd<3>}}, + {0x2c, {DIV_CMD_FM_FINE, "2Cxy: Set fine multiplier (x: operator from 1 to 4 (0 for all ops); y: fine)", effectOpVal<4>, effectValAnd<15>}}, + }); + const EffectHandler fmOPZFixFreqHandler[4]={ + {DIV_CMD_FM_FIXFREQ, "3xyy: Set fixed frequency of operator 1 (x: octave from 0 to 7; y: frequency)", constVal<0>, effectValLong<11>}, + {DIV_CMD_FM_FIXFREQ, "3xyy: Set fixed frequency of operator 2 (x: octave from 8 to F; y: frequency)", constVal<1>, effectValLong<11>}, + {DIV_CMD_FM_FIXFREQ, "4xyy: Set fixed frequency of operator 3 (x: octave from 0 to 7; y: frequency)", constVal<2>, effectValLong<11>}, + {DIV_CMD_FM_FIXFREQ, "4xyy: Set fixed frequency of operator 4 (x: octave from 8 to F; y: frequency)", constVal<3>, effectValLong<11>}, + }; + for (int i=0; i<32; i++) { + fmOPZPostEffectHandlerMap.emplace(0x30+i,fmOPZFixFreqHandler[i/8]); + } + + fmOPNPostEffectHandlerMap.insert({ + {0x10, {DIV_CMD_FM_LFO, "10xy: Setup LFO (x: enable; y: speed)"}}, + {0x18, {DIV_CMD_FM_EXTCH, "18xx: Toggle extended channel 3 mode"}}, + {0x55, {DIV_CMD_FM_SSG, "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)", effectOpVal<4>, effectValAnd<15>}}, + }); + EffectHandlerMap fmOPN2PostEffectHandlerMap(fmOPNPostEffectHandlerMap); + + fmOPNPostEffectHandlerMap.insert(ayPostEffectHandlerMap.begin(), ayPostEffectHandlerMap.end()); + + EffectHandlerMap fmOPLLPostEffectHandlerMap={ + {0x11, {DIV_CMD_FM_FB, "11xx: Set feedback (0 to 7)"}}, + {0x12, {DIV_CMD_FM_TL, "12xx: Set level of operator 1 (0 highest, 3F lowest)", constVal<0>, effectVal}}, + {0x13, {DIV_CMD_FM_TL, "13xx: Set level of operator 2 (0 highest, 3F lowest)", constVal<1>, effectVal}}, + {0x16, {DIV_CMD_FM_MULT, "16xy: Set operator multiplier (x: operator from 1 to 2; y: multiplier)", effectOpValNoZero<2>, effectValAnd<15>}}, + {0x19, {DIV_CMD_FM_AR, "19xx: Set attack of all operators (0 to F)", constVal<-1>, effectValAnd<15>}}, + {0x1a, {DIV_CMD_FM_AR, "1Axx: Set attack of operator 1 (0 to F)", constVal<0>, effectValAnd<15>}}, + {0x1b, {DIV_CMD_FM_AR, "1Bxx: Set attack of operator 2 (0 to F)", constVal<1>, effectValAnd<15>}}, + {0x50, {DIV_CMD_FM_AM, "50xy: Set AM (x: operator from 1 to 2 (0 for all ops); y: AM)", effectOpVal<2>, effectValAnd<1>}}, + {0x51, {DIV_CMD_FM_SL, "51xy: Set sustain level (x: operator from 1 to 2 (0 for all ops); y: sustain)", effectOpVal<2>, effectValAnd<15>}}, + {0x52, {DIV_CMD_FM_RR, "52xy: Set release (x: operator from 1 to 2 (0 for all ops); y: release)", effectOpVal<2>, effectValAnd<15>}}, + {0x53, {DIV_CMD_FM_VIB, "53xy: Set vibrato (x: operator from 1 to 2 (0 for all ops); y: enabled)", effectOpVal<2>, effectValAnd<1>}}, + {0x54, {DIV_CMD_FM_RS, "54xy: Set envelope scale (x: operator from 1 to 2 (0 for all ops); y: scale from 0 to 3)", effectOpVal<2>, effectValAnd<3>}}, + {0x55, {DIV_CMD_FM_SUS, "55xy: Set envelope sustain (x: operator from 1 to 2 (0 for all ops); y: enabled)", effectOpVal<2>, effectValAnd<1>}}, + {0x56, {DIV_CMD_FM_DR, "56xx: Set decay of all operators (0 to F)", constVal<-1>, effectValAnd<15>}}, + {0x57, {DIV_CMD_FM_DR, "57xx: Set decay of operator 1 (0 to F)", constVal<0>, effectValAnd<15>}}, + {0x58, {DIV_CMD_FM_DR, "58xx: Set decay of operator 2 (0 to F)", constVal<1>, effectValAnd<15>}}, + {0x5b, {DIV_CMD_FM_KSR, "5Bxy: Set whether key will scale envelope (x: operator from 1 to 2 (0 for all ops); y: enabled)", effectOpVal<2>, effectValAnd<1>}}, }; - auto ayPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x12: // duty on 8930 - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,0x10+(effectVal&15))); - break; - case 0x20: // mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal&15)); - break; - case 0x21: // noise freq - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - break; - case 0x22: // envelope enable - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); - break; - case 0x23: // envelope period low - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); - break; - case 0x24: // envelope period high - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); - break; - case 0x25: // envelope slide up - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal)); - break; - case 0x26: // envelope slide down - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal)); - break; - case 0x27: // noise and mask - dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_AND,ch,effectVal)); - break; - case 0x28: // noise or mask - dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_OR,ch,effectVal)); - break; - case 0x29: // auto-envelope - dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); - break; - case 0x2d: // TEST - dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,255,effectVal)); - break; - case 0x2e: // I/O port A - dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,0,effectVal)); - break; - case 0x2f: // I/O port B - dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,1,effectVal)); - break; - default: - return false; - } - return true; + EffectHandlerMap fmOPLPostEffectHandlerMap={ + {0x10, {DIV_CMD_FM_LFO, "10xx: Set global AM depth (0: 1dB, 1: 4.8dB)", effectValAnd<1>}}, + {0x11, {DIV_CMD_FM_FB, "11xx: Set feedback (0 to 7)"}}, + {0x12, {DIV_CMD_FM_TL, "12xx: Set level of operator 1 (0 highest, 3F lowest)", constVal<0>, effectVal}}, + {0x13, {DIV_CMD_FM_TL, "13xx: Set level of operator 2 (0 highest, 3F lowest)", constVal<1>, effectVal}}, + {0x14, {DIV_CMD_FM_TL, "14xx: Set level of operator 3 (0 highest, 3F lowest)", constVal<2>, effectVal}}, + {0x15, {DIV_CMD_FM_TL, "15xx: Set level of operator 4 (0 highest, 3F lowest)", constVal<3>, effectVal}}, + {0x16, {DIV_CMD_FM_MULT, "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)", effectOpValNoZero<4>, effectValAnd<15>}}, + {0x17, {DIV_CMD_FM_LFO, "17xx: Set global vibrato depth (0: normal, 1: double)", [](unsigned char, unsigned char val) -> int { return (val&1)+2; }}}, + {0x19, {DIV_CMD_FM_AR, "19xx: Set attack of all operators (0 to F)", constVal<-1>, effectValAnd<15>}}, + {0x1a, {DIV_CMD_FM_AR, "1Axx: Set attack of operator 1 (0 to F)", constVal<0>, effectValAnd<15>}}, + {0x1b, {DIV_CMD_FM_AR, "1Bxx: Set attack of operator 2 (0 to F)", constVal<1>, effectValAnd<15>}}, + {0x1c, {DIV_CMD_FM_AR, "1Cxx: Set attack of operator 3 (0 to F)", constVal<2>, effectValAnd<15>}}, + {0x1d, {DIV_CMD_FM_AR, "1Dxx: Set attack of operator 4 (0 to F)", constVal<3>, effectValAnd<15>}}, + {0x2a, {DIV_CMD_FM_WS, "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 3 in OPL2 and 0 to 7 in OPL3)", effectOpVal<4>, effectValAnd<7>}}, + {0x50, {DIV_CMD_FM_AM, "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)", effectOpVal<4>, effectValAnd<1>}}, + {0x51, {DIV_CMD_FM_SL, "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)", effectOpVal<4>, effectValAnd<15>}}, + {0x52, {DIV_CMD_FM_RR, "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)", effectOpVal<4>, effectValAnd<15>}}, + {0x53, {DIV_CMD_FM_VIB, "53xy: Set vibrato (x: operator from 1 to 4 (0 for all ops); y: enabled)", effectOpVal<4>, effectValAnd<1>}}, + {0x54, {DIV_CMD_FM_RS, "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)", effectOpVal<4>, effectValAnd<3>}}, + {0x55, {DIV_CMD_FM_SUS, "55xy: Set envelope sustain (x: operator from 1 to 4 (0 for all ops); y: enabled)", effectOpVal<4>, effectValAnd<1>}}, + {0x56, {DIV_CMD_FM_DR, "56xx: Set decay of all operators (0 to F)", constVal<-1>, effectValAnd<15>}}, + {0x57, {DIV_CMD_FM_DR, "57xx: Set decay of operator 1 (0 to F)", constVal<0>, effectValAnd<15>}}, + {0x58, {DIV_CMD_FM_DR, "58xx: Set decay of operator 2 (0 to F)", constVal<1>, effectValAnd<15>}}, + {0x59, {DIV_CMD_FM_DR, "59xx: Set decay of operator 3 (0 to F)", constVal<2>, effectValAnd<15>}}, + {0x5a, {DIV_CMD_FM_DR, "5Axx: Set decay of operator 4 (0 to F)", constVal<3>, effectValAnd<15>}}, + {0x5b, {DIV_CMD_FM_KSR, "5Bxy: Set whether key will scale envelope (x: operator from 1 to 4 (0 for all ops); y: enabled)", effectOpVal<4>, effectValAnd<1>}}, }; - auto segaPCMPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // PCM frequency - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); - break; - default: - return false; - } - return true; + EffectHandlerMap c64PostEffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform (bit 0: triangle; bit 1: saw; bit 2: pulse; bit 3: noise)"}}, + {0x11, {DIV_CMD_C64_CUTOFF, "11xx: Set coarse cutoff (not recommended; use 4xxx instead)"}}, + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set coarse pulse width (not recommended; use 3xxx instead)"}}, + {0x13, {DIV_CMD_C64_RESONANCE, "13xx: Set resonance (0 to F)"}}, + {0x14, {DIV_CMD_C64_FILTER_MODE, "14xx: Set filter mode (bit 0: low pass; bit 1: band pass; bit 2: high pass)"}}, + {0x15, {DIV_CMD_C64_RESET_TIME, "15xx: Set envelope reset time"}}, + {0x1a, {DIV_CMD_C64_RESET_MASK, "1Axx: Disable envelope reset for this channel (1 disables; 0 enables)"}}, + {0x1b, {DIV_CMD_C64_FILTER_RESET, "1Bxy: Reset cutoff (x: on new note; y: now)"}}, + {0x1c, {DIV_CMD_C64_DUTY_RESET, "1Cxy: Reset pulse width (x: on new note; y: now)"}}, + {0x1e, {DIV_CMD_C64_EXTENDED, "1Exy: Change additional parameters"}}, }; + const EffectHandler c64FineDutyHandler(DIV_CMD_C64_FINE_DUTY, "3xxx: Set pulse width (0 to FFF)", effectValLong<12>); + const EffectHandler c64FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, "4xxx: Set cutoff (0 to 7FF)", effectValLong<11>); + for (int i=0; i<16; i++) c64PostEffectHandlerMap.emplace(0x30+i,c64FineDutyHandler); + for (int i=0; i<8; i++) c64PostEffectHandlerMap.emplace(0x40+i,c64FineCutoffHandler); + + EffectHandlerMap waveOnlyEffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + }; + + EffectHandlerMap segaPCMPostEffectHandlerMap={ + {0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set PCM frequency"}} + }; + + // SysDefs sysDefs[DIV_SYSTEM_YMU759]=new DivSysDef( "Yamaha YMU759 (MA-2)", NULL, 0x01, 0x01, 17, true, false, 0, false, @@ -774,15 +606,8 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // SN noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x20, {DIV_CMD_STD_NOISE_MODE, "20xy: Set noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)"}} } ); @@ -800,24 +625,12 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE}, {DIV_INS_GB, DIV_INS_GB, DIV_INS_GB, DIV_INS_GB}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // sweep params - dispatchCmd(DivCommand(DIV_CMD_GB_SWEEP_TIME,ch,effectVal)); - break; - case 0x14: // sweep direction - dispatchCmd(DivCommand(DIV_CMD_GB_SWEEP_DIR,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Set noise length (0: long; 1: short)"}}, + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle (0 to 3)"}}, + {0x13, {DIV_CMD_GB_SWEEP_TIME, "13xy: Setup sweep (x: time; y: shift)"}}, + {0x14, {DIV_CMD_GB_SWEEP_DIR, "14xx: Set sweep direction (0: up; 1: down)"}} } ); @@ -829,27 +642,12 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x12: // LFO mode - dispatchCmd(DivCommand(DIV_CMD_PCE_LFO_MODE,ch,effectVal)); - break; - case 0x13: // LFO speed - dispatchCmd(DivCommand(DIV_CMD_PCE_LFO_SPEED,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - return true; + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}}, + {0x12, {DIV_CMD_PCE_LFO_MODE, "12xx: Setup LFO (0: disabled; 1: 1x depth; 2: 16x depth; 3: 256x depth)"}}, + {0x13, {DIV_CMD_PCE_LFO_SPEED, "13xx: Set LFO speed"}}, + {0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode"}} } ); @@ -861,27 +659,12 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x11: // DMC write - dispatchCmd(DivCommand(DIV_CMD_NES_DMC,ch,effectVal)); - break; - case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // sweep up - dispatchCmd(DivCommand(DIV_CMD_NES_SWEEP,ch,0,effectVal)); - break; - case 0x14: // sweep down - dispatchCmd(DivCommand(DIV_CMD_NES_SWEEP,ch,1,effectVal)); - break; - case 0x18: // DPCM mode - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x11, {DIV_CMD_NES_DMC, "11xx: Write to delta modulation counter (0 to 7F)"}}, + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}}, + {0x13, {DIV_CMD_NES_SWEEP, "13xy: Sweep up (x: time; y: shift)",constVal<0>,effectVal}}, + {0x14, {DIV_CMD_NES_SWEEP, "14xy: Sweep down (x: time; y: shift)",constVal<1>,effectVal}}, + {0x18, {DIV_CMD_SAMPLE_MODE, "18xx: Select PCM/DPCM mode (0: PCM; 1: DPCM)"}} } ); @@ -905,8 +688,8 @@ void DivEngine::registerSystems() { {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - c64PostEffectHandler + {}, + c64PostEffectHandlerMap ); sysDefs[DIV_SYSTEM_C64_8580]=new DivSysDef( @@ -917,8 +700,8 @@ void DivEngine::registerSystems() { {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - c64PostEffectHandler + {}, + c64PostEffectHandlerMap ); sysDefs[DIV_SYSTEM_ARCADE]=new DivSysDef( @@ -927,17 +710,6 @@ void DivEngine::registerSystems() { {}, {}, {}, {} ); - auto fmHardResetEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - return true; - }; - sysDefs[DIV_SYSTEM_YM2610]=new DivSysDef( "Neo Geo CD", NULL, 0x09, 0x09, 13, true, true, 0x151, false, "like Neo Geo, but lacking the ADPCM-B channel since they couldn't connect the pins.", @@ -946,8 +718,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_YM2610_EXT]=new DivSysDef( @@ -958,8 +730,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_AY8910]=new DivSysDef( @@ -970,8 +742,8 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_AY, DIV_INS_AY, DIV_INS_AY}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - ayPostEffectHandler + {}, + ayPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_AMIGA]=new DivSysDef( @@ -982,22 +754,11 @@ void DivEngine::registerSystems() { {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // toggle filter - dispatchCmd(DivCommand(DIV_CMD_AMIGA_FILTER,ch,effectVal)); - break; - case 0x11: // toggle AM - dispatchCmd(DivCommand(DIV_CMD_AMIGA_AM,ch,effectVal)); - break; - case 0x12: // toggle PM - dispatchCmd(DivCommand(DIV_CMD_AMIGA_PM,ch,effectVal)); - break; - default: - return false; - } - return true; + {}, + { + {0x10, {DIV_CMD_AMIGA_FILTER, "10xx: Toggle filter (0 disables; 1 enables)"}}, + {0x11, {DIV_CMD_AMIGA_AM, "11xx: Toggle AM with next channel"}}, + {0x12, {DIV_CMD_AMIGA_PM, "12xx: Toggle period modulation with next channel"}}, } ); @@ -1009,24 +770,10 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPMPostEffectHandlerMap ); - auto opn2EffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x17: // DAC enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - return true; - }; - sysDefs[DIV_SYSTEM_YM2612]=new DivSysDef( "Yamaha YM2612 (OPN2)", NULL, 0x83, 0, 6, true, false, 0x150, false, "this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).", @@ -1035,8 +782,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - opn2EffectHandler, - fmPostEffectHandler + fmOPN2EffectHandlerMap, + fmOPN2PostEffectHandlerMap ); sysDefs[DIV_SYSTEM_TIA]=new DivSysDef( @@ -1047,17 +794,8 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_TIA, DIV_INS_TIA}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - default: - return false; - } - return true; - } + {}, + waveOnlyEffectHandlerMap ); sysDefs[DIV_SYSTEM_SAA1099]=new DivSysDef( @@ -1068,22 +806,11 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select channel mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x11: // set noise freq - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - break; - case 0x12: // setup envelope - dispatchCmd(DivCommand(DIV_CMD_SAA_ENVELOPE,ch,effectVal)); - break; - default: - return false; - } - return true; + {}, + { + {0x10, {DIV_CMD_STD_NOISE_MODE, "10xy: Set channel mode (x: noise; y: tone)"}}, + {0x11, {DIV_CMD_STD_NOISE_FREQ, "11xx: Set noise frequency"}}, + {0x12, {DIV_CMD_SAA_ENVELOPE, "12xx: Setup envelope (refer to docs for more information)"}}, } ); @@ -1095,21 +822,10 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_AY8930, DIV_INS_AY8930, DIV_INS_AY8930}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - ayPostEffectHandler + {}, + ay8930PostEffectHandlerMap ); - auto waveOnlyEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - default: - return false; - } - return true; - }; - sysDefs[DIV_SYSTEM_VIC20]=new DivSysDef( "Commodore VIC-20", NULL, 0x85, 0, 4, false, true, 0, false, "Commodore's successor to the PET.\nits square wave channels are more than just square...", @@ -1118,7 +834,7 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, {DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC}, {}, - waveOnlyEffectHandler + waveOnlyEffectHandlerMap ); sysDefs[DIV_SYSTEM_PET]=new DivSysDef( @@ -1129,7 +845,7 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE}, {DIV_INS_PET}, {}, - waveOnlyEffectHandler + waveOnlyEffectHandlerMap ); sysDefs[DIV_SYSTEM_SNES]=new DivSysDef( @@ -1149,32 +865,12 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE}, {DIV_INS_VRC6, DIV_INS_VRC6, DIV_INS_VRC6_SAW}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_NULL}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - return true; + { + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle (pulse: 0 to 7)"}}, + {0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode (pulse channel)"}}, } ); - auto oplEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - return true; - }; - sysDefs[DIV_SYSTEM_OPLL]=new DivSysDef( "Yamaha YM2413 (OPLL)", NULL, 0x89, 0, 9, true, false, 0x150, false, "cost-reduced version of the OPL with 16 patches and only one of them is user-configurable.", @@ -1183,8 +879,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, {}, - oplEffectHandler, - fmOPLLPostEffectHandler + fmEffectHandlerMap, + fmOPLLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_FDS]=new DivSysDef( @@ -1195,30 +891,13 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE}, {DIV_INS_FDS}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // modulation depth - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_DEPTH,ch,effectVal)); - break; - case 0x12: // modulation enable/high - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_HIGH,ch,effectVal)); - break; - case 0x13: // modulation low - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_LOW,ch,effectVal)); - break; - case 0x14: // modulation pos - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_POS,ch,effectVal)); - break; - case 0x15: // modulation wave - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_WAVE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_FDS_MOD_DEPTH, "11xx: Set modulation depth"}}, + {0x12, {DIV_CMD_FDS_MOD_HIGH, "12xy: Set modulation speed high byte (x: enable; y: value)"}}, + {0x13, {DIV_CMD_FDS_MOD_LOW, "13xx: Set modulation speed low byte"}}, + {0x14, {DIV_CMD_FDS_MOD_POS, "14xx: Set modulator position"}}, + {0x15, {DIV_CMD_FDS_MOD_WAVE, "15xx: Set modulator table to waveform"}}, } ); @@ -1230,18 +909,8 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM}, {DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x11: // DMC write - dispatchCmd(DivCommand(DIV_CMD_NES_DMC,ch,effectVal)); - break; - case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}}, } ); @@ -1253,51 +922,20 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select instrument waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // select instrument waveform position in RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_POSITION,ch,effectVal)); - break; - case 0x12: // select instrument waveform length in RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LENGTH,ch,effectVal)); - break; - case 0x13: // change instrument waveform update mode - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_MODE,ch,effectVal)); - break; - case 0x14: // select waveform for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOAD,ch,effectVal)); - break; - case 0x15: // select waveform position for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADPOS,ch,effectVal)); - break; - case 0x16: // select waveform length for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADLEN,ch,effectVal)); - break; - case 0x17: // change waveform load mode - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADMODE,ch,effectVal)); - break; - case 0x18: // change channel limits - dispatchCmd(DivCommand(DIV_CMD_N163_CHANNEL_LIMIT,ch,effectVal)); - break; - case 0x20: // (global) select waveform for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOAD,ch,effectVal)); - break; - case 0x21: // (global) select waveform position for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADPOS,ch,effectVal)); - break; - case 0x22: // (global) select waveform length for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADLEN,ch,effectVal)); - break; - case 0x23: // (global) change waveform load mode - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADMODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x10, {DIV_CMD_WAVE, "10xx: Select waveform"}}, + {0x11, {DIV_CMD_N163_WAVE_POSITION, "11xx: Set waveform position in RAM (single nibble unit)"}}, + {0x12, {DIV_CMD_N163_WAVE_LENGTH, "12xx: Set waveform length in RAM (04 to FC, 4 nibble unit)"}}, + {0x13, {DIV_CMD_N163_WAVE_MODE, "130x: Change waveform update mode (0: off; bit 0: update now; bit 1: update when every waveform changes)"}}, + {0x14, {DIV_CMD_N163_WAVE_LOAD, "14xx: Select waveform for load to RAM"}}, + {0x15, {DIV_CMD_N163_WAVE_LOADPOS, "15xx: Set waveform position for load to RAM (single nibble unit)"}}, + {0x16, {DIV_CMD_N163_WAVE_LOADLEN, "16xx: Set waveform length for load to RAM (04 to FC, 4 nibble unit)"}}, + {0x17, {DIV_CMD_N163_WAVE_LOADMODE, "170x: Change waveform load mode (0: off; bit 0: load now; bit 1: load when every waveform changes)"}}, + {0x18, {DIV_CMD_N163_CHANNEL_LIMIT, "180x: Change channel limits (0 to 7, x + 1)"}}, + {0x20, {DIV_CMD_N163_GLOBAL_WAVE_LOAD, "20xx: (Global) Select waveform for load to RAM"}}, + {0x21, {DIV_CMD_N163_GLOBAL_WAVE_LOADPOS, "21xx: (Global) Set waveform position for load to RAM (single nibble unit)"}}, + {0x22, {DIV_CMD_N163_GLOBAL_WAVE_LOADLEN, "22xx: (Global) Set waveform length for load to RAM (04 to FC, 4 nibble unit)"}}, + {0x23, {DIV_CMD_N163_GLOBAL_WAVE_LOADMODE, "230x: (Global) Change waveform load mode (0: off; bit 0: load now; bit 1: load when every waveform changes)"}}, } ); @@ -1309,8 +947,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPN_EXT]=new DivSysDef( @@ -1321,8 +959,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_PC98]=new DivSysDef( @@ -1333,8 +971,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef( @@ -1345,8 +983,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPL]=new DivSysDef( @@ -1357,8 +995,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, {}, - oplEffectHandler, - fmOPLPostEffectHandler + fmEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPL2]=new DivSysDef( @@ -1369,8 +1007,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, {}, - oplEffectHandler, - fmOPLPostEffectHandler + fmEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPL3]=new DivSysDef( @@ -1381,8 +1019,8 @@ void DivEngine::registerSystems() { {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, {}, - oplEffectHandler, - fmOPLPostEffectHandler + fmEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_MULTIPCM]=new DivSysDef( @@ -1429,27 +1067,12 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE}, {DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN}, {DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL, DIV_INS_NULL}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x12: // sweep period - dispatchCmd(DivCommand(DIV_CMD_WS_SWEEP_TIME,ch,effectVal)); - break; - case 0x13: // sweep amount - dispatchCmd(DivCommand(DIV_CMD_WS_SWEEP_AMOUNT,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - return true; + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Setup noise mode (0: disabled; 1-8: enabled/tap)"}}, + {0x12, {DIV_CMD_WS_SWEEP_TIME, "12xx: Setup sweep period (0: disabled; 1-20: enabled/period)"}}, + {0x13, {DIV_CMD_WS_SWEEP_AMOUNT, "13xx: Set sweep amount"}}, + {0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode"}}, } ); @@ -1461,17 +1084,10 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x2f: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x2f, {DIV_CMD_FM_HARD_RESET, "2Fxx: Toggle hard envelope reset on new notes"}}, }, - fmPostEffectHandler + fmOPZPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_POKEMINI]=new DivSysDef( @@ -1491,8 +1107,8 @@ void DivEngine::registerSystems() { {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - segaPCMPostEffectHandler + {}, + segaPCMPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_VBOY]=new DivSysDef( @@ -1512,8 +1128,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, {}, - oplEffectHandler, - fmOPLLPostEffectHandler + fmEffectHandlerMap, + fmOPLLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_YM2610B]=new DivSysDef( @@ -1524,8 +1140,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_SFX_BEEPER]=new DivSysDef( @@ -1536,18 +1152,9 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x12: // pulse width - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x17: // overlay sample - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set pulse width"}}, + {0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Trigger overlay drum"}}, } ); @@ -1559,8 +1166,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - opn2EffectHandler, - fmPostEffectHandler + fmOPN2EffectHandlerMap, + fmOPN2PostEffectHandlerMap ); sysDefs[DIV_SYSTEM_SCC]=new DivSysDef( @@ -1571,23 +1178,9 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC}, {}, - waveOnlyEffectHandler + waveOnlyEffectHandlerMap ); - auto oplDrumsEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x18: // drum mode toggle - dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); - break; - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - return true; - }; - sysDefs[DIV_SYSTEM_OPL_DRUMS]=new DivSysDef( "Yamaha YM3526 (OPL) with drums", NULL, 0xa2, 0, 11, true, false, 0x151, false, "the OPL chip but with drums mode enabled.", @@ -1596,8 +1189,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - oplDrumsEffectHandler, - fmOPLPostEffectHandler + fmOPLDrumsEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPL2_DRUMS]=new DivSysDef( @@ -1608,8 +1201,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - oplDrumsEffectHandler, - fmOPLPostEffectHandler + fmOPLDrumsEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPL3_DRUMS]=new DivSysDef( @@ -1620,8 +1213,8 @@ void DivEngine::registerSystems() { {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - oplDrumsEffectHandler, - fmOPLPostEffectHandler + fmOPLDrumsEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_YM2610_FULL]=new DivSysDef( @@ -1632,8 +1225,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_YM2610_FULL_EXT]=new DivSysDef( @@ -1644,8 +1237,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_OPLL_DRUMS]=new DivSysDef( @@ -1656,10 +1249,16 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, {}, - oplDrumsEffectHandler, - fmOPLLPostEffectHandler + fmOPLDrumsEffectHandlerMap, + fmOPLLPostEffectHandlerMap ); + EffectHandlerMap lynxEffectHandlerMap; + const EffectHandler lynxLFSRHandler(DIV_CMD_LYNX_LFSR_LOAD, "3xxx: Load LFSR (0 to FFF)", effectValLong<12>); + for (int i=0; i<16; i++) { + lynxEffectHandlerMap.emplace(0x30+i, lynxLFSRHandler); + } + sysDefs[DIV_SYSTEM_LYNX]=new DivSysDef( "Atari Lynx", NULL, 0xa8, 0, 4, false, true, 0, false, "a portable console made by Atari. it has all of Atari's trademark waveforms.", @@ -1668,17 +1267,20 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - if (effect>=0x30 && effect<0x40) { - int value=((int)(effect&0x0f)<<8)|effectVal; - dispatchCmd(DivCommand(DIV_CMD_LYNX_LFSR_LOAD,ch,value)); - return true; - } - return false; - } + {}, + lynxEffectHandlerMap ); + EffectHandlerMap qSoundEffectHandlerMap={ + {0x10, {DIV_CMD_QSOUND_ECHO_FEEDBACK, "10xx: Set echo feedback level (00 to FF)"}}, + {0x11, {DIV_CMD_QSOUND_ECHO_LEVEL, "11xx: Set channel echo level (00 to FF)"}}, + {0x12, {DIV_CMD_QSOUND_SURROUND, "12xx: Toggle QSound algorithm (0: disabled; 1: enabled)"}}, + }; + const EffectHandler qSoundEchoDelayHandler(DIV_CMD_QSOUND_ECHO_DELAY, "3xxx: Set echo delay buffer length (000 to AA5)", effectValLong<12>); + for (int i=0; i<16; i++) { + qSoundEffectHandlerMap.emplace(0x30+i, qSoundEchoDelayHandler); + } + sysDefs[DIV_SYSTEM_QSOUND]=new DivSysDef( "Capcom QSound", NULL, 0xe0, 0, 19, false, true, 0x161, false, "used in some of Capcom's arcade boards. surround-like sampled sound with echo.", @@ -1687,27 +1289,7 @@ void DivEngine::registerSystems() { {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // echo feedback - dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_FEEDBACK,ch,effectVal)); - break; - case 0x11: // echo level - dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal)); - break; - case 0x12: // surround - dispatchCmd(DivCommand(DIV_CMD_QSOUND_SURROUND,ch,effectVal)); - break; - default: - if ((effect&0xf0)==0x30) { - dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal)); - } else { - return false; - } - break; - } - return true; - } + qSoundEffectHandlerMap ); sysDefs[DIV_SYSTEM_VERA]=new DivSysDef( @@ -1718,18 +1300,9 @@ void DivEngine::registerSystems() { {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_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM}, {DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_AMIGA}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x22: // duty - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x20, {DIV_CMD_WAVE, "20xx: Set waveform"}}, + {0x22, {DIV_CMD_STD_NOISE_MODE, "22xx: Set duty cycle (0 to 3F)"}}, } ); @@ -1741,8 +1314,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - fmHardResetEffectHandler, - fmPostEffectHandler + fmEffectHandlerMap, + fmOPNPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_SEGAPCM_COMPAT]=new DivSysDef( @@ -1753,8 +1326,8 @@ void DivEngine::registerSystems() { {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - segaPCMPostEffectHandler + {}, + segaPCMPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_X1_010]=new DivSysDef( @@ -1765,46 +1338,18 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // select envelope shape - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SHAPE,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - return true; + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_X1_010_ENVELOPE_SHAPE, "11xx: Set envelope shape"}}, + {0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode"}}, }, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // PCM frequency - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); - break; - case 0x22: // envelope mode - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_MODE,ch,effectVal)); - break; - case 0x23: // envelope period - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_PERIOD,ch,effectVal)); - break; - case 0x25: // envelope slide up - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SLIDE,ch,effectVal)); - break; - case 0x26: // envelope slide down - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SLIDE,ch,-effectVal)); - break; - case 0x29: // auto-envelope - dispatchCmd(DivCommand(DIV_CMD_X1_010_AUTO_ENVELOPE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set PCM frequency (1 to FF)"}}, + {0x22, {DIV_CMD_X1_010_ENVELOPE_MODE, "22xx: Set envelope mode (bit 0: enable; bit 1: one-shot; bit 2: split shape to L/R; bit 3/5: H.invert right/left; bit 4/6: V.invert right/left)"}}, + {0x23, {DIV_CMD_X1_010_ENVELOPE_PERIOD, "23xx: Set envelope period"}}, + {0x25, {DIV_CMD_X1_010_ENVELOPE_SLIDE, "25xx: Envelope slide up"}}, + {0x26, {DIV_CMD_X1_010_ENVELOPE_SLIDE, "26xx: Envelope slide down", negEffectVal}}, + {0x29, {DIV_CMD_X1_010_AUTO_ENVELOPE, "29xy: Set auto-envelope (x: numerator; y: denominator)"}}, } ); @@ -1816,7 +1361,7 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_SCC, DIV_INS_SCC}, {}, - waveOnlyEffectHandler + waveOnlyEffectHandlerMap ); // to Grauw: feel free to change this to 24 during development of OPL4's PCM part. @@ -1855,8 +1400,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, {}, - oplEffectHandler, - fmOPLPostEffectHandler + fmEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef( @@ -1867,8 +1412,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_NULL}, - oplEffectHandler, - fmOPLPostEffectHandler + fmEffectHandlerMap, + fmOPLPostEffectHandlerMap ); sysDefs[DIV_SYSTEM_SCC_PLUS]=new DivSysDef( @@ -1879,9 +1424,34 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC}, {}, - waveOnlyEffectHandler + waveOnlyEffectHandlerMap ); + EffectHandlerMap suEffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform (0 to 7)"}}, + {0x12, {DIV_CMD_STD_NOISE_MODE, "22xx: Set envelope mode (bit 0: enable; bit 1: one-shot; bit 2: split shape to L/R; bit 3/5: H.invert right/left; bit 4/6: V.invert right/left)"}}, + {0x13, {DIV_CMD_C64_RESONANCE, "23xx: Set envelope period"}}, + {0x14, {DIV_CMD_C64_FILTER_MODE, "25xx: Envelope slide up"}}, + {0x15, {DIV_CMD_SU_SWEEP_PERIOD_LOW, "15xx: Set frequency sweep period low byte", constVal<0>, effectVal}}, + {0x16, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "16xx: Set frequency sweep period high byte", constVal<0>, effectVal}}, + {0x17, {DIV_CMD_SU_SWEEP_PERIOD_LOW, "17xx: Set volume sweep period low byte", constVal<1>, effectVal}}, + {0x18, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "18xx: Set volume sweep period high byte", constVal<1>, effectVal}}, + {0x19, {DIV_CMD_SU_SWEEP_PERIOD_LOW, "19xx: Set cutoff sweep period low byte", constVal<2>, effectVal}}, + {0x1a, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "1axx: Set cutoff sweep period high byte", constVal<2>, effectVal}}, + {0x1b, {DIV_CMD_SU_SWEEP_BOUND, "1Bxx: Set frequency sweep boundary", constVal<0>, effectVal}}, + {0x1c, {DIV_CMD_SU_SWEEP_BOUND, "1Cxx: Set volume sweep boundary", constVal<1>, effectVal}}, + {0x1d, {DIV_CMD_SU_SWEEP_BOUND, "1Dxx: Set cutoff sweep boundary", constVal<2>, effectVal}}, + {0x1e, {DIV_CMD_SU_SYNC_PERIOD_LOW, "1Exx: Set phase reset period low byte"}}, + {0x1f, {DIV_CMD_SU_SYNC_PERIOD_HIGH, "1Fxx: Set phase reset period high byte"}}, + {0x20, {DIV_CMD_SU_SWEEP_ENABLE, "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)", constVal<0>, effectVal}}, + {0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}}, + {0x22, {DIV_CMD_SU_SWEEP_ENABLE, "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)", constVal<2>, effectVal}}, + }; + const EffectHandler suCutoffHandler(DIV_CMD_C64_FINE_DUTY, "4xxx: Set cutoff (0 to FFF)", effectValLong<12>); + for (int i=0; i<16; i++) { + suEffectHandlerMap.emplace(0x40+i, suCutoffHandler); + } + sysDefs[DIV_SYSTEM_SOUND_UNIT]=new DivSysDef( "tildearrow Sound Unit", NULL, 0xb5, 0, 8, false, true, 0, false, "tildearrow's fantasy sound chip. put SID, AY and VERA in a blender, and you get this!", @@ -1890,74 +1460,8 @@ void DivEngine::registerSystems() { {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_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - [](int,unsigned char,unsigned char) -> bool {return false;}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x12: // duty cycle - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // resonance - dispatchCmd(DivCommand(DIV_CMD_C64_RESONANCE,ch,effectVal)); - break; - case 0x14: // filter mode - dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_MODE,ch,effectVal)); - break; - case 0x15: // freq sweep - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_LOW,ch,0,effectVal)); - break; - case 0x16: // freq sweep - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_HIGH,ch,0,effectVal)); - break; - case 0x17: // vol sweep - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_LOW,ch,1,effectVal)); - break; - case 0x18: // vol sweep - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_HIGH,ch,1,effectVal)); - break; - case 0x19: // cut sweep - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_LOW,ch,2,effectVal)); - break; - case 0x1a: // cut sweep - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_HIGH,ch,2,effectVal)); - break; - case 0x1b: // freq sweep bound - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_BOUND,ch,0,effectVal)); - break; - case 0x1c: // vol sweep bound - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_BOUND,ch,1,effectVal)); - break; - case 0x1d: // cut sweep bound - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_BOUND,ch,2,effectVal)); - break; - case 0x1e: // sync low - dispatchCmd(DivCommand(DIV_CMD_SU_SYNC_PERIOD_LOW,ch,effectVal)); - break; - case 0x1f: // sync high - dispatchCmd(DivCommand(DIV_CMD_SU_SYNC_PERIOD_HIGH,ch,effectVal)); - break; - case 0x20: // freq sweep enable - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_ENABLE,ch,0,effectVal)); - break; - case 0x21: // vol sweep enable - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_ENABLE,ch,1,effectVal)); - break; - case 0x22: // cut sweep enable - dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_ENABLE,ch,2,effectVal)); - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: // cutoff - dispatchCmd(DivCommand(DIV_CMD_C64_FINE_CUTOFF,ch,(((effect&0x0f)<<8)|effectVal)*4)); - break; - default: - return false; - } - return true; - } + {}, + suEffectHandlerMap ); sysDefs[DIV_SYSTEM_MSM6295]=new DivSysDef( @@ -1968,15 +1472,8 @@ void DivEngine::registerSystems() { {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // select rate - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set chip output rate (0: clock/132; 1: clock/165)"}}, } ); @@ -1988,18 +1485,9 @@ void DivEngine::registerSystems() { {DIV_CH_PCM}, {DIV_INS_AMIGA}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // select rate - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); - break; - case 0x21: // select clock - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set frequency divider (0-2)"}}, + {0x21, {DIV_CMD_SAMPLE_MODE, "21xx: Select clock rate (0: full; 1: half)"}}, } ); @@ -2012,18 +1500,9 @@ void DivEngine::registerSystems() { {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} ); - auto namcoEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + EffectHandlerMap namcoEffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}}, }; sysDefs[DIV_SYSTEM_NAMCO]=new DivSysDef( @@ -2034,7 +1513,7 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, {}, - namcoEffectHandler + namcoEffectHandlerMap ); sysDefs[DIV_SYSTEM_NAMCO_15XX]=new DivSysDef( @@ -2045,7 +1524,7 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, {}, - namcoEffectHandler + namcoEffectHandlerMap ); sysDefs[DIV_SYSTEM_NAMCO_CUS30]=new DivSysDef( @@ -2056,7 +1535,7 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, {}, - namcoEffectHandler + namcoEffectHandlerMap ); // replace with an 8-channel chip in a future @@ -2077,8 +1556,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AMIGA}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL}, - opn2EffectHandler, - fmPostEffectHandler + fmOPN2EffectHandlerMap, + fmOPN2PostEffectHandlerMap ); sysDefs[DIV_SYSTEM_YM2612_FRAC_EXT]=new DivSysDef( @@ -2089,8 +1568,8 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AMIGA, DIV_INS_FM}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL, DIV_INS_NULL}, - opn2EffectHandler, - fmPostEffectHandler + fmOPN2EffectHandlerMap, + fmOPN2PostEffectHandlerMap ); sysDefs[DIV_SYSTEM_T6W28]=new DivSysDef( @@ -2101,15 +1580,8 @@ void DivEngine::registerSystems() { {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, {}, - [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { - switch (effect) { - case 0x20: // SN noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - return true; + { + {0x20, {DIV_CMD_STD_NOISE_MODE, "20xy: Set noise mode (x: preset/variable; y: thin pulse/noise)"}} } ); From 5190c6daabd36efa0e53b8b799c0366958dcd661 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 18 Aug 2022 21:20:10 +0900 Subject: [PATCH 233/515] Implement ES5506 instrument type ES5506 has these features: - 16 bit independent volume register per left/right output (Logarithmic, 4 LSB is for envelope) - Programmable filter per each channels, 4 pole, 4 filter mode and 2 16 bit coefficient register (4 LSB is for envelope) - Hardware envelope Add more than 2 macro type support "Delta" macro type: Use delta from previous value --- src/engine/instrument.h | 38 +++++++ src/gui/gui.h | 7 +- src/gui/insEdit.cpp | 217 +++++++++++++++++++++++++++++++--------- src/gui/intConst.cpp | 3 + src/gui/intConst.h | 3 + 5 files changed, 219 insertions(+), 49 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 9f49a627a..cfbed65a3 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -465,6 +465,43 @@ struct DivInstrumentSoundUnit { switchRoles(false) {} }; +struct DivInstrumentES5506 { + struct Filter { + enum FilterMode: unsigned char { // filter mode for pole 4,3 + FILTER_MODE_HPK2_HPK2, + FILTER_MODE_HPK2_LPK1, + FILTER_MODE_LPK2_LPK2, + FILTER_MODE_LPK2_LPK1, + }; + FilterMode mode; + unsigned short k1, k2; + Filter(): + mode(FILTER_MODE_LPK2_LPK1), + k1(0xffff), + k2(0xffff) {} + }; + struct Envelope { + unsigned short ecount; + signed char lVRamp, rVRamp; + signed char k1Ramp, k2Ramp; + bool k1Slow, k2Slow; + Envelope(): + ecount(0), + lVRamp(0), + rVRamp(0), + k1Ramp(0), + k2Ramp(0), + k1Slow(false), + k2Slow(false) {} + }; + signed int lVol, rVol; + Filter filter; + Envelope envelope; + DivInstrumentES5506(): + lVol(0xffff), + rVol(0xffff) {} +}; + struct DivInstrument { String name; bool mode; @@ -479,6 +516,7 @@ struct DivInstrument { DivInstrumentMultiPCM multipcm; DivInstrumentWaveSynth ws; DivInstrumentSoundUnit su; + DivInstrumentES5506 es5506; /** * save the instrument to a SafeWriter. diff --git a/src/gui/gui.h b/src/gui/gui.h index 3e3401195..3e70e1210 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -864,13 +864,13 @@ struct FurnaceGUIMacroDesc { float height; const char* displayName; const char** bitfieldBits; - const char* modeName; + const char** modeName; ImVec4 color; unsigned int bitOffset; - bool isBitfield, blockMode; + bool isBitfield, blockMode, useMacroMode; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName={NULL}, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): macro(m), height(macroHeight), displayName(name), @@ -880,6 +880,7 @@ struct FurnaceGUIMacroDesc { bitOffset(bitOff), isBitfield(bitfield), blockMode(block), + useMacroMode(mMode), hoverFunc(hf) { // MSVC -> hell this->min=macroMin; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index a306e366c..1b51e02ac 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -250,6 +250,10 @@ const char* suControlBits[5]={ "ring mod", "low pass", "high pass", "band pass", NULL }; +const char* es5506FilterModes[4]={ + "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", +}; + const char* panBits[3]={ "right", "left", NULL }; @@ -258,6 +262,14 @@ const char* oneBit[2]={ "on", NULL }; +const char* es5506EnvelopeModes[3]={ + "k1 slowdown", "k2 slowdown", NULL +}; + +const char* es5506ControlModes[2]={ + "pause", NULL +}; + const int orderedOps[4]={ 0, 2, 1, 3 }; @@ -293,11 +305,34 @@ const char* gbHWSeqCmdTypes[6]={ "Loop until Release" }; -const char* macroAbsoluteMode="Fixed"; -const char* macroRelativeMode="Relative"; -const char* macroQSoundMode="QSound"; +const char* macroAbsoluteMode[3]={ + "Relative", + "Absolute", + NULL +}; -const char* macroDummyMode="Bug"; +const char* macroRelativeMode[3]={ + "Absolute", + "Relative", + NULL +}; + +const char* macroQSoundMode[3]={ + "Independent", + "QSound", + NULL +}; + +const char* macroDummyMode[1]={ + NULL +}; + +const char* macroFilterMode[4]={ + "Relative", + "Absolute", + "Delta", + NULL +}; String macroHoverNote(int id, float val) { if (val<-60 || val>=120) return "???"; @@ -314,6 +349,27 @@ String macroHoverLoop(int id, float val) { return ""; } +String macroHoverES5506FilterMode(int id, float val) { + String mode="???"; + switch (((int)val)&3) { + case 0: + mode="HP/K2, HP/K2"; + break; + case 1: + mode="HP/K2, LP/K1"; + break; + case 2: + mode="LP/K2, LP/K2"; + break; + case 3: + mode="LP/K2, LP/K1"; + break; + default: + break; + } + return fmt::sprintf("%d: %s",id,mode); +} + String macroLFOWaves(int id, float val) { switch (((int)val)&3) { case 0: @@ -1203,11 +1259,12 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&i.macro->len,&_ONE,&_THREE)) { MARK_MODIFIED if (i.macro->len>128) i.macro->len=128; } - if (i.modeName!=NULL) { - bool modeVal=i.macro->mode; - String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); - if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { - i.macro->mode=modeVal; + if (i.useMacroMode && i.modeName[0]!=NULL) { + for (int m=0; i.modeName[m]!=NULL; m++) { + String modeName=fmt::sprintf("%s##IMacroMode%d",i.modeName[m],m); + if (ImGui::RadioButton(modeName.c_str(),(int)i.macro->mode==m)) { + i.macro->mode=m; + } } } } @@ -2862,10 +2919,10 @@ void FurnaceGUI::drawInsEdit() { } if (ImGui::BeginTabItem("FM Macros")) { if (ins->type==DIV_INS_OPLL) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_ALG),&ins->std.algMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2885,8 +2942,8 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); - macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,fmOperatorBits)); + macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,macroLFOWaves)); + macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,fmOperatorBits)); } drawMacros(macroList); ImGui::EndTabItem(); @@ -2924,10 +2981,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_WS),&ins->std.opMacros[ordi].wsMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } else if (ins->type==DIV_INS_OPLL) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2937,10 +2994,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2952,10 +3009,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT),&ins->std.opMacros[ordi].dtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); if (ins->type==DIV_INS_FM) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,ssgEnvBits)); } } drawMacros(macroList); @@ -3331,7 +3388,9 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest)); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SU) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { + if (ins->type==DIV_INS_AMIGA || + ins->type==DIV_INS_SU || + ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { String sName; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { sName="none selected"; @@ -3488,6 +3547,42 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTabItem(); } + if (ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("ES5506")) { + if (ImGui::BeginTable("ESParams",2,ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + // filter + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2",ImGuiDataType_U16,&ins->es5506.filter.k2,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + // envelope + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Envelope count",ImGuiDataType_U16,&ins->es5506.envelope.ecount,&_ZERO,&_FIVE_HUNDRED_ELEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Left Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.lVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Right Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.rVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k1Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k2Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("K1 Ramp Slowdown",&ins->es5506.envelope.k1Slow); + ImGui::TableNextColumn(); + ImGui::Checkbox("K2 Ramp Slowdown",&ins->es5506.envelope.k2Slow); + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_MULTIPCM) { if (ImGui::BeginTabItem("MultiPCM")) { String sName; @@ -3785,6 +3880,9 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FDS) { volMax=32; } + if (ins->type==DIV_INS_ES5506) { + volMax=65535; + } const char* dutyLabel="Duty/Noise"; int dutyMin=0; @@ -3847,6 +3945,10 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SU) { dutyMax=127; } + if (ins->type==DIV_INS_ES5506) { + dutyLabel="Filter Mode"; + dutyMax=3; + } const char* waveLabel="Waveform"; int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255; @@ -3902,6 +4004,10 @@ void FurnaceGUI::drawInsEdit() { ex2Max=255; } if (ins->type==DIV_INS_SAA1099) ex1Max=8; + if (ins->type==DIV_INS_ES5506) { + ex1Max=65535; + ex2Max=65535; + } int panMin=0; int panMax=0; @@ -3937,40 +4043,45 @@ void FurnaceGUI::drawInsEdit() { panMax=127; panSingleNoBit=true; } + if (ins->type==DIV_INS_ES5506) { + panMax=65535; + } if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } - macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroAbsoluteMode,ins->std.arpMacro.mode?(¯oHoverNote):NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,true,macroAbsoluteMode,ins->std.arpMacro.mode?(¯oHoverNote):NULL)); 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)); + macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,0,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,mikeyFeedbackBits)); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,¯oHoverES5506FilterMode)); } else { macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER])); } } if (waveMax>0) { - macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); + macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,false,macroDummyMode,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); } if (panMax>0) { if (panSingle) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,panBits)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { - macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); } } } } - macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); + macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,true,macroRelativeMode)); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_STD || ins->type==DIV_INS_OPL || @@ -3985,22 +4096,25 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SWAN || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || - ins->type==DIV_INS_MIKEY) { - macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,filtModeBits)); + macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,filtModeBits)); } else if (ins->type==DIV_INS_SAA1099) { - macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,saaEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,saaEnvBits)); } else if (ins->type==DIV_INS_X1_010) { - macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,x1_010EnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,x1_010EnvBits)); } else if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("Wave Length",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Depth",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,true,macroFilterMode)); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4009,18 +4123,20 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_N163) { - macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,n163UpdateBits)); } else if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,true,macroFilterMode)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,ex2Bit,ayEnvBits)); } } if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64SpecialBits)); - macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,c64SpecialBits)); + macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) { macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Num",&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -4028,22 +4144,31 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Wave",&ins->std.ex3Macro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Pos",&ins->std.algMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Len",&ins->std.fbMacro,0,252,160,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,n163UpdateBits)); } if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Position",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); } if (ins->type==DIV_INS_SU) { - macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,suControlBits)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,suControlBits)); macroList.push_back(FurnaceGUIMacroDesc("Phase Reset Timer",&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); // again reuse code from resonance macro but use ex4 instead } + if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Envelope counter",&ins->std.ex3Macro,0,511,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope left volume ramp",&ins->std.ex4Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope right volume ramp",&ins->std.ex5Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope K1 ramp",&ins->std.ex6Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope K2 ramp",&ins->std.ex7Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,es5506EnvelopeModes)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,es5506ControlModes)); + } drawMacros(macroList); ImGui::EndTabItem(); diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index 8bee0f88c..9a41486e1 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -31,6 +31,9 @@ const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; const int _ONE_HUNDRED_TWENTY_SEVEN=127; const int _TWO_HUNDRED_FIFTY_FIVE=255; +const int _FIVE_HUNDRED_ELEVEN=511; const int _TWO_THOUSAND_FORTY_SEVEN=2047; const int _FOUR_THOUSAND_NINETY_FIVE=4095; +const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE=65535; const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN=-127; +const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT=-128; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index 98c6c34ff..ff11a4968 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -33,6 +33,9 @@ extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; extern const int _ONE_HUNDRED_TWENTY_SEVEN; extern const int _TWO_HUNDRED_FIFTY_FIVE; +extern const int _FIVE_HUNDRED_ELEVEN; extern const int _TWO_THOUSAND_FORTY_SEVEN; extern const int _FOUR_THOUSAND_NINETY_FIVE; +extern const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE; extern const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN; +extern const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT; From 0b09408ee87cc3f2efa4b8908b6e8124ff1da33b Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 18 Aug 2022 21:28:25 +0900 Subject: [PATCH 234/515] Fix initializing --- src/gui/gui.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 3e70e1210..9e10e4643 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -858,6 +858,10 @@ struct FurnaceGUISysCategory { description(NULL) {} }; +static const char* dummyMode[1]={ + NULL +}; + struct FurnaceGUIMacroDesc { DivInstrumentMacro* macro; int min, max; @@ -870,7 +874,7 @@ struct FurnaceGUIMacroDesc { bool isBitfield, blockMode, useMacroMode; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName={NULL}, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName=dummyMode, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): macro(m), height(macroHeight), displayName(name), From 446e62c69fb3146f20689f30bcc8a0eda3b566f8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 18 Aug 2022 21:29:48 +0900 Subject: [PATCH 235/515] Fix duplication --- src/gui/gui.h | 2 +- src/gui/insEdit.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 9e10e4643..6dd78caa4 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -858,7 +858,7 @@ struct FurnaceGUISysCategory { description(NULL) {} }; -static const char* dummyMode[1]={ +static const char* macroDummyMode[1]={ NULL }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1b51e02ac..75f3c1f2b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -323,10 +323,6 @@ const char* macroQSoundMode[3]={ NULL }; -const char* macroDummyMode[1]={ - NULL -}; - const char* macroFilterMode[4]={ "Relative", "Absolute", From 1f65b104f2a811bfccd19935965fb6e9a78ee6d2 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 18 Aug 2022 21:30:08 +0900 Subject: [PATCH 236/515] oops --- src/gui/gui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 6dd78caa4..98767d573 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -874,7 +874,7 @@ struct FurnaceGUIMacroDesc { bool isBitfield, blockMode, useMacroMode; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName=dummyMode, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName=macroDummyMode, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): macro(m), height(macroHeight), displayName(name), From 087ff27f06a6ad2ad77b9ecf211f152bfadd485c Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 19 Aug 2022 00:18:46 +0900 Subject: [PATCH 237/515] Fix panning macro height --- src/gui/insEdit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 75f3c1f2b..97b706a9d 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4064,15 +4064,15 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,panBits)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); } } } From fa6a61e49353756bebd3443208941a3a90f2034e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 18:05:13 -0500 Subject: [PATCH 238/515] Revert "Fix panning macro height" This reverts commit 087ff27f06a6ad2ad77b9ecf211f152bfadd485c. --- src/gui/insEdit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 97b706a9d..75f3c1f2b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4064,15 +4064,15 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,panBits)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); } } } From 90633b2cbceb9efcdc2b797fd3fdcc10c97d99ec Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 18:05:31 -0500 Subject: [PATCH 239/515] Revert "oops" This reverts commit 1f65b104f2a811bfccd19935965fb6e9a78ee6d2. --- src/gui/gui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 98767d573..6dd78caa4 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -874,7 +874,7 @@ struct FurnaceGUIMacroDesc { bool isBitfield, blockMode, useMacroMode; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName=macroDummyMode, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName=dummyMode, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): macro(m), height(macroHeight), displayName(name), From aa1e34ffd353ae14fd2b9249d761c091a08af0bc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 18:05:34 -0500 Subject: [PATCH 240/515] Revert "Fix duplication" This reverts commit 446e62c69fb3146f20689f30bcc8a0eda3b566f8. --- src/gui/gui.h | 2 +- src/gui/insEdit.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 6dd78caa4..9e10e4643 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -858,7 +858,7 @@ struct FurnaceGUISysCategory { description(NULL) {} }; -static const char* macroDummyMode[1]={ +static const char* dummyMode[1]={ NULL }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 75f3c1f2b..1b51e02ac 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -323,6 +323,10 @@ const char* macroQSoundMode[3]={ NULL }; +const char* macroDummyMode[1]={ + NULL +}; + const char* macroFilterMode[4]={ "Relative", "Absolute", From 3f14625361f2cc8e3bfae3e6e0095993fcc49da2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 18:05:45 -0500 Subject: [PATCH 241/515] Revert "Fix initializing" This reverts commit 0b09408ee87cc3f2efa4b8908b6e8124ff1da33b. --- src/gui/gui.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 9e10e4643..3e70e1210 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -858,10 +858,6 @@ struct FurnaceGUISysCategory { description(NULL) {} }; -static const char* dummyMode[1]={ - NULL -}; - struct FurnaceGUIMacroDesc { DivInstrumentMacro* macro; int min, max; @@ -874,7 +870,7 @@ struct FurnaceGUIMacroDesc { bool isBitfield, blockMode, useMacroMode; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName=dummyMode, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName={NULL}, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): macro(m), height(macroHeight), displayName(name), From c473f94f0d6901d19017e6474ea7c8a4b0592f37 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 18:21:51 -0500 Subject: [PATCH 242/515] remove delta mode it's unnecessary in my opinion unless I am missing something --- src/gui/gui.h | 7 +++---- src/gui/insEdit.cpp | 51 +++++++++++++++------------------------------ 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 3e70e1210..3e3401195 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -864,13 +864,13 @@ struct FurnaceGUIMacroDesc { float height; const char* displayName; const char** bitfieldBits; - const char** modeName; + const char* modeName; ImVec4 color; unsigned int bitOffset; - bool isBitfield, blockMode, useMacroMode; + bool isBitfield, blockMode; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, bool mMode=false, const char** mName={NULL}, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): macro(m), height(macroHeight), displayName(name), @@ -880,7 +880,6 @@ struct FurnaceGUIMacroDesc { bitOffset(bitOff), isBitfield(bitfield), blockMode(block), - useMacroMode(mMode), hoverFunc(hf) { // MSVC -> hell this->min=macroMin; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1b51e02ac..9287f1806 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -305,34 +305,15 @@ const char* gbHWSeqCmdTypes[6]={ "Loop until Release" }; -const char* macroAbsoluteMode[3]={ - "Relative", - "Absolute", - NULL -}; - -const char* macroRelativeMode[3]={ - "Absolute", - "Relative", - NULL -}; - -const char* macroQSoundMode[3]={ - "Independent", - "QSound", - NULL -}; - -const char* macroDummyMode[1]={ - NULL -}; - -const char* macroFilterMode[4]={ - "Relative", - "Absolute", - "Delta", - NULL -}; +// do not change these! +// anything other than a checkbox will look ugly! +// +// if you really need to, and have a good rationale (and by good I mean a VERY +// good one), please tell me and we'll sort it out. +const char* macroAbsoluteMode="Fixed"; +const char* macroRelativeMode="Relative"; +const char* macroQSoundMode="QSound"; +const char* macroDummyMode="Bug"; String macroHoverNote(int id, float val) { if (val<-60 || val>=120) return "???"; @@ -1259,12 +1240,14 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&i.macro->len,&_ONE,&_THREE)) { MARK_MODIFIED if (i.macro->len>128) i.macro->len=128; } - if (i.useMacroMode && i.modeName[0]!=NULL) { - for (int m=0; i.modeName[m]!=NULL; m++) { - String modeName=fmt::sprintf("%s##IMacroMode%d",i.modeName[m],m); - if (ImGui::RadioButton(modeName.c_str(),(int)i.macro->mode==m)) { - i.macro->mode=m; - } + // do not change this! + // anything other than a checkbox will look ugly! + // if you really need more than two macro modes please tell me. + if (i.modeName!=NULL) { + bool modeVal=i.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + i.macro->mode=modeVal; } } } From 9bd3f6c34bdd469a4e3204f90ea73c447b34eb05 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 18:36:22 -0500 Subject: [PATCH 243/515] remove delta mode entirely so it was used on the filter but i'm not sure why couldn't it be done in absolute mode instead --- src/gui/insEdit.cpp | 80 ++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9287f1806..4db506d20 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2902,10 +2902,10 @@ void FurnaceGUI::drawInsEdit() { } if (ImGui::BeginTabItem("FM Macros")) { if (ins->type==DIV_INS_OPLL) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_ALG),&ins->std.algMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2925,8 +2925,8 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,macroLFOWaves)); - macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,fmOperatorBits)); + macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); + macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,fmOperatorBits)); } drawMacros(macroList); ImGui::EndTabItem(); @@ -2964,10 +2964,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_WS),&ins->std.opMacros[ordi].wsMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else if (ins->type==DIV_INS_OPLL) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2977,10 +2977,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2992,10 +2992,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT),&ins->std.opMacros[ordi].dtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); if (ins->type==DIV_INS_FM) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,ssgEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } drawMacros(macroList); @@ -4033,38 +4033,38 @@ void FurnaceGUI::drawInsEdit() { if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } - macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,true,macroAbsoluteMode,ins->std.arpMacro.mode?(¯oHoverNote):NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroAbsoluteMode,ins->std.arpMacro.mode?(¯oHoverNote):NULL)); 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,false,macroDummyMode,NULL,true,mikeyFeedbackBits)); + 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_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,¯oHoverES5506FilterMode)); + macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,¯oHoverES5506FilterMode)); } else { macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER])); } } if (waveMax>0) { - macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,false,macroDummyMode,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); + macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); } if (panMax>0) { if (panSingle) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,panBits)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA),macroQSoundMode)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { - macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); } } } } - macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,true,macroRelativeMode)); + 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_STD || ins->type==DIV_INS_OPL || @@ -4081,15 +4081,15 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SU || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,filtModeBits)); + macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,filtModeBits)); } else if (ins->type==DIV_INS_SAA1099) { - macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,saaEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,saaEnvBits)); } else if (ins->type==DIV_INS_X1_010) { - macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,x1_010EnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,x1_010EnvBits)); } else if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("Wave Length",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_FDS) { @@ -4097,7 +4097,7 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,true,macroFilterMode)); + macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4106,20 +4106,20 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_N163) { - macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); } else if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,true,macroFilterMode)); + macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,ex2Bit,ayEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } } if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,c64SpecialBits)); - macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64SpecialBits)); + macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) { macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Num",&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -4127,20 +4127,20 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Wave",&ins->std.ex3Macro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Pos",&ins->std.algMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Len",&ins->std.fbMacro,0,252,160,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); } if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Position",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); } if (ins->type==DIV_INS_SU) { - macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,macroDummyMode,NULL,true,suControlBits)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,suControlBits)); macroList.push_back(FurnaceGUIMacroDesc("Phase Reset Timer",&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); // again reuse code from resonance macro but use ex4 instead } if (ins->type==DIV_INS_ES5506) { @@ -4149,8 +4149,8 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Envelope right volume ramp",&ins->std.ex5Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("Envelope K1 ramp",&ins->std.ex6Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("Envelope K2 ramp",&ins->std.ex7Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,es5506EnvelopeModes)); - macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,es5506ControlModes)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes)); } drawMacros(macroList); From 13158b86cf0e97374b1ff23017069448471488ce Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 19 Aug 2022 12:03:25 +0900 Subject: [PATCH 244/515] Clamp height of panning macro when higher than 128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit so, current filter macro behavior is: "Fixed" option enabled: override current filter value to macro value "Fixed" option disabled: current filter value = filter value determined from ES5506 tab or command ± filter macro value --- src/gui/insEdit.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 4db506d20..bff4c0153 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4051,15 +4051,15 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); } } } @@ -4097,7 +4097,7 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroAbsoluteMode)); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4112,7 +4112,7 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroAbsoluteMode)); } else { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } From 952a2a66e87e3bedb0286f69200f73bd4b834734 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 18 Aug 2022 23:55:29 -0500 Subject: [PATCH 245/515] store ES5506 params in format --- papers/format.md | 16 ++++++++++++++++ src/engine/engine.h | 4 ++-- src/engine/instrument.cpp | 26 ++++++++++++++++++++++++++ src/engine/instrument.h | 7 ++----- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/papers/format.md b/papers/format.md index 1a8cd7219..5dd7d206a 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 107: Furnace dev107 - 106: Furnace dev106 - 105: Furnace dev105 - 104: Furnace dev104 @@ -850,6 +851,21 @@ size | description --- | **Game Boy extra flags** (>=106) 1 | use software envelope 1 | always init hard env on new note + --- | **ES5506 data** (>=107) + 1 | filter mode + | - 0: HPK2_HPK2 + | - 1: HPK2_LPK1 + | - 2: LPK2_LPK2 + | - 3: LPK2_LPK1 + 2 | K1 + 2 | K2 + 2 | envelope count + 1 | left volume ramp + 1 | right volume ramp + 1 | K1 ramp + 1 | K2 ramp + 1 | K1 slow + 1 | K2 slow ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index 191414f5f..8e2c094da 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev106" -#define DIV_ENGINE_VERSION 106 +#define DIV_VERSION "dev107" +#define DIV_ENGINE_VERSION 107 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 2836e6f95..1720bf56a 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -543,6 +543,18 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(gb.softEnv); w->writeC(gb.alwaysInit); + // ES5506 + w->writeC(es5506.filter.mode); + w->writeS(es5506.filter.k1); + w->writeS(es5506.filter.k2); + w->writeS(es5506.envelope.ecount); + w->writeC(es5506.envelope.lVRamp); + w->writeC(es5506.envelope.rVRamp); + w->writeC(es5506.envelope.k1Ramp); + w->writeC(es5506.envelope.k2Ramp); + w->writeC(es5506.envelope.k1Slow); + w->writeC(es5506.envelope.k2Slow); + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); @@ -1111,6 +1123,20 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { gb.alwaysInit=reader.readC(); } + // ES5506 + if (version>=107) { + es5506.filter.mode=(DivInstrumentES5506::Filter::FilterMode)reader.readC(); + es5506.filter.k1=reader.readS(); + es5506.filter.k2=reader.readS(); + es5506.envelope.ecount=reader.readS(); + es5506.envelope.lVRamp=reader.readC(); + es5506.envelope.rVRamp=reader.readC(); + es5506.envelope.k1Ramp=reader.readC(); + es5506.envelope.k2Ramp=reader.readC(); + es5506.envelope.k1Slow=reader.readC(); + es5506.envelope.k2Slow=reader.readC(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index cfbed65a3..d3df4b631 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -468,7 +468,7 @@ struct DivInstrumentSoundUnit { struct DivInstrumentES5506 { struct Filter { enum FilterMode: unsigned char { // filter mode for pole 4,3 - FILTER_MODE_HPK2_HPK2, + FILTER_MODE_HPK2_HPK2=0, FILTER_MODE_HPK2_LPK1, FILTER_MODE_LPK2_LPK2, FILTER_MODE_LPK2_LPK1, @@ -494,12 +494,9 @@ struct DivInstrumentES5506 { k1Slow(false), k2Slow(false) {} }; - signed int lVol, rVol; Filter filter; Envelope envelope; - DivInstrumentES5506(): - lVol(0xffff), - rVol(0xffff) {} + DivInstrumentES5506() {} }; struct DivInstrument { From 9c80f91870ffbf5794acf6e481ab2088977d46c3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 00:00:10 -0500 Subject: [PATCH 246/515] relative --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index bff4c0153..f928e1f87 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4097,7 +4097,7 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroAbsoluteMode)); + macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode==1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4112,7 +4112,7 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { - macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroAbsoluteMode)); + macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode==1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); } else { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } From 142c21e20b9f5889cea8798ea19d0f637e4da5a1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 00:23:45 -0500 Subject: [PATCH 247/515] partially fix big-endian build samples are the next thing to tackle --- CMakeLists.txt | 11 +++++- TODO.md | 2 +- src/engine/safeReader.cpp | 80 +++++++++++++++++++++++++++++++++++++++ src/engine/safeWriter.cpp | 78 ++++++++++++++++++++++++++++++++++---- 4 files changed, 160 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 732cb623f..6b6b7788e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ set(USE_SNDFILE_DEFAULT ON) set(SYSTEM_SDL2_DEFAULT OFF) include(CheckIncludeFile) +include(TestBigEndian) if (ANDROID) set(USE_RTMIDI_DEFAULT OFF) @@ -72,9 +73,15 @@ option(WITH_INSTRUMENTS "Install instruments" ON) set(DEPENDENCIES_INCLUDE_DIRS "") if (ANDROID AND NOT TERMUX) -set(DEPENDENCIES_DEFINES "IS_MOBILE") + set(DEPENDENCIES_DEFINES "IS_MOBILE") else() -set(DEPENDENCIES_DEFINES "") + set(DEPENDENCIES_DEFINES "") +endif() + +TEST_BIG_ENDIAN(IS_BIG_ENDIAN) + +if (IS_BIG_ENDIAN) + list(APPEND DEPENDENCIES_DEFINES "TA_BIG_ENDIAN") endif() set(DEPENDENCIES_COMPILE_OPTIONS "") diff --git a/TODO.md b/TODO.md index 13f31300e..cba0b7c65 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,5 @@ # to-do for 0.6pre1.5-0.6pre2 - volume commands should work on Game Boy -- ability to customize `OFF`, `===` and `REL` - stereo separation control for AY +- "paste with instrument" \ No newline at end of file diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index 3cb1f4b1f..a367bfb7f 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -77,6 +77,85 @@ signed char SafeReader::readC() { return (signed char)buf[curSeek++]; } +#ifdef TA_BIG_ENDIAN +short SafeReader::readS_BE() { +#ifdef READ_DEBUG + logD("SR: reading short %x:",curSeek); +#endif + if (curSeek+2>len) throw EndOfFileException(this,len); + short ret; + memcpy(&ret,&buf[curSeek],2); +#ifdef READ_DEBUG + logD("SR: %.4x",ret); +#endif + curSeek+=2; + return ret; +} + +short SafeReader::readS() { + if (curSeek+2>len) throw EndOfFileException(this,len); + short ret; + memcpy(&ret,&buf[curSeek],2); + curSeek+=2; + return ((ret>>8)&0xff)|(ret<<8); +} + +int SafeReader::readI_BE() { +#ifdef READ_DEBUG + logD("SR: reading int %x:",curSeek); +#endif + if (curSeek+4>len) throw EndOfFileException(this,len); + int ret; + memcpy(&ret,&buf[curSeek],4); + curSeek+=4; +#ifdef READ_DEBUG + logD("SR: %.8x",ret); +#endif + return ret; +} + +int SafeReader::readI() { + if (curSeek+4>len) throw EndOfFileException(this,len); + unsigned int ret; + memcpy(&ret,&buf[curSeek],4); + curSeek+=4; + return (int)((ret>>24)|((ret&0xff0000)>>8)|((ret&0xff00)<<8)|((ret&0xff)<<24)); +} + +int64_t SafeReader::readL() { + if (curSeek+8>len) throw EndOfFileException(this,len); + unsigned char ret[8]; + memcpy(ret,&buf[curSeek],8); + curSeek+=8; + return (int64_t)(ret[0]|(ret[1]<<8)|(ret[2]<<16)|(ret[3]<<24)|(ret[4]<<32)|(ret[5]<<40)|(ret[6]<<48)|(ret[7]<<56)); +} + +float SafeReader::readF() { + if (curSeek+4>len) throw EndOfFileException(this,len); + unsigned int ret; + memcpy(&ret,&buf[curSeek],4); + curSeek+=4; + ret=((ret>>24)|((ret&0xff0000)>>8)|((ret&0xff00)<<8)|((ret&0xff)<<24)); + return *((float*)(&ret)); +} + +double SafeReader::readD() { + if (curSeek+8>len) throw EndOfFileException(this,len); + unsigned char ret[8]; + unsigned char retB[8]; + memcpy(ret,&buf[curSeek],8); + curSeek+=8; + retB[0]=ret[7]; + retB[1]=ret[6]; + retB[2]=ret[5]; + retB[3]=ret[4]; + retB[4]=ret[3]; + retB[5]=ret[2]; + retB[6]=ret[1]; + retB[7]=ret[0]; + return *((double*)retB); +} +#else short SafeReader::readS() { #ifdef READ_DEBUG logD("SR: reading short %x:",curSeek); @@ -144,6 +223,7 @@ double SafeReader::readD() { curSeek+=8; return ret; } +#endif String SafeReader::readString(size_t stlen) { String ret; diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index e61380936..a2a7315a0 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -77,9 +77,64 @@ int SafeWriter::writeC(signed char val) { return write(&val,1); } +#ifdef TA_BIG_ENDIAN +int SafeWriter::writeS_BE(short val) { + return write(&val,2); +} + +int SafeWriter::writeS(short val) { + unsigned char bytes[2]{(unsigned char)((val>>8)&0xff), (unsigned char)(val&0xff)}; + return write(bytes,2); +} + +int SafeWriter::writeI(int val) { + unsigned char bytes[4]; + bytes[0]=((unsigned int)val)&0xff; + bytes[1]=(((unsigned int)val)>>8)&0xff; + bytes[2]=(((unsigned int)val)>>16)&0xff; + bytes[3]=(((unsigned int)val)>>24)&0xff; + return write(bytes,4); +} + +int SafeWriter::writeL(int64_t val) { + unsigned char bytes[8]; + bytes[0]=((uint64_t)val)&0xff; + bytes[1]=(((uint64_t)val)>>8)&0xff; + bytes[2]=(((uint64_t)val)>>16)&0xff; + bytes[3]=(((uint64_t)val)>>24)&0xff; + bytes[4]=(((uint64_t)val)>>32)&0xff; + bytes[5]=(((uint64_t)val)>>40)&0xff; + bytes[6]=(((uint64_t)val)>>48)&0xff; + bytes[7]=(((uint64_t)val)>>56)&0xff; + return write(bytes,8); +} + +int SafeWriter::writeF(float val) { + unsigned char bytes[4]; + bytes[0]=((unsigned char*)(&val))[3]; + bytes[1]=((unsigned char*)(&val))[2]; + bytes[2]=((unsigned char*)(&val))[1]; + bytes[3]=((unsigned char*)(&val))[0]; + return write(bytes,4); +} + +int SafeWriter::writeD(double val) { + unsigned char bytes[8]; + bytes[0]=((unsigned char*)(&val))[7]; + bytes[1]=((unsigned char*)(&val))[6]; + bytes[2]=((unsigned char*)(&val))[5]; + bytes[3]=((unsigned char*)(&val))[4]; + bytes[4]=((unsigned char*)(&val))[3]; + bytes[5]=((unsigned char*)(&val))[2]; + bytes[6]=((unsigned char*)(&val))[1]; + bytes[7]=((unsigned char*)(&val))[0]; + return write(bytes,8); +} +#else int SafeWriter::writeS(short val) { return write(&val,2); } + int SafeWriter::writeS_BE(short val) { unsigned char bytes[2]{(unsigned char)((val>>8)&0xff), (unsigned char)(val&0xff)}; return write(bytes,2); @@ -88,23 +143,20 @@ int SafeWriter::writeS_BE(short val) { int SafeWriter::writeI(int val) { return write(&val,4); } + int SafeWriter::writeL(int64_t val) { return write(&val,8); } + int SafeWriter::writeF(float val) { return write(&val,4); } + int SafeWriter::writeD(double val) { return write(&val,8); } -int SafeWriter::writeString(String val, bool pascal) { - if (pascal) { - writeC((unsigned char)val.size()); - return write(val.c_str(),val.size())+1; - } else { - return write(val.c_str(),val.size()+1); - } -} +#endif + int SafeWriter::writeWString(WString val, bool pascal) { if (pascal) { writeS((unsigned short)val.size()); @@ -120,10 +172,20 @@ int SafeWriter::writeWString(WString val, bool pascal) { return 2+val.size()*2; } } + int SafeWriter::writeText(String val) { return write(val.c_str(),val.size()); } +int SafeWriter::writeString(String val, bool pascal) { + if (pascal) { + writeC((unsigned char)val.size()); + return write(val.c_str(),val.size())+1; + } else { + return write(val.c_str(),val.size()+1); + } +} + void SafeWriter::init() { if (operative) return; buf=new unsigned char[WRITER_BUF_SIZE]; From 42006e338c5ba1bd579beebb7eb601643ce8ebfb Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 19 Aug 2022 14:49:10 +0900 Subject: [PATCH 248/515] Fix Initializer --- src/engine/instrument.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index d3df4b631..e45fd02ff 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -496,7 +496,9 @@ struct DivInstrumentES5506 { }; Filter filter; Envelope envelope; - DivInstrumentES5506() {} + DivInstrumentES5506(): + filter(Filter()), + envelope(Envelope()) {} }; struct DivInstrument { From 5c7338930fde2e9688af79f32718a75d60b72de3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 01:26:11 -0500 Subject: [PATCH 249/515] fix big-endian build (i think) --- src/engine/fileOps.cpp | 98 +++++++++++++++++++++++++++++++++++---- src/engine/instrument.cpp | 43 +++++++++-------- 2 files changed, 113 insertions(+), 28 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 589ca6a58..05d93abe8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -825,6 +825,13 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { data=new short[length]; reader.read(data,length*2); } + +#ifdef TA_BIG_ENDIAN + // convert to big-endian + for (size_t pos=0; pos>8)); + } +#endif if (pitch!=5) { logD("%d: scaling from %d...",i,pitch); @@ -1323,9 +1330,15 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } // pointers - reader.read(insPtr,ds.insLen*4); - reader.read(wavePtr,ds.waveLen*4); - reader.read(samplePtr,ds.sampleLen*4); + for (int i=0; iordersLen); @@ -1703,11 +1716,36 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version>=58) { // modern sample sample->init(sample->samples); reader.read(sample->getCurBuf(),sample->getCurBufLen()); +#ifdef TA_BIG_ENDIAN + // convert 16-bit samples to big-endian + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { + unsigned char* sampleBuf=sample->getCurBuf(); + size_t sampleBufLen=sample->getCurBufLen(); + for (size_t pos=0; possamples; short* data=new short[length]; reader.read(data,2*length); +#ifdef TA_BIG_ENDIAN + // convert 16-bit samples to big-endian + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { + unsigned char* sampleBuf=sample->getCurBuf(); + size_t sampleBufLen=sample->getCurBufLen(); + for (size_t pos=0; poswriteI(0xffffffff); } +#ifdef TA_BIG_ENDIAN + // store 16-bit samples as little-endian + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { + unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); + size_t bufLen=sample->getCurBufLen(); + for (size_t i=0; iwriteC(sampleBuf[i+1]); + w->writeC(sampleBuf[i]); + } + } else { + w->write(sample->getCurBuf(),sample->getCurBufLen()); + } +#else w->write(sample->getCurBuf(),sample->getCurBufLen()); +#endif blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); @@ -3834,7 +3886,13 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeS(pat->data[j][1]); // octave w->writeS(pat->data[j][2]); // instrument w->writeS(pat->data[j][3]); // volume +#ifdef TA_BIG_ENDIAN + for (int k=0; kpat[i.chan].effectCols*2; k++) { + w->writeS(pat->data[j][4+k]); + } +#else w->write(&pat->data[j][4],2*song.subsong[i.subsong]->pat[i.chan].effectCols*2); // effects +#endif } w->writeString(pat->name,false); @@ -4116,7 +4174,9 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeI(i->std.volMacro.val[j]+18); } } else { - w->write(i->std.volMacro.val,4*i->std.volMacro.len); + for (int j=0; jstd.volMacro.len; j++) { + w->writeI(i->std.volMacro.val[j]); + } } if (i->std.volMacro.len>0) { w->writeC(i->std.volMacro.loop); @@ -4125,7 +4185,9 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeC(i->std.arpMacro.len); if (i->std.arpMacro.mode) { - w->write(i->std.arpMacro.val,4*i->std.arpMacro.len); + for (int j=0; jstd.arpMacro.len; j++) { + w->writeI(i->std.arpMacro.val[j]); + } } else { for (int j=0; jstd.arpMacro.len; j++) { w->writeI(i->std.arpMacro.val[j]+12); @@ -4142,14 +4204,18 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeI(i->std.dutyMacro.val[j]+12); } } else { - w->write(i->std.dutyMacro.val,4*i->std.dutyMacro.len); + for (int j=0; jstd.dutyMacro.len; j++) { + w->writeI(i->std.dutyMacro.val[j]); + } } if (i->std.dutyMacro.len>0) { w->writeC(i->std.dutyMacro.loop); } w->writeC(i->std.waveMacro.len); - w->write(i->std.waveMacro.val,4*i->std.waveMacro.len); + for (int j=0; jstd.waveMacro.len; j++) { + w->writeI(i->std.waveMacro.val[j]); + } if (i->std.waveMacro.len>0) { w->writeC(i->std.waveMacro.loop); } @@ -4200,7 +4266,9 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeI(i->data[j]>>2); } } else { - w->write(i->data,4*i->len); + for (int j=0; jlen; j++) { + w->writeI(i->data[j]); + } } } @@ -4213,7 +4281,13 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeS(pat->data[k][0]); // note w->writeS(pat->data[k][1]); // octave w->writeS(pat->data[k][3]); // volume +#ifdef TA_BIG_ENDIAN + for (int l=0; lwriteS(pat->data[k][4+l]); + } +#else w->write(&pat->data[k][4],2*curPat[i].effectCols*2); // effects +#endif w->writeS(pat->data[k][2]); // instrument } } @@ -4232,7 +4306,15 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeC(50); // i'm too lazy to deal with .dmf's weird way of storing 8-bit samples w->writeC(16); + // well I can't be lazy if it's on a big-endian system +#ifdef TA_BIG_ENDIAN + for (unsigned int j=0; jlength16; j++) { + w->writeC(((unsigned short)i->data16[j])&0xff); + w->writeC(((unsigned short)i->data16[j])>>8); + } +#else w->write(i->data16,i->length16); +#endif } saveLock.unlock(); diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 2836e6f95..687ba53f8 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -549,6 +549,9 @@ void DivInstrument::putInsData(SafeWriter* w) { w->seek(0,SEEK_END); } +#define READ_MACRO_VALS(x,y) \ + for (int macroValPos=0; macroValPos=17) { - reader.read(std.pitchMacro.val,4*std.pitchMacro.len); - reader.read(std.ex1Macro.val,4*std.ex1Macro.len); - reader.read(std.ex2Macro.val,4*std.ex2Macro.len); - reader.read(std.ex3Macro.val,4*std.ex3Macro.len); + READ_MACRO_VALS(std.pitchMacro.val,std.pitchMacro.len); + READ_MACRO_VALS(std.ex1Macro.val,std.ex1Macro.len); + READ_MACRO_VALS(std.ex2Macro.val,std.ex2Macro.len); + READ_MACRO_VALS(std.ex3Macro.val,std.ex3Macro.len); } else { if (type==DIV_INS_STD) { if (oldVolHeight==31) { @@ -730,10 +733,10 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { std.fmsMacro.open=reader.readC(); std.amsMacro.open=reader.readC(); - reader.read(std.algMacro.val,4*std.algMacro.len); - reader.read(std.fbMacro.val,4*std.fbMacro.len); - reader.read(std.fmsMacro.val,4*std.fmsMacro.len); - reader.read(std.amsMacro.val,4*std.amsMacro.len); + READ_MACRO_VALS(std.algMacro.val,std.algMacro.len); + READ_MACRO_VALS(std.fbMacro.val,std.fbMacro.len); + READ_MACRO_VALS(std.fmsMacro.val,std.fmsMacro.len); + READ_MACRO_VALS(std.amsMacro.val,std.amsMacro.len); for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; @@ -1007,14 +1010,14 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { std.ex7Macro.open=reader.readC(); std.ex8Macro.open=reader.readC(); - reader.read(std.panLMacro.val,4*std.panLMacro.len); - reader.read(std.panRMacro.val,4*std.panRMacro.len); - reader.read(std.phaseResetMacro.val,4*std.phaseResetMacro.len); - reader.read(std.ex4Macro.val,4*std.ex4Macro.len); - reader.read(std.ex5Macro.val,4*std.ex5Macro.len); - reader.read(std.ex6Macro.val,4*std.ex6Macro.len); - reader.read(std.ex7Macro.val,4*std.ex7Macro.len); - reader.read(std.ex8Macro.val,4*std.ex8Macro.len); + READ_MACRO_VALS(std.panLMacro.val,std.panLMacro.len); + READ_MACRO_VALS(std.panRMacro.val,std.panRMacro.len); + READ_MACRO_VALS(std.phaseResetMacro.val,std.phaseResetMacro.len); + READ_MACRO_VALS(std.ex4Macro.val,std.ex4Macro.len); + READ_MACRO_VALS(std.ex5Macro.val,std.ex5Macro.len); + READ_MACRO_VALS(std.ex6Macro.val,std.ex6Macro.len); + READ_MACRO_VALS(std.ex7Macro.val,std.ex7Macro.len); + READ_MACRO_VALS(std.ex8Macro.val,std.ex8Macro.len); // FDS fds.modSpeed=reader.readI(); From 65278405564929b3c21bb88f164ffdc66a0e951d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 01:27:21 -0500 Subject: [PATCH 250/515] Fix Initializer Again --- src/engine/instrument.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index e45fd02ff..32c03f451 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -497,8 +497,8 @@ struct DivInstrumentES5506 { Filter filter; Envelope envelope; DivInstrumentES5506(): - filter(Filter()), - envelope(Envelope()) {} + filter(Filter()), + envelope(Envelope()) {} }; struct DivInstrument { From 3787d2ae87171e3a81ee17516998599eb24eb750 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 04:41:32 -0500 Subject: [PATCH 251/515] one more big endian fix --- src/engine/safeReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index a367bfb7f..76e337a3d 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -127,7 +127,7 @@ int64_t SafeReader::readL() { unsigned char ret[8]; memcpy(ret,&buf[curSeek],8); curSeek+=8; - return (int64_t)(ret[0]|(ret[1]<<8)|(ret[2]<<16)|(ret[3]<<24)|(ret[4]<<32)|(ret[5]<<40)|(ret[6]<<48)|(ret[7]<<56)); + return (int64_t)(ret[0]|(ret[1]<<8)|(ret[2]<<16)|(ret[3]<<24)|((uint64_t)ret[4]<<32)|((uint64_t)ret[5]<<40)|((uint64_t)ret[6]<<48)|((uint64_t)ret[7]<<56)); } float SafeReader::readF() { From 94cf589e924f56d510a4101eb47e40f2416fc123 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 04:41:45 -0500 Subject: [PATCH 252/515] GUI: prepare for chip manager window --- CMakeLists.txt | 1 + src/gui/doAction.cpp | 6 ++++++ src/gui/gui.cpp | 5 +++++ src/gui/gui.h | 5 ++++- src/gui/guiConst.cpp | 1 + src/gui/sysManager.cpp | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/gui/sysManager.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b6b7788e..7c8d39396 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,6 +552,7 @@ src/gui/stats.cpp src/gui/subSongs.cpp src/gui/sysConf.cpp src/gui/sysEx.cpp +src/gui/sysManager.cpp src/gui/util.cpp src/gui/waveEdit.cpp src/gui/volMeter.cpp diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 5c840df4e..e0f0ca30a 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -241,6 +241,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_PAT_MANAGER: nextWindow=GUI_WINDOW_PAT_MANAGER; break; + case GUI_ACTION_WINDOW_SYS_MANAGER: + nextWindow=GUI_WINDOW_SYS_MANAGER; + break; case GUI_ACTION_WINDOW_REGISTER_VIEW: nextWindow=GUI_WINDOW_REGISTER_VIEW; break; @@ -328,6 +331,9 @@ void FurnaceGUI::doAction(int what) { case GUI_WINDOW_PAT_MANAGER: patManagerOpen=false; break; + case GUI_WINDOW_SYS_MANAGER: + sysManagerOpen=false; + break; case GUI_WINDOW_REGISTER_VIEW: regViewOpen=false; break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4a6f3f39a..9189618df 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3108,6 +3108,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("mixer",BIND_FOR(GUI_ACTION_WINDOW_MIXER),mixerOpen)) mixerOpen=!mixerOpen; if (ImGui::MenuItem("channels",BIND_FOR(GUI_ACTION_WINDOW_CHANNELS),channelsOpen)) channelsOpen=!channelsOpen; if (ImGui::MenuItem("pattern manager",BIND_FOR(GUI_ACTION_WINDOW_PAT_MANAGER),patManagerOpen)) patManagerOpen=!patManagerOpen; + if (ImGui::MenuItem("chip manager",BIND_FOR(GUI_ACTION_WINDOW_SYS_MANAGER),sysManagerOpen)) sysManagerOpen=!sysManagerOpen; if (ImGui::MenuItem("compatibility flags",BIND_FOR(GUI_ACTION_WINDOW_COMPAT_FLAGS),compatFlagsOpen)) compatFlagsOpen=!compatFlagsOpen; if (ImGui::MenuItem("song comments",BIND_FOR(GUI_ACTION_WINDOW_NOTES),notesOpen)) notesOpen=!notesOpen; ImGui::Separator(); @@ -3243,6 +3244,7 @@ bool FurnaceGUI::loop() { drawNotes(); drawChannels(); drawPatManager(); + drawSysManager(); drawRegView(); drawLog(); drawEffectList(); @@ -4364,6 +4366,7 @@ bool FurnaceGUI::init() { notesOpen=e->getConfBool("notesOpen",false); channelsOpen=e->getConfBool("channelsOpen",false); patManagerOpen=e->getConfBool("patManagerOpen",false); + sysManagerOpen=e->getConfBool("sysManagerOpen",false); regViewOpen=e->getConfBool("regViewOpen",false); logOpen=e->getConfBool("logOpen",false); effectListOpen=e->getConfBool("effectListOpen",false); @@ -4607,6 +4610,7 @@ bool FurnaceGUI::finish() { e->setConf("notesOpen",notesOpen); e->setConf("channelsOpen",channelsOpen); e->setConf("patManagerOpen",patManagerOpen); + e->setConf("sysManagerOpen",sysManagerOpen); e->setConf("regViewOpen",regViewOpen); e->setConf("logOpen",logOpen); e->setConf("effectListOpen",effectListOpen); @@ -4787,6 +4791,7 @@ FurnaceGUI::FurnaceGUI(): findOpen(false), spoilerOpen(false), patManagerOpen(false), + sysManagerOpen(false), selecting(false), selectingFull(false), dragging(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 3e3401195..8a3548f2f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -250,6 +250,7 @@ enum FurnaceGUIWindows { GUI_WINDOW_NOTES, GUI_WINDOW_CHANNELS, GUI_WINDOW_PAT_MANAGER, + GUI_WINDOW_SYS_MANAGER, GUI_WINDOW_REGISTER_VIEW, GUI_WINDOW_LOG, GUI_WINDOW_EFFECT_LIST, @@ -370,6 +371,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_NOTES, GUI_ACTION_WINDOW_CHANNELS, GUI_ACTION_WINDOW_PAT_MANAGER, + GUI_ACTION_WINDOW_SYS_MANAGER, GUI_ACTION_WINDOW_REGISTER_VIEW, GUI_ACTION_WINDOW_LOG, GUI_ACTION_WINDOW_EFFECT_LIST, @@ -1278,7 +1280,7 @@ class FurnaceGUI { bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; - bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen; + bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen; SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; @@ -1588,6 +1590,7 @@ class FurnaceGUI { void drawNotes(); void drawChannels(); void drawPatManager(); + void drawSysManager(); void drawRegView(); void drawAbout(); void drawSettings(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 714e77709..1940946d6 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -488,6 +488,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_NOTES", "Song Comments", 0), D("WINDOW_CHANNELS", "Channels", 0), D("WINDOW_PAT_MANAGER", "Pattern Manager", 0), + D("WINDOW_SYS_MANAGER", "Chip Manager", 0), D("WINDOW_REGISTER_VIEW", "Register View", 0), D("WINDOW_LOG", "Log Viewer", 0), D("EFFECT_LIST", "Effect List", 0), diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp new file mode 100644 index 000000000..e43b4dfed --- /dev/null +++ b/src/gui/sysManager.cpp @@ -0,0 +1,37 @@ +/** + * 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 "gui.h" +#include "misc/cpp/imgui_stdlib.h" +#include "IconsFontAwesome4.h" +#include + +void FurnaceGUI::drawSysManager() { + if (nextWindow==GUI_WINDOW_SYS_MANAGER) { + sysManagerOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!sysManagerOpen) return; + if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) { + ImGui::Text("Stuff here..."); + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SYS_MANAGER; + ImGui::End(); +} From 27555c3c0ae8fcdb7ef3654643cbf0600ef222f8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 04:45:59 -0500 Subject: [PATCH 253/515] aaaand more fixing --- src/engine/fileOps.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 05d93abe8..196721afa 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -828,7 +828,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { #ifdef TA_BIG_ENDIAN // convert to big-endian - for (size_t pos=0; pos>8)); } #endif @@ -1719,7 +1719,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { #ifdef TA_BIG_ENDIAN // convert 16-bit samples to big-endian if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { - unsigned char* sampleBuf=sample->getCurBuf(); + unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); size_t sampleBufLen=sample->getCurBufLen(); for (size_t pos=0; posdepth==DIV_SAMPLE_DEPTH_16BIT) { - unsigned char* sampleBuf=sample->getCurBuf(); + unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); size_t sampleBufLen=sample->getCurBufLen(); for (size_t pos=0; pos Date: Fri, 19 Aug 2022 14:36:22 -0500 Subject: [PATCH 254/515] one moreeee big-endian fix --- src/audio/sdlAudio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/audio/sdlAudio.cpp b/src/audio/sdlAudio.cpp index 5c11a0342..f1d0e1e9d 100644 --- a/src/audio/sdlAudio.cpp +++ b/src/audio/sdlAudio.cpp @@ -110,7 +110,11 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { desc.outFormat=TA_AUDIO_FORMAT_F32; ac.freq=desc.rate; +#ifdef TA_BIG_ENDIAN + ac.format=AUDIO_F32MSB; +#else ac.format=AUDIO_F32; +#endif ac.channels=desc.outChans; ac.samples=desc.bufsize; ac.callback=taSDLProcess; From 5fe3a3c35a99ca9ae300ecff583cbce574038f31 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 16:25:32 -0500 Subject: [PATCH 255/515] prepare for moving chips --- src/engine/engine.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++ src/engine/engine.h | 3 +++ 2 files changed, 54 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5fe2db695..7bf184f0a 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1386,6 +1386,57 @@ bool DivEngine::removeSystem(int index, bool preserveOrder) { return true; } +bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) { + if (src==dest) { + lastError="source and destination are equal"; + return false; + } + if (src<0 || src>=song.systemLen) { + lastError="invalid source index"; + return false; + } + if (dest<0 || dest>=song.systemLen) { + lastError="invalid destination index"; + return false; + } + //int chanCount=chans; + quitDispatch(); + BUSY_BEGIN; + saveLock.lock(); + + if (!preserveOrder) { + // move channels + // TODO: a lot of work! + } + + DivSystem srcSystem=song.system[src]; + + song.system[src]=song.system[dest]; + song.system[dest]=srcSystem; + + song.systemVol[src]^=song.systemVol[dest]; + song.systemVol[dest]^=song.systemVol[src]; + song.systemVol[src]^=song.systemVol[dest]; + + song.systemPan[src]^=song.systemPan[dest]; + song.systemPan[dest]^=song.systemPan[src]; + song.systemPan[src]^=song.systemPan[dest]; + + song.systemFlags[src]^=song.systemFlags[dest]; + song.systemFlags[dest]^=song.systemFlags[src]; + song.systemFlags[src]^=song.systemFlags[dest]; + + recalcChans(); + saveLock.unlock(); + BUSY_END; + initDispatch(); + BUSY_BEGIN; + renderSamples(); + reset(); + BUSY_END; + return true; +} + void DivEngine::poke(int sys, unsigned int addr, unsigned short val) { if (sys<0 || sys>=song.systemLen) return; BUSY_BEGIN; diff --git a/src/engine/engine.h b/src/engine/engine.h index 8e2c094da..d86e532bb 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -905,6 +905,9 @@ class DivEngine { // remove system bool removeSystem(int index, bool preserveOrder=true); + + // move system + bool swapSystem(int src, int dest, bool preserveOrder=true); // write to register on system void poke(int sys, unsigned int addr, unsigned short val); From c74d7fab3733c2c0dcfa71a2b269329e122c38a3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 18:46:19 -0500 Subject: [PATCH 256/515] dev108 - add SN period range compat flag there's room for possible improvement --- papers/format.md | 4 +++- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 14 ++++++++++++-- src/engine/platform/sms.cpp | 10 ++++++++-- src/engine/song.h | 4 +++- src/gui/compatFlags.cpp | 4 ++++ 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/papers/format.md b/papers/format.md index 5dd7d206a..7bd3bba7e 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 108: Furnace dev108 - 107: Furnace dev107 - 106: Furnace dev106 - 105: Furnace dev105 @@ -331,7 +332,8 @@ size | description 1 | broken outVol (>=99) or reserved 1 | E1xy and E2xy stop on same note (>=100) or reserved 1 | broken initial position of porta after arp (>=101) or reserved - 7 | reserved + 1 | SN periods under 8 are treated as 1 (>=108) or reserved + 6 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved diff --git a/src/engine/engine.h b/src/engine/engine.h index d86e532bb..4f11e82e8 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev107" -#define DIV_ENGINE_VERSION 107 +#define DIV_VERSION "dev108" +#define DIV_ENGINE_VERSION 108 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 196721afa..df32f0553 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -175,6 +175,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenOutVol=true; // ??? ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; + ds.snNoLowPeriods=true; // 1.1 compat flags if (ds.version>24) { @@ -1063,6 +1064,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<101) { ds.brokenPortaArp=true; } + if (ds.version<108) { + ds.snNoLowPeriods=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1475,7 +1479,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<7; i++) { + if (ds.version>=108) { + ds.snNoLowPeriods=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<6; i++) { reader.readC(); } } @@ -3719,7 +3728,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.brokenOutVol); w->writeC(song.e1e2StopOnSameNote); w->writeC(song.brokenPortaArp); - for (int i=0; i<7; i++) { + w->writeC(song.snNoLowPeriods); + for (int i=0; i<6; i++) { w->writeC(0); } diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 2988be2f8..40a8616ef 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -188,7 +188,11 @@ void DivPlatformSMS::tick(bool sysTick) { if (chan[i].freqChanged) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,toneDivider); if (chan[i].freq>1023) chan[i].freq=1023; - if (chan[i].freq<8) chan[i].freq=1; + if (parent->song.snNoLowPeriods) { + if (chan[i].freq<8) chan[i].freq=1; + } else { + if (chan[i].freq<0) chan[i].freq=0; + } //if (chan[i].actualNote>0x5d) chan[i].freq=0x01; rWrite(0,0x80|i<<5|(chan[i].freq&15)); rWrite(0,chan[i].freq>>4); @@ -203,7 +207,9 @@ void DivPlatformSMS::tick(bool sysTick) { if (chan[3].freqChanged || updateSNMode) { chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,noiseDivider); if (chan[3].freq>1023) chan[3].freq=1023; - if (chan[3].actualNote>0x5d) chan[3].freq=0x01; + if (parent->song.snNoLowPeriods) { + if (chan[3].actualNote>0x5d) chan[3].freq=0x01; + } if (snNoiseMode&2) { // take period from channel 3 if (updateSNMode || resetPhase) { if (snNoiseMode&1) { diff --git a/src/engine/song.h b/src/engine/song.h index de422a24a..30f5ef245 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -500,6 +500,7 @@ struct DivSong { bool brokenOutVol; bool e1e2StopOnSameNote; bool brokenPortaArp; + bool snNoLowPeriods; std::vector ins; std::vector wave; @@ -600,7 +601,8 @@ struct DivSong { volMacroLinger(true), brokenOutVol(false), e1e2StopOnSameNote(false), - brokenPortaArp(false) { + brokenPortaArp(false), + snNoLowPeriods(false) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 9024992e7..e6d0aed85 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -139,6 +139,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("if enabled, no checks for the presence of a volume macro will be made.\nthis will cause the last macro value to linger unless a value in the volume column is present."); } + ImGui::Checkbox("Treat SN76489 periods under 8 as 1",&e->song.snNoLowPeriods); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, any SN period under 8 will be written as 1 instead.\nthis replicates DefleMask behavior, but reduces available period range."); + } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { From 4d057d3328b90452de702b045b6b864602b72eb8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 19:42:01 -0500 Subject: [PATCH 257/515] dev109 - define SNES instrument params --- src/engine/engine.h | 4 +- src/engine/instrument.cpp | 20 ++++++++ src/engine/instrument.h | 23 ++++++++++ src/gui/insEdit.cpp | 97 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 4f11e82e8..c433def8e 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev108" -#define DIV_ENGINE_VERSION 108 +#define DIV_VERSION "dev109" +#define DIV_ENGINE_VERSION 109 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 838e13846..9f1f5fff6 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -554,6 +554,15 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(es5506.envelope.k2Ramp); w->writeC(es5506.envelope.k1Slow); w->writeC(es5506.envelope.k2Slow); + + // SNES + w->writeC(snes.useEnv); + w->writeC(snes.gainMode); + w->writeC(snes.gain); + w->writeC(snes.a); + w->writeC(snes.d); + w->writeC(snes.s); + w->writeC(snes.r); blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); @@ -1140,6 +1149,17 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { es5506.envelope.k2Slow=reader.readC(); } + // SNES + if (version>=109) { + snes.useEnv=reader.readC(); + snes.gainMode=(DivInstrumentSNES::GainMode)reader.readC(); + snes.gain=reader.readC(); + snes.a=reader.readC(); + snes.d=reader.readC(); + snes.s=reader.readC(); + snes.r=reader.readC(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 32c03f451..da6d08415 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -501,6 +501,28 @@ struct DivInstrumentES5506 { envelope(Envelope()) {} }; +struct DivInstrumentSNES { + enum GainMode: unsigned char { + GAIN_MODE_DIRECT=0, + GAIN_MODE_DEC_LINEAR=4, + GAIN_MODE_DEC_LOG=5, + GAIN_MODE_INC_LINEAR=6, + GAIN_MODE_INC_INVLOG=7 + }; + bool useEnv; + GainMode gainMode; + unsigned char gain; + unsigned char a, d, s, r; + DivInstrumentSNES(): + useEnv(true), + gainMode(GAIN_MODE_DIRECT), + gain(127), + a(15), + d(7), + s(7), + r(0) {} +}; + struct DivInstrument { String name; bool mode; @@ -516,6 +538,7 @@ struct DivInstrument { DivInstrumentWaveSynth ws; DivInstrumentSoundUnit su; DivInstrumentES5506 es5506; + DivInstrumentSNES snes; /** * save the instrument to a SafeWriter. diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index f928e1f87..d09c8e2e7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3373,6 +3373,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SU || + ins->type==DIV_INS_SNES || ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { String sName; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { @@ -3668,6 +3669,101 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } } + if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { + P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv)); + ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); + if (ins->snes.useEnv) { + if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("A"); + ImGui::TextUnformatted("A"); + ImGui::TableNextColumn(); + CENTER_TEXT("D"); + ImGui::TextUnformatted("D"); + ImGui::TableNextColumn(); + CENTER_TEXT("S"); + ImGui::TextUnformatted("S"); + ImGui::TableNextColumn(); + CENTER_TEXT("R"); + ImGui::TextUnformatted("R"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); + ImGui::TableNextColumn(); + drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + + ImGui::EndTable(); + } + } else { + if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("Gain Mode"); + ImGui::TextUnformatted("Gain Mode"); + ImGui::TableNextColumn(); + CENTER_TEXT("Gain"); + ImGui::TextUnformatted("Gain"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; + PARAMETER; + } + if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; + PARAMETER; + } + if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; + PARAMETER; + } + if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; + PARAMETER; + } + if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; + PARAMETER; + } + + ImGui::TableNextColumn(); + unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; + if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; + P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); + + ImGui::TableNextColumn(); + ImGui::Text("Envelope goes here..."); + + ImGui::EndTable(); + } + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_GB || (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || ins->type==DIV_INS_X1_010 || @@ -3676,6 +3772,7 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SWAN || ins->type==DIV_INS_PCE || ins->type==DIV_INS_SCC || + ins->type==DIV_INS_SNES || ins->type==DIV_INS_NAMCO) { if (ImGui::BeginTabItem("Wavetable")) { if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) { From 24e3dec84f60e540e4210a5846271bfcc6f67930 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 19 Aug 2022 22:37:54 -0500 Subject: [PATCH 258/515] another big-endian fix! --- src/engine/wavetable.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/wavetable.cpp b/src/engine/wavetable.cpp index 0b13497ef..9de8544fe 100644 --- a/src/engine/wavetable.cpp +++ b/src/engine/wavetable.cpp @@ -59,7 +59,9 @@ DivDataErrors DivWavetable::readWaveData(SafeReader& reader, short version) { if (len>256 || min!=0 || max>255) return DIV_DATA_INVALID_DATA; - reader.read(data,4*len); + for (int i=0; i Date: Sat, 20 Aug 2022 01:10:30 -0500 Subject: [PATCH 259/515] GUI: highlight current macro position not for op macros (yet) --- src/engine/macroInt.cpp | 108 ++++++++++++++++++++++++++++++++++++++++ src/engine/macroInt.h | 11 +++- src/gui/insEdit.cpp | 30 +++++++++-- src/gui/plot_nolerp.cpp | 24 ++++++--- src/gui/plot_nolerp.h | 4 +- 5 files changed, 162 insertions(+), 15 deletions(-) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 06f04682e..83ad906fa 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -41,6 +41,7 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic actualHad=has; had=actualHad; if (has) { + lastPos=pos; val=source.val[pos++]; if (source.rel>=0 && pos>source.rel && !released) { if (source.loop=0 && source.loop>8)^hashTable[(unsigned char)*i]; + } + return nameHash; +} + +#define CONSIDER(x) case NAME_HASH(#x): return &x; break; + +DivMacroStruct* DivMacroInt::structByName(const String& name) { + unsigned int hash=NAME_HASH(name.c_str()); + + switch (hash) { + CONSIDER(vol) + CONSIDER(arp) + CONSIDER(duty) + CONSIDER(wave) + CONSIDER(pitch) + CONSIDER(ex1) + CONSIDER(ex2) + CONSIDER(ex3) + CONSIDER(alg) + CONSIDER(fb) + CONSIDER(fms) + CONSIDER(ams) + CONSIDER(panL) + CONSIDER(panR) + CONSIDER(phaseReset) + CONSIDER(ex4) + CONSIDER(ex5) + CONSIDER(ex6) + CONSIDER(ex7) + CONSIDER(ex8) + } + + return NULL; +} diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 839625558..8569dce42 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -25,13 +25,13 @@ class DivEngine; struct DivMacroStruct { - int pos; + int pos, lastPos; int val; bool has, had, actualHad, finished, will, linger; unsigned int mode; void doMacro(DivInstrumentMacro& source, bool released, bool tick); void init() { - pos=mode=0; + pos=lastPos=mode=0; has=had=actualHad=will=false; linger=false; // TODO: test whether this breaks anything? @@ -127,6 +127,13 @@ class DivMacroInt { */ void notifyInsDeletion(DivInstrument* which); + /** + * get DivMacroStruct by macro name. + * @param which the macro name. + * @return a DivMacroStruct, or NULL if none found. + */ + DivMacroStruct* structByName(const String& name); + DivMacroInt(): e(NULL), ins(NULL), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index d09c8e2e7..dc239fcd7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -19,6 +19,7 @@ #include "gui.h" #include "imgui_internal.h" +#include "../engine/macroInt.h" #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" #include "guiConst.h" @@ -1195,6 +1196,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; float loopIndicator[256]; + bool doHighlight[256]; int index=0; float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; @@ -1285,11 +1287,33 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (i.macro->vZoom>(i.max-i.min)) { i.macro->vZoom=i.max-i.min; } - + + memset(doHighlight,0,256*sizeof(bool)); + if (e->isRunning()) for (int j=0; jgetTotalChannelCount(); j++) { + DivChannelState* chanState=e->getChanState(j); + if (chanState==NULL) continue; + + if (chanState->keyOff) continue; + if (chanState->lastIns!=curIns) continue; + + DivMacroInt* macroInt=e->getMacroInt(j); + if (macroInt==NULL) continue; + + DivMacroStruct* macroStruct=macroInt->structByName(i.macro->name); + if (macroStruct==NULL) continue; + + if (macroStruct->lastPos>i.macro->len) continue; + if (macroStruct->lastPoslastPos>255) continue; + if (!macroStruct->actualHad) continue; + + doHighlight[macroStruct->lastPos-macroDragScroll]=true; + } + if (i.isBitfield) { - PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale))); + PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight); } else { - PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.blockMode,i.macro->open?genericGuide:NULL); + PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.blockMode,i.macro->open?genericGuide:NULL,doHighlight); } if (i.macro->open && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { macroDragStart=ImGui::GetItemRectMin(); diff --git a/src/gui/plot_nolerp.cpp b/src/gui/plot_nolerp.cpp index 64ffc4100..d802cbc52 100644 --- a/src/gui/plot_nolerp.cpp +++ b/src/gui/plot_nolerp.cpp @@ -183,7 +183,7 @@ void PlotNoLerp(const char* label, const float* values, int values_count, int va PlotNoLerpEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); } -int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 frame_size) +int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 frame_size, const bool* values_highlight, ImVec4 highlightColor) { ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindow(); @@ -253,7 +253,11 @@ int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), if (pos1.y <= pos0.y - 2.0f) pos1.y += 1.0f; if (v1&(1<DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + ImU32 rCol=(idx_hovered == v1_idx ? col_hovered : col_base); + if (values_highlight!=NULL) { + if (values_highlight[v1_idx]) rCol=ImGui::GetColorU32(highlightColor); + } + window->DrawList->AddRectFilled(pos0, pos1, rCol); } } tp0 = tp1; @@ -283,13 +287,13 @@ int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), return idx_hovered; } -void PlotBitfield(const char* label, const int* values, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 graph_size, int stride) +void PlotBitfield(const char* label, const int* values, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 graph_size, int stride, const bool* values_highlight, ImVec4 highlightColor) { FurnacePlotIntArrayGetterData data(values, stride); - PlotBitfieldEx(label, &Plot_IntArrayGetter, (void*)&data, values_count, values_offset, overlay_text, bits, graph_size); + PlotBitfieldEx(label, &Plot_IntArrayGetter, (void*)&data, values_count, values_offset, overlay_text, bits, graph_size, values_highlight, highlightColor); } -int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float)) +int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor) { ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindow(); @@ -413,7 +417,11 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett pos0.y-=(inner_bb.Max.y-inner_bb.Min.y)*inv_scale; //pos1.y+=1.0f; } - window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + ImU32 rCol=(idx_hovered == v1_idx ? col_hovered : col_base); + if (values_highlight!=NULL) { + if (values_highlight[v1_idx]) rCol=ImGui::GetColorU32(highlightColor); + } + window->DrawList->AddRectFilled(pos0, pos1, rCol); } t0 = t1; @@ -451,8 +459,8 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett return idx_hovered; } -void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float)) +void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor) { FurnacePlotArrayGetterData data(values, stride); - PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, blockMode, guideFunc); + PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, blockMode, guideFunc, values_highlight, highlightColor); } \ No newline at end of file diff --git a/src/gui/plot_nolerp.h b/src/gui/plot_nolerp.h index 5862dfadc..b353e6f8b 100644 --- a/src/gui/plot_nolerp.h +++ b/src/gui/plot_nolerp.h @@ -21,5 +21,5 @@ #include void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); -void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); -void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL, bool blockMode=false, std::string (*guideFunc)(float) = NULL); \ No newline at end of file +void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); +void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL, bool blockMode=false, std::string (*guideFunc)(float) = NULL, const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); \ No newline at end of file From 0f92c4e35a51d1df3e8e8bc3305783b857d93b25 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 20 Aug 2022 04:46:45 -0500 Subject: [PATCH 260/515] GUI: fix change ins applying to off and release --- src/gui/editing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 21b1a72eb..1ca3ff691 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -577,7 +577,7 @@ void FurnaceGUI::doChangeIns(int ins) { if (!e->curSubSong->chanShow[iCoarse]) continue; DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true); for (int j=selStart.y; j<=selEnd.y; j++) { - if (pat->data[j][2]!=-1 || !(pat->data[j][0]==0 && pat->data[j][1]==0)) { + if (pat->data[j][2]!=-1 || !((pat->data[j][0]==0 || pat->data[j][0]==100 || pat->data[j][0]==101 || pat->data[j][0]==102) && pat->data[j][1]==0)) { pat->data[j][2]=ins; } } From 1b2d2fdb985733cfd18bb95e1a519129b8949d1e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 20 Aug 2022 17:04:57 -0500 Subject: [PATCH 261/515] system --- src/gui/effectList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/effectList.cpp b/src/gui/effectList.cpp index a71a2fec7..488d4e794 100644 --- a/src/gui/effectList.cpp +++ b/src/gui/effectList.cpp @@ -10,7 +10,7 @@ void FurnaceGUI::drawEffectList() { } if (!effectListOpen) return; if (ImGui::Begin("Effect List",&effectListOpen,globalWinFlags)) { - ImGui::Text("System at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse])); + ImGui::Text("Chip at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse])); if (ImGui::BeginTable("effectList",2)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); From dfb663d8765b00016e81d50f0a3ef08e61d2419c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 21 Aug 2022 12:46:56 +0900 Subject: [PATCH 262/515] Fix this for preparing OPL3-L and OPL4 --- src/engine/platform/opl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 784bd08fa..88b1cbdae 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1595,7 +1595,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { adpcmChan=drums?11:9; } break; - case 3: case 759: + case 3: case 4: case 759: slotsNonDrums=slotsOPL3; slotsDrums=slotsOPL3Drums; slots=drums?slotsDrums:slotsNonDrums; From 2863f1662f1e7f3eac658ec77685760c6d0ae903 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 21 Aug 2022 12:57:53 +0900 Subject: [PATCH 263/515] Fix pitch --- src/engine/platform/opl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 88b1cbdae..78ef25a29 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1609,6 +1609,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { pretendYMU=true; adpcmChan=16; } else if (type==4) { + chipFreqBase=32768*684; downsample=true; } break; From 0b2f49199764bceeccb4f7be2dd34614de1160d7 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 21 Aug 2022 13:10:46 +0900 Subject: [PATCH 264/515] More preparing, Add OPL type docs --- src/engine/dispatchContainer.cpp | 27 +++++---------------------- src/engine/platform/opl.cpp | 15 ++++++++++++--- src/engine/platform/opl.h | 4 ++++ 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 8d8db5c5a..f116b1ca7 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -179,8 +179,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do switch (sys) { case DIV_SYSTEM_YMU759: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(759,false); + dispatch=new DivPlatformOPL(759,false); break; case DIV_SYSTEM_YM2612: dispatch=new DivPlatformGenesis; @@ -278,36 +277,20 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do ((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS); break; case DIV_SYSTEM_OPL: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(1,false); - break; case DIV_SYSTEM_OPL_DRUMS: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(1,true); + dispatch=new DivPlatformOPL(1,sys==DIV_SYSTEM_OPL_DRUMS); break; case DIV_SYSTEM_OPL2: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(2,false); - break; case DIV_SYSTEM_OPL2_DRUMS: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(2,true); + dispatch=new DivPlatformOPL(2,sys==DIV_SYSTEM_OPL2_DRUMS); break; case DIV_SYSTEM_OPL3: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(3,false); - break; case DIV_SYSTEM_OPL3_DRUMS: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(3,true); + dispatch=new DivPlatformOPL(3,sys==DIV_SYSTEM_OPL3_DRUMS); break; case DIV_SYSTEM_Y8950: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(8950,false); - break; case DIV_SYSTEM_Y8950_DRUMS: - dispatch=new DivPlatformOPL; - ((DivPlatformOPL*)dispatch)->setOPLType(8950,true); + dispatch=new DivPlatformOPL(8950,sys==DIV_SYSTEM_Y8950_DRUMS); break; case DIV_SYSTEM_OPZ: dispatch=new DivPlatformTX81Z; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 78ef25a29..a808ab624 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1580,6 +1580,14 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { pretendYMU=false; downsample=false; adpcmChan=-1; + // Vaild type value: + // 1 (YM3526) + // 2 (YM3812) + // 3 (YMF262) + // 4 (YMF278; Not implemented) + // 289 (YMF289; Not implemented) + // 759 (YMU759) + // 8950 (Y8950) switch (type) { case 1: case 2: case 8950: slotsNonDrums=slotsOPL2; @@ -1595,7 +1603,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { adpcmChan=drums?11:9; } break; - case 3: case 4: case 759: + case 3: case 4: case 289: case 759: slotsNonDrums=slotsOPL3; slotsDrums=slotsOPL3Drums; slots=drums?slotsDrums:slotsNonDrums; @@ -1608,14 +1616,14 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { if (type==759) { pretendYMU=true; adpcmChan=16; - } else if (type==4) { + } else if (type==4 || type==289) { chipFreqBase=32768*684; downsample=true; } break; } chipType=type; - if (type==759 || type==4) { + if (type==759 || type==289 || type==4) { oplType=3; } else if (type==8950) { oplType=1; @@ -1698,6 +1706,7 @@ void DivPlatformOPL::setFlags(unsigned int flags) { chipRateBase=rate; break; case 4: + case 289: switch (flags&0xff) { case 0x01: chipClock=COLOR_PAL*32.0/5.0; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index e3b16679f..a885814a9 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -151,6 +151,10 @@ class DivPlatformOPL: public DivDispatch { void renderSamples(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformOPL(int type, bool drums): + DivDispatch() { + setOPLType(type,drums); + } ~DivPlatformOPL(); }; #endif From f2950fa1d69a0830152acd706422ac20cdb06728 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 20 Aug 2022 23:35:13 -0500 Subject: [PATCH 265/515] Revert "More preparing, Add OPL type docs" This reverts commit 0b2f49199764bceeccb4f7be2dd34614de1160d7. do not add a constructor to any of the DivPlatforms. it will break things. --- src/engine/dispatchContainer.cpp | 27 ++++++++++++++++++++++----- src/engine/platform/opl.cpp | 15 +++------------ src/engine/platform/opl.h | 4 ---- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index f116b1ca7..8d8db5c5a 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -179,7 +179,8 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do switch (sys) { case DIV_SYSTEM_YMU759: - dispatch=new DivPlatformOPL(759,false); + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(759,false); break; case DIV_SYSTEM_YM2612: dispatch=new DivPlatformGenesis; @@ -277,20 +278,36 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do ((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS); break; case DIV_SYSTEM_OPL: + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(1,false); + break; case DIV_SYSTEM_OPL_DRUMS: - dispatch=new DivPlatformOPL(1,sys==DIV_SYSTEM_OPL_DRUMS); + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(1,true); break; case DIV_SYSTEM_OPL2: + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(2,false); + break; case DIV_SYSTEM_OPL2_DRUMS: - dispatch=new DivPlatformOPL(2,sys==DIV_SYSTEM_OPL2_DRUMS); + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(2,true); break; case DIV_SYSTEM_OPL3: + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(3,false); + break; case DIV_SYSTEM_OPL3_DRUMS: - dispatch=new DivPlatformOPL(3,sys==DIV_SYSTEM_OPL3_DRUMS); + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(3,true); break; case DIV_SYSTEM_Y8950: + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(8950,false); + break; case DIV_SYSTEM_Y8950_DRUMS: - dispatch=new DivPlatformOPL(8950,sys==DIV_SYSTEM_Y8950_DRUMS); + dispatch=new DivPlatformOPL; + ((DivPlatformOPL*)dispatch)->setOPLType(8950,true); break; case DIV_SYSTEM_OPZ: dispatch=new DivPlatformTX81Z; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index a808ab624..78ef25a29 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1580,14 +1580,6 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { pretendYMU=false; downsample=false; adpcmChan=-1; - // Vaild type value: - // 1 (YM3526) - // 2 (YM3812) - // 3 (YMF262) - // 4 (YMF278; Not implemented) - // 289 (YMF289; Not implemented) - // 759 (YMU759) - // 8950 (Y8950) switch (type) { case 1: case 2: case 8950: slotsNonDrums=slotsOPL2; @@ -1603,7 +1595,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { adpcmChan=drums?11:9; } break; - case 3: case 4: case 289: case 759: + case 3: case 4: case 759: slotsNonDrums=slotsOPL3; slotsDrums=slotsOPL3Drums; slots=drums?slotsDrums:slotsNonDrums; @@ -1616,14 +1608,14 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { if (type==759) { pretendYMU=true; adpcmChan=16; - } else if (type==4 || type==289) { + } else if (type==4) { chipFreqBase=32768*684; downsample=true; } break; } chipType=type; - if (type==759 || type==289 || type==4) { + if (type==759 || type==4) { oplType=3; } else if (type==8950) { oplType=1; @@ -1706,7 +1698,6 @@ void DivPlatformOPL::setFlags(unsigned int flags) { chipRateBase=rate; break; case 4: - case 289: switch (flags&0xff) { case 0x01: chipClock=COLOR_PAL*32.0/5.0; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index a885814a9..e3b16679f 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -151,10 +151,6 @@ class DivPlatformOPL: public DivDispatch { void renderSamples(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); - DivPlatformOPL(int type, bool drums): - DivDispatch() { - setOPLType(type,drums); - } ~DivPlatformOPL(); }; #endif From ba126b820aade878b64df9df21b3ae2f1da7ca4d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 21 Aug 2022 14:07:24 +0900 Subject: [PATCH 266/515] Add preset MSX + Neotron MSX sound expansion with YM2610 or YM2610B (optional), from Neo Geo and bunch of arcade boards - especially Taito's. MSX + SIMPL Covox speech thing-ish 8bit DAC for MSX. --- src/gui/presets.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 571cda441..18bcc5097 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -854,6 +854,41 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "MSX + Neotron", { + DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_YM2610_FULL, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "MSX + Neotron (extended channel 2)", { + DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "MSX + Neotron (with YM2610B)", { + DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_YM2610B, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "MSX + Neotron (with YM2610B; extended channel 3)", { + DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "MSX + SIMPL", { + DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, DAC + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-26/K)", { DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz From 16d7cd33202797868ef766fc212b3a71aaffec93 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 21 Aug 2022 14:08:14 +0900 Subject: [PATCH 267/515] More docs --- src/gui/presets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 18bcc5097..04049bdfc 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -885,7 +885,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "MSX + SIMPL", { DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, Mono DAC 0 } )); From 96feeced869ee3823faa691ec706dfd75ee3b574 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 16:34:43 -0500 Subject: [PATCH 268/515] to-do --- CONTRIBUTING.md | 2 ++ src/engine/platform/tia.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51903d8b7..c6931ce8f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,7 @@ the coding style is described here: - indent switch cases - preprocessor directives not intended - if macro comprises more than one line, indent + - no new line after `template<>` - prefer built-in types: - `bool` - `signed char` or `unsigned char` are 8-bit @@ -81,6 +82,7 @@ just put your demo song in `demos/`! be noted there are some guidelines: - avoid Nintendo song covers. - avoid big label song covers. +- avoid poor quality songs. # Finishing diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index bebc1ff2e..ed556e4fa 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -118,6 +118,7 @@ void DivPlatformTIA::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (chan[i].insChanged) { + // TODO: fix 10xx bug here if (!chan[i].std.wave.will) { chan[i].shape=4; rWrite(0x15+i,chan[i].shape); From 808832864c505f54ea8079c126616b72417298ac Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 16:53:45 -0500 Subject: [PATCH 269/515] add another demo song by Raijin --- demos/Waterworld_-_Map.fur | Bin 0 -> 2795 bytes src/gui/about.cpp | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 demos/Waterworld_-_Map.fur diff --git a/demos/Waterworld_-_Map.fur b/demos/Waterworld_-_Map.fur new file mode 100644 index 0000000000000000000000000000000000000000..2bf8a7af78bf33271550a1a603323531e42269b6 GIT binary patch literal 2795 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 literal 0 HcmV?d00001 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index ae0792aef..65baf4fd3 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -49,6 +49,7 @@ const char* aboutLine[]={ "tildearrow", "BlastBrothers", "Mahbod Karamoozian", + "nicco1690", "Raijin", "", "-- documentation --", @@ -87,6 +88,7 @@ const char* aboutLine[]={ "nicco1690", "NikonTeen", "psdominator", + "Raijin", "SuperJet Spade", "TheDuccinator", "theloredev", From e226d09807d28edb5baefbed9e9c2f4c11345c0d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 17:15:05 -0500 Subject: [PATCH 270/515] TIA: fix 10xx not working when changing instrument --- src/engine/platform/tia.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index ed556e4fa..18bdcb0c3 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -117,14 +117,6 @@ void DivPlatformTIA::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - if (chan[i].insChanged) { - // TODO: fix 10xx bug here - if (!chan[i].std.wave.will) { - chan[i].shape=4; - rWrite(0x15+i,chan[i].shape); - } - chan[i].insChanged=false; - } chan[i].freq=dealWithFreq(chan[i].shape,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2; if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) { if (chan[i].baseFreq<39*256) { @@ -165,6 +157,13 @@ int DivPlatformTIA::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } + if (chan[c.chan].insChanged) { + if (!chan[c.chan].std.wave.will) { + chan[c.chan].shape=4; + rWrite(0x15+c.chan,chan[c.chan].shape); + } + chan[c.chan].insChanged=false; + } if (isMuted[c.chan]) { rWrite(0x19+c.chan,0); } else { From 05b5265bbb0c90998f962ab20396484c9bf4949c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 19:46:48 -0500 Subject: [PATCH 271/515] YM2612: #632 --- src/engine/platform/genesis.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 0260ea06c..143a90fe8 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -279,10 +279,24 @@ void DivPlatformGenesis::tick(bool sysTick) { } } - if (chan[i].std.panL.had) { - chan[i].pan=chan[i].std.panL.val&3; - if (i<6) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + if (i>=5 && chan[i].furnaceDac) { + if (chan[i].std.panL.had) { + chan[5].pan&=1; + chan[5].pan|=chan[i].std.panL.val?2:0; + } + if (chan[i].std.panR.had) { + chan[5].pan&=2; + chan[5].pan|=chan[i].std.panR.val?1:0; + } + if (chan[i].std.panL.had || chan[i].std.panR.had) { + rWrite(chanOffs[5]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[5].pan<<6))|(chan[5].state.fms&7)|((chan[5].state.ams&3)<<4)); + } + } else { + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + if (i<6) { + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + } } } From e88e0a4e4ef6ece61866480f7c9463f4905d700c Mon Sep 17 00:00:00 2001 From: aurora Date: Mon, 22 Aug 2022 03:47:00 +0300 Subject: [PATCH 272/515] GUI: Remember window x/y position and maximized state. Warning: This may cause issues when windows are re-ordered. Is there a way to fix windows spawning outside of screen boundaries? --- src/gui/gui.cpp | 61 +++++++++++++++++++++++++++++++++++++------------ src/gui/gui.h | 8 ++++--- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9189618df..20c3fc58d 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -862,7 +862,7 @@ void FurnaceGUI::stopPreviewNote(SDL_Scancode scancode, bool autoNote) { void FurnaceGUI::noteInput(int num, int key, int vol) { DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],true); - + prepareUndo(GUI_UNDO_PATTERN_EDIT); if (key==100) { // note off @@ -2103,7 +2103,7 @@ void FurnaceGUI::editOptions(bool topMenu) { snprintf(id,63,"%.2x##LatchFX",data); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]); } - + if (ImGui::Selectable(id,latchTarget==3,ImGuiSelectableFlags_DontClosePopups)) { latchTarget=3; latchNibble=false; @@ -2176,7 +2176,7 @@ void FurnaceGUI::editOptions(bool topMenu) { doTranspose(transposeAmount,opMaskTransposeValue); ImGui::CloseCurrentPopup(); } - + ImGui::Separator(); if (ImGui::MenuItem("interpolate",BIND_FOR(GUI_ACTION_PAT_INTERPOLATE))) doInterpolate(); if (ImGui::BeginMenu("change instrument...")) { @@ -2303,7 +2303,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) { if (mobileUI!=enable || force) { if (!mobileUI && enable) { ImGui::SaveIniSettingsToDisk(finalLayoutPath); - } + } mobileUI=enable; if (mobileUI) { ImGui::GetIO().IniFilename=NULL; @@ -2311,7 +2311,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) { ImGui::GetIO().IniFilename=finalLayoutPath; ImGui::LoadIniSettingsFromDisk(finalLayoutPath); } - } + } } int _processEvent(void* instance, SDL_Event* event) { @@ -2536,6 +2536,7 @@ bool FurnaceGUI::loop() { if (settings.powerSave) SDL_WaitEventTimeout(NULL,500); } eventTimeBegin=SDL_GetPerformanceCounter(); + bool updateWindow = false; while (SDL_PollEvent(&ev)) { WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); @@ -2642,6 +2643,20 @@ bool FurnaceGUI::loop() { scrW=ev.window.data1/dpiScale; scrH=ev.window.data2/dpiScale; #endif + updateWindow=true; + break; + case SDL_WINDOWEVENT_MOVED: + scrX=ev.window.data1; + scrY=ev.window.data2; + updateWindow=true; + break; + case SDL_WINDOWEVENT_MAXIMIZED: + scrMax=true; + updateWindow=true; + break; + case SDL_WINDOWEVENT_RESTORED: + scrMax=false; + updateWindow=true; break; } break; @@ -2697,6 +2712,18 @@ bool FurnaceGUI::loop() { } } + // update config x/y/w/h values based on scrMax state + if(updateWindow) { + if(scrMax) { + scrConfY=scrConfX = SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(sdlWin)); + } else { + scrConfX=scrX; + scrConfY=scrY; + scrConfW=scrW; + scrConfH=scrH; + } + } + wantCaptureKeyboard=ImGui::GetIO().WantTextInput; if (wantCaptureKeyboard!=oldWantCaptureKeyboard) { @@ -2714,7 +2741,7 @@ bool FurnaceGUI::loop() { if (ImGui::GetIO().MouseDown[0] || ImGui::GetIO().MouseDown[1] || ImGui::GetIO().MouseDown[2] || ImGui::GetIO().MouseDown[3] || ImGui::GetIO().MouseDown[4]) { WAKE_UP; } - + while (true) { midiLock.lock(); if (midiQueue.empty()) { @@ -2870,7 +2897,7 @@ bool FurnaceGUI::loop() { eventTimeEnd=SDL_GetPerformanceCounter(); layoutTimeBegin=SDL_GetPerformanceCounter(); - + ImGui_ImplSDLRenderer_NewFrame(); ImGui_ImplSDL2_NewFrame(sdlWin); ImGui::NewFrame(); @@ -3125,7 +3152,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; if (spoilerOpen) if (ImGui::MenuItem("spoiler",NULL,spoilerOpen)) spoilerOpen=!spoilerOpen; - + ImGui::EndMenu(); } if (ImGui::BeginMenu("help")) { @@ -4263,7 +4290,7 @@ bool FurnaceGUI::loop() { } logD("saving backup..."); SafeWriter* w=e->saveFur(true); - + if (w!=NULL) { FILE* outFile=ps_fopen(backupPath.c_str(),"wb"); if (outFile!=NULL) { @@ -4436,8 +4463,11 @@ bool FurnaceGUI::init() { SDL_Surface* icon=SDL_CreateRGBSurfaceFrom(furIcon,256,256,32,256*4,0xff,0xff00,0xff0000,0xff000000); #endif - scrW=e->getConfInt("lastWindowWidth",1280); - scrH=e->getConfInt("lastWindowHeight",800); + scrW=scrConfW=e->getConfInt("lastWindowWidth",1280); + scrH=scrConfH=e->getConfInt("lastWindowHeight",800); + scrX=scrConfX=e->getConfInt("lastWindowX",SDL_WINDOWPOS_CENTERED); + scrY=scrConfY=e->getConfInt("lastWindowY",SDL_WINDOWPOS_CENTERED); + scrMax=e->getConfBool("lastWindowMax",false); #ifndef __APPLE__ SDL_Rect displaySize; @@ -4453,7 +4483,7 @@ bool FurnaceGUI::init() { SDL_Init(SDL_INIT_VIDEO); - sdlWin=SDL_CreateWindow("Furnace",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI|(fullScreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); + sdlWin=SDL_CreateWindow("Furnace",scrX,scrY,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI|(scrMax?SDL_WINDOW_MAXIMIZED:0)|(fullScreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); if (sdlWin==NULL) { logE("could not open window! %s",SDL_GetError()); return false; @@ -4619,8 +4649,11 @@ bool FurnaceGUI::finish() { e->setConf("spoilerOpen",spoilerOpen); // commit last window size - e->setConf("lastWindowWidth",scrW); - e->setConf("lastWindowHeight",scrH); + e->setConf("lastWindowWidth",scrConfW); + e->setConf("lastWindowHeight",scrConfH); + e->setConf("lastWindowX",scrConfX); + e->setConf("lastWindowY",scrConfY); + e->setConf("lastWindowMax",scrMax); e->setConf("tempoView",tempoView); e->setConf("waveHex",waveHex); diff --git a/src/gui/gui.h b/src/gui/gui.h index 8a3548f2f..7d42eb84e 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -996,7 +996,9 @@ class FurnaceGUI { FurnaceGUIFileDialog* fileDialog; - int scrW, scrH; + int scrW, scrH, scrConfW, scrConfH; + int scrX, scrY, scrConfX, scrConfY; + bool scrMax; double dpiScale; @@ -1429,7 +1431,7 @@ class FurnaceGUI { int chanToMove; ImVec2 patWindowPos, patWindowSize; - + // pattern view specific ImVec2 fourChars, threeChars, twoChars; ImVec2 noteCellSize, insCellSize, volCellSize, effectCellSize, effectValCellSize; @@ -1505,7 +1507,7 @@ class FurnaceGUI { // visualizer float keyHit[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; - + // log window bool followLog; From 10aaf7f0cb9dcddad32a444125cef56224e17abd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 19:57:01 -0500 Subject: [PATCH 273/515] YM2612: #580 --- src/engine/platform/genesisext.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 1f320dd34..dfd7d514c 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -561,6 +561,11 @@ void DivPlatformGenesisExt::forceIns() { opChan[i].freqChanged=true; } } + if (extMode && softPCM && chan[7].active) { // CSM + chan[7].insChanged=true; + chan[7].freqChanged=true; + chan[7].keyOn=true; + } } void* DivPlatformGenesisExt::getChanState(int ch) { From b223bc80de9f16fc137f033e7ed50d0037cebbe1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 20:06:01 -0500 Subject: [PATCH 274/515] YM2612: #581 --- src/engine/platform/genesis.cpp | 36 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 143a90fe8..7dde9790e 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -263,19 +263,37 @@ void DivPlatformGenesis::tick(bool sysTick) { } } - if (chan[i].std.arp.had) { - if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); + if (i>=5 && chan[i].furnaceDac) { + if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + if (chan[i].std.arp.mode) { + chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].std.arp.val,false); + } else { + chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].note+(signed char)chan[i].std.arp.val,false); + } + } + chan[i].freqChanged=true; + } else { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { + chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].note,false); + chan[i].freqChanged=true; } } - chan[i].freqChanged=true; } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); + if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); + } else { + chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); + } + } chan[i].freqChanged=true; + } else { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { + chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); + chan[i].freqChanged=true; + } } } From 38afdd3378bcac8878c41d6442f6b54caf50c458 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 23:56:58 -0500 Subject: [PATCH 275/515] dev110 - add cut/delay effect policy compat flag INCOMPLETE!!! --- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 15 +++++++++++++-- src/engine/playback.cpp | 5 ++++- src/engine/song.h | 6 ++++++ src/gui/compatFlags.cpp | 20 ++++++++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index c433def8e..d379540c5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev109" -#define DIV_ENGINE_VERSION 109 +#define DIV_VERSION "dev110" +#define DIV_ENGINE_VERSION 110 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index df32f0553..e64e02a04 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -176,6 +176,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; ds.snNoLowPeriods=true; + ds.delayBehavior=0; // 1.1 compat flags if (ds.version>24) { @@ -1067,6 +1068,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<108) { ds.snNoLowPeriods=true; } + if (ds.version<110) { + ds.delayBehavior=1; + } ds.isDMF=false; reader.readS(); // reserved @@ -1484,7 +1488,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<6; i++) { + if (ds.version>=110) { + ds.delayBehavior=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<5; i++) { reader.readC(); } } @@ -1917,6 +1926,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { ds.noSlidesOnFirstTick=true; ds.rowResetsArpPos=true; ds.ignoreJumpAtEnd=false; + ds.delayBehavior=0; int insCount=31; bool bypassLimits=false; @@ -3729,7 +3739,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.e1e2StopOnSameNote); w->writeC(song.brokenPortaArp); w->writeC(song.snNoLowPeriods); - for (int i=0; i<6; i++) { + w->writeC(song.delayBehavior); + for (int i=0; i<5; i++) { w->writeC(0); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 63203ab54..fbd9e8db3 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -361,7 +361,9 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xed: // delay if (effectVal!=0) { - if (effectVal<=nextSpeed) { + bool comparison=(song.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal%d",effectVal,nextSpeed); chan[i].delayLocked=false; } } diff --git a/src/engine/song.h b/src/engine/song.h index 30f5ef245..83509efbf 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -463,6 +463,11 @@ struct DivSong { // 1: fake reset on loop // 2: don't do anything on loop unsigned char loopModality; + // cut/delay effect behavior + // 0: strict (don't allow value higher than or equal to speed) + // 1: broken (don't allow value higher than speed) + // 2: lax (allow value higher than speed) + unsigned char delayBehavior; bool properNoiseLayout; bool waveDutyIsVol; bool resetMacroOnPorta; @@ -565,6 +570,7 @@ struct DivSong { linearPitch(2), pitchSlideSpeed(4), loopModality(0), + delayBehavior(2), properNoiseLayout(true), waveDutyIsVol(false), resetMacroOnPorta(false), diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index e6d0aed85..74d493e7f 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -193,6 +193,26 @@ void FurnaceGUI::drawCompatFlags() { ImGui::SetTooltip("select to not reset channels on loop."); } + ImGui::Text("Cut/delay effect policy:"); + if (ImGui::RadioButton("Strict",e->song.delayBehavior==0)) { + e->song.delayBehavior=0; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("only when time is less than speed (like DefleMask/ProTracker)"); + } + if (ImGui::RadioButton("Strict (old)",e->song.delayBehavior==1)) { + e->song.delayBehavior=1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("only when time is less than or equal to speed (original buggy behavior)"); + } + if (ImGui::RadioButton("Lax",e->song.delayBehavior==2)) { + e->song.delayBehavior=2; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("no checks (like FamiTracker)"); + } + ImGui::Separator(); ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions."); From 629cca9df19560e34af4586337e9f1207fe1214e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 00:01:21 -0500 Subject: [PATCH 276/515] ECxx --- src/engine/playback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index fbd9e8db3..8c8fa5729 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -707,7 +707,7 @@ void DivEngine::processRow(int i, bool afterDelay) { dispatchCmd(DivCommand(DIV_CMD_SAMPLE_BANK,i,effectVal)); break; case 0xec: // delayed note cut - if (effectVal>0 && effectVal0 && (song.delayBehavior==2 || effectVal Date: Mon, 22 Aug 2022 00:20:40 -0500 Subject: [PATCH 277/515] allow it --- src/engine/playback.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8c8fa5729..f4c4968d1 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -382,6 +382,8 @@ void DivEngine::processRow(int i, bool afterDelay) { } } if (returnAfterPre) return; + } else { + logV("honoring delay at position %d",whatRow); } if (chan[i].delayLocked) return; @@ -903,7 +905,9 @@ void DivEngine::nextRow() { prevRow=curRow; for (int i=0; i Date: Mon, 22 Aug 2022 13:11:29 +0700 Subject: [PATCH 278/515] new demo song.. --- demos/rule2.fur | Bin 0 -> 2179 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/rule2.fur diff --git a/demos/rule2.fur b/demos/rule2.fur new file mode 100644 index 0000000000000000000000000000000000000000..aa6375916934671667382ca2232272e3c6d3f3f8 GIT binary patch literal 2179 zcmV-}2z>W=ob6m)Y#h}UK6hqzcKuV9kUzI|vXhpdB;?m24L=Xw#lbjD;-5GM3@LQt zY{|lU*Ilm(RwdR7s#2;5@qiFQP}+yKLMlJv0U@MT8|8rqr1k-Vc;F$1_MuW~snk?e za6FtlbH{UcJ=Z(etRsfbalZAPGv|Ki-gEBknYruD_TH&d!5qsPQc{)Q18!_d99 z3SdVEz^fYpR^JHl$~J)RTL3QH0g&qf_}_kj@w))bUH}X6Odr6e9|F925TNHUzz6*R z*+GE+4gs7Q2Iv?;j(Y%ZzYpNOQGjC)0DN`~;E4wTl0OFcwF$6$%pHvbMdgpYmj6+$ zU}sg+VtPDI6vByb0B5>k!888T+>j`?`Z@e@WAwRtZ zj-JdKN3v!IDJnk*0+nPuZdae4gj0RSP8LfiLS25!0yEHqNviy;sMt-7O3Hw&!arPkl zSTR2}o(=WA#8-Kg{at{5(W7j5eaZF>yEHqNviy;sMt-9DW7nTktp5CTDwi$)-@rA^wi| zE8-&JW5h>@_Yr?VyoY!faUSs}#5;($5N{%0MZALeE#fzbmk`e*o<%%^IEy%gcoI=T z{0wmlQ39F-fJYENL70diAx04+h#|xwL?2>5BF*MYH+bnLF5RT18?khQm2RTaO;WlM zN~)bR*I)UG?#ZHW|a~OSW&=rP;BR<&XR{@)K2AyUISz9`eTW#fi{XS(-jg zz!fAh^rN_T*B0-&Cuf}+;P%MSELeXcOrJe)b-$9b3a%kreJu7+=Rps#dlI&mZAUvB;7ChGJb)OmmA$X)O`t;7Ez@Q2f$PpYf;`Du6O{P|g{dmi)LIZvwe@Eqx! z{}iiql^Qr}p<3Ik<|?ZVUQ&39KjZP)&d<+wcUI5MQs)HbaHZO#!WU>J_ z!#$g!bEf~t$AA;)Th+yZrn>q`lWDkAu><`EnIBG9dZruEO@$}`kUzq8QaOGt(v97m0KXcof4^rvD3!TT_x7J<+xHsK?$+GUf zFgFud*IXRT96j zj2lCcgw*Q&`FVSO%s~?3&m-m+B*f`(f?Ewdf!9_AdL@882-?l!S5}z+DvaMti1!vB z>IwPqQ}JtG4IBR}grB=o+jbM;mJ#|^LqP2O>)zHwK7KACZVd_dgjPBsswBVkc-(}z z+ktH%Pe^OX$Im5%L5r zCB(h$)$qqL3PPYW`+9vspl=oE#cvV*_H6=vyN`YrGQznKoVg#5D$vW?>yq|dLYy04 zKZmn$r>}mgz{mz(l)z>z1Ui1%l`6XsMD}sXd2tC**%d-_=T6#d^ZMF>c=|T3O^cbI zy~^o%8&zPh32ZchJ Date: Mon, 22 Aug 2022 02:13:33 -0500 Subject: [PATCH 279/515] dev111 - many macro changes - max macro length is now 255 - loop/rel pos is now unsigned (255 = no) - prepare for macro speed/delay --- papers/format.md | 96 ++++++++++++++++++- src/engine/engine.h | 4 +- src/engine/fileOps.cpp | 24 ++--- src/engine/instrument.cpp | 190 +++++++++++++++++++++++++++++++++++++- src/engine/instrument.h | 11 +-- src/engine/macroInt.cpp | 8 +- src/gui/gui.cpp | 14 +-- src/gui/gui.h | 4 +- src/gui/insEdit.cpp | 37 ++++---- 9 files changed, 333 insertions(+), 55 deletions(-) diff --git a/papers/format.md b/papers/format.md index 7bd3bba7e..4d9c15a24 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,9 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 111: Furnace dev111 +- 110: Furnace dev110 +- 109: Furnace dev109 - 108: Furnace dev108 - 107: Furnace dev107 - 106: Furnace dev106 @@ -333,7 +336,8 @@ size | description 1 | E1xy and E2xy stop on same note (>=100) or reserved 1 | broken initial position of porta after arp (>=101) or reserved 1 | SN periods under 8 are treated as 1 (>=108) or reserved - 6 | reserved + 1 | cut/delay effect policy (>=110) or reserved + 5 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved @@ -868,6 +872,96 @@ size | description 1 | K2 ramp 1 | K1 slow 1 | K2 slow + --- | **SNES data** (>=109) + 1 | use envelope + 1 | gain mode + 1 | gain + 1 | attack + 1 | decay + 1 | sustain + 1 | release + --- | **macro speeds/delays** (>=111) + 1 | volume macro speed + 1 | arp macro speed + 1 | duty macro speed + 1 | wave macro speed + 1 | pitch macro speed + 1 | extra 1 macro speed + 1 | extra 2 macro speed + 1 | extra 3 macro speed + 1 | alg macro speed + 1 | fb macro speed + 1 | fms macro speed + 1 | ams macro speed + 1 | left panning macro speed + 1 | right panning macro speed + 1 | phase reset macro speed + 1 | extra 4 macro speed + 1 | extra 5 macro speed + 1 | extra 6 macro speed + 1 | extra 7 macro speed + 1 | extra 8 macro speed + 1 | volume macro delay + 1 | arp macro delay + 1 | duty macro delay + 1 | wave macro delay + 1 | pitch macro delay + 1 | extra 1 macro delay + 1 | extra 2 macro delay + 1 | extra 3 macro delay + 1 | alg macro delay + 1 | fb macro delay + 1 | fms macro delay + 1 | ams macro delay + 1 | left panning macro delay + 1 | right panning macro delay + 1 | phase reset macro delay + 1 | extra 4 macro delay + 1 | extra 5 macro delay + 1 | extra 6 macro delay + 1 | extra 7 macro delay + 1 | extra 8 macro delay + --- | **operator macro speeds/delay** × 4 (>=111) + 1 | AM macro speed + 1 | AR macro speed + 1 | DR macro speed + 1 | MULT macro speed + 1 | RR macro speed + 1 | SL macro speed + 1 | TL macro speed + 1 | DT2 macro speed + 1 | RS macro speed + 1 | DT macro speed + 1 | D2R macro speed + 1 | SSG-EG macro speed + 1 | DAM macro speed + 1 | DVB macro speed + 1 | EGT macro speed + 1 | KSL macro speed + 1 | SUS macro speed + 1 | VIB macro speed + 1 | WS macro speed + 1 | KSR macro speed + 1 | AM macro delay + 1 | AR macro delay + 1 | DR macro delay + 1 | MULT macro delay + 1 | RR macro delay + 1 | SL macro delay + 1 | TL macro delay + 1 | DT2 macro delay + 1 | RS macro delay + 1 | DT macro delay + 1 | D2R macro delay + 1 | SSG-EG macro delay + 1 | DAM macro delay + 1 | DVB macro delay + 1 | EGT macro delay + 1 | KSL macro delay + 1 | SUS macro delay + 1 | VIB macro delay + 1 | WS macro delay + 1 | KSR macro delay ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index d379540c5..363210ab2 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev110" -#define DIV_ENGINE_VERSION 110 +#define DIV_VERSION "dev111" +#define DIV_ENGINE_VERSION 111 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index e64e02a04..32b98d2e7 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2843,9 +2843,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { // TODO: <= or std.volMacro.val[ins->std.volMacro.len]=lastVal; - if (++ins->std.volMacro.len>=128) break; + if (++ins->std.volMacro.len>=255) break; } - if (ins->std.volMacro.len>=128) break; + if (ins->std.volMacro.len>=255) break; } else if (m.val[j]==0xe9 || m.val[j]==0xea) { // volume slide if (++j>=64) break; signed char slideStep=m.val[j]; @@ -2864,16 +2864,16 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } ins->std.volMacro.val[ins->std.volMacro.len]=lastVal; - if (++ins->std.volMacro.len>=128) break; + if (++ins->std.volMacro.len>=255) break; } } else { // TODO: replace with upcoming macro speed for (int k=0; kstd.volMacro.val[ins->std.volMacro.len]=m.val[j]; lastVal=m.val[j]; - if (++ins->std.volMacro.len>=128) break; + if (++ins->std.volMacro.len>=255) break; } - if (ins->std.volMacro.len>=128) break; + if (ins->std.volMacro.len>=255) break; } } @@ -2902,7 +2902,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.waveMacro.val[ins->std.waveMacro.len]=wave-10; ins->std.waveMacro.open=true; lastVal=wave; - //if (++ins->std.arpMacro.len>=128) break; + //if (++ins->std.arpMacro.len>=255) break; } } else if (fm.val[j]==0xe0) { if (++j>=64) break; @@ -2932,8 +2932,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.waveMacro.val[ins->std.waveMacro.len]=lastVal-10; } ins->std.arpMacro.open=true; - if (++ins->std.arpMacro.len>=128) break; - if (++ins->std.waveMacro.len>=128) break; + if (++ins->std.arpMacro.len>=255) break; + if (++ins->std.waveMacro.len>=255) break; } } } @@ -2946,7 +2946,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { // vibrato for (int j=0; j<=vibDelay; j++) { ins->std.pitchMacro.val[ins->std.pitchMacro.len]=0; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } int vibPos=0; ins->std.pitchMacro.loop=ins->std.pitchMacro.len; @@ -2954,19 +2954,19 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { vibPos+=vibSpeed; if (vibPos>vibDepth) vibPos=vibDepth; ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } while (vibPosstd.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } while (vibPos>-vibDepth); do { vibPos+=vibSpeed; if (vibPos>0) vibPos=0; ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } while (vibPos<0); ds.ins.push_back(ins); diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 9f1f5fff6..b2203ebf6 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -564,6 +564,96 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(snes.s); w->writeC(snes.r); + // macro speed/delay + w->writeC(std.volMacro.speed); + w->writeC(std.arpMacro.speed); + w->writeC(std.dutyMacro.speed); + w->writeC(std.waveMacro.speed); + w->writeC(std.pitchMacro.speed); + w->writeC(std.ex1Macro.speed); + w->writeC(std.ex2Macro.speed); + w->writeC(std.ex3Macro.speed); + w->writeC(std.algMacro.speed); + w->writeC(std.fbMacro.speed); + w->writeC(std.fmsMacro.speed); + w->writeC(std.amsMacro.speed); + w->writeC(std.panLMacro.speed); + w->writeC(std.panRMacro.speed); + w->writeC(std.phaseResetMacro.speed); + w->writeC(std.ex4Macro.speed); + w->writeC(std.ex5Macro.speed); + w->writeC(std.ex6Macro.speed); + w->writeC(std.ex7Macro.speed); + w->writeC(std.ex8Macro.speed); + + w->writeC(std.volMacro.delay); + w->writeC(std.arpMacro.delay); + w->writeC(std.dutyMacro.delay); + w->writeC(std.waveMacro.delay); + w->writeC(std.pitchMacro.delay); + w->writeC(std.ex1Macro.delay); + w->writeC(std.ex2Macro.delay); + w->writeC(std.ex3Macro.delay); + w->writeC(std.algMacro.delay); + w->writeC(std.fbMacro.delay); + w->writeC(std.fmsMacro.delay); + w->writeC(std.amsMacro.delay); + w->writeC(std.panLMacro.delay); + w->writeC(std.panRMacro.delay); + w->writeC(std.phaseResetMacro.delay); + w->writeC(std.ex4Macro.delay); + w->writeC(std.ex5Macro.delay); + w->writeC(std.ex6Macro.delay); + w->writeC(std.ex7Macro.delay); + w->writeC(std.ex8Macro.delay); + + // op macro speed/delay + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + w->writeC(op.amMacro.speed); + w->writeC(op.arMacro.speed); + w->writeC(op.drMacro.speed); + w->writeC(op.multMacro.speed); + w->writeC(op.rrMacro.speed); + w->writeC(op.slMacro.speed); + w->writeC(op.tlMacro.speed); + w->writeC(op.dt2Macro.speed); + w->writeC(op.rsMacro.speed); + w->writeC(op.dtMacro.speed); + w->writeC(op.d2rMacro.speed); + w->writeC(op.ssgMacro.speed); + w->writeC(op.damMacro.speed); + w->writeC(op.dvbMacro.speed); + w->writeC(op.egtMacro.speed); + w->writeC(op.kslMacro.speed); + w->writeC(op.susMacro.speed); + w->writeC(op.vibMacro.speed); + w->writeC(op.wsMacro.speed); + w->writeC(op.ksrMacro.speed); + + w->writeC(op.amMacro.delay); + w->writeC(op.arMacro.delay); + w->writeC(op.drMacro.delay); + w->writeC(op.multMacro.delay); + w->writeC(op.rrMacro.delay); + w->writeC(op.slMacro.delay); + w->writeC(op.tlMacro.delay); + w->writeC(op.dt2Macro.delay); + w->writeC(op.rsMacro.delay); + w->writeC(op.dtMacro.delay); + w->writeC(op.d2rMacro.delay); + w->writeC(op.ssgMacro.delay); + w->writeC(op.damMacro.delay); + w->writeC(op.dvbMacro.delay); + w->writeC(op.egtMacro.delay); + w->writeC(op.kslMacro.delay); + w->writeC(op.susMacro.delay); + w->writeC(op.vibMacro.delay); + w->writeC(op.wsMacro.delay); + w->writeC(op.ksrMacro.delay); + } + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); @@ -960,15 +1050,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // clear noise macro if PCE instrument and version<63 if (version<63 && type==DIV_INS_PCE) { std.dutyMacro.len=0; - std.dutyMacro.loop=-1; - std.dutyMacro.rel=-1; + std.dutyMacro.loop=255; + std.dutyMacro.rel=255; } // clear wave macro if OPLL instrument and version<70 if (version<70 && type==DIV_INS_OPLL) { std.waveMacro.len=0; - std.waveMacro.loop=-1; - std.waveMacro.rel=-1; + std.waveMacro.loop=255; + std.waveMacro.rel=255; } // sample map @@ -1160,6 +1250,98 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { snes.r=reader.readC(); } + // macro speed/delay + if (version>=111) { + std.volMacro.speed=reader.readC(); + std.arpMacro.speed=reader.readC(); + std.dutyMacro.speed=reader.readC(); + std.waveMacro.speed=reader.readC(); + std.pitchMacro.speed=reader.readC(); + std.ex1Macro.speed=reader.readC(); + std.ex2Macro.speed=reader.readC(); + std.ex3Macro.speed=reader.readC(); + std.algMacro.speed=reader.readC(); + std.fbMacro.speed=reader.readC(); + std.fmsMacro.speed=reader.readC(); + std.amsMacro.speed=reader.readC(); + std.panLMacro.speed=reader.readC(); + std.panRMacro.speed=reader.readC(); + std.phaseResetMacro.speed=reader.readC(); + std.ex4Macro.speed=reader.readC(); + std.ex5Macro.speed=reader.readC(); + std.ex6Macro.speed=reader.readC(); + std.ex7Macro.speed=reader.readC(); + std.ex8Macro.speed=reader.readC(); + + std.volMacro.delay=reader.readC(); + std.arpMacro.delay=reader.readC(); + std.dutyMacro.delay=reader.readC(); + std.waveMacro.delay=reader.readC(); + std.pitchMacro.delay=reader.readC(); + std.ex1Macro.delay=reader.readC(); + std.ex2Macro.delay=reader.readC(); + std.ex3Macro.delay=reader.readC(); + std.algMacro.delay=reader.readC(); + std.fbMacro.delay=reader.readC(); + std.fmsMacro.delay=reader.readC(); + std.amsMacro.delay=reader.readC(); + std.panLMacro.delay=reader.readC(); + std.panRMacro.delay=reader.readC(); + std.phaseResetMacro.delay=reader.readC(); + std.ex4Macro.delay=reader.readC(); + std.ex5Macro.delay=reader.readC(); + std.ex6Macro.delay=reader.readC(); + std.ex7Macro.delay=reader.readC(); + std.ex8Macro.delay=reader.readC(); + + // op macro speed/delay + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + op.amMacro.speed=reader.readC(); + op.arMacro.speed=reader.readC(); + op.drMacro.speed=reader.readC(); + op.multMacro.speed=reader.readC(); + op.rrMacro.speed=reader.readC(); + op.slMacro.speed=reader.readC(); + op.tlMacro.speed=reader.readC(); + op.dt2Macro.speed=reader.readC(); + op.rsMacro.speed=reader.readC(); + op.dtMacro.speed=reader.readC(); + op.d2rMacro.speed=reader.readC(); + op.ssgMacro.speed=reader.readC(); + op.damMacro.speed=reader.readC(); + op.dvbMacro.speed=reader.readC(); + op.egtMacro.speed=reader.readC(); + op.kslMacro.speed=reader.readC(); + op.susMacro.speed=reader.readC(); + op.vibMacro.speed=reader.readC(); + op.wsMacro.speed=reader.readC(); + op.ksrMacro.speed=reader.readC(); + + op.amMacro.delay=reader.readC(); + op.arMacro.delay=reader.readC(); + op.drMacro.delay=reader.readC(); + op.multMacro.delay=reader.readC(); + op.rrMacro.delay=reader.readC(); + op.slMacro.delay=reader.readC(); + op.tlMacro.delay=reader.readC(); + op.dt2Macro.delay=reader.readC(); + op.rsMacro.delay=reader.readC(); + op.dtMacro.delay=reader.readC(); + op.d2rMacro.delay=reader.readC(); + op.ssgMacro.delay=reader.readC(); + op.damMacro.delay=reader.readC(); + op.dvbMacro.delay=reader.readC(); + op.egtMacro.delay=reader.readC(); + op.kslMacro.delay=reader.readC(); + op.susMacro.delay=reader.readC(); + op.vibMacro.delay=reader.readC(); + op.wsMacro.delay=reader.readC(); + op.ksrMacro.delay=reader.readC(); + } + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index da6d08415..e5372933d 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -165,21 +165,20 @@ struct DivInstrumentMacro { int val[256]; unsigned int mode; bool open; - unsigned char len; - signed char loop; - signed char rel; + unsigned char len, delay, speed, loop, rel; // the following variables are used by the GUI and not saved in the file int vScroll, vZoom; - explicit DivInstrumentMacro(const String& n, bool initOpen=false): name(n), mode(0), open(initOpen), len(0), - loop(-1), - rel(-1), + delay(0), + speed(1), + loop(255), + rel(255), vScroll(0), vZoom(-1) { memset(val,0,256*sizeof(int)); diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 83ad906fa..1566b9438 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -43,15 +43,15 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic if (has) { lastPos=pos; val=source.val[pos++]; - if (source.rel>=0 && pos>source.rel && !released) { - if (source.loop=0 && source.loopsource.rel && !released) { + if (source.loop=source.len) { - if (source.loop=0 && (source.loop>=source.rel || source.rel>=source.len)) { + if (source.loop=source.rel || source.rel>=source.len)) { pos=source.loop; } else if (linger) { pos--; @@ -240,7 +240,7 @@ void DivMacroInt::init(DivInstrument* which) { for (size_t i=0; iprepare(*macroSource[i],e); - hasRelease=(macroSource[i]->rel>=0 && macroSource[i]->rellen); + hasRelease=(macroSource[i]->rellen); } else { hasRelease=false; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9189618df..b5ccbd7b2 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -276,13 +276,13 @@ void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int ma } } -void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, signed char& macroLoop, int macroMin, int macroMax, signed char& macroRel) { +void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel) { int buf=0; bool negaBuf=false; bool hasVal=false; macroLen=0; - macroLoop=-1; - macroRel=-1; + macroLoop=255; + macroRel=255; for (char& i: source) { switch (i) { case '0': case '1': case '2': case '3': case '4': @@ -318,7 +318,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe macroLen++; buf=0; } - if (macroLoop==-1) { + if (macroLoop==255) { macroLoop=macroLen; } break; @@ -332,14 +332,14 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe macroLen++; buf=0; } - if (macroRel==-1) { + if (macroRel==255) { macroRel=macroLen; } break; } - if (macroLen>=128) break; + if (macroLen>=255) break; } - if (hasVal && macroLen<128) { + if (hasVal && macroLen<255) { hasVal=false; macro[macroLen]=negaBuf?-buf:buf; negaBuf=false; diff --git a/src/gui/gui.h b/src/gui/gui.h index 8a3548f2f..f7b13b073 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1406,7 +1406,7 @@ class FurnaceGUI { ImVec2 macroLoopDragStart; ImVec2 macroLoopDragAreaSize; - signed char* macroLoopDragTarget; + unsigned char* macroLoopDragTarget; int macroLoopDragLen; bool macroLoopDragActive; @@ -1687,7 +1687,7 @@ class FurnaceGUI { void initSystemPresets(); void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false); - void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, signed char& macroLoop, int macroMin, int macroMax, signed char& macroRel); + void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel); void decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMax, bool hex=false); String encodeKeyMap(std::map& map); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index dc239fcd7..2a97744ff 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1215,14 +1215,14 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } ImGui::TableNextColumn(); float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; - int totalFit=MIN(128,availableWidth/MAX(1,macroPointSize*dpiScale)); - if (macroDragScroll>128-totalFit) { - macroDragScroll=128-totalFit; + int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); + if (macroDragScroll>255-totalFit) { + macroDragScroll=255-totalFit; } ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) { + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; } // draw macros @@ -1239,8 +1239,11 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } if (i.macro->open) { ImGui::SetNextItemWidth(lenAvail); - if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&i.macro->len,&_ONE,&_THREE)) { MARK_MODIFIED - if (i.macro->len>128) i.macro->len=128; + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; } // do not change this! // anything other than a checkbox will look ugly! @@ -1267,7 +1270,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { loopIndicator[j]=0; } else { - loopIndicator[j]=((i.macro->loop!=-1 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=-1 && (j+macroDragScroll)==i.macro->rel)<<1); + loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); } } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); @@ -1414,9 +1417,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - i.macro->rel=-1; + i.macro->rel=255; } else { - i.macro->loop=-1; + i.macro->loop=255; } } ImGui::SetNextItemWidth(availableWidth); @@ -1437,9 +1440,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) { + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; } ImGui::EndTable(); } @@ -4311,8 +4314,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::Separator(); if (ImGui::MenuItem("clear")) { lastMacroDesc.macro->len=0; - lastMacroDesc.macro->loop=-1; - lastMacroDesc.macro->rel=-1; + lastMacroDesc.macro->loop=255; + lastMacroDesc.macro->rel=255; for (int i=0; i<256; i++) { lastMacroDesc.macro->val[i]=0; } @@ -4341,15 +4344,15 @@ void FurnaceGUI::drawInsEdit() { lastMacroDesc.macro->val[i]=val; } - if (lastMacroDesc.macro->loop>=0 && lastMacroDesc.macro->looplen) { + if (lastMacroDesc.macro->looplen) { lastMacroDesc.macro->loop+=macroOffX; } else { - lastMacroDesc.macro->loop=-1; + lastMacroDesc.macro->loop=255; } if ((lastMacroDesc.macro->rel+macroOffX)>=0 && (lastMacroDesc.macro->rel+macroOffX)len) { lastMacroDesc.macro->rel+=macroOffX; } else { - lastMacroDesc.macro->rel=-1; + lastMacroDesc.macro->rel=255; } ImGui::CloseCurrentPopup(); From 3b6fa212b849aa83f5222cf5768f2d6286b384eb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 03:52:32 -0500 Subject: [PATCH 280/515] implement macro speed/delay --- src/engine/macroInt.cpp | 12 ++++++++++++ src/engine/macroInt.h | 10 +++++++--- src/gui/insEdit.cpp | 21 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 1566b9438..36850818f 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -32,6 +32,18 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic had=false; return; } + if (delay>0) { + delay--; + return; + } + if (began && source.delay>0) { + delay=source.delay; + } else { + delay=source.speed-1; + } + if (began) { + began=false; + } if (finished) { finished=false; } diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 8569dce42..ad761ba53 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -25,21 +25,24 @@ class DivEngine; struct DivMacroStruct { - int pos, lastPos; + int pos, lastPos, delay; int val; - bool has, had, actualHad, finished, will, linger; + bool has, had, actualHad, finished, will, linger, began; unsigned int mode; void doMacro(DivInstrumentMacro& source, bool released, bool tick); void init() { - pos=lastPos=mode=0; + pos=lastPos=mode=delay=0; has=had=actualHad=will=false; linger=false; + began=true; // TODO: test whether this breaks anything? val=0; } void prepare(DivInstrumentMacro& source, DivEngine* e); DivMacroStruct(): pos(0), + lastPos(0), + delay(0), val(0), has(false), had(false), @@ -47,6 +50,7 @@ struct DivMacroStruct { finished(false), will(false), linger(false), + began(false), mode(0) {} }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2a97744ff..f7e80c535 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1245,6 +1245,27 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (macroLen>255) macroLen=255; i.macro->len=macroLen; } + if (ImGui::Button(ICON_FA_BAR_CHART "##IMacroType")) { + + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Coming soon!"); + } + ImGui::SameLine(); + ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Delay/Step Length"); + } + if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { + if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { + if (i.macro->speed<1) i.macro->speed=1; + MARK_MODIFIED; + } + if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { + MARK_MODIFIED; + } + ImGui::EndPopup(); + } // do not change this! // anything other than a checkbox will look ugly! // if you really need more than two macro modes please tell me. From 6e87bc5dd6c5ad3255e0c2662c6eec640309c338 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 04:38:46 -0500 Subject: [PATCH 281/515] update format.md --- papers/format.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/papers/format.md b/papers/format.md index 4d9c15a24..cfe159edd 100644 --- a/papers/format.md +++ b/papers/format.md @@ -972,9 +972,9 @@ size | description 4 | "WAVE" block ID 4 | size of this block STR | wavetable name - 4 | wavetable size - 4 | wavetable min - 4 | wavetable max + 4 | wavetable width + 4 | reserved + 4 | wavetable height 4?? | wavetable data ``` From 8b3c4a84a81a3c9d72c3c1d3624e006be6136e09 Mon Sep 17 00:00:00 2001 From: aurora Date: Mon, 22 Aug 2022 22:05:16 +0300 Subject: [PATCH 282/515] implement bounds check for window spawning --- src/gui/gui.cpp | 40 +++++++++++++++++++++++++++++++++++++--- src/gui/gui.h | 1 + 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 20c3fc58d..204be1af6 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2517,6 +2517,35 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { } } +// how many pixels should be visible at least at x/y dir +#define OOB_PIXELS_SAFETY 25 + +bool FurnaceGUI::detectOutOfBoundsWindow() { + int count = SDL_GetNumVideoDisplays(); + if(count < 1) { + logW("bounds check: error %s", SDL_GetError()); + return false; + } + + SDL_Rect rect; + for(int i = 0;i < count;i ++) { + if(SDL_GetDisplayUsableBounds(i, &rect) != 0) { + logW("bounds check: error %s", SDL_GetError()); + return false; + } + + bool xbound = (rect.x + OOB_PIXELS_SAFETY) <= (scrX + scrW) && (rect.x + rect.w - OOB_PIXELS_SAFETY) >= scrX; + bool ybound = (rect.y + OOB_PIXELS_SAFETY) <= (scrY + scrH) && (rect.y + rect.h - OOB_PIXELS_SAFETY) >= scrY; + logD("bounds check: display %d is at %dx%dx%dx%d: %s%s", i, rect.x + OOB_PIXELS_SAFETY, rect.y + OOB_PIXELS_SAFETY, rect.x + rect.w - OOB_PIXELS_SAFETY, rect.y + rect.h - OOB_PIXELS_SAFETY, xbound ? "x" : "", ybound ? "y" : ""); + + if(xbound && ybound) { + return true; + } + } + + return false; +} + bool FurnaceGUI::loop() { bool doThreadedInput=!settings.noThreadedInput; if (doThreadedInput) { @@ -2714,9 +2743,7 @@ bool FurnaceGUI::loop() { // update config x/y/w/h values based on scrMax state if(updateWindow) { - if(scrMax) { - scrConfY=scrConfX = SDL_WINDOWPOS_CENTERED_DISPLAY(SDL_GetWindowDisplayIndex(sdlWin)); - } else { + if(!scrMax) { scrConfX=scrX; scrConfY=scrY; scrConfW=scrW; @@ -4483,6 +4510,13 @@ bool FurnaceGUI::init() { SDL_Init(SDL_INIT_VIDEO); + // if window would spawn out of bounds, force it to be get default position + if(!detectOutOfBoundsWindow()) { + scrMax = false; + scrX=scrConfX=SDL_WINDOWPOS_CENTERED; + scrY=scrConfY=SDL_WINDOWPOS_CENTERED; + } + sdlWin=SDL_CreateWindow("Furnace",scrX,scrY,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI|(scrMax?SDL_WINDOW_MAXIMIZED:0)|(fullScreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); if (sdlWin==NULL) { logE("could not open window! %s",SDL_GetError()); diff --git a/src/gui/gui.h b/src/gui/gui.h index 7d42eb84e..f4276f052 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1710,6 +1710,7 @@ class FurnaceGUI { void runBackupThread(); void pushPartBlend(); void popPartBlend(); + bool detectOutOfBoundsWindow(); int processEvent(SDL_Event* ev); bool loop(); bool finish(); From 0e847dc1aab974d8adf18ead6e73eda287f2919b Mon Sep 17 00:00:00 2001 From: aurora Date: Mon, 22 Aug 2022 22:17:19 +0300 Subject: [PATCH 283/515] add setting for choosing whether to save window position --- src/gui/gui.cpp | 4 ++-- src/gui/gui.h | 1 + src/gui/settings.cpp | 35 +++++++++++++++++++++++------------ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 204be1af6..76e2b8a16 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4685,8 +4685,8 @@ bool FurnaceGUI::finish() { // commit last window size e->setConf("lastWindowWidth",scrConfW); e->setConf("lastWindowHeight",scrConfH); - e->setConf("lastWindowX",scrConfX); - e->setConf("lastWindowY",scrConfY); + e->setConf("lastWindowX",settings.saveWindowPos?scrConfX:(int)SDL_WINDOWPOS_CENTERED); + e->setConf("lastWindowY",settings.saveWindowPos?scrConfY:(int)SDL_WINDOWPOS_CENTERED); e->setConf("lastWindowMax",scrMax); e->setConf("tempoView",tempoView); diff --git a/src/gui/gui.h b/src/gui/gui.h index f4276f052..21e4ecf53 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1129,6 +1129,7 @@ class FurnaceGUI { int dragMovesSelection; int unsignedDetune; int noThreadedInput; + int saveWindowPos; int clampSamples; int saveUnusedPatterns; int channelColors; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 03c32e655..cb720da43 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -259,7 +259,7 @@ void FurnaceGUI::drawSettings() { } ImGui::Separator(); - + ImGui::Text("Initial system:"); ImGui::SameLine(); if (ImGui::Button("Current system")) { @@ -369,7 +369,7 @@ void FurnaceGUI::drawSettings() { } rightClickable ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale)); CWSliderScalar("Panning",ImGuiDataType_S8,&settings.initialSys[i+2],&_MINUS_ONE_HUNDRED_TWENTY_SEVEN,&_ONE_HUNDRED_TWENTY_SEVEN); rightClickable - + // oh please MSVC don't cry if (ImGui::TreeNode("Configure")) { drawSysConf(-1,(DivSystem)settings.initialSys[i],(unsigned int&)settings.initialSys[i+3],false); @@ -452,7 +452,7 @@ void FurnaceGUI::drawSettings() { if (ImGui::Checkbox("Double click selects entire column",&doubleClickColumnB)) { settings.doubleClickColumn=doubleClickColumnB; } - + bool allowEditDockingB=settings.allowEditDocking; if (ImGui::Checkbox("Allow docking editors",&allowEditDockingB)) { settings.allowEditDocking=allowEditDockingB; @@ -509,6 +509,14 @@ void FurnaceGUI::drawSettings() { ImGui::SetTooltip("threaded input processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.\nhowever, crashes have been reported when threaded input is on. enable this option if that is the case."); } + bool saveWindowPosB=settings.saveWindowPos; + if (ImGui::Checkbox("Remember window location",&saveWindowPosB)) { + settings.saveWindowPos=saveWindowPosB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("remembers where window was last located on start-up. When disabled, window will start in a defaul location."); + } + bool blankInsB=settings.blankIns; if (ImGui::Checkbox("New instruments are blank",&blankInsB)) { settings.blankIns=blankInsB; @@ -639,7 +647,7 @@ void FurnaceGUI::drawSettings() { BUFFER_SIZE_SELECTABLE(2048); ImGui::EndCombo(); } - + ImGui::Text("Quality"); ImGui::SameLine(); ImGui::Combo("##Quality",&settings.audioQuality,audioQualities,2); @@ -697,7 +705,7 @@ void FurnaceGUI::drawSettings() { } if (hasToReloadMidi) { - midiMap.read(e->getConfigPath()+DIR_SEPARATOR_STR+"midiIn_"+stripName(settings.midiInDevice)+".cfg"); + midiMap.read(e->getConfigPath()+DIR_SEPARATOR_STR+"midiIn_"+stripName(settings.midiInDevice)+".cfg"); midiMap.compile(); } @@ -1344,7 +1352,7 @@ void FurnaceGUI::drawSettings() { if (ImGui::Checkbox("Unsigned FM detune values",&unsignedDetuneB)) { settings.unsignedDetune=unsignedDetuneB; } - + // sorry. temporarily disabled until ImGui has a way to add separators in tables arbitrarily. /*bool sysSeparatorsB=settings.sysSeparators; if (ImGui::Checkbox("Add separators between systems in Orders",&sysSeparatorsB)) { @@ -1553,12 +1561,12 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_FM_SECONDARY_MOD,"Mod. accent (secondary)"); UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_MOD,"Mod. border"); UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_SHADOW_MOD,"Mod. border shadow"); - + UI_COLOR_CONFIG(GUI_COLOR_FM_PRIMARY_CAR,"Car. accent (primary"); UI_COLOR_CONFIG(GUI_COLOR_FM_SECONDARY_CAR,"Car. accent (secondary)"); UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_CAR,"Car. border"); UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_SHADOW_CAR,"Car. border shadow"); - + ImGui::TreePop(); } if (ImGui::TreeNode("Macro Editor")) { @@ -1917,7 +1925,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_ROWS); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_ROWS); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_LATCH); - + // TODO: collapse/expand pattern and song KEYBIND_CONFIG_END; @@ -2213,6 +2221,7 @@ void FurnaceGUI::syncSettings() { settings.dragMovesSelection=e->getConfInt("dragMovesSelection",2); settings.unsignedDetune=e->getConfInt("unsignedDetune",0); settings.noThreadedInput=e->getConfInt("noThreadedInput",0); + settings.saveWindowPos=e->getConfInt("saveWindowPos",1); settings.initialSysName=e->getConfString("initialSysName",""); settings.clampSamples=e->getConfInt("clampSamples",0); settings.noteOffLabel=e->getConfString("noteOffLabel","OFF"); @@ -2313,6 +2322,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.dragMovesSelection,0,2); clampSetting(settings.unsignedDetune,0,1); clampSetting(settings.noThreadedInput,0,1); + clampSetting(settings.saveWindowPos,0,1); clampSetting(settings.clampSamples,0,1); clampSetting(settings.saveUnusedPatterns,0,1); clampSetting(settings.channelColors,0,2); @@ -2344,7 +2354,7 @@ void FurnaceGUI::syncSettings() { parseKeybinds(); - midiMap.read(e->getConfigPath()+DIR_SEPARATOR_STR+"midiIn_"+stripName(settings.midiInDevice)+".cfg"); + midiMap.read(e->getConfigPath()+DIR_SEPARATOR_STR+"midiIn_"+stripName(settings.midiInDevice)+".cfg"); midiMap.compile(); e->setMidiDirect(midiMap.directChannel); @@ -2458,6 +2468,7 @@ void FurnaceGUI::commitSettings() { e->setConf("dragMovesSelection",settings.dragMovesSelection); e->setConf("unsignedDetune",settings.unsignedDetune); e->setConf("noThreadedInput",settings.noThreadedInput); + e->setConf("saveWindowPos",settings.saveWindowPos); e->setConf("clampSamples",settings.clampSamples); e->setConf("noteOffLabel",settings.noteOffLabel); e->setConf("noteRelLabel",settings.noteRelLabel); @@ -3130,7 +3141,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) { logE("could not load icon font!"); } - + if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) { logD("using main font for pat font."); patFont=mainFont; @@ -3164,7 +3175,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { } } } - + if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) { logE("could not load big UI font!"); } From d406380773f25d8ce7940c98e98280bb446c9113 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 14:20:47 -0500 Subject: [PATCH 284/515] SoundUnit: fix some effect definitions --- src/engine/sysDef.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 63cb6faca..5ac6bf34e 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1429,15 +1429,15 @@ void DivEngine::registerSystems() { EffectHandlerMap suEffectHandlerMap={ {0x10, {DIV_CMD_WAVE, "10xx: Set waveform (0 to 7)"}}, - {0x12, {DIV_CMD_STD_NOISE_MODE, "22xx: Set envelope mode (bit 0: enable; bit 1: one-shot; bit 2: split shape to L/R; bit 3/5: H.invert right/left; bit 4/6: V.invert right/left)"}}, - {0x13, {DIV_CMD_C64_RESONANCE, "23xx: Set envelope period"}}, - {0x14, {DIV_CMD_C64_FILTER_MODE, "25xx: Envelope slide up"}}, + {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set pulse width (0 to 7F)"}}, + {0x13, {DIV_CMD_C64_RESONANCE, "13xx: Set resonance (0 to FF)"}}, + {0x14, {DIV_CMD_C64_FILTER_MODE, "14xx: Set filter mode (bit 0: ring mod; bit 1: low pass; bit 2: high pass; bit 3: band pass)"}}, {0x15, {DIV_CMD_SU_SWEEP_PERIOD_LOW, "15xx: Set frequency sweep period low byte", constVal<0>, effectVal}}, {0x16, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "16xx: Set frequency sweep period high byte", constVal<0>, effectVal}}, {0x17, {DIV_CMD_SU_SWEEP_PERIOD_LOW, "17xx: Set volume sweep period low byte", constVal<1>, effectVal}}, {0x18, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "18xx: Set volume sweep period high byte", constVal<1>, effectVal}}, {0x19, {DIV_CMD_SU_SWEEP_PERIOD_LOW, "19xx: Set cutoff sweep period low byte", constVal<2>, effectVal}}, - {0x1a, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "1axx: Set cutoff sweep period high byte", constVal<2>, effectVal}}, + {0x1a, {DIV_CMD_SU_SWEEP_PERIOD_HIGH, "1Axx: Set cutoff sweep period high byte", constVal<2>, effectVal}}, {0x1b, {DIV_CMD_SU_SWEEP_BOUND, "1Bxx: Set frequency sweep boundary", constVal<0>, effectVal}}, {0x1c, {DIV_CMD_SU_SWEEP_BOUND, "1Cxx: Set volume sweep boundary", constVal<1>, effectVal}}, {0x1d, {DIV_CMD_SU_SWEEP_BOUND, "1Dxx: Set cutoff sweep boundary", constVal<2>, effectVal}}, From c009cb3536645a9f6bb1d15f0baf6e835cf04a76 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 15:59:45 -0500 Subject: [PATCH 285/515] dev112 - prepare for advanced arp macro this new advanced arp macro offers more flexibility and reduces code duplication it allows you to set each step of the macro to either relative or fixed mode (instead of just one mode for the entire macro) the UI is still a work in progress and doesn't work well this change is big and may break things! further fixes incoming --- papers/format.md | 16 ++++++++++++- src/engine/engine.cpp | 5 ++++ src/engine/engine.h | 7 ++++-- src/engine/fileOps.cpp | 16 +++++++++---- src/engine/instrument.cpp | 15 +++++++++++- src/engine/platform/amiga.cpp | 14 ++--------- src/engine/platform/arcade.cpp | 11 +-------- src/engine/platform/ay.cpp | 11 +-------- src/engine/platform/ay8930.cpp | 11 +-------- src/engine/platform/bubsyswsg.cpp | 11 +-------- src/engine/platform/c64.cpp | 11 +-------- src/engine/platform/fds.cpp | 11 +-------- src/engine/platform/gb.cpp | 19 ++------------- src/engine/platform/genesis.cpp | 22 ++--------------- src/engine/platform/lynx.cpp | 19 +++------------ src/engine/platform/mmc5.cpp | 12 ++-------- src/engine/platform/n163.cpp | 11 +-------- src/engine/platform/namcowsg.cpp | 11 +-------- src/engine/platform/nes.cpp | 17 ++------------ src/engine/platform/opl.cpp | 22 ++--------------- src/engine/platform/opll.cpp | 11 +-------- src/engine/platform/pce.cpp | 22 +++-------------- src/engine/platform/pcmdac.cpp | 11 +-------- src/engine/platform/pcspkr.cpp | 11 +-------- src/engine/platform/pet.cpp | 11 +-------- src/engine/platform/qsound.cpp | 11 +-------- src/engine/platform/rf5c68.cpp | 11 +-------- src/engine/platform/saa.cpp | 11 +-------- src/engine/platform/scc.cpp | 11 +-------- src/engine/platform/segapcm.cpp | 11 +-------- src/engine/platform/sms.cpp | 22 +++++------------ src/engine/platform/su.cpp | 11 +-------- src/engine/platform/swan.cpp | 11 +-------- src/engine/platform/tia.cpp | 10 +++----- src/engine/platform/tx81z.cpp | 11 +-------- src/engine/platform/vera.cpp | 22 ++--------------- src/engine/platform/vic20.cpp | 11 +-------- src/engine/platform/vrc6.cpp | 11 +-------- src/engine/platform/x1_010.cpp | 11 +-------- src/engine/platform/ym2203.cpp | 11 +-------- src/engine/platform/ym2608.cpp | 22 ++--------------- src/engine/platform/ym2610.cpp | 22 ++--------------- src/engine/platform/ym2610b.cpp | 22 ++--------------- src/engine/platform/ymz280b.cpp | 11 +-------- src/engine/platform/zxbeeper.cpp | 11 +-------- src/gui/gui.cpp | 39 +++++++++++++++++++++++-------- src/gui/gui.h | 10 ++++---- src/gui/insEdit.cpp | 21 ++++++++++++++--- 48 files changed, 164 insertions(+), 518 deletions(-) diff --git a/papers/format.md b/papers/format.md index cfe159edd..def8cba16 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 112: Furnace dev112 - 111: Furnace dev111 - 110: Furnace dev110 - 109: Furnace dev109 @@ -454,6 +455,7 @@ size | description | - 29: SNES | - 30: Sound Unit | - 31: Namco WSG + | - 32: OPL (drums) 1 | reserved STR | instrument name --- | **FM instrument data** @@ -545,7 +547,18 @@ size | description 4 | extra 1 macro loop (>=17) 4 | extra 2 macro loop (>=17) 4 | extra 3 macro loop (>=17) - 1 | arp macro mode + 1 | arp macro mode (<112) or reserved + | - treat this value in a special way. + | - before version 112, this byte indicates whether the arp macro mode is fixed or not. + | - from that version onwards, the fixed mode is part of the macro values. + | - to convert a <112 macro mode to a modern one, do the following: + | - is the macro mode set to fixed? + | - if yes, then: + | - set bit 30 of all arp macro values (this is the fixed mode bit) + | - does the macro loop? + | - if yes, then do nothing else + | - if no, then add one to the macro length, and set the last macro value to 0 + | - if no, then do nothing 1 | reserved (>=17) or volume macro height (>=15) or reserved 1 | reserved (>=17) or duty macro height (>=15) or reserved 1 | reserved (>=17) or wave macro height (>=15) or reserved @@ -553,6 +566,7 @@ size | description | - before version 87, if this is the C64 relative cutoff macro, its values were stored offset by 18. 4?? | arp macro | - before version 31, this macro's values were stored offset by 12. + | - from version 112 onward, bit 30 of a value indicates fixed mode. 4?? | duty macro | - before version 87, if this is the C64 relative duty macro, its values were stored offset by 12. 4?? | wave macro diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 7bf184f0a..4ee8e48bb 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1712,6 +1712,11 @@ int DivEngine::calcFreq(int base, int pitch, bool period, int octave, int pitch2 base+((pitch*octave)>>1)+pitch2; } +int DivEngine::calcArp(int note, int arp, int offset) { + if (arp&0x40000000) return (arp&(~0x40000000))+offset; + return note+arp; +} + int DivEngine::convertPanSplitToLinear(unsigned int val, unsigned char bits, int range) { int panL=val>>bits; int panR=val&((1<std.arpMacro.len; j++) { ins->std.arpMacro.val[j]-=12; } + } else { + ins->std.arpMacro.mode=0; + for (int j=0; jstd.arpMacro.len; j++) { + ins->std.arpMacro.val[i]|=0x40000000; + } + if (ins->std.arpMacro.loopstd.arpMacro.len && ins->std.arpMacro.len<255) { + ins->std.arpMacro.val[ins->std.arpMacro.len++]=0; + } } ins->std.dutyMacro.len=reader.readC(); @@ -2886,9 +2894,6 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { loopMapFreq[j]=ins->std.arpMacro.len; loopMapWave[j]=ins->std.waveMacro.len; if (fm.val[j]==0xe1) { - if (ins->std.arpMacro.mode) { - ins->std.arpMacro.loop=(signed int)ins->std.arpMacro.len-1; - } break; } else if (fm.val[j]==0xe2 || fm.val[j]==0xe4) { if (++j>=64) break; @@ -2923,8 +2928,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { logV("unhandled pitch!"); } else { if (fm.val[j]>0x80) { - ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j]-0x80+24; - ins->std.arpMacro.mode=1; // TODO: variable fixed/relative mode + ins->std.arpMacro.val[ins->std.arpMacro.len]=(fm.val[j]-0x80+24)|0x40000000; } else { ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j]; } @@ -3293,6 +3297,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { ins->std.arpMacro.len=reader.readC(); ins->std.arpMacro.loop=reader.readI(); ins->std.arpMacro.rel=reader.readI(); + // TODO: get rid ins->std.arpMacro.mode=reader.readI(); for (int j=0; jstd.arpMacro.len; j++) { ins->std.arpMacro.val[j]=reader.readC(); @@ -4204,6 +4209,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } } + // TODO: take care of new arp macro format w->writeC(i->std.arpMacro.len); if (i->std.arpMacro.mode) { for (int j=0; jstd.arpMacro.len; j++) { diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index b2203ebf6..bd28834c4 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -132,7 +132,7 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeI(std.ex1Macro.loop); w->writeI(std.ex2Macro.loop); w->writeI(std.ex3Macro.loop); - w->writeC(std.arpMacro.mode); + w->writeC(0); // this was arp macro mode w->writeC(0); // reserved w->writeC(0); w->writeC(0); @@ -1342,6 +1342,19 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { } } + // old arp macro format + if (version<112) { + if (std.arpMacro.mode) { + std.arpMacro.mode=0; + for (int i=0; istd.arpMacro.loop && std.arpMacro.len<255) { + std.arpMacro.val[std.arpMacro.len++]=0; + } + } + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 57c0e3e21..ed71d76a4 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -163,19 +163,9 @@ void DivPlatformAmiga::tick(bool sysTick) { } } if (chan[i].std.arp.had) { - if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp.val)); - } else { - chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note+chan[i].std.arp.val)); - } - } + // TODO: why the off mult? this may be a bug! + chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(parent->calcArp(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=round(off*NOTE_PERIODIC_NOROUND(chan[i].note)); - chan[i].freqChanged=true; - } } if (chan[i].useWave && chan[i].std.wave.had) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 1f51dc9bd..cca54d28b 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -161,18 +161,9 @@ void DivPlatformArcade::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_LINEAR(parent->calcArp(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_LINEAR(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 1b24ac733..f45c51ea7 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -159,18 +159,9 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { rWrite(0x06,31-chan[i].std.duty.val); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 0fc9091f2..d77457d66 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -167,18 +167,9 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { rWrite(0x06,chan[i].std.duty.val); diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index fd00ebeeb..89503cceb 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -92,18 +92,9 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.wave.had) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index dc0cd8a2d..9825f189e 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -104,18 +104,9 @@ void DivPlatformC64::tick(bool sysTick) { } 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+(signed char)chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(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) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64); diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index fc4d3e775..7622a0990 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -121,18 +121,9 @@ void DivPlatformFDS::tick(bool sysTick) { } 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].baseFreq=NOTE_FREQUENCY(parent->calcArp(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) { diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index ab603266c..afed615d2 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -165,28 +165,13 @@ void DivPlatformGB::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (i==3) { // noise - if (chan[i].std.arp.mode) { - chan[i].baseFreq=chan[i].std.arp.val+24; - } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp.val; - } + chan[i].baseFreq=parent->calcArp(chan[i].note,chan[i].std.arp.val,24); if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { - if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val+24); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 7dde9790e..f499865ef 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -266,34 +266,16 @@ void DivPlatformGenesis::tick(bool sysTick) { if (i>=5 && chan[i].furnaceDac) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].std.arp.val,false); - } else { - chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].note+(signed char)chan[i].std.arp.val,false); - } + chan[i].baseFreq=parent->calcBaseFreq(1,1,parent->calcArp(chan[i].note,chan[i].std.arp.val),false); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].note,false); - chan[i].freqChanged=true; - } } } else { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); - } + chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); - chan[i].freqChanged=true; - } } } diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index ead20590a..f771be334 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -172,22 +172,9 @@ void DivPlatformLynx::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].std.arp.val,false); - chan[i].actualNote=chan[i].std.arp.val; - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note+chan[i].std.arp.val,false); - chan[i].actualNote=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_PERIODIC(chan[i].note); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note,false); - chan[i].actualNote=chan[i].note; + chan[i].actualNote=parent->calcArp(chan[i].note,chan[i].std.arp.val); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].actualNote); + if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].actualNote,false); chan[i].freqChanged=true; } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index b5bb5a9e8..0a3bfb9e7 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -101,20 +101,12 @@ void DivPlatformMMC5::tick(bool sysTick) { if (chan[i].outVol<0) chan[i].outVol=0; rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } + // TODO: arp macros on NES PCM? if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 52352dc62..7da2e0a16 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -189,18 +189,9 @@ void DivPlatformN163::tick(bool sysTick) { } 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+(signed char)chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(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) { if (chan[i].wavePos!=chan[i].std.duty.val) { diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index e88bb0ebf..236790e37 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -206,18 +206,9 @@ void DivPlatformNamcoWSG::tick(bool sysTick) { } 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].baseFreq=NOTE_FREQUENCY(parent->calcArp(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.wave.had) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index a55199d15..ab466f1b5 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -219,28 +219,15 @@ void DivPlatformNES::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (i==3) { // noise - if (chan[i].std.arp.mode) { - chan[i].baseFreq=chan[i].std.arp.val; - } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp.val; - } + chan[i].baseFreq=parent->calcArp(chan[i].note,chan[i].std.arp.val); if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 78ef25a29..eb49637e3 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -297,18 +297,9 @@ void DivPlatformOPL::tick(bool sysTick) { 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+(signed char)chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(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 (oplType==3 && chan[i].std.panL.had) { @@ -491,18 +482,9 @@ void DivPlatformOPL::tick(bool sysTick) { if (chan[adpcmChan].std.arp.had) { if (!chan[adpcmChan].inPorta) { - if (chan[adpcmChan].std.arp.mode) { - chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].std.arp.val); - } else { - chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].note+(signed char)chan[adpcmChan].std.arp.val); - } + chan[adpcmChan].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmChan].note,chan[adpcmChan].std.arp.val)); } chan[adpcmChan].freqChanged=true; - } else { - if (chan[adpcmChan].std.arp.mode && chan[adpcmChan].std.arp.finished) { - chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].note); - chan[adpcmChan].freqChanged=true; - } } } if (chan[adpcmChan].freqChanged) { diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index e29f6e622..9485551aa 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -107,18 +107,9 @@ void DivPlatformOPLL::tick(bool sysTick) { 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+(signed char)chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(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.wave.had && chan[i].state.opllPreset!=16) { diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 1dcf24511..476b1ecca 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -162,28 +162,12 @@ void DivPlatformPCE::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - // noise - int noiseSeek=chan[i].std.arp.val; - if (noiseSeek<0) noiseSeek=0; - chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - int noiseSeek=chan[i].note+chan[i].std.arp.val; - if (noiseSeek<0) noiseSeek=0; - chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); - } - } - chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); - int noiseSeek=chan[i].note; + int noiseSeek=parent->calcArp(chan[i].note,chan[i].std.arp.val); + chan[i].baseFreq=NOTE_PERIODIC(noiseSeek); if (noiseSeek<0) noiseSeek=0; chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); - chan[i].freqChanged=true; } + chan[i].freqChanged=true; } if (chan[i].std.wave.had && !chan[i].pcm) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 213cb85a3..026e989cc 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -83,18 +83,9 @@ void DivPlatformPCMDAC::tick(bool sysTick) { } if (chan.std.arp.had) { if (!chan.inPorta) { - if (chan.std.arp.mode) { - chan.baseFreq=NOTE_FREQUENCY(chan.std.arp.val); - } else { - chan.baseFreq=NOTE_FREQUENCY(chan.note+chan.std.arp.val); - } + chan.baseFreq=NOTE_FREQUENCY(parent->calcArp(chan.note,chan.std.arp.val)); } chan.freqChanged=true; - } else { - if (chan.std.arp.mode && chan.std.arp.finished) { - chan.baseFreq=NOTE_FREQUENCY(chan.note); - chan.freqChanged=true; - } } if (chan.useWave && chan.std.wave.had) { if (chan.wave!=chan.std.wave.val || chan.ws.activeChanged()) { diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 260f5bbd6..ab3b8a7ca 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -347,18 +347,9 @@ void DivPlatformPCSpeaker::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 4e1c39a97..c314edf6f 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -104,18 +104,9 @@ void DivPlatformPET::tick(bool sysTick) { } if (chan.std.arp.had) { if (!chan.inPorta) { - if (chan.std.arp.mode) { - chan.baseFreq=NOTE_PERIODIC(chan.std.arp.val); - } else { - chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp.val); - } + chan.baseFreq=NOTE_PERIODIC(parent->calcArp(chan.note,chan.std.arp.val)); } chan.freqChanged=true; - } else { - if (chan.std.arp.mode && chan.std.arp.finished) { - chan.baseFreq=NOTE_PERIODIC(chan.note); - chan.freqChanged=true; - } } if (chan.std.wave.had) { if (chan.wave!=chan.std.wave.val) { diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 863c0e1fd..1339d70af 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -297,18 +297,9 @@ void DivPlatformQSound::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=QS_NOTE_FREQUENCY(chan[i].std.arp.val); - } else { - chan[i].baseFreq=QS_NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=QS_NOTE_FREQUENCY(parent->calcArp(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=QS_NOTE_FREQUENCY(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index e19b945b0..3aa922e47 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -84,18 +84,9 @@ void DivPlatformRF5C68::tick(bool sysTick) { } 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].baseFreq=NOTE_FREQUENCY(parent->calcArp(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.pitch.had) { if (chan[i].std.pitch.mode) { diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index a05a61d4f..b7a77d968 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -99,18 +99,9 @@ void DivPlatformSAA1099::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { saaNoise[i/3]=chan[i].std.duty.val&3; diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index a72257629..d8859cffd 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -115,18 +115,9 @@ void DivPlatformSCC::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.wave.had) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index e406e293b..329e3b82a 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -88,18 +88,9 @@ void DivPlatformSegaPCM::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=(chan[i].std.arp.val<<6); - } else { - chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp.val)<<6); - } + chan[i].baseFreq=(parent->calcArp(chan[i].note,chan[i].std.arp.val)<<6); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=(chan[i].note<<6); - chan[i].freqChanged=true; - } } if (chan[i].std.panL.had) { diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 40a8616ef..497095c17 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -132,22 +132,12 @@ void DivPlatformSMS::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - chan[i].actualNote=chan[i].std.arp.val; - } else { - // TODO: check whether this weird octave boundary thing applies to other systems as well - int areYouSerious=chan[i].note+chan[i].std.arp.val; - while (areYouSerious>0x60) areYouSerious-=12; - chan[i].baseFreq=NOTE_PERIODIC(areYouSerious); - chan[i].actualNote=areYouSerious; - } - chan[i].freqChanged=true; - } - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); - chan[i].actualNote=chan[i].note; + // TODO: check whether this weird octave boundary thing applies to other systems as well + // TODO: add compatibility flag. this is horrible. + int areYouSerious=parent->calcArp(chan[i].note,chan[i].std.arp.val); + while (areYouSerious>0x60) areYouSerious-=12; + chan[i].baseFreq=NOTE_PERIODIC(areYouSerious); + chan[i].actualNote=areYouSerious; chan[i].freqChanged=true; } } diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index ca933650f..a28ed3047 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -78,18 +78,9 @@ void DivPlatformSoundUnit::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_SU(i,chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_SU(i,chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_SU(i,parent->calcArp(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_SU(i,chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index cdab93d5c..7f1e10a02 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -134,18 +134,9 @@ void DivPlatformSwan::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.wave.had && !(i==1 && pcm)) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 18bdcb0c3..fe7273a1c 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -87,20 +87,16 @@ void DivPlatformTIA::tick(bool sysTick) { rWrite(0x19+i,chan[i].outVol&15); } } + // TODO: the way arps work on TIA is really weird if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=0x80000000|chan[i].std.arp.val; + if (chan[i].std.arp.val&0x40000000) { + chan[i].baseFreq=0x80000000|(chan[i].std.arp.val&(~0x40000000)); } else { chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8; } } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=chan[i].note<<8; - chan[i].freqChanged=true; - } } if (chan[i].std.wave.had) { chan[i].shape=chan[i].std.wave.val&15; diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index e6e38a128..0fe0265e1 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -123,18 +123,9 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_LINEAR(parent->calcArp(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_LINEAR(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index e50bcd6ea..bf47df5a5 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -159,18 +159,9 @@ void DivPlatformVERA::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp.val); - } else { - chan[i].baseFreq=calcNoteFreq(0,chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=calcNoteFreq(0,parent->calcArp(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=calcNoteFreq(0,chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { rWriteLo(i,3,chan[i].std.duty.val); @@ -209,18 +200,9 @@ void DivPlatformVERA::tick(bool sysTick) { } if (chan[16].std.arp.had) { if (!chan[16].inPorta) { - if (chan[16].std.arp.mode) { - chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp.val); - } else { - chan[16].baseFreq=calcNoteFreq(16,chan[16].note+chan[16].std.arp.val); - } + chan[16].baseFreq=calcNoteFreq(16,parent->calcArp(chan[16].note,chan[16].std.arp.val)); } chan[16].freqChanged=true; - } else { - if (chan[16].std.arp.mode && chan[16].std.arp.finished) { - chan[16].baseFreq=calcNoteFreq(16,chan[16].note); - chan[16].freqChanged=true; - } } if (chan[16].freqChanged) { double off=65536.0; diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 5c0bdf461..93c119484 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -94,18 +94,9 @@ void DivPlatformVIC20::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.wave.had) { if (chan[i].wave!=chan[i].std.wave.val) { diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 9a7bcef0d..2500ce190 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -153,18 +153,9 @@ void DivPlatformVRC6::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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_PERIODIC(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index f6aa1c651..0f989ac9d 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -321,18 +321,9 @@ void DivPlatformX1_010::tick(bool sysTick) { if ((!chan[i].pcm) || chan[i].furnacePCM) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp.val); - } else { - chan[i].baseFreq=NoteX1_010(i,chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NoteX1_010(i,parent->calcArp(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=NoteX1_010(i,chan[i].note); - chan[i].freqChanged=true; - } } } if (chan[i].std.wave.had && !chan[i].pcm) { diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index afb4f526c..178ef05b8 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -231,18 +231,9 @@ void DivPlatformYM2203::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); - } + chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); - chan[i].freqChanged=true; - } } if (chan[i].std.pitch.had) { diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 9e76e6e3f..244e4a16e 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -386,18 +386,9 @@ void DivPlatformYM2608::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); - } + chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); - chan[i].freqChanged=true; - } } if (chan[i].std.panL.had) { @@ -538,18 +529,9 @@ void DivPlatformYM2608::tick(bool sysTick) { if (chan[15].std.arp.had) { if (!chan[15].inPorta) { - if (chan[15].std.arp.mode) { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val); - } else { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp.val); - } + chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val)); } chan[15].freqChanged=true; - } else { - if (chan[15].std.arp.mode && chan[15].std.arp.finished) { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].note); - chan[15].freqChanged=true; - } } } if (chan[15].freqChanged) { diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 920d9b144..064b49f2d 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -427,18 +427,9 @@ void DivPlatformYM2610::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); - } + chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); - chan[i].freqChanged=true; - } } if (chan[i].std.panL.had) { @@ -580,18 +571,9 @@ void DivPlatformYM2610::tick(bool sysTick) { if (chan[13].std.arp.had) { if (!chan[13].inPorta) { - if (chan[13].std.arp.mode) { - chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp.val); - } else { - chan[13].baseFreq=NOTE_ADPCMB(chan[13].note+(signed char)chan[13].std.arp.val); - } + chan[13].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[13].note,chan[13].std.arp.val)); } chan[13].freqChanged=true; - } else { - if (chan[13].std.arp.mode && chan[13].std.arp.finished) { - chan[13].baseFreq=NOTE_ADPCMB(chan[13].note); - chan[13].freqChanged=true; - } } } if (chan[13].freqChanged) { diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 039691e74..8d283374d 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -410,18 +410,9 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); - } + chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); - chan[i].freqChanged=true; - } } if (chan[i].std.panL.had) { @@ -562,18 +553,9 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (chan[15].std.arp.had) { if (!chan[15].inPorta) { - if (chan[15].std.arp.mode) { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val); - } else { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp.val); - } + chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val)); } chan[15].freqChanged=true; - } else { - if (chan[15].std.arp.mode && chan[15].std.arp.finished) { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].note); - chan[15].freqChanged=true; - } } } if (chan[15].freqChanged) { diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index ca1b225d2..eb65a7bda 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -95,18 +95,9 @@ void DivPlatformYMZ280B::tick(bool sysTick) { } 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].baseFreq=NOTE_FREQUENCY(parent->calcArp(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.pitch.had) { if (chan[i].std.pitch.mode) { diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index d83903094..5fa3840bb 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -81,18 +81,9 @@ void DivPlatformZXBeeper::tick(bool sysTick) { } 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].baseFreq=NOTE_FREQUENCY(parent->calcArp(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.pitch.had) { if (chan[i].std.pitch.mode) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b5ccbd7b2..c044ae664 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -195,23 +195,25 @@ void FurnaceGUI::decodeKeyMap(std::map& map, String source) { } } -void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex) { +void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex, bool bit30) { target=""; char buf[32]; for (int i=0; imacroMax) macro[macroLen]=macroMax; + if (setBit30) macro[macroLen]|=0x40000000; + setBit30=false; macroLen++; buf=0; } @@ -315,6 +325,8 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; + if (setBit30) macro[macroLen]|=0x40000000; + setBit30=false; macroLen++; buf=0; } @@ -329,6 +341,8 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; + if (setBit30) macro[macroLen]|=0x40000000; + setBit30=false; macroLen++; buf=0; } @@ -345,6 +359,8 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; + if (setBit30) macro[macroLen]|=0x40000000; + setBit30=false; macroLen++; buf=0; } @@ -1758,6 +1774,8 @@ void FurnaceGUI::showError(String what) { displayError=true; } +#define B30(tt) (macroDragBit30?((tt)&0x40000000):0) + #define MACRO_DRAG(t) \ if (macroDragBitMode) { \ if (macroDragLastX!=x || macroDragLastY!=y) { \ @@ -1790,25 +1808,25 @@ void FurnaceGUI::showError(String what) { } \ if (macroDragMouseMoved) { \ if ((int)round(x-macroDragLineInitial.x)==0) { \ - t[x]=macroDragLineInitial.y; \ + t[x]=B30(t[x])|(int)(macroDragLineInitial.y); \ } else { \ if ((int)round(x-macroDragLineInitial.x)<0) { \ for (int i=0; i<=(int)round(macroDragLineInitial.x-x); i++) { \ int index=(int)round(x+i); \ if (index<0) continue; \ - t[index]=y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x)); \ + t[index]=B30(t[index])|(int)(y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x))); \ } \ } else { \ for (int i=0; i<=(int)round(x-macroDragLineInitial.x); i++) { \ int index=(int)round(i+macroDragLineInitial.x); \ if (index<0) continue; \ - t[index]=macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x)); \ + t[index]=B30(t[index])|(int)(macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x))); \ } \ } \ } \ } \ } else { \ - t[x]=y; \ + t[x]=B30(t[x])|(y); \ } \ } @@ -4868,6 +4886,7 @@ FurnaceGUI::FurnaceGUI(): macroDragInitialValueSet(false), macroDragInitialValue(false), macroDragChar(false), + macroDragBit30(false), macroDragLineMode(false), macroDragMouseMoved(false), macroDragLineInitial(0,0), diff --git a/src/gui/gui.h b/src/gui/gui.h index f7b13b073..a7f906aea 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -869,10 +869,10 @@ struct FurnaceGUIMacroDesc { const char* modeName; ImVec4 color; unsigned int bitOffset; - bool isBitfield, blockMode; + bool isBitfield, blockMode, bit30; String (*hoverFunc)(int,float); - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0, bool bit30Special=false): macro(m), height(macroHeight), displayName(name), @@ -882,6 +882,7 @@ struct FurnaceGUIMacroDesc { bitOffset(bitOff), isBitfield(bitfield), blockMode(block), + bit30(bit30Special), hoverFunc(hf) { // MSVC -> hell this->min=macroMin; @@ -1395,6 +1396,7 @@ class FurnaceGUI { bool macroDragInitialValueSet; bool macroDragInitialValue; bool macroDragChar; + bool macroDragBit30; bool macroDragLineMode; bool macroDragMouseMoved; ImVec2 macroDragLineInitial; @@ -1686,8 +1688,8 @@ class FurnaceGUI { void applyUISettings(bool updateFonts=true); void initSystemPresets(); - void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false); - void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel); + void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false, bool bit30=false); + void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel, bool bit30=false); void decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMax, bool hex=false); String encodeKeyMap(std::map& map); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index f7e80c535..ea0717154 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -331,6 +331,11 @@ String macroHoverLoop(int id, float val) { return ""; } +String macroHoverBit30(int id, float val) { + if (val>0) return "Fixed"; + return "Relative"; +} + String macroHoverES5506FilterMode(int id, float val) { String mode="???"; switch (((int)val)&3) { @@ -1196,6 +1201,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; float loopIndicator[256]; + float bit30Indicator[256]; bool doHighlight[256]; int index=0; @@ -1281,12 +1287,14 @@ void FurnaceGUI::drawMacros(std::vector& macros) { // macro area ImGui::TableNextColumn(); for (int j=0; j<256; j++) { + bit30Indicator[j]=0; if (j+macroDragScroll>=i.macro->len) { asFloat[j]=0; asInt[j]=0; } else { - asFloat[j]=i.macro->val[j+macroDragScroll]; - asInt[j]=i.macro->val[j+macroDragScroll]+i.bitOffset; + asFloat[j]=i.macro->val[j+macroDragScroll]&(i.bit30?(~0x40000000):0xffffffff); + asInt[j]=(i.macro->val[j+macroDragScroll]&(i.bit30?(~0x40000000):0xffffffff))+i.bitOffset; + if (i.bit30) bit30Indicator[j]=(i.macro->val[j+macroDragScroll]&0x40000000)?1:0; } if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { loopIndicator[j]=0; @@ -1355,6 +1363,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { macroDragInitialValue=false; macroDragLen=totalFit; macroDragActive=true; + macroDragBit30=i.bit30; macroDragTarget=i.macro->val; macroDragChar=false; macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); @@ -1422,6 +1431,12 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } } + // bit 30 area + // TODO: ability to set it + if (i.bit30) { + PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); + } + // loop area PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { @@ -4178,7 +4193,7 @@ void FurnaceGUI::drawInsEdit() { if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } - macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroAbsoluteMode,ins->std.arpMacro.mode?(¯oHoverNote):NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,NULL,false,NULL,0,true)); 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)); From 226f43fea38e50296e6e897f8ede985d39be45db Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 19:09:08 -0500 Subject: [PATCH 286/515] several important bug fixes to advanced arp macro --- src/engine/engine.cpp | 6 +++++- src/engine/fileOps.cpp | 6 +++--- src/engine/instrument.cpp | 4 ++-- src/engine/platform/gb.cpp | 2 +- src/engine/platform/tia.cpp | 4 +++- src/gui/gui.cpp | 28 +++++++++++++++++----------- src/gui/insEdit.cpp | 20 +++++++++++++++----- 7 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 4ee8e48bb..153a8db97 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1713,7 +1713,11 @@ int DivEngine::calcFreq(int base, int pitch, bool period, int octave, int pitch2 } int DivEngine::calcArp(int note, int arp, int offset) { - if (arp&0x40000000) return (arp&(~0x40000000))+offset; + if (arp<0) { + if (!(arp&0x40000000)) return (arp|0x40000000)+offset; + } else { + if (arp&0x40000000) return (arp&(~0x40000000))+offset; + } return note+arp; } diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index c2acd45d4..506dfc6f9 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -510,9 +510,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } else { ins->std.arpMacro.mode=0; for (int j=0; jstd.arpMacro.len; j++) { - ins->std.arpMacro.val[i]|=0x40000000; + ins->std.arpMacro.val[j]^=0x40000000; } - if (ins->std.arpMacro.loopstd.arpMacro.len && ins->std.arpMacro.len<255) { + if (ins->std.arpMacro.loop>=ins->std.arpMacro.len && ins->std.arpMacro.len<255) { ins->std.arpMacro.val[ins->std.arpMacro.len++]=0; } } @@ -2928,7 +2928,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { logV("unhandled pitch!"); } else { if (fm.val[j]>0x80) { - ins->std.arpMacro.val[ins->std.arpMacro.len]=(fm.val[j]-0x80+24)|0x40000000; + ins->std.arpMacro.val[ins->std.arpMacro.len]=(fm.val[j]-0x80+24)^0x40000000; } else { ins->std.arpMacro.val[ins->std.arpMacro.len]=fm.val[j]; } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index bd28834c4..430e361ae 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -1347,9 +1347,9 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { if (std.arpMacro.mode) { std.arpMacro.mode=0; for (int i=0; istd.arpMacro.loop && std.arpMacro.len<255) { + if ((std.arpMacro.loop>=std.arpMacro.len || std.arpMacro.rel>std.arpMacro.loop) && std.arpMacro.len<255) { std.arpMacro.val[std.arpMacro.len++]=0; } } diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index afed615d2..fea89c71d 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -169,7 +169,7 @@ void DivPlatformGB::tick(bool sysTick) { if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { - chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val)); + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val,24)); } chan[i].freqChanged=true; } diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index fe7273a1c..d55200f9f 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -90,7 +90,9 @@ void DivPlatformTIA::tick(bool sysTick) { // TODO: the way arps work on TIA is really weird if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.val&0x40000000) { + if (chan[i].std.arp.val<0 && (!(chan[i].std.arp.val&0x40000000))) { + chan[i].baseFreq=0x80000000|(chan[i].std.arp.val|0x40000000); + } else if (chan[i].std.arp.val&0x40000000) { chan[i].baseFreq=0x80000000|(chan[i].std.arp.val&(~0x40000000)); } else { chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c044ae664..8ea22a144 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -201,8 +201,13 @@ void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macr for (int i=0; imacroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -325,7 +330,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -341,7 +346,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -359,7 +364,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe negaBuf=false; if (macro[macroLen]macroMax) macro[macroLen]=macroMax; - if (setBit30) macro[macroLen]|=0x40000000; + if (setBit30) macro[macroLen]^=0x40000000; setBit30=false; macroLen++; buf=0; @@ -1774,7 +1779,8 @@ void FurnaceGUI::showError(String what) { displayError=true; } -#define B30(tt) (macroDragBit30?((tt)&0x40000000):0) +// what monster did I just create here? +#define B30(tt) (macroDragBit30?((((tt)&0xc0000000)==0x40000000 || ((tt)&0xc0000000)==0x80000000)?0x40000000:0):0) #define MACRO_DRAG(t) \ if (macroDragBitMode) { \ @@ -1808,25 +1814,25 @@ void FurnaceGUI::showError(String what) { } \ if (macroDragMouseMoved) { \ if ((int)round(x-macroDragLineInitial.x)==0) { \ - t[x]=B30(t[x])|(int)(macroDragLineInitial.y); \ + t[x]=B30(t[x])^(int)(macroDragLineInitial.y); \ } else { \ if ((int)round(x-macroDragLineInitial.x)<0) { \ for (int i=0; i<=(int)round(macroDragLineInitial.x-x); i++) { \ int index=(int)round(x+i); \ if (index<0) continue; \ - t[index]=B30(t[index])|(int)(y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x))); \ + t[index]=B30(t[index])^(int)(y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x))); \ } \ } else { \ for (int i=0; i<=(int)round(x-macroDragLineInitial.x); i++) { \ int index=(int)round(i+macroDragLineInitial.x); \ if (index<0) continue; \ - t[index]=B30(t[index])|(int)(macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x))); \ + t[index]=B30(t[index])^(int)(macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x))); \ } \ } \ } \ } \ } else { \ - t[x]=B30(t[x])|(y); \ + t[x]=B30(t[x])^(y); \ } \ } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ea0717154..2a2c8ecd5 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1197,6 +1197,16 @@ String genericGuide(float value) { return fmt::sprintf("%d",(int)value); } +inline int deBit30(const int val) { + if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return val^0x40000000; + return val; +} + +inline bool enBit30(const int val) { + if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return true; + return false; +} + void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; @@ -1292,9 +1302,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { asFloat[j]=0; asInt[j]=0; } else { - asFloat[j]=i.macro->val[j+macroDragScroll]&(i.bit30?(~0x40000000):0xffffffff); - asInt[j]=(i.macro->val[j+macroDragScroll]&(i.bit30?(~0x40000000):0xffffffff))+i.bitOffset; - if (i.bit30) bit30Indicator[j]=(i.macro->val[j+macroDragScroll]&0x40000000)?1:0; + asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); + asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset; + if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); } if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { loopIndicator[j]=0; @@ -1461,10 +1471,10 @@ void FurnaceGUI::drawMacros(std::vector& macros) { ImGui::SetNextItemWidth(availableWidth); String& mmlStr=mmlString[index]; if (ImGui::InputText("##IMacroMML",&mmlStr)) { - decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel); + decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30); } if (!ImGui::IsItemActive()) { - encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel); + encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); } } ImGui::PopStyleVar(); From e158591ccbec487d1c9240dee4159cefb4fe81c8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 23 Aug 2022 02:31:39 -0500 Subject: [PATCH 287/515] even more fixes --- src/engine/fileOps.cpp | 6 ++++-- src/engine/instrument.cpp | 2 +- src/engine/platform/sms.cpp | 8 ++------ src/engine/platform/tia.cpp | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 506dfc6f9..fe220aae8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -145,7 +145,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.loopModality=0; ds.properNoiseLayout=false; ds.waveDutyIsVol=false; - ds.resetMacroOnPorta=true; + // TODO: WHAT?! geodude.dmf fails when this is true + // but isn't that how Defle behaves??? + ds.resetMacroOnPorta=false; ds.legacyVolumeSlides=true; ds.compatibleArpeggio=true; ds.noteOffResetsSlides=true; @@ -512,7 +514,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { for (int j=0; jstd.arpMacro.len; j++) { ins->std.arpMacro.val[j]^=0x40000000; } - if (ins->std.arpMacro.loop>=ins->std.arpMacro.len && ins->std.arpMacro.len<255) { + if (ins->std.arpMacro.loop==255 && ins->std.arpMacro.len<255) { ins->std.arpMacro.val[ins->std.arpMacro.len++]=0; } } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 430e361ae..19cb1ba55 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -1349,7 +1349,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int i=0; i=std.arpMacro.len || std.arpMacro.rel>std.arpMacro.loop) && std.arpMacro.len<255) { + if ((std.arpMacro.loop>=std.arpMacro.len || (std.arpMacro.rel>std.arpMacro.loop && std.arpMacro.relcalcArp(chan[3].note,chan[3].std.arp.val)%12; + } else { // pardon? value=chan[3].note%12; } if (value<3) { diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index d55200f9f..82d032703 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -92,7 +92,7 @@ void DivPlatformTIA::tick(bool sysTick) { if (!chan[i].inPorta) { if (chan[i].std.arp.val<0 && (!(chan[i].std.arp.val&0x40000000))) { chan[i].baseFreq=0x80000000|(chan[i].std.arp.val|0x40000000); - } else if (chan[i].std.arp.val&0x40000000) { + } else if (chan[i].std.arp.val>=0 && chan[i].std.arp.val&0x40000000) { chan[i].baseFreq=0x80000000|(chan[i].std.arp.val&(~0x40000000)); } else { chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8; From 96b3ccab8ae245c6d0d92c9b7c2c64dbdd978275 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 23 Aug 2022 03:57:21 -0500 Subject: [PATCH 288/515] I see UI!!!! --- src/gui/gui.cpp | 27 ++++++++++++++++++++++++++- src/gui/gui.h | 1 + src/gui/insEdit.cpp | 18 +++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 8ea22a144..0d53e97da 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1783,7 +1783,31 @@ void FurnaceGUI::showError(String what) { #define B30(tt) (macroDragBit30?((((tt)&0xc0000000)==0x40000000 || ((tt)&0xc0000000)==0x80000000)?0x40000000:0):0) #define MACRO_DRAG(t) \ - if (macroDragBitMode) { \ + if (macroDragSettingBit30) { \ + if (macroDragLastX!=x || macroDragLastY!=y) { \ + macroDragLastX=x; \ + macroDragLastY=y; \ + if (macroDragInitialValueSet) { \ + if (!macroDragInitialValue) { \ + if (t[x]&0x80000000) { \ + t[x]&=~0x40000000; \ + } else { \ + t[x]|=0x40000000; \ + } \ + } else { \ + if (t[x]&0x80000000) { \ + t[x]|=0x40000000; \ + } else { \ + t[x]&=~0x40000000; \ + } \ + } \ + } else { \ + macroDragInitialValue=(((t[x])&0xc0000000)==0x40000000 || ((t[x])&0xc0000000)==0x80000000); \ + macroDragInitialValueSet=true; \ + t[x]^=0x40000000; \ + } \ + } \ + } else if (macroDragBitMode) { \ if (macroDragLastX!=x || macroDragLastY!=y) { \ macroDragLastX=x; \ macroDragLastY=y; \ @@ -4893,6 +4917,7 @@ FurnaceGUI::FurnaceGUI(): macroDragInitialValue(false), macroDragChar(false), macroDragBit30(false), + macroDragSettingBit30(false), macroDragLineMode(false), macroDragMouseMoved(false), macroDragLineInitial(0,0), diff --git a/src/gui/gui.h b/src/gui/gui.h index a7f906aea..80aa087ff 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1397,6 +1397,7 @@ class FurnaceGUI { bool macroDragInitialValue; bool macroDragChar; bool macroDragBit30; + bool macroDragSettingBit30; bool macroDragLineMode; bool macroDragMouseMoved; ImVec2 macroDragLineInitial; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2a2c8ecd5..c89652a37 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1374,6 +1374,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { macroDragLen=totalFit; macroDragActive=true; macroDragBit30=i.bit30; + macroDragSettingBit30=false; macroDragTarget=i.macro->val; macroDragChar=false; macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); @@ -1442,9 +1443,24 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } // bit 30 area - // TODO: ability to set it if (i.bit30) { PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); + macroDragInitialValueSet=false; + macroDragInitialValue=false; + macroDragLen=totalFit; + macroDragActive=true; + macroDragBit30=i.bit30; + macroDragSettingBit30=true; + macroDragTarget=i.macro->val; + macroDragChar=false; + macroDragLineMode=false; + macroDragLineInitial=ImVec2(0,0); + lastMacroDesc=i; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + } } // loop area From 9c29b7e7cab951f25a76d9b8921872b353fb53db Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 25 Aug 2022 00:24:49 +0900 Subject: [PATCH 289/515] Fix RF5C68 panning macro --- src/engine/platform/rf5c68.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 3aa922e47..c032284f1 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -107,7 +107,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { chan[i].panning|=(chan[i].std.panR.val&15)<<4; } if (chan[i].std.panL.had || chan[i].std.panR.had) { - chWrite(i,0x05,isMuted[i]?0:chan[i].panning); + chWrite(i,1,isMuted[i]?0:chan[i].panning); } if (chan[i].setPos) { // force keyon From fc5b26c49a1d11ffc959abce7becc1ec67260017 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 25 Aug 2022 01:34:21 -0500 Subject: [PATCH 290/515] SoundUnit: fix 4xxx not working --- src/engine/platform/su.cpp | 2 +- src/engine/sysDef.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index a28ed3047..136503457 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -357,7 +357,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { writeControlUpper(c.chan); break; case DIV_CMD_C64_FINE_CUTOFF: - chan[c.chan].baseCutoff=c.value; + chan[c.chan].baseCutoff=c.value*4; if (!chan[c.chan].std.ex1.has) { chan[c.chan].cutoff=chan[c.chan].baseCutoff; chWrite(c.chan,0x06,chan[c.chan].cutoff&0xff); diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 5ac6bf34e..0487873b8 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1447,7 +1447,7 @@ void DivEngine::registerSystems() { {0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}}, {0x22, {DIV_CMD_SU_SWEEP_ENABLE, "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)", constVal<2>, effectVal}}, }; - const EffectHandler suCutoffHandler(DIV_CMD_C64_FINE_DUTY, "4xxx: Set cutoff (0 to FFF)", effectValLong<12>); + const EffectHandler suCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, "4xxx: Set cutoff (0 to FFF)", effectValLong<12>); for (int i=0; i<16; i++) { suEffectHandlerMap.emplace(0x40+i, suCutoffHandler); } From bc0f696eb3743f233801bbd50a27d753fdb20fee Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Thu, 25 Aug 2022 18:55:32 +0200 Subject: [PATCH 291/515] Update soundunit.md fix 12xx description --- papers/doc/7-systems/soundunit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/soundunit.md b/papers/doc/7-systems/soundunit.md index 89e346558..8c3863b96 100644 --- a/papers/doc/7-systems/soundunit.md +++ b/papers/doc/7-systems/soundunit.md @@ -12,7 +12,7 @@ This is a fantasy sound chip, used in the specs2 fantasy computer designed by ti - 5: periodic noise - 6: XOR sine - 7: XOR triangle -- `12xx`: set waveform (0 to 7F) +- `12xx`: set pulse width (0 to 7F) - `13xx`: set resonance of filter (0 to FF) - despite what the internal effects list says (0 to F), you can use a resonance value from 0 to FF (255) - `14xx`: set filter mode and ringmod From 0b7592e031b0109d6906ded580df10ce7768d0fb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 25 Aug 2022 16:06:10 -0500 Subject: [PATCH 292/515] new default loop modality --- src/engine/song.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/song.h b/src/engine/song.h index 83509efbf..ac49832e7 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -569,7 +569,7 @@ struct DivSong { limitSlides(false), linearPitch(2), pitchSlideSpeed(4), - loopModality(0), + loopModality(2), delayBehavior(2), properNoiseLayout(true), waveDutyIsVol(false), From a7d0949eacc2e7fc71e7bfd7657c15d32f47917f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 25 Aug 2022 18:13:46 -0500 Subject: [PATCH 293/515] GUI: different pattern manager layout --- src/gui/patManager.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/gui/patManager.cpp b/src/gui/patManager.cpp index d597bd9c2..22d5b645e 100644 --- a/src/gui/patManager.cpp +++ b/src/gui/patManager.cpp @@ -47,21 +47,24 @@ void FurnaceGUI::drawPatManager() { }); } - for (int i=0; igetTotalChannelCount(); i++) { - memset(isUsed,0,256); - memset(isNull,0,256*sizeof(bool)); - for (int j=0; jcurSubSong->ordersLen; j++) { - isUsed[e->curSubSong->orders.ord[i][j]]++; - } - for (int j=0; j<256; j++) { - isNull[j]=(e->curSubSong->pat[i].data[j]==NULL); - } - ImGui::Text("%d. %s",i+1,e->getChannelName(i)); - ImGui::PushID(1000+i); + if (ImGui::BeginTable("PatManTable",257,ImGuiTableFlags_ScrollX|ImGuiTableFlags_SizingFixedFit)) { ImGui::PushFont(patFont); - if (ImGui::BeginTable("PatManTable",32)) { + + for (int i=0; igetTotalChannelCount(); i++) { + ImGui::TableNextRow(); + memset(isUsed,0,256); + memset(isNull,0,256*sizeof(bool)); + for (int j=0; jcurSubSong->ordersLen; j++) { + isUsed[e->curSubSong->orders.ord[i][j]]++; + } + for (int j=0; j<256; j++) { + isNull[j]=(e->curSubSong->pat[i].data[j]==NULL); + } + ImGui::TableNextColumn(); + ImGui::Text("%s",e->getChannelShortName(i)); + + ImGui::PushID(1000+i); for (int k=0; k<256; k++) { - if ((k&31)==0) ImGui::TableNextRow(); ImGui::TableNextColumn(); snprintf(id,1023,"%.2X",k); @@ -98,10 +101,11 @@ void FurnaceGUI::drawPatManager() { } ImGui::PopStyleColor(); } - ImGui::EndTable(); + ImGui::PopID(); } ImGui::PopFont(); - ImGui::PopID(); + + ImGui::EndTable(); } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PAT_MANAGER; From 3597e57bb2aeaae27ff362a763e98acd874dee1a Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 26 Aug 2022 08:49:08 +0900 Subject: [PATCH 294/515] Add Traditional Chinese and Korean support --- src/gui/gui.h | 8 +++++-- src/gui/settings.cpp | 52 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 80aa087ff..922182769 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1085,7 +1085,9 @@ class FurnaceGUI { int roundedButtons; int roundedMenus; int loadJapanese; - int loadChinese; + int loadChineseSimplified; + int loadChineseTraditional; + int loadKorean; int fmLayout; int sampleLayout; int waveLayout; @@ -1202,7 +1204,9 @@ class FurnaceGUI { roundedButtons(1), roundedMenus(0), loadJapanese(0), - loadChinese(0), + loadChineseSimplified(0), + loadChineseTraditional(0), + loadKorean(0), fmLayout(0), sampleLayout(0), waveLayout(0), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 03c32e655..0e1ed3893 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1072,9 +1072,9 @@ void FurnaceGUI::drawSettings() { ); } - bool loadChineseB=settings.loadChinese; - if (ImGui::Checkbox("Display Chinese (Simplified) characters",&loadChineseB)) { - settings.loadChinese=loadChineseB; + bool loadChineseSimplifiedB=settings.loadChineseSimplified; + if (ImGui::Checkbox("Display Chinese (Simplified) characters",&loadChineseSimplifiedB)) { + settings.loadChineseSimplified=loadChineseSimplifiedB; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip( @@ -1085,6 +1085,32 @@ void FurnaceGUI::drawSettings() { ); } + bool loadChineseTraditionalB=settings.loadChineseTraditional; + if (ImGui::Checkbox("Display Chinese (Traditional) characters",&loadChineseTraditionalB)) { + settings.loadChineseTraditional=loadChineseTraditionalB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip( + "Only toggle this option if you have enough graphics memory.\n" + "This is a temporary solution until dynamic font atlas is implemented in Dear ImGui.\n\n" + "請在確保你有足夠的顯存后再啟動此設定\n" + "這是一個在ImGui實現動態字體加載之前的臨時解決方案" + ); + } + + bool loadKoreanB=settings.loadKorean; + if (ImGui::Checkbox("Display Korean characters",&loadKoreanB)) { + settings.loadKorean=loadKoreanB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip( + "Only toggle this option if you have enough graphics memory.\n" + "This is a temporary solution until dynamic font atlas is implemented in Dear ImGui.\n\n" + "그래픽 메모리가 충분한 경우에만 이 옵션을 선택하십시오.\n" + "이 옵션은 Dear ImGui에 동적 글꼴 아틀라스가 구현될 때까지 임시 솔루션입니다." + ); + } + ImGui::Separator(); ImGui::Text("Pattern view labels:"); @@ -2170,7 +2196,9 @@ void FurnaceGUI::syncSettings() { settings.roundedButtons=e->getConfInt("roundedButtons",1); settings.roundedMenus=e->getConfInt("roundedMenus",0); settings.loadJapanese=e->getConfInt("loadJapanese",0); - settings.loadChinese=e->getConfInt("loadChinese",0); + settings.loadChineseSimplified=e->getConfInt("loadChineseSimplified",0); + settings.loadChineseTraditional=e->getConfInt("loadChineseTraditional",0); + settings.loadKorean=e->getConfInt("loadKorean",0); settings.fmLayout=e->getConfInt("fmLayout",0); settings.sampleLayout=e->getConfInt("sampleLayout",0); settings.waveLayout=e->getConfInt("waveLayout",0); @@ -2274,7 +2302,9 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.roundedButtons,0,1); clampSetting(settings.roundedMenus,0,1); clampSetting(settings.loadJapanese,0,1); - clampSetting(settings.loadChinese,0,1); + clampSetting(settings.loadChineseSimplified,0,1); + clampSetting(settings.loadChineseTraditional,0,1); + clampSetting(settings.loadKorean,0,1); clampSetting(settings.fmLayout,0,6); clampSetting(settings.susPosition,0,1); clampSetting(settings.effectCursorDir,0,2); @@ -2413,7 +2443,9 @@ void FurnaceGUI::commitSettings() { e->setConf("roundedButtons",settings.roundedButtons); e->setConf("roundedMenus",settings.roundedMenus); e->setConf("loadJapanese",settings.loadJapanese); - e->setConf("loadChinese",settings.loadChinese); + e->setConf("loadChineseSimplified",settings.loadChineseSimplified); + e->setConf("loadChineseTraditional",settings.loadChineseTraditional); + e->setConf("loadKorean",settings.loadKorean); e->setConf("fmLayout",settings.fmLayout); e->setConf("sampleLayout",settings.sampleLayout); e->setConf("waveLayout",settings.waveLayout); @@ -3061,9 +3093,15 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { if (settings.loadJapanese) { range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese()); } - if (settings.loadChinese) { + if (settings.loadChineseSimplified) { range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon()); } + if (settings.loadChineseTraditional) { + range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesChineseFull()); + } + if (settings.loadKorean) { + range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesKorean()); + } // I'm terribly sorry range.UsedChars[0x80>>5]=0; From 24c5ba89e229bd9b42a29f021bd0c287b6e34149 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 25 Aug 2022 22:09:32 -0500 Subject: [PATCH 295/515] GUI: don't rename settings --- src/gui/gui.h | 4 ++-- src/gui/settings.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 922182769..4654851db 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1085,7 +1085,7 @@ class FurnaceGUI { int roundedButtons; int roundedMenus; int loadJapanese; - int loadChineseSimplified; + int loadChinese; int loadChineseTraditional; int loadKorean; int fmLayout; @@ -1204,7 +1204,7 @@ class FurnaceGUI { roundedButtons(1), roundedMenus(0), loadJapanese(0), - loadChineseSimplified(0), + loadChinese(0), loadChineseTraditional(0), loadKorean(0), fmLayout(0), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 0e1ed3893..1e9a14457 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1072,9 +1072,9 @@ void FurnaceGUI::drawSettings() { ); } - bool loadChineseSimplifiedB=settings.loadChineseSimplified; - if (ImGui::Checkbox("Display Chinese (Simplified) characters",&loadChineseSimplifiedB)) { - settings.loadChineseSimplified=loadChineseSimplifiedB; + bool loadChineseB=settings.loadChinese; + if (ImGui::Checkbox("Display Chinese (Simplified) characters",&loadChineseB)) { + settings.loadChinese=loadChineseB; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip( @@ -2196,7 +2196,7 @@ void FurnaceGUI::syncSettings() { settings.roundedButtons=e->getConfInt("roundedButtons",1); settings.roundedMenus=e->getConfInt("roundedMenus",0); settings.loadJapanese=e->getConfInt("loadJapanese",0); - settings.loadChineseSimplified=e->getConfInt("loadChineseSimplified",0); + settings.loadChinese=e->getConfInt("loadChinese",0); settings.loadChineseTraditional=e->getConfInt("loadChineseTraditional",0); settings.loadKorean=e->getConfInt("loadKorean",0); settings.fmLayout=e->getConfInt("fmLayout",0); @@ -2302,7 +2302,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.roundedButtons,0,1); clampSetting(settings.roundedMenus,0,1); clampSetting(settings.loadJapanese,0,1); - clampSetting(settings.loadChineseSimplified,0,1); + clampSetting(settings.loadChinese,0,1); clampSetting(settings.loadChineseTraditional,0,1); clampSetting(settings.loadKorean,0,1); clampSetting(settings.fmLayout,0,6); @@ -2443,7 +2443,7 @@ void FurnaceGUI::commitSettings() { e->setConf("roundedButtons",settings.roundedButtons); e->setConf("roundedMenus",settings.roundedMenus); e->setConf("loadJapanese",settings.loadJapanese); - e->setConf("loadChineseSimplified",settings.loadChineseSimplified); + e->setConf("loadChinese",settings.loadChinese); e->setConf("loadChineseTraditional",settings.loadChineseTraditional); e->setConf("loadKorean",settings.loadKorean); e->setConf("fmLayout",settings.fmLayout); @@ -3093,7 +3093,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { if (settings.loadJapanese) { range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese()); } - if (settings.loadChineseSimplified) { + if (settings.loadChinese) { range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon()); } if (settings.loadChineseTraditional) { From 46d5a8759c64c51083386af0c03300c0fd666798 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 25 Aug 2022 23:39:55 -0500 Subject: [PATCH 296/515] GUI: fix some interpolate issues --- src/gui/editing.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 1ca3ff691..391a39f62 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -616,9 +616,9 @@ void FurnaceGUI::doInterpolate() { } } else { for (int j=selStart.y; j<=selEnd.y; j++) { - if (pat->data[j][0]!=0 && pat->data[j][1]!=0) { + if (pat->data[j][0]!=0 || pat->data[j][1]!=0) { if (pat->data[j][0]!=100 && pat->data[j][0]!=101 && pat->data[j][0]!=102) { - points.emplace(points.end(),j,pat->data[j][0]+pat->data[j][1]*12); + points.emplace(points.end(),j,pat->data[j][0]+(signed char)pat->data[j][1]*12); } } } From c58f1daeb804d842fc2286b975db1cc9f62bd983 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 26 Aug 2022 03:00:37 -0500 Subject: [PATCH 297/515] QSound: disable key on log we already debugged the issue --- src/engine/platform/qsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 1339d70af..9120464e6 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -338,7 +338,7 @@ void DivPlatformQSound::tick(bool sysTick) { rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); rWrite(q1_reg_map[Q1V_START][i], qsound_addr); rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); - logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); + //logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume if (!chan[i].std.vol.had) { rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4); From 1b80b9618924380871c710fa0367df0c81f9e384 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 26 Aug 2022 03:03:36 -0500 Subject: [PATCH 298/515] prepare for chip swapping --- src/engine/engine.cpp | 61 +++++++++++++++++++++++++++++++++++++++++- src/gui/sysManager.cpp | 13 ++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 153a8db97..c4e1346eb 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -18,6 +18,7 @@ */ #include "dispatch.h" +#include "song.h" #define _USE_MATH_DEFINES #include "engine.h" #include "instrument.h" @@ -1406,7 +1407,65 @@ bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) { if (!preserveOrder) { // move channels - // TODO: a lot of work! + unsigned char unswappedChannels[DIV_MAX_CHANS]; + unsigned char swappedChannels[DIV_MAX_CHANS]; + std::vector> swapList; + std::vector chanList; + + int tchans=0; + + for (int i=0; i& i: swapList) { + for (int& j: i) { + swappedChannels[index++]=j; + } + } + + logV("swap list:"); + for (int i=0; i %d",unswappedChannels[i],swappedChannels[i]); + } + + // swap channels + bool allComplete=false; + while (!allComplete) { + logD("doing swap..."); + allComplete=true; + for (int i=0; i %d -> %d",unswappedChannels[i],unswappedChannels[swappedChannels[i]]); + unswappedChannels[i]^=unswappedChannels[swappedChannels[i]]; + unswappedChannels[swappedChannels[i]]^=unswappedChannels[i]; + unswappedChannels[i]^=unswappedChannels[swappedChannels[i]]; + } + } + } } DivSystem srcSystem=song.system[src]; diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index e43b4dfed..2be87fc9a 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -22,6 +22,9 @@ #include "IconsFontAwesome4.h" #include +static int _src, _dest; +static bool _preserveOrder; + void FurnaceGUI::drawSysManager() { if (nextWindow==GUI_WINDOW_SYS_MANAGER) { sysManagerOpen=true; @@ -30,7 +33,15 @@ void FurnaceGUI::drawSysManager() { } if (!sysManagerOpen) return; if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) { - ImGui::Text("Stuff here..."); + ImGui::Text("Call swapSystem() with arguments:"); + ImGui::InputInt("src",&_src); + ImGui::InputInt("dest",&_dest); + ImGui::Checkbox("preserveOrder",&_preserveOrder); + if (ImGui::Button("Call")) { + if (!e->swapSystem(_src,_dest,_preserveOrder)) { + showError(e->getLastError()); + } + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SYS_MANAGER; ImGui::End(); From 897a61db85ccfc41fda22779dc2657f73a12bafb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 26 Aug 2022 16:44:27 -0500 Subject: [PATCH 299/515] copy paste --- src/gui/sysManager.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index 2be87fc9a..81fcd8e9b 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -42,6 +42,54 @@ void FurnaceGUI::drawSysManager() { showError(e->getLastError()); } } + + if (ImGui::BeginTable("SystemList",3)) { + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Visible"); + ImGui::TableNextColumn(); + ImGui::Text("Name"); + for (int i=0; igetTotalChannelCount(); i++) { + ImGui::PushID(i); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_ARROWS)) { + } + if (ImGui::BeginDragDropSource()) { + chanToMove=i; + ImGui::SetDragDropPayload("FUR_CHAN",NULL,0,ImGuiCond_Once); + ImGui::Button(ICON_FA_ARROWS "##ChanDrag"); + ImGui::EndDragDropSource(); + } else if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s #%d\n(drag to swap channels)",e->getSystemName(e->sysOfChan[i]),e->dispatchChanOfChan[i]); + } + if (ImGui::BeginDragDropTarget()) { + const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_CHAN"); + if (dragItem!=NULL) { + if (dragItem->IsDataType("FUR_CHAN")) { + if (chanToMove!=i && chanToMove>=0) { + e->swapChannelsP(chanToMove,i); + } + chanToMove=-1; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::InputTextWithHint("##ChanShortName",e->getChannelShortName(i),&e->curSubSong->chanShortName[i]); + ImGui::PopID(); + } + ImGui::EndTable(); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SYS_MANAGER; ImGui::End(); From be9385f70139a5adeb2f4056a9a674b1d0c4c21b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 26 Aug 2022 18:51:17 -0500 Subject: [PATCH 300/515] GUI: work on chip manager --- src/gui/gui.cpp | 12 +++++++ src/gui/gui.h | 3 +- src/gui/sysManager.cpp | 74 +++++++++++++++++++++++------------------- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0d53e97da..fb127648a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4161,6 +4161,16 @@ bool FurnaceGUI::loop() { ImGui::CloseCurrentPopup(); } break; + case GUI_WARN_SYSTEM_DEL: + if (ImGui::Button("Yes")) { + e->removeSystem(sysToDelete,preserveChanPos); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No")) { + ImGui::CloseCurrentPopup(); + } + break; case GUI_WARN_GENERIC: if (ImGui::Button("OK")) { ImGui::CloseCurrentPopup(); @@ -4956,6 +4966,8 @@ FurnaceGUI::FurnaceGUI(): eventTimeEnd(0), eventTimeDelta(0), chanToMove(-1), + sysToMove(-1), + sysToDelete(-1), transposeAmount(0), randomizeMin(0), randomizeMax(255), diff --git a/src/gui/gui.h b/src/gui/gui.h index 4654851db..a93e59a9f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -310,6 +310,7 @@ enum FurnaceGUIWarnings { GUI_WARN_CLOSE_SETTINGS, GUI_WARN_CLEAR, GUI_WARN_SUBSONG_DEL, + GUI_WARN_SYSTEM_DEL, GUI_WARN_GENERIC }; @@ -1433,7 +1434,7 @@ class FurnaceGUI { int renderTimeBegin, renderTimeEnd, renderTimeDelta; int eventTimeBegin, eventTimeEnd, eventTimeDelta; - int chanToMove; + int chanToMove, sysToMove, sysToDelete; ImVec2 patWindowPos, patWindowSize; diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index 81fcd8e9b..619345ba8 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -20,11 +20,9 @@ #include "gui.h" #include "misc/cpp/imgui_stdlib.h" #include "IconsFontAwesome4.h" +#include #include -static int _src, _dest; -static bool _preserveOrder; - void FurnaceGUI::drawSysManager() { if (nextWindow==GUI_WINDOW_SYS_MANAGER) { sysManagerOpen=true; @@ -33,61 +31,71 @@ void FurnaceGUI::drawSysManager() { } if (!sysManagerOpen) return; if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) { - ImGui::Text("Call swapSystem() with arguments:"); - ImGui::InputInt("src",&_src); - ImGui::InputInt("dest",&_dest); - ImGui::Checkbox("preserveOrder",&_preserveOrder); - if (ImGui::Button("Call")) { - if (!e->swapSystem(_src,_dest,_preserveOrder)) { - showError(e->getLastError()); - } - } - + ImGui::Checkbox("Preserve channel order",&preserveChanPos); if (ImGui::BeginTable("SystemList",3)) { - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); - ImGui::Text("Visible"); ImGui::TableNextColumn(); ImGui::Text("Name"); - for (int i=0; igetTotalChannelCount(); i++) { + ImGui::TableNextColumn(); + ImGui::Text("Actions"); + for (unsigned char i=0; isong.systemLen; i++) { ImGui::PushID(i); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]); - ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROWS)) { } if (ImGui::BeginDragDropSource()) { - chanToMove=i; - ImGui::SetDragDropPayload("FUR_CHAN",NULL,0,ImGuiCond_Once); - ImGui::Button(ICON_FA_ARROWS "##ChanDrag"); + sysToMove=i; + ImGui::SetDragDropPayload("FUR_SYS",NULL,0,ImGuiCond_Once); + ImGui::Button(ICON_FA_ARROWS "##SysDrag"); ImGui::EndDragDropSource(); } else if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s #%d\n(drag to swap channels)",e->getSystemName(e->sysOfChan[i]),e->dispatchChanOfChan[i]); + ImGui::SetTooltip("(drag to swap chips)"); } if (ImGui::BeginDragDropTarget()) { - const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_CHAN"); + const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_SYS"); if (dragItem!=NULL) { - if (dragItem->IsDataType("FUR_CHAN")) { - if (chanToMove!=i && chanToMove>=0) { - e->swapChannelsP(chanToMove,i); + if (dragItem->IsDataType("FUR_SYS")) { + if (sysToMove!=i && sysToMove>=0) { + e->swapSystem(sysToMove,i,preserveChanPos); } - chanToMove=-1; + sysToMove=-1; } } ImGui::EndDragDropTarget(); } ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]); + if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSM%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { + drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true); + ImGui::TreePop(); + } ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::InputTextWithHint("##ChanShortName",e->getChannelShortName(i),&e->curSubSong->chanShortName[i]); + ImGui::Button(ICON_FA_CHEVRON_DOWN "##SysChange"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Change"); + } + ImGui::SameLine(); + ImGui::BeginDisabled(e->song.systemLen<=1); + if (ImGui::Button(ICON_FA_TIMES "##SysRemove")) { + sysToDelete=i; + showWarning("Are you sure you want to remove this chip?",GUI_WARN_SYSTEM_DEL); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Remove"); + } + ImGui::EndDisabled(); ImGui::PopID(); } + if (e->song.systemLen<32) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + ImGui::Button(ICON_FA_PLUS "##SysAdd"); + } ImGui::EndTable(); } } From daf176e197c35cd82b0b6208cc7ac3349c6eef65 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 26 Aug 2022 19:30:13 -0500 Subject: [PATCH 301/515] GUI: prepare for new chip picker --- CMakeLists.txt | 1 + src/engine/engine.h | 3 ++ src/engine/sysDef.cpp | 4 +++ src/gui/gui.cpp | 30 ++++++----------- src/gui/gui.h | 6 +++- src/gui/sysManager.cpp | 18 ++++++++++ src/gui/sysPicker.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 src/gui/sysPicker.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c8d39396..b47d2a74c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -553,6 +553,7 @@ src/gui/subSongs.cpp src/gui/sysConf.cpp src/gui/sysEx.cpp src/gui/sysManager.cpp +src/gui/sysPicker.cpp src/gui/util.cpp src/gui/waveEdit.cpp src/gui/volMeter.cpp diff --git a/src/engine/engine.h b/src/engine/engine.h index 3e75bef6b..ccfed7c3a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -627,6 +627,9 @@ class DivEngine { // get japanese system name const char* getSystemNameJ(DivSystem sys); + // get sys definition + const DivSysDef* getSystemDef(DivSystem sys); + // convert sample rate format int fileToDivRate(int frate); int divToFileRate(int drate); diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 0487873b8..6dc3a8a4e 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -284,6 +284,10 @@ const char* DivEngine::getSystemNameJ(DivSystem sys) { */ } +const DivSysDef* DivEngine::getSystemDef(DivSystem sys) { + return sysDefs[sys]; +} + bool DivEngine::isFMSystem(DivSystem sys) { if (sysDefs[sys]==NULL) return false; return sysDefs[sys]->isFM; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index fb127648a..09ecad39e 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1941,20 +1941,6 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { } } -#define sysAddOption(x) \ - if (ImGui::MenuItem(getSystemName(x))) { \ - if (!e->addSystem(x)) { \ - showError("cannot add chip! ("+e->getLastError()+")"); \ - } \ - updateWindowTitle(); \ - } - -#define sysChangeOption(x,y) \ - if (ImGui::MenuItem(getSystemName(y),NULL,e->song.system[x]==y)) { \ - e->changeSystem(x,y,preserveChanPos); \ - updateWindowTitle(); \ - } - #define checkExtension(x) \ String lowerCase=fileName; \ for (char& i: lowerCase) { \ @@ -3051,9 +3037,12 @@ bool FurnaceGUI::loop() { } ImGui::Separator(); if (ImGui::BeginMenu("add chip...")) { - for (int j=0; availableSystems[j]; j++) { - if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue; - sysAddOption((DivSystem)availableSystems[j]); + DivSystem picked=systemPicker(); + if (picked!=DIV_SYSTEM_NULL) { + if (!e->addSystem(picked)) { + showError("cannot add chip! ("+e->getLastError()+")"); + } + updateWindowTitle(); } ImGui::EndMenu(); } @@ -3070,9 +3059,10 @@ bool FurnaceGUI::loop() { ImGui::Checkbox("Preserve channel positions",&preserveChanPos); for (int i=0; isong.systemLen; i++) { if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - for (int j=0; availableSystems[j]; j++) { - if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue; - sysChangeOption(i,(DivSystem)availableSystems[j]); + DivSystem picked=systemPicker(); + if (picked!=DIV_SYSTEM_NULL) { + e->changeSystem(i,picked,preserveChanPos); + updateWindowTitle(); } ImGui::EndMenu(); } diff --git a/src/gui/gui.h b/src/gui/gui.h index a93e59a9f..283edc829 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -969,13 +969,15 @@ class FurnaceGUI { int sampleTexW, sampleTexH; bool updateSampleTex; - String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; + String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery; String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport; String workingDirVGMExport, workingDirROMExport, workingDirFont, workingDirColors, workingDirKeybinds; String workingDirLayout, workingDirROM, workingDirTest; String mmlString[32]; String mmlStringW; + std::vector sysSearchResults; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; @@ -1666,6 +1668,8 @@ class FurnaceGUI { void doReplace(); void doDrag(); void editOptions(bool topMenu); + DivSystem systemPicker(); + bool systemPickerOption(DivSystem sys); void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index 619345ba8..bab348e3c 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -78,6 +78,14 @@ void FurnaceGUI::drawSysManager() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Change"); } + if (ImGui::BeginPopupContextItem("SysPickerC",ImGuiPopupFlags_MouseButtonLeft)) { + DivSystem picked=systemPicker(); + if (picked!=DIV_SYSTEM_NULL) { + e->changeSystem(i,picked,preserveChanPos); + updateWindowTitle(); + } + ImGui::EndPopup(); + } ImGui::SameLine(); ImGui::BeginDisabled(e->song.systemLen<=1); if (ImGui::Button(ICON_FA_TIMES "##SysRemove")) { @@ -95,6 +103,16 @@ void FurnaceGUI::drawSysManager() { ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::Button(ICON_FA_PLUS "##SysAdd"); + if (ImGui::BeginPopupContextItem("SysPickerA",ImGuiPopupFlags_MouseButtonLeft)) { + DivSystem picked=systemPicker(); + if (picked!=DIV_SYSTEM_NULL) { + if (!e->addSystem(picked)) { + showError("cannot add chip! ("+e->getLastError()+")"); + } + updateWindowTitle(); + } + ImGui::EndPopup(); + } } ImGui::EndTable(); } diff --git a/src/gui/sysPicker.cpp b/src/gui/sysPicker.cpp new file mode 100644 index 000000000..bcfc95aea --- /dev/null +++ b/src/gui/sysPicker.cpp @@ -0,0 +1,74 @@ +/** + * 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 "gui.h" +#include "misc/cpp/imgui_stdlib.h" +#include "IconsFontAwesome4.h" +#include "guiConst.h" +#include + +bool FurnaceGUI::systemPickerOption(DivSystem sys) { + const DivSysDef* sysDef=e->getSystemDef(sys); + if (sysDef==NULL) return false; + bool ret=ImGui::Selectable(sysDef->name); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(sysDef->description); + ImGui::EndTooltip(); + } + return ret; +} + +DivSystem FurnaceGUI::systemPicker() { + DivSystem ret=DIV_SYSTEM_NULL; + /* + for (int j=0; availableSystems[j]; j++) { + if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue; + sysAddOption((DivSystem)availableSystems[j]); + } + */ + if (ImGui::InputTextWithHint("##SysSearch","Search...",&sysSearchQuery)) { + String lowerCase=sysSearchQuery; + for (char& i: lowerCase) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + sysSearchResults.clear(); + for (int j=0; availableSystems[j]; j++) { + String lowerCase1=e->getSystemName((DivSystem)availableSystems[j]); + for (char& i: lowerCase1) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + if (lowerCase1.find(lowerCase)!=String::npos) { + sysSearchResults.push_back((DivSystem)availableSystems[j]); + } + } + } + if (sysSearchQuery.empty()) { + // display chip list + for (int j=0; availableSystems[j]; j++) { + if (systemPickerOption((DivSystem)availableSystems[j])) ret=(DivSystem)availableSystems[j]; + } + } else { + // display search results + for (DivSystem i: sysSearchResults) { + if (systemPickerOption(i)) ret=i; + } + } + return ret; +} \ No newline at end of file From 73f88c7635836b9e9c5b8f2e69b311f471ef6e10 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 26 Aug 2022 23:35:16 -0500 Subject: [PATCH 302/515] GUI: and here is the new chip selector --- src/gui/gui.cpp | 3 ++ src/gui/gui.h | 2 +- src/gui/guiConst.cpp | 116 ++++++++++++++++++++++++++++++++++++++++- src/gui/guiConst.h | 7 +++ src/gui/sysManager.cpp | 2 + src/gui/sysPicker.cpp | 83 ++++++++++++++++++----------- 6 files changed, 181 insertions(+), 32 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 09ecad39e..5cb4d520b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3042,6 +3042,7 @@ bool FurnaceGUI::loop() { if (!e->addSystem(picked)) { showError("cannot add chip! ("+e->getLastError()+")"); } + ImGui::CloseCurrentPopup(); updateWindowTitle(); } ImGui::EndMenu(); @@ -3063,6 +3064,7 @@ bool FurnaceGUI::loop() { if (picked!=DIV_SYSTEM_NULL) { e->changeSystem(i,picked,preserveChanPos); updateWindowTitle(); + ImGui::CloseCurrentPopup(); } ImGui::EndMenu(); } @@ -4756,6 +4758,7 @@ FurnaceGUI::FurnaceGUI(): drawHalt(10), macroPointSize(16), waveEditStyle(0), + curSysSection(NULL), pendingRawSampleDepth(8), pendingRawSampleChannels(1), pendingRawSampleUnsigned(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 283edc829..b47784d21 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -987,6 +987,7 @@ class FurnaceGUI { int drawHalt; int macroPointSize; int waveEditStyle; + const int* curSysSection; String pendingRawSample; int pendingRawSampleDepth, pendingRawSampleChannels; @@ -1669,7 +1670,6 @@ class FurnaceGUI { void doDrag(); void editOptions(bool topMenu); DivSystem systemPicker(); - bool systemPickerOption(DivSystem sys); void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 1940946d6..d1ef835c9 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -839,7 +839,9 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ }; #undef D -// define systems. +// define chips here + +// all chips const int availableSystems[]={ DIV_SYSTEM_YM2612, DIV_SYSTEM_YM2612_EXT, @@ -911,3 +913,115 @@ const int availableSystems[]={ 0 // don't remove this last one! }; +// FM +const int chipsFM[]={ + DIV_SYSTEM_YM2612, + DIV_SYSTEM_YM2612_EXT, + DIV_SYSTEM_YM2612_FRAC, + DIV_SYSTEM_YM2612_FRAC_EXT, + DIV_SYSTEM_YM2151, + DIV_SYSTEM_YM2610, + DIV_SYSTEM_YM2610_EXT, + DIV_SYSTEM_YM2610_FULL, + DIV_SYSTEM_YM2610_FULL_EXT, + DIV_SYSTEM_YM2610B, + DIV_SYSTEM_YM2610B_EXT, + DIV_SYSTEM_YMU759, + DIV_SYSTEM_OPN, + DIV_SYSTEM_OPN_EXT, + DIV_SYSTEM_PC98, + DIV_SYSTEM_PC98_EXT, + DIV_SYSTEM_OPLL, + DIV_SYSTEM_OPLL_DRUMS, + DIV_SYSTEM_VRC7, + DIV_SYSTEM_OPL, + DIV_SYSTEM_OPL_DRUMS, + DIV_SYSTEM_Y8950, + DIV_SYSTEM_Y8950_DRUMS, + DIV_SYSTEM_OPL2, + DIV_SYSTEM_OPL2_DRUMS, + DIV_SYSTEM_OPL3, + DIV_SYSTEM_OPL3_DRUMS, + DIV_SYSTEM_OPZ, + 0 // don't remove this last one! +}; + +// square +const int chipsSquare[]={ + DIV_SYSTEM_SMS, + DIV_SYSTEM_AY8910, + DIV_SYSTEM_PCSPKR, + DIV_SYSTEM_SAA1099, + DIV_SYSTEM_VIC20, + 0 // don't remove this last one! +}; + +// wavetable +const int chipsWave[]={ + DIV_SYSTEM_PCE, + DIV_SYSTEM_X1_010, + DIV_SYSTEM_SWAN, + DIV_SYSTEM_BUBSYS_WSG, + DIV_SYSTEM_N163, + DIV_SYSTEM_FDS, + DIV_SYSTEM_SCC, + DIV_SYSTEM_SCC_PLUS, + DIV_SYSTEM_NAMCO, + DIV_SYSTEM_NAMCO_15XX, + DIV_SYSTEM_NAMCO_CUS30, + 0 // don't remove this last one! +}; + +// specialized +const int chipsSpecial[]={ + DIV_SYSTEM_GB, + DIV_SYSTEM_NES, + DIV_SYSTEM_C64_8580, + DIV_SYSTEM_C64_6581, + DIV_SYSTEM_SFX_BEEPER, + DIV_SYSTEM_DUMMY, + DIV_SYSTEM_SOUND_UNIT, + DIV_SYSTEM_TIA, + DIV_SYSTEM_AY8930, + DIV_SYSTEM_LYNX, + DIV_SYSTEM_VERA, + DIV_SYSTEM_PET, + DIV_SYSTEM_VRC6, + DIV_SYSTEM_MMC5, + 0 // don't remove this last one! +}; + +// sample +const int chipsSample[]={ + DIV_SYSTEM_SEGAPCM, + DIV_SYSTEM_SEGAPCM_COMPAT, + DIV_SYSTEM_AMIGA, + DIV_SYSTEM_QSOUND, + DIV_SYSTEM_X1_010, + DIV_SYSTEM_YMZ280B, + DIV_SYSTEM_MSM6258, + DIV_SYSTEM_MSM6295, + DIV_SYSTEM_RF5C68, + DIV_SYSTEM_PCM_DAC, + 0 // don't remove this last one! +}; + +const int* chipCategories[]={ + availableSystems, + chipsFM, + chipsSquare, + chipsWave, + chipsSpecial, + chipsSample, + NULL +}; + +const char* chipCategoryNames[]={ + "All chips", + "FM", + "Square", + "Wavetable", + "Special", + "Sample", + NULL +}; \ No newline at end of file diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index a6df68f62..24bdac47f 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -42,7 +42,14 @@ extern const char* pitchLabel[11]; extern const char* insTypes[]; extern const char* sampleDepths[]; extern const char* resampleStrats[]; +extern const char* chipCategoryNames[]; extern const int availableSystems[]; +extern const int chipsFM[]; +extern const int chipsSquare[]; +extern const int chipsWavetable[]; +extern const int chipsSpecial[]; +extern const int chipsSample[]; +extern const int* chipCategories[]; extern const FurnaceGUIActionDef guiActions[]; extern const FurnaceGUIColorDef guiColors[]; extern const int altValues[24]; diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index bab348e3c..98f939d0f 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -83,6 +83,7 @@ void FurnaceGUI::drawSysManager() { if (picked!=DIV_SYSTEM_NULL) { e->changeSystem(i,picked,preserveChanPos); updateWindowTitle(); + ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } @@ -110,6 +111,7 @@ void FurnaceGUI::drawSysManager() { showError("cannot add chip! ("+e->getLastError()+")"); } updateWindowTitle(); + ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } diff --git a/src/gui/sysPicker.cpp b/src/gui/sysPicker.cpp index bcfc95aea..f59e547ad 100644 --- a/src/gui/sysPicker.cpp +++ b/src/gui/sysPicker.cpp @@ -23,52 +23,75 @@ #include "guiConst.h" #include -bool FurnaceGUI::systemPickerOption(DivSystem sys) { - const DivSysDef* sysDef=e->getSystemDef(sys); - if (sysDef==NULL) return false; - bool ret=ImGui::Selectable(sysDef->name); - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::TextUnformatted(sysDef->description); - ImGui::EndTooltip(); - } - return ret; -} - DivSystem FurnaceGUI::systemPicker() { DivSystem ret=DIV_SYSTEM_NULL; - /* - for (int j=0; availableSystems[j]; j++) { - if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue; - sysAddOption((DivSystem)availableSystems[j]); - } - */ - if (ImGui::InputTextWithHint("##SysSearch","Search...",&sysSearchQuery)) { + DivSystem hoveredSys=DIV_SYSTEM_NULL; + bool reissueSearch=false; + if (curSysSection==NULL) { + curSysSection=availableSystems; + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputTextWithHint("##SysSearch","Search...",&sysSearchQuery)) reissueSearch=true; + if (ImGui::BeginTabBar("SysCats")) { + for (int i=0; chipCategories[i]; i++) { + if (ImGui::BeginTabItem(chipCategoryNames[i])) { + if (ImGui::IsItemActive()) { + reissueSearch=true; + } + curSysSection=chipCategories[i]; + ImGui::EndTabItem(); + } + } + ImGui::EndTabBar(); + } + if (reissueSearch) { String lowerCase=sysSearchQuery; for (char& i: lowerCase) { if (i>='A' && i<='Z') i+='a'-'A'; } sysSearchResults.clear(); - for (int j=0; availableSystems[j]; j++) { - String lowerCase1=e->getSystemName((DivSystem)availableSystems[j]); + for (int j=0; curSysSection[j]; j++) { + String lowerCase1=e->getSystemName((DivSystem)curSysSection[j]); for (char& i: lowerCase1) { if (i>='A' && i<='Z') i+='a'-'A'; } if (lowerCase1.find(lowerCase)!=String::npos) { - sysSearchResults.push_back((DivSystem)availableSystems[j]); + sysSearchResults.push_back((DivSystem)curSysSection[j]); } } } - if (sysSearchQuery.empty()) { - // display chip list - for (int j=0; availableSystems[j]; j++) { - if (systemPickerOption((DivSystem)availableSystems[j])) ret=(DivSystem)availableSystems[j]; + if (ImGui::BeginTable("SysList",1,ImGuiTableFlags_ScrollY,ImVec2(500.0f*dpiScale,200.0*dpiScale))) { + if (sysSearchQuery.empty()) { + // display chip list + for (int j=0; curSysSection[j]; j++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Selectable(e->getSystemName((DivSystem)curSysSection[j]),false,0,ImVec2(500.0f*dpiScale,0.0f))) ret=(DivSystem)curSysSection[j]; + if (ImGui::IsItemHovered()) { + hoveredSys=(DivSystem)curSysSection[j]; + } + } + } else { + // display search results + for (DivSystem i: sysSearchResults) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Selectable(e->getSystemName(i),false,0,ImVec2(500.0f*dpiScale,0.0f))) ret=i; + if (ImGui::IsItemHovered()) { + hoveredSys=i; + } + } } - } else { - // display search results - for (DivSystem i: sysSearchResults) { - if (systemPickerOption(i)) ret=i; + ImGui::EndTable(); + } + ImGui::Separator(); + if (ImGui::BeginChild("SysDesc",ImVec2(0.0f,150.0f*dpiScale),false,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse)) { + if (hoveredSys!=DIV_SYSTEM_NULL) { + const DivSysDef* sysDef=e->getSystemDef(hoveredSys); + ImGui::TextWrapped("%s",sysDef->description); } } + ImGui::EndChild(); return ret; } \ No newline at end of file From efd5cc0dacf050533bd826f829d1021260f0aa5e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 27 Aug 2022 00:14:17 -0500 Subject: [PATCH 303/515] GUI: implement search in "Choose a System!" --- src/gui/gui.h | 3 +- src/gui/newSong.cpp | 78 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index b47784d21..48b8e12cb 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -969,7 +969,7 @@ class FurnaceGUI { int sampleTexW, sampleTexH; bool updateSampleTex; - String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery; + String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery, newSongQuery; String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport; String workingDirVGMExport, workingDirROMExport, workingDirFont, workingDirColors, workingDirKeybinds; String workingDirLayout, workingDirROM, workingDirTest; @@ -977,6 +977,7 @@ class FurnaceGUI { String mmlStringW; std::vector sysSearchResults; + std::vector newSongSearchResults; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index 26fddf9fb..c819ffd3a 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -18,7 +18,8 @@ */ #include "gui.h" -#include +#include "misc/cpp/imgui_stdlib.h" +#include void FurnaceGUI::drawNewSong() { bool accepted=false; @@ -32,35 +33,76 @@ void FurnaceGUI::drawNewSong() { avail.y-=ImGui::GetFrameHeightWithSpacing(); if (ImGui::BeginChild("sysPickerC",avail,false,ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) { - if (ImGui::BeginTable("sysPicker",2,ImGuiTableFlags_BordersInnerV)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputTextWithHint("##SysSearch","Search...",&newSongQuery)) { + String lowerCase=newSongQuery; + for (char& i: lowerCase) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + auto lastItem=std::remove_if(lowerCase.begin(),lowerCase.end(),[](char c) { + return (c==' ' || c=='_' || c=='-'); + }); + lowerCase.erase(lastItem,lowerCase.end()); + newSongSearchResults.clear(); + for (FurnaceGUISysCategory& i: sysCategories) { + for (FurnaceGUISysDef& j: i.systems) { + String lowerCase1=j.name; + for (char& i: lowerCase1) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + auto lastItem=std::remove_if(lowerCase1.begin(),lowerCase1.end(),[](char c) { + return (c==' ' || c=='_' || c=='-'); + }); + lowerCase1.erase(lastItem,lowerCase1.end()); + if (lowerCase1.find(lowerCase)!=String::npos) { + newSongSearchResults.push_back(j); + } + } + std::sort(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) { + return strcmp(a.name,b.name)<0; + }); + auto lastItem=std::unique(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) { + return strcmp(a.name,b.name)==0; + }); + newSongSearchResults.erase(lastItem,newSongSearchResults.end()); + } + } + if (ImGui::BeginTable("sysPicker",newSongQuery.empty()?2:1,ImGuiTableFlags_BordersInnerV)) { + if (newSongQuery.empty()) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f); + } ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0f); - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::Text("Categories"); - ImGui::TableNextColumn(); - ImGui::Text("Systems"); + if (newSongQuery.empty()) { + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Categories"); + ImGui::TableNextColumn(); + ImGui::Text("Systems"); + } ImGui::TableNextRow(); // CATEGORIES - ImGui::TableNextColumn(); - int index=0; - for (FurnaceGUISysCategory& i: sysCategories) { - if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \ - newSongCategory=index; + if (newSongQuery.empty()) { + ImGui::TableNextColumn(); + int index=0; + for (FurnaceGUISysCategory& i: sysCategories) { + if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \ + newSongCategory=index; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s",i.description); + } + index++; } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s",i.description); - } - index++; } // SYSTEMS ImGui::TableNextColumn(); if (ImGui::BeginTable("Systems",1,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollY)) { - for (FurnaceGUISysDef& i: sysCategories[newSongCategory].systems) { + std::vector& category=(newSongQuery.empty())?(sysCategories[newSongCategory].systems):(newSongSearchResults); + for (FurnaceGUISysDef& i: category) { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) { From d577755035892fc082c13725d865d0a6e1ce9eea Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 27 Aug 2022 00:37:32 -0500 Subject: [PATCH 304/515] fix note on sometimes not working in jam mode --- src/engine/engine.cpp | 12 ++++++------ src/engine/engine.h | 4 ++-- src/engine/playback.cpp | 27 ++++++++++++++++++++++----- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index c4e1346eb..1230cb599 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3210,7 +3210,7 @@ bool DivEngine::moveSampleDown(int which) { void DivEngine::noteOn(int chan, int ins, int note, int vol) { if (chan<0 || chan>=chans) return; BUSY_BEGIN; - pendingNotes.push(DivNoteEvent(chan,ins,note,vol,true)); + pendingNotes.push_back(DivNoteEvent(chan,ins,note,vol,true)); if (!playing) { reset(); freelance=true; @@ -3222,7 +3222,7 @@ void DivEngine::noteOn(int chan, int ins, int note, int vol) { void DivEngine::noteOff(int chan) { if (chan<0 || chan>=chans) return; BUSY_BEGIN; - pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false)); + pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false)); if (!playing) { reset(); freelance=true; @@ -3274,7 +3274,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { if ((!midiPoly) || (isViable[finalChan] && chan[finalChan].midiNote==-1 && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel))) { chan[finalChan].midiNote=note; chan[finalChan].midiAge=midiAgeCounter++; - pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true)); + pendingNotes.push_back(DivNoteEvent(finalChan,ins,note,vol,true)); return; } if (++finalChan>=chans) { @@ -3295,7 +3295,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { chan[candidate].midiNote=note; chan[candidate].midiAge=midiAgeCounter++; - pendingNotes.push(DivNoteEvent(candidate,ins,note,vol,true)); + pendingNotes.push_back(DivNoteEvent(candidate,ins,note,vol,true)); } void DivEngine::autoNoteOff(int ch, int note, int vol) { @@ -3307,7 +3307,7 @@ void DivEngine::autoNoteOff(int ch, int note, int vol) { //if (ch<0 || ch>=chans) return; for (int i=0; i #include #include -#include +#include #define addWarning(x) \ if (warnings.empty()) { \ @@ -357,7 +357,7 @@ class DivEngine { DivAudioExportModes exportMode; double exportFadeOut; std::map conf; - std::queue pendingNotes; + std::deque pendingNotes; bool isMuted[DIV_MAX_CHANS]; std::mutex isBusy, saveLock; String configPath; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index f4c4968d1..7fb9583d7 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1010,10 +1010,27 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { //output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0)); } + if (!pendingNotes.empty()) { + bool isOn[DIV_MAX_CHANS]; + memset(isOn,0,DIV_MAX_CHANS*sizeof(bool)); + + for (int i=pendingNotes.size()-1; i>=0; i--) { + if (pendingNotes[i].channel<0 || pendingNotes[i].channel>=chans) continue; + if (pendingNotes[i].on) { + isOn[pendingNotes[i].channel]=true; + } else { + if (isOn[pendingNotes[i].channel]) { + logV("erasing off -> on sequence in %d",pendingNotes[i].channel); + pendingNotes.erase(pendingNotes.begin()+i); + } + } + } + } + while (!pendingNotes.empty()) { DivNoteEvent& note=pendingNotes.front(); if (note.channel<0 || note.channel>=chans) { - pendingNotes.pop(); + pendingNotes.pop_front(); continue; } if (note.on) { @@ -1033,7 +1050,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel)); } } - pendingNotes.pop(); + pendingNotes.pop_front(); } if (!freelance) { @@ -1245,7 +1262,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi case TA_MIDI_NOTE_OFF: { if (chan<0 || chan>=chans) break; if (midiIsDirect) { - pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false)); + pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false)); } else { autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]); } @@ -1260,13 +1277,13 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (chan<0 || chan>=chans) break; if (msg.data[1]==0) { if (midiIsDirect) { - pendingNotes.push(DivNoteEvent(chan,-1,-1,-1,false)); + pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false)); } else { autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]); } } else { if (midiIsDirect) { - pendingNotes.push(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true)); + pendingNotes.push_back(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true)); } else { autoNoteOn(msg.type&15,ins,msg.data[0]-12,msg.data[1]); } From 4cc79fb49ddb24ca428a618fea7779915b9e546f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 16:27:36 +0900 Subject: [PATCH 305/515] Prepare for split sample chip instrument (MSM6258, MSM6295, QSound, Sega PCM, ADPCM-A, ADPCM-B, YMZ280B, RF5C68) Instrument color and icons are placeholder. different volume range, hard panned/soft panned and/or independent volume per output, chip-dependent features (global volume, echo, etc) Allow use sample in instrument tab for chip with sample support Prepare to support X1-010 Seta 2 style bankswitch behavior Prepare to support AY89x0 PCM DAC Support volume for PCE sample (DAC) Fix Lynx, Y8950 sample pitch matches to sample preview Support PCM DAC with backward and pingpong loop mode Reduce some codes Add Sega PCM, AY89x0, QSound, PCM DAC, Lynx per-channel debug support --- src/engine/dispatch.h | 3 + src/engine/instrument.cpp | 4 +- src/engine/instrument.h | 80 +++- src/engine/platform/ay.cpp | 267 ++++++++--- src/engine/platform/ay.h | 76 +++- src/engine/platform/ay8930.cpp | 220 +++++++-- src/engine/platform/ay8930.h | 76 +++- src/engine/platform/lynx.cpp | 26 +- src/engine/platform/lynx.h | 4 +- src/engine/platform/msm6258.cpp | 56 ++- src/engine/platform/msm6295.cpp | 33 +- src/engine/platform/msm6295.h | 4 +- src/engine/platform/opl.cpp | 67 +-- src/engine/platform/opl.h | 4 +- src/engine/platform/pce.cpp | 36 +- src/engine/platform/pce.h | 7 +- src/engine/platform/pcmdac.cpp | 72 ++- src/engine/platform/pcmdac.h | 4 +- src/engine/platform/qsound.cpp | 58 ++- src/engine/platform/qsound.h | 14 +- src/engine/platform/rf5c68.cpp | 11 +- src/engine/platform/rf5c68.h | 4 +- src/engine/platform/segapcm.cpp | 122 ++--- src/engine/platform/segapcm.h | 12 +- src/engine/platform/su.cpp | 6 +- src/engine/platform/swan.cpp | 4 +- src/engine/platform/vrc6.cpp | 23 +- src/engine/platform/x1_010.cpp | 104 +++-- src/engine/platform/x1_010.h | 32 +- src/engine/platform/ym2608.cpp | 154 +++++-- src/engine/platform/ym2608.h | 5 +- src/engine/platform/ym2610.cpp | 507 ++++++++++----------- src/engine/platform/ym2610.h | 97 +--- src/engine/platform/ym2610Interface.cpp | 4 +- src/engine/platform/ym2610b.cpp | 421 ++++++++++-------- src/engine/platform/ym2610b.h | 69 +-- src/engine/platform/ym2610bext.cpp | 138 +++--- src/engine/platform/ym2610bext.h | 14 +- src/engine/platform/ym2610ext.cpp | 134 +++--- src/engine/platform/ym2610ext.h | 14 +- src/engine/platform/ym2610shared.h | 315 +++++++++++++ src/engine/platform/ymz280b.cpp | 16 +- src/engine/platform/ymz280b.h | 7 +- src/engine/playback.cpp | 3 + src/engine/sysDef.cpp | 50 ++- src/gui/dataList.cpp | 32 ++ src/gui/debug.cpp | 214 +++++++++ src/gui/gui.h | 8 + src/gui/guiConst.cpp | 18 +- src/gui/insEdit.cpp | 563 ++++++++++++++++++------ src/gui/intConst.cpp | 3 + src/gui/intConst.h | 3 + src/gui/settings.cpp | 11 +- 53 files changed, 2928 insertions(+), 1301 deletions(-) create mode 100644 src/engine/platform/ym2610shared.h diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index fb9be5800..496369433 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -165,6 +165,7 @@ enum DivDispatchCmds { DIV_CMD_X1_010_ENVELOPE_PERIOD, DIV_CMD_X1_010_ENVELOPE_SLIDE, DIV_CMD_X1_010_AUTO_ENVELOPE, + DIV_CMD_X1_010_SAMPLE_BANK_SLOT, DIV_CMD_WS_SWEEP_TIME, DIV_CMD_WS_SWEEP_AMOUNT, @@ -189,6 +190,8 @@ enum DivDispatchCmds { DIV_CMD_SU_SYNC_PERIOD_LOW, DIV_CMD_SU_SYNC_PERIOD_HIGH, + DIV_CMD_ADPCMA_GLOBAL_VOLUME, + DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 555d7d17f..d5262a622 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -529,7 +529,7 @@ void DivInstrument::putInsData(SafeWriter* w) { } // Sound Unit - w->writeC(su.useSample); + w->writeC(amiga.useSample); w->writeC(su.switchRoles); // GB hardware sequence @@ -1092,7 +1092,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // Sound Unit if (version>=104) { - su.useSample=reader.readC(); + amiga.useSample=reader.readC(); su.switchRoles=reader.readC(); } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index df7a6b361..bab20ddf4 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,6 +60,14 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, + DIV_INS_MSM6258=33, + DIV_INS_MSM6295=34, + DIV_INS_ADPCMA=35, + DIV_INS_ADPCMB=36, + DIV_INS_SEGAPCM=37, + DIV_INS_QSOUND=38, + DIV_INS_YMZ280B=39, + DIV_INS_RF5C68=40, DIV_INS_MAX, DIV_INS_NULL }; @@ -335,6 +343,7 @@ struct DivInstrumentAmiga { }; short initSample; bool useNoteMap; + bool useSample; bool useWave; unsigned char waveLen; SampleMap noteMap[120]; @@ -368,6 +377,7 @@ struct DivInstrumentAmiga { DivInstrumentAmiga(): initSample(0), useNoteMap(false), + useSample(false), useWave(false), waveLen(31) { for (SampleMap& elem: noteMap) { @@ -376,6 +386,13 @@ struct DivInstrumentAmiga { } }; +struct DivInstrumentX1_010 { + int bankSlot; + + DivInstrumentX1_010(): + bankSlot(0) {} +}; + struct DivInstrumentN163 { int wave, wavePos, waveLen; unsigned char waveMode; @@ -458,13 +475,69 @@ struct DivInstrumentWaveSynth { }; struct DivInstrumentSoundUnit { - bool useSample; bool switchRoles; DivInstrumentSoundUnit(): - useSample(false), switchRoles(false) {} }; +struct DivInstrumentES5506 { + struct Filter { + enum FilterMode: unsigned char { // filter mode for pole 4,3 + FILTER_MODE_HPK2_HPK2=0, + FILTER_MODE_HPK2_LPK1, + FILTER_MODE_LPK2_LPK2, + FILTER_MODE_LPK2_LPK1, + }; + FilterMode mode; + unsigned short k1, k2; + Filter(): + mode(FILTER_MODE_LPK2_LPK1), + k1(0xffff), + k2(0xffff) {} + }; + struct Envelope { + unsigned short ecount; + signed char lVRamp, rVRamp; + signed char k1Ramp, k2Ramp; + bool k1Slow, k2Slow; + Envelope(): + ecount(0), + lVRamp(0), + rVRamp(0), + k1Ramp(0), + k2Ramp(0), + k1Slow(false), + k2Slow(false) {} + }; + Filter filter; + Envelope envelope; + DivInstrumentES5506(): + filter(Filter()), + envelope(Envelope()) {} +}; + +struct DivInstrumentSNES { + enum GainMode: unsigned char { + GAIN_MODE_DIRECT=0, + GAIN_MODE_DEC_LINEAR=4, + GAIN_MODE_DEC_LOG=5, + GAIN_MODE_INC_LINEAR=6, + GAIN_MODE_INC_INVLOG=7 + }; + bool useEnv; + GainMode gainMode; + unsigned char gain; + unsigned char a, d, s, r; + DivInstrumentSNES(): + useEnv(true), + gainMode(GAIN_MODE_DIRECT), + gain(127), + a(15), + d(7), + s(7), + r(0) {} +}; + struct DivInstrument { String name; bool mode; @@ -474,11 +547,14 @@ struct DivInstrument { DivInstrumentGB gb; DivInstrumentC64 c64; DivInstrumentAmiga amiga; + DivInstrumentX1_010 x1_010; DivInstrumentN163 n163; DivInstrumentFDS fds; DivInstrumentMultiPCM multipcm; DivInstrumentWaveSynth ws; DivInstrumentSoundUnit su; + DivInstrumentES5506 es5506; + DivInstrumentSNES snes; /** * save the instrument to a SafeWriter. diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 8df5bd4ce..c9d059722 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -117,6 +117,46 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // PCM part + for (int i=0; i<3; i++) { + if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { + chan[i].dac.period+=chan[i].dac.rate; + bool end=false; + bool changed=false; + int prev_out = chan[i].dac.out; + while (chan[i].dac.period>rate && !end) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->getEndPosition()<=0) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4); + chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15)); + if (prev_out!=chan[i].dac.out) { + prev_out=chan[i].dac.out; + changed=true; + } + chan[i].dac.pos++; + if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { + chan[i].dac.pos=s->getLoopStartPosition(); + } else if (chan[i].dac.pos>=s->getEndPosition()) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + chan[i].dac.period-=rate; + } + if (changed && !end) { + if (!isMuted[i]) { + rWrite(0x08+i,chan[i].dac.out); + } + } + } + } + while (!writes.empty()) { QueuedWrite w=writes.front(); if (intellivision) { @@ -157,22 +197,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformAY8910::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } else { rWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } @@ -185,12 +225,14 @@ void DivPlatformAY8910::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else if (intellivision && (chan[i].psgMode&4)) { - rWrite(0x08+i,(chan[i].outVol&0xc)<<2); - } else { - rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); + if (!chan[i].psgMode.dac) { + if (isMuted[i]) { + rWrite(0x08+i,0); + } else if (intellivision && (chan[i].psgMode.getEnvelope())) { + rWrite(0x08+i,(chan[i].outVol&0xc)<<2); + } else { + rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2)); + } } } if (chan[i].std.arp.had) { @@ -212,13 +254,15 @@ void DivPlatformAY8910::tick(bool sysTick) { rWrite(0x06,31-chan[i].std.duty.val); } if (chan[i].std.wave.had) { - chan[i].psgMode=(chan[i].std.wave.val+1)&7; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else if (intellivision && (chan[i].psgMode&4)) { - rWrite(0x08+i,(chan[i].outVol&0xc)<<2); - } else { - rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); + if (!chan[i].psgMode.dac) { + chan[i].psgMode=(chan[i].std.wave.val+1)&7; + if (isMuted[i]) { + rWrite(0x08+i,0); + } else if (intellivision && (chan[i].psgMode.getEnvelope())) { + rWrite(0x08+i,(chan[i].outVol&0xc)<<2); + } else { + rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2)); + } } } if (chan[i].std.pitch.had) { @@ -232,6 +276,20 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { + if (chan[i].psgMode.dac) { + if (dumpWrites) addWrite(0xffff0002+(i<<8),0); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY); + chan[i].dac.sample=ins->amiga.getSample(chan[i].note); + if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) { + if (dumpWrites) { + rWrite(0x08+i,0); + addWrite(0xffff0000+(i<<8),chan[i].dac.sample); + } + chan[i].dac.pos=0; + chan[i].dac.period=0; + chan[i].keyOn=true; + } + } oldWrites[0x08+i]=-1; oldWrites[0x0d]=-1; } @@ -252,6 +310,19 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + if (chan[i].dac.furnaceDAC) { + double off=1.0; + if (chan[i].dac.sample>=0 && chan[i].dac.samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + chan[i].dac.rate=((double)chipClock*4096.0)/(double)(MAX(1,off*chan[i].freq)); + if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); + } if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].keyOn) { //rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); @@ -307,6 +378,62 @@ int DivPlatformAY8910::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].psgMode.dac=true; + } else if (chan[c.chan].dac.furnaceDAC) { + chan[c.chan].psgMode.dac=false; + } + if (chan[c.chan].psgMode.dac) { + if (skipRegisterWrites) break; + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].dac.sample=ins->amiga.getSample(c.value); + if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=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].keyOn=true; + chan[c.chan].dac.furnaceDAC=true; + } else { + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + } + chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12; + if (chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); + } + chan[c.chan].dac.furnaceDAC=false; + } + break; + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -318,16 +445,21 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (intellivision && (chan[c.chan].psgMode&4)) { - rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + } } break; } case DIV_CMD_NOTE_OFF: + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + chan[c.chan].psgMode.dac=false; chan[c.chan].keyOff=true; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); @@ -341,14 +473,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else { - if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].psgMode&4)) { - rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else { + if (chan[c.chan].active) { + if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + } } } } @@ -398,15 +532,17 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; } case DIV_CMD_STD_NOISE_MODE: - if (c.value<16) { - chan[c.chan].psgMode=(c.value+1)&7; - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].psgMode&4)) { - rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode&4)<<2)); + if (!chan[c.chan].psgMode.dac) { + if (c.value<16) { + chan[c.chan].psgMode=(c.value+1)&7; + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (chan[c.chan].active) { + if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + } } } } @@ -418,16 +554,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) { ayEnvMode=c.value>>4; rWrite(0x0d,ayEnvMode); if (c.value&15) { - chan[c.chan].psgMode|=4; + chan[c.chan].psgMode.envelope|=1; } else { - chan[c.chan].psgMode&=~4; + chan[c.chan].psgMode.envelope&=~1; } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); - } else if (intellivision && (chan[c.chan].psgMode&4)) { + } else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2)); + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); } break; case DIV_CMD_AY_ENVELOPE_LOW: @@ -464,6 +600,15 @@ int DivPlatformAY8910::dispatch(DivCommand c) { updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; + case DIV_CMD_SAMPLE_MODE: + chan[c.chan].psgMode.dac=(c.value>0)?1:0; + break; + case DIV_CMD_SAMPLE_BANK: + sampleBank=c.value; + if (sampleBank>(parent->song.sample.size()/12)) { + sampleBank=parent->song.sample.size()/12; + } + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; @@ -492,10 +637,14 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) { isMuted[ch]=mute; if (isMuted[ch]) { rWrite(0x08+ch,0); - } else if (intellivision && (chan[ch].psgMode&4) && chan[ch].active) { - rWrite(0x08+ch,(chan[ch].vol&0xc)<<2); - } else if (chan[ch].active) { - rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2)); + } else if (chan[ch].active && chan[ch].psgMode.dac) { + rWrite(0x08+ch,chan[ch].dac.out); + } else { + if (intellivision && (chan[ch].psgMode.getEnvelope()) && chan[ch].active) { + rWrite(0x08+ch,(chan[ch].vol&0xc)<<2); + } else if (chan[ch].active) { + rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode.getEnvelope())<<2)); + } } } @@ -554,12 +703,6 @@ void DivPlatformAY8910::reset() { pendingWrites[i]=-1; } - lastBusy=60; - dacMode=0; - dacPeriod=0; - dacPos=0; - dacRate=0; - dacSample=-1; sampleBank=0; ayEnvPeriod=0; ayEnvMode=0; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index f67a2ad97..2ef8d702b 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -31,20 +31,83 @@ class DivPlatformAY8910: public DivDispatch { }; inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; } struct Channel { - unsigned char freqH, freqL; + struct PSGMode { + unsigned char tone: 1; + unsigned char noise: 1; + unsigned char envelope: 1; + unsigned char dac: 1; + + unsigned char getTone() { + return dac?0:(tone<<0); + } + + unsigned char getNoise() { + return dac?0:(noise<<1); + } + + unsigned char getEnvelope() { + return dac?0:(envelope<<2); + } + + PSGMode& operator=(unsigned char s) { + tone=(s>>0)&1; + noise=(s>>1)&1; + envelope=(s>>2)&1; + dac=(s>>3)&1; + return *this; + } + + PSGMode(): + tone(1), + noise(0), + envelope(0), + dac(0) {} + } psgMode; + + struct DAC { + int sample, rate, period, pos, out; + unsigned char furnaceDAC: 1; + + DAC(): + sample(-1), + rate(0), + period(0), + pos(0), + out(0), + furnaceDAC(0) {} + } dac; + int freq, baseFreq, note, pitch, pitch2; int ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + unsigned char autoEnvNum, autoEnvDen; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; int vol, outVol; - unsigned char pan; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; } - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {} + Channel(): + psgMode(PSGMode()), + dac(DAC()), + freq(0), + baseFreq(0), + note(0), + pitch(0), + pitch2(0), + ins(-1), + autoEnvNum(0), + autoEnvDen(0), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + vol(0), + outVol(15) {} }; Channel chan[3]; bool isMuted[3]; @@ -60,11 +123,6 @@ class DivPlatformAY8910: public DivDispatch { unsigned char regPool[16]; unsigned char lastBusy; - bool dacMode; - int dacPeriod; - int dacRate; - int dacPos; - int dacSample; unsigned char sampleBank; int delay; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 581ebb9e8..f60d36c74 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -133,6 +133,46 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // PCM part + for (int i=0; i<3; i++) { + if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { + chan[i].dac.period+=chan[i].dac.rate; + bool end=false; + bool changed=false; + int prev_out = chan[i].dac.out; + while (chan[i].dac.period>rate && !end) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->getEndPosition()<=0) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>3); + chan[i].dac.out=MAX(0,MIN(31,(dacData*chan[i].outVol)/31)); + if (prev_out!=chan[i].dac.out) { + prev_out=chan[i].dac.out; + changed=true; + } + chan[i].dac.pos++; + if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { + chan[i].dac.pos=s->getLoopStartPosition(); + } else if (chan[i].dac.pos>=s->getEndPosition()) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + chan[i].dac.period-=rate; + } + if (changed && !end) { + if (!isMuted[i]) { + rWrite(0x08+i,chan[i].dac.out); + } + } + } + } + while (!writes.empty()) { QueuedWrite w=writes.front(); ay->address_w(w.addr); @@ -167,22 +207,22 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformAY8930::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } else { rWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } @@ -207,10 +247,12 @@ void DivPlatformAY8930::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31)); if (chan[i].outVol<0) chan[i].outVol=0; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else { - rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); + if (!chan[i].psgMode.dac) { + if (isMuted[i]) { + rWrite(0x08+i,0); + } else { + rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3)); + } } } if (chan[i].std.arp.had) { @@ -232,11 +274,13 @@ void DivPlatformAY8930::tick(bool sysTick) { rWrite(0x06,chan[i].std.duty.val); } if (chan[i].std.wave.had) { + if (!chan[i].psgMode.dac) { chan[i].psgMode=(chan[i].std.wave.val+1)&7; if (isMuted[i]) { rWrite(0x08+i,0); } else { - rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); + rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3)); + } } } if (chan[i].std.pitch.had) { @@ -250,6 +294,20 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { + if (chan[i].psgMode.dac) { + if (dumpWrites) addWrite(0xffff0002+(i<<8),0); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY8930); + chan[i].dac.sample=ins->amiga.getSample(chan[i].note); + if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) { + if (dumpWrites) { + rWrite(0x08+i,0); + addWrite(0xffff0000+(i<<8),chan[i].dac.sample); + } + chan[i].dac.pos=0; + chan[i].dac.period=0; + chan[i].keyOn=true; + } + } oldWrites[0x08+i]=-1; oldWrites[regMode[i]]=-1; } @@ -281,6 +339,19 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + if (chan[i].dac.furnaceDAC) { + double off=1.0; + if (chan[i].dac.sample>=0 && chan[i].dac.samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + chan[i].dac.rate=((double)chipClock*16384.0)/(double)(MAX(1,off*chan[i].freq)); + if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); + } if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].keyOn) { if (chan[i].insChanged) { @@ -338,6 +409,62 @@ int DivPlatformAY8930::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930); + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].psgMode.dac=true; + } else if (chan[c.chan].dac.furnaceDAC) { + chan[c.chan].psgMode.dac=false; + } + if (chan[c.chan].psgMode.dac) { + if (skipRegisterWrites) break; + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].dac.sample=ins->amiga.getSample(c.value); + if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=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].keyOn=true; + chan[c.chan].dac.furnaceDAC=true; + } else { + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + } + chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12; + if (chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); + } + chan[c.chan].dac.furnaceDAC=false; + } + break; + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -349,14 +476,19 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else { + rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + } } break; } case DIV_CMD_NOTE_OFF: + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + chan[c.chan].psgMode.dac=false; chan[c.chan].keyOff=true; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); @@ -370,13 +502,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else { - if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else { + if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + } + break; } break; - break; } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; @@ -423,11 +557,13 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } case DIV_CMD_STD_NOISE_MODE: if (c.value<0x10) { - chan[c.chan].psgMode=(c.value+1)&7; - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (chan[c.chan].active) { - rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode&4)<<3)); + if (!chan[c.chan].psgMode.dac) { + chan[c.chan].psgMode=(c.value+1)&7; + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (chan[c.chan].active) { + rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + } } } else { chan[c.chan].duty=c.value&15; @@ -441,14 +577,14 @@ int DivPlatformAY8930::dispatch(DivCommand c) { chan[c.chan].envelope.mode=c.value>>4; rWrite(regMode[c.chan],chan[c.chan].envelope.mode); if (c.value&15) { - chan[c.chan].psgMode|=4; + chan[c.chan].psgMode.envelope|=1; } else { - chan[c.chan].psgMode&=~4; + chan[c.chan].psgMode.envelope&=~1; } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3)); + rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); } break; case DIV_CMD_AY_ENVELOPE_LOW: @@ -496,6 +632,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) { updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; + case DIV_CMD_SAMPLE_MODE: + chan[c.chan].psgMode.dac=(c.value>0)?1:0; + break; + case DIV_CMD_SAMPLE_BANK: + sampleBank=c.value; + if (sampleBank>(parent->song.sample.size()/12)) { + sampleBank=parent->song.sample.size()/12; + } + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; @@ -523,7 +668,11 @@ void DivPlatformAY8930::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(0x08+ch,0); } else if (chan[ch].active) { - rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode&4)<<3)); + if (chan[ch].psgMode.dac) { + rWrite(0x08+ch,chan[ch].dac.out&31); + } else { + rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode.getEnvelope())<<3)); + } } } @@ -578,6 +727,7 @@ void DivPlatformAY8930::reset() { pendingWrites[i]=-1; } + sampleBank=0; ayNoiseAnd=2; ayNoiseOr=0; delay=0; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 10ac7736b..61d793dd3 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -38,20 +38,86 @@ class DivPlatformAY8930: public DivDispatch { slideLow(0), slide(0) {} } envelope; - unsigned char freqH, freqL; + + struct PSGMode { + unsigned char tone: 1; + unsigned char noise: 1; + unsigned char envelope: 1; + unsigned char dac: 1; + + unsigned char getTone() { + return dac?0:(tone<<0); + } + + unsigned char getNoise() { + return dac?0:(noise<<1); + } + + unsigned char getEnvelope() { + return dac?0:(envelope<<2); + } + + PSGMode& operator=(unsigned char s) { + tone=(s>>0)&1; + noise=(s>>1)&1; + envelope=(s>>2)&1; + dac=(s>>3)&1; + return *this; + } + + PSGMode(): + tone(1), + noise(0), + envelope(0), + dac(0) {} + } psgMode; + + struct DAC { + int sample, rate, period, pos, out; + unsigned char furnaceDAC: 1; + + DAC(): + sample(-1), + rate(0), + period(0), + pos(0), + out(0), + furnaceDAC(0) {} + } dac; + int freq, baseFreq, note, pitch, pitch2; int ins; - unsigned char psgMode, autoEnvNum, autoEnvDen, duty; + unsigned char autoEnvNum, autoEnvDen, duty; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; int vol, outVol; - unsigned char pan; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; } - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {} + Channel(): + envelope(Envelope()), + psgMode(PSGMode()), + dac(DAC()), + freq(0), + baseFreq(0), + note(0), + pitch(0), + pitch2(0), + ins(-1), + autoEnvNum(0), + autoEnvDen(0), + duty(4), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + vol(0), + outVol(31) {} }; Channel chan[3]; bool isMuted[3]; @@ -68,6 +134,8 @@ class DivPlatformAY8930: public DivDispatch { unsigned char ayNoiseAnd, ayNoiseOr; bool bank; + unsigned char sampleBank; + int delay; bool extMode, stereo, clockSel; diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 836ce3155..9bfea2963 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -34,6 +34,7 @@ #define WRITE_STEREO(v) rWrite(0x50,(v)) #define CHIP_DIVIDER 64 +#define CHIP_FREQBASE 4000000 #if defined( _MSC_VER ) @@ -155,7 +156,7 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,0); chan[i].samplePos++; } else { - WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7); + WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127)); } if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) { @@ -177,7 +178,7 @@ void DivPlatformLynx::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { if (chan[i].pcm) { - chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6; + chan[i].outVol=((chan[i].vol&127)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; } else { chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7; } @@ -187,11 +188,11 @@ void DivPlatformLynx::tick(bool sysTick) { if (!chan[i].inPorta) { if (chan[i].std.arp.mode) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].std.arp.val,false); + if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); chan[i].actualNote=chan[i].std.arp.val; } else { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note+chan[i].std.arp.val,false); + if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); chan[i].actualNote=chan[i].note+chan[i].std.arp.val; } chan[i].freqChanged=true; @@ -199,7 +200,7 @@ void DivPlatformLynx::tick(bool sysTick) { } else { if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note,false); + if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].actualNote=chan[i].note; chan[i].freqChanged=true; } @@ -231,6 +232,10 @@ void DivPlatformLynx::tick(bool sysTick) { if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { + if (chan[i].pcm && chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + chan[i].sampleAccum=0; + chan[i].samplePos=0; + } WRITE_LFSR(i, 0); WRITE_OTHER(i, 0); } @@ -247,7 +252,7 @@ void DivPlatformLynx::tick(bool sysTick) { off=(double)s->centerRate/8363.0; } } - chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1); + chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE); } else { if (chan[i].lfsr >= 0) { WRITE_LFSR(i, (chan[i].lfsr&0xff)); @@ -277,11 +282,12 @@ int DivPlatformLynx::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY); - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA); + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:127; + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); if (chan[c.chan].pcm) { - chan[c.chan].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,c.value,false); + chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].sample=ins->amiga.getSample(c.value); chan[c.chan].sampleAccum=0; chan[c.chan].samplePos=0; @@ -294,7 +300,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { } chan[c.chan].active=true; WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127))); - chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); + chan[c.chan].macroInit(ins); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -374,7 +380,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { int whatAMess=c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)); chan[c.chan].baseFreq=NOTE_PERIODIC(whatAMess); if (chan[c.chan].pcm) { - chan[c.chan].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,whatAMess,false); + chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(whatAMess); } chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index 849c3182b..b977a67d7 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -48,6 +48,7 @@ class DivPlatformLynx: public DivDispatch { unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm; signed char vol, outVol; + int macroVolMul; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -77,7 +78,8 @@ class DivPlatformLynx: public DivDispatch { inPorta(false), pcm(false), vol(127), - outVol(127) {} + outVol(127), + macroVolMul(127) {} }; Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index dc81950ef..1fdbc3000 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -102,14 +102,54 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6258::tick(bool sysTick) { - // nothing + for (int i=0; i<1; i++) { + chan[i].std.next(); + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&3)) { + rateSel=chan[i].std.duty.val&3; + rWrite(12,rateSel); + } + } + if (chan[i].std.panL.had) { + if (chan[i].pan!=(chan[i].std.panL.val&3)) { + chan[i].pan=chan[i].std.panL.val&3; + rWrite(2,chan[i].pan); + } + } + if (chan[i].std.ex1.had) { + if (clockSel!=(chan[i].std.ex1.val&1)) { + clockSel=chan[i].std.ex1.val&1; + rWrite(8,clockSel); + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } + } + if (chan[i].keyOn || chan[i].keyOff) { + samplePos=0; + rWrite(0,1); // turn off + if (chan[i].active && !chan[i].keyOff) { + if (sample>=0 && samplesong.sampleLen) { + rWrite(0,2); + } else { + sample=-1; + } + } else { + sample=-1; + } + chan[i].keyOn=false; + chan[i].keyOff=false; + } + } } int DivPlatformMSM6258::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_MSM6258 || ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -130,8 +170,6 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - rWrite(0,1); - rWrite(0,2); } else { break; } @@ -145,8 +183,8 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { //DivSample* s=parent->getSample(12*sampleBank+c.value%12); sample=12*sampleBank+c.value%12; samplePos=0; - rWrite(0,1); - rWrite(0,2); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } break; } @@ -154,18 +192,12 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - rWrite(0,1); // turn off - sample=-1; - samplePos=0; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - rWrite(0,1); // turn off - sample=-1; - samplePos=0; chan[c.chan].std.release(); break; case DIV_CMD_ENV_RELEASE: diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index fc5f9ea30..b0059d1a9 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -95,7 +95,38 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6295::tick(bool sysTick) { - // nothing + for (int i=0; i<4; i++) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); + } + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&1)) { + rateSel=chan[i].std.duty.val&1; + rWrite(12,!rateSel); + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } + } + if (chan[i].keyOn || chan[i].keyOff) { + rWriteDelay(0,(8<=0 && chan[i].samplesong.sampleLen) { + rWrite(0,0x80|chan[i].sample); // set phrase + rWrite(0,(16<=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/144,off,note,false); + return parent->calcBaseFreq((double)chipClock/((oplType==3)?288:72),off,note,false); } return 0; } @@ -577,7 +577,7 @@ void DivPlatformOPL::tick(bool sysTick) { chan[adpcmChan].std.next(); if (chan[adpcmChan].std.vol.had) { - chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(64,chan[adpcmChan].std.vol.val))/64; + chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(chan[adpcmChan].macroVolMul,chan[adpcmChan].std.vol.val))/chan[adpcmChan].macroVolMul; immWrite(18,chan[adpcmChan].outVol); } @@ -596,16 +596,32 @@ void DivPlatformOPL::tick(bool sysTick) { chan[adpcmChan].freqChanged=true; } } + if (chan[adpcmChan].std.phaseReset.had) { + if ((chan[adpcmChan].std.phaseReset.val==1) && chan[adpcmChan].active) { + chan[adpcmChan].keyOn=true; + } + } } - if (chan[adpcmChan].freqChanged) { + if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/144,off); + chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/((oplType==3)?288:72),off); } else { chan[adpcmChan].freq=0; } immWrite(16,chan[adpcmChan].freq&0xff); immWrite(17,(chan[adpcmChan].freq>>8)&0xff); + if (chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { + immWrite(7,0x01); // reset + if (chan[adpcmChan].active && chan[adpcmChan].keyOn && !chan[adpcmChan].keyOff) { + if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[adpcmChan].sample); + immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat + } + } + chan[adpcmChan].keyOn=false; + chan[adpcmChan].keyOff=false; + } chan[adpcmChan].freqChanged=false; } } @@ -749,7 +765,8 @@ int DivPlatformOPL::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { if (c.chan==adpcmChan) { // ADPCM DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -765,13 +782,11 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { DivSample* s=parent->getSample(chan[c.chan].sample); immWrite(8,0); - immWrite(7,0x01); // reset immWrite(9,(s->offB>>2)&0xff); immWrite(10,(s->offB>>10)&0xff); int end=s->offB+s->lengthB-1; immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); - immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -792,25 +807,29 @@ int DivPlatformOPL::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(8,0); + immWrite(9,(s->offB>>2)&0xff); + immWrite(10,(s->offB>>10)&0xff); + int end=s->offB+s->lengthB-1; + immWrite(11,(end>>2)&0xff); + immWrite(12,(end>>10)&0xff); + int freq=(65536.0*(double)s->rate)/(double)chipRateBase; + immWrite(16,freq&0xff); + immWrite(17,(freq>>8)&0xff); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { immWrite(7,0x01); // reset immWrite(9,0); immWrite(10,0); immWrite(11,0); immWrite(12,0); - break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(8,0); - immWrite(7,0x01); // reset - immWrite(9,(s->offB>>2)&0xff); - immWrite(10,(s->offB>>10)&0xff); - int end=s->offB+s->lengthB-1; - immWrite(11,(end>>2)&0xff); - immWrite(12,(end>>10)&0xff); - immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat - int freq=(65536.0*(double)s->rate)/(double)chipRateBase; - immWrite(16,freq&0xff); - immWrite(17,(freq>>8)&0xff); } break; } @@ -955,19 +974,11 @@ int DivPlatformOPL::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan==adpcmChan) { - immWrite(7,0x01); // reset - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan==adpcmChan) { - immWrite(7,0x01); // reset - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 3d6497367..4c8a943f1 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -44,6 +44,7 @@ class DivPlatformOPL: public DivDispatch { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnacePCM, inPorta, fourOp, hardReset; int vol, outVol; unsigned char pan; + int macroVolMul; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -70,7 +71,8 @@ class DivPlatformOPL: public DivDispatch { fourOp(false), hardReset(false), vol(0), - pan(3) { + pan(3), + macroVolMul(64) { state.ops=2; } }; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index ee479f5b4..b36d5d133 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -87,8 +87,15 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) continue; } chWrite(i,0x07,0); - chWrite(i,0x04,0xdf); - chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); + signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; + chan[i].dacOut=CLAMP(dacData,-16,15); + if (!isMuted[i]) { + chWrite(i,0x04,0xc0|chan[i].outVol); + chWrite(i,0x06,chan[i].dacOut&0x1f); + } else { + chWrite(i,0x04,0xc0); + chWrite(i,0x06,0x10); + } chan[i].dacPos++; if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { chan[i].dacPos=s->getLoopStartPosition(); @@ -234,6 +241,15 @@ void DivPlatformPCE::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) { + if (chan[i].furnaceDac && chan[i].pcm) { + if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { + chan[i].dacPos=0; + chan[i].dacPeriod=0; + chWrite(i,0x04,0xc0|chan[i].vol); + addWrite(0xffff0000+(i<<8),chan[i].dacSample); + chan[i].keyOn=true; + } + } chan[i].antiClickWavePos=0; chan[i].antiClickPeriodCount=0; } @@ -279,13 +295,14 @@ int DivPlatformPCE::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:31; + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].pcm=true; } else if (chan[c.chan].furnaceDac) { chan[c.chan].pcm=false; } if (chan[c.chan].pcm) { - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].furnaceDac=true; if (skipRegisterWrites) break; chan[c.chan].dacSample=ins->amiga.getSample(c.value); @@ -295,7 +312,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } else { if (dumpWrites) { - chWrite(c.chan,0x04,0xdf); + chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); } } @@ -308,6 +325,9 @@ int DivPlatformPCE::dispatch(DivCommand c) { } chan[c.chan].active=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].keyOn=true; } else { chan[c.chan].furnaceDac=false; @@ -327,7 +347,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPeriod=0; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; if (dumpWrites) { - chWrite(c.chan,0x04,0xdf); + chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); } } @@ -480,6 +500,10 @@ int DivPlatformPCE::dispatch(DivCommand c) { void DivPlatformPCE::muteChannel(int ch, bool mute) { isMuted[ch]=mute; chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); + if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) { + chWrite(ch,0x04,0xc0|chan[ch].outVol); + chWrite(ch,0x06,chan[ch].dacOut&0x1f); + } } void DivPlatformPCE::forceIns() { diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 17e191d44..02ee861f7 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -29,12 +29,13 @@ class DivPlatformPCE: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, antiClickPeriodCount, antiClickWavePos; - int dacPeriod, dacRate; + int dacPeriod, dacRate, dacOut; unsigned int dacPos; int dacSample, ins; unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac, deferredWaveUpdate; signed char vol, outVol, wave; + int macroVolMul; DivMacroInt std; DivWaveSynth ws; void macroInit(DivInstrument* which) { @@ -51,6 +52,7 @@ class DivPlatformPCE: public DivDispatch { antiClickWavePos(0), dacPeriod(0), dacRate(0), + dacOut(0), dacPos(0), dacSample(-1), ins(-1), @@ -67,7 +69,8 @@ class DivPlatformPCE: public DivDispatch { deferredWaveUpdate(false), vol(31), outVol(31), - wave(-1) {} + wave(-1), + macroVolMul(31) {} }; Channel chan[6]; DivDispatchOscBuffer* oscBuf[6]; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 67a533b1b..4d83bd7d1 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -36,26 +36,71 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l continue; } if (chan.useWave || (chan.sample>=0 && chan.samplesong.sampleLen)) { - chan.audPos+=chan.freq>>16; + chan.audPos+=((!chan.useWave) && chan.audDir)?-(chan.freq>>16):(chan.freq>>16); chan.audSub+=(chan.freq&0xffff); if (chan.audSub>=0x10000) { chan.audSub-=0x10000; - chan.audPos+=1; + chan.audPos+=((!chan.useWave) && chan.audDir)?-1:1; } if (chan.useWave) { - if (chan.audPos>=(unsigned int)(chan.audLen<<1)) { - chan.audPos=0; + if (chan.audPos>=(int)chan.audLen) { + chan.audPos%=chan.audLen; + chan.audDir=false; } output=(chan.ws.output[chan.audPos]^0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); if (s->getEndPosition()>0) { - if (s->isLoopable() && chan.audPos>=(unsigned int)s->getLoopEndPosition()) { - chan.audPos=s->getLoopStartPosition(); - } else if (chan.audPos>=(unsigned int)s->getEndPosition()) { - chan.sample=-1; + if (chan.audDir) { + if (s->isLoopable()) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: + case DIV_SAMPLE_LOOP_PINGPONG: + if (chan.audPosgetLoopStartPosition()) { + chan.audPos=s->getLoopStartPosition()+(s->getLoopStartPosition()-chan.audPos); + chan.audDir=false; + } + break; + case DIV_SAMPLE_LOOP_BACKWARD: + if (chan.audPosgetLoopStartPosition()) { + chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos); + chan.audDir=true; + } + default: + if (chan.audPos<0) { + chan.sample=-1; + } + break; + } + } else if (chan.audPos>=s->getEndPosition()) { + chan.sample=-1; + } + } else { + if (s->isLoopable()) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: + if (chan.audPos>=s->getLoopEndPosition()) { + chan.audPos=(chan.audPos+s->getLoopStartPosition())-s->getLoopEndPosition(); + chan.audDir=false; + } + break; + case DIV_SAMPLE_LOOP_BACKWARD: + case DIV_SAMPLE_LOOP_PINGPONG: + if (chan.audPos>=s->getLoopEndPosition()) { + chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos); + chan.audDir=true; + } + default: + if (chan.audPos>=s->getEndPosition()) { + chan.sample=-1; + } + break; + } + } else if (chan.audPos>=s->getEndPosition()) { + chan.sample=-1; + } } - if (chan.audPos<(unsigned int)s->getEndPosition()) { + if (chan.audPos>=0 && chan.audPosgetEndPosition()) { output=s->data16[chan.audPos]; } } else { @@ -125,6 +170,7 @@ void DivPlatformPCMDAC::tick(bool sysTick) { } if (chan.std.phaseReset.had) { if (chan.std.phaseReset.val==1) { + chan.audDir=false; chan.audPos=0; } } @@ -156,11 +202,11 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA); if (ins->amiga.useWave) { chan.useWave=true; - chan.audLen=(ins->amiga.waveLen+1)>>1; + chan.audLen=ins->amiga.waveLen; if (chan.insChanged) { if (chan.wave<0) { chan.wave=0; - chan.ws.setWidth(chan.audLen<<1); + chan.ws.setWidth(chan.audLen); chan.ws.changeWave1(chan.wave); } } @@ -177,6 +223,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { if (chan.setPos) { chan.setPos=false; } else { + chan.audDir=false; chan.audPos=0; } chan.audSub=0; @@ -191,7 +238,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { chan.envVol=64; } if (chan.useWave) { - chan.ws.init(ins,chan.audLen<<1,255,chan.insChanged); + chan.ws.init(ins,chan.audLen,255,chan.insChanged); } chan.insChanged=false; break; @@ -298,6 +345,7 @@ void DivPlatformPCMDAC::muteChannel(int ch, bool mute) { void DivPlatformPCMDAC::forceIns() { chan.insChanged=true; chan.freqChanged=true; + chan.audDir=false; chan.audPos=0; chan.sample=-1; } diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h index 60d2a6fc0..127d39aae 100644 --- a/src/engine/platform/pcmdac.h +++ b/src/engine/platform/pcmdac.h @@ -28,9 +28,10 @@ class DivPlatformPCMDAC: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2; + bool audDir; unsigned int audLoc; unsigned short audLen; - unsigned int audPos; + int audPos; int audSub; int sample, wave, ins; int note; @@ -48,6 +49,7 @@ class DivPlatformPCMDAC: public DivDispatch { baseFreq(0), pitch(0), pitch2(0), + audDir(false), audLoc(0), audLen(0), audPos(0), diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 64daed60a..d28d724c1 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -286,10 +286,16 @@ void DivPlatformQSound::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; + if (chan[i].isNewQSound) { + chan[i].outVol=((chan[i].vol&0xff)*MIN(16383,chan[i].std.vol.val))/16383; + chan[i].resVol=((chan[i].vol&0xff)*MIN(16383,chan[i].std.vol.val))/255; + } else { + chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; + chan[i].resVol=chan[i].outVol<<4; + } // Check if enabled and write volume if (chan[i].active) { - rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4); + rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); } } uint16_t qsound_bank = 0; @@ -329,6 +335,16 @@ void DivPlatformQSound::tick(bool sysTick) { chan[i].freqChanged=true; } } + if (chan[i].std.duty.had) { + chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767); + immWrite(Q1_ECHO+i,chan[i].echo&0x7fff); + } + if (chan[i].std.ex1.had) { + immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff); + } + if (chan[i].std.ex2.had) { + immWrite(Q1_ECHO_LENGTH,0xfff-(2725-CLAMP(chan[i].std.ex2.val&0xfff,0,2725))); + } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { chan[i].pitch2+=chan[i].std.pitch.val; @@ -347,6 +363,11 @@ void DivPlatformQSound::tick(bool sysTick) { if (chan[i].std.panL.had || chan[i].std.panR.had) { immWrite(Q1_PAN+i,chan[i].panning+0x110+(chan[i].surround?0:0x30)); } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active && (chan[i].sample>=0 && chan[i].samplesong.sampleLen)) { + chan[i].keyOn=true; + } + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); double off=1.0; @@ -366,19 +387,24 @@ void DivPlatformQSound::tick(bool sysTick) { rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); rWrite(q1_reg_map[Q1V_START][i], qsound_addr); rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); - logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); + //logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume if (!chan[i].std.vol.had) { - rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4); + if (chan[i].isNewQSound) { + chan[i].resVol=(chan[i].vol*16383)/255; + } else { + chan[i].resVol=chan[i].vol<<4; + } + rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); } } if (chan[i].keyOff) { // Disable volume - rWrite(q1_reg_map[Q1V_VOL][i], 0); - rWrite(q1_reg_map[Q1V_FREQ][i], 0); + rWrite(q1_reg_map[Q1V_VOL][i],0); + rWrite(q1_reg_map[Q1V_FREQ][i],0); } else if (chan[i].active) { //logV("ch %d frequency set to %04x, off=%f, note=%d, %04x!",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note)); - rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq); + rWrite(q1_reg_map[Q1V_FREQ][i],chan[i].freq); } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; @@ -391,6 +417,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].isNewQSound=(ins->type==DIV_INS_QSOUND); chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value); @@ -407,6 +434,11 @@ int DivPlatformQSound::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; + if (chan[c.chan].isNewQSound) { + chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255; + } else { + chan[c.chan].resVol=chan[c.chan].outVol<<4; + } } break; } @@ -431,8 +463,13 @@ int DivPlatformQSound::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { // Check if enabled and write volume chan[c.chan].outVol=c.value; - if (chan[c.chan].active && c.chan < 16) { - rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 4); + if (chan[c.chan].isNewQSound) { + chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255; + } else { + chan[c.chan].resVol=chan[c.chan].outVol<<4; + } + if (chan[c.chan].active && c.chan<16) { + rWrite(q1_reg_map[Q1V_VOL][c.chan],chan[c.chan].resVol); } } } @@ -448,7 +485,8 @@ int DivPlatformQSound::dispatch(DivCommand c) { immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30)); break; case DIV_CMD_QSOUND_ECHO_LEVEL: - immWrite(Q1_ECHO+c.chan, c.value << 7); + chan[c.chan].echo=c.value<<7; + immWrite(Q1_ECHO+c.chan,chan[c.chan].echo&0x7fff); break; case DIV_CMD_QSOUND_ECHO_FEEDBACK: immWrite(Q1_ECHO_FEEDBACK, c.value << 6); diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 285760138..553560559 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -28,13 +28,12 @@ class DivPlatformQSound: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2; - unsigned short audLen; - unsigned int audPos; int sample, wave, ins; int note; int panning; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround; - int vol, outVol; + int echo; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround, isNewQSound; + int vol, outVol, resVol; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -45,12 +44,11 @@ class DivPlatformQSound: public DivDispatch { baseFreq(0), pitch(0), pitch2(0), - audLen(0), - audPos(0), sample(-1), ins(-1), note(0), panning(0x10), + echo(0), active(false), insChanged(true), freqChanged(false), @@ -59,8 +57,10 @@ class DivPlatformQSound: public DivDispatch { inPorta(false), useWave(false), surround(true), + isNewQSound(false), vol(255), - outVol(255) {} + outVol(255), + resVol(4096) {} }; Channel chan[19]; DivDispatchOscBuffer* oscBuf[19]; diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 5b829c348..456b2b128 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -83,7 +83,7 @@ void DivPlatformRF5C68::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&0xff)*chan[i].std.vol.val)>>6; + chan[i].outVol=((chan[i].vol&0xff)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; chWrite(i,0,chan[i].outVol); } if (chan[i].std.arp.had) { @@ -120,7 +120,13 @@ void DivPlatformRF5C68::tick(bool sysTick) { chan[i].panning|=(chan[i].std.panR.val&15)<<4; } if (chan[i].std.panL.had || chan[i].std.panR.had) { - chWrite(i,0x05,isMuted[i]?0:chan[i].panning); + chWrite(i,1,isMuted[i]?0:chan[i].panning); + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active) { + chan[i].audPos=0; + chan[i].setPos=true; + } } if (chan[i].setPos) { // force keyon @@ -175,6 +181,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 6946b4900..94aca4fea 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -34,6 +34,7 @@ class DivPlatformRF5C68: public DivDispatch { int panning; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos; int vol, outVol; + int macroVolMul; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -57,7 +58,8 @@ class DivPlatformRF5C68: public DivDispatch { inPorta(false), setPos(false), vol(255), - outVol(255) {} + outVol(255), + macroVolMul(64) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 6a63f823b..3ad775c51 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -83,9 +83,9 @@ void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); - if (parent->song.newSegaPCM) { + if (chan[i].isNewSegaPCM) { if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(64,chan[i].std.vol.val))>>6; + chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; if (dumpWrites) { @@ -112,7 +112,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].std.panL.had) { - if (parent->song.newSegaPCM) { + if (chan[i].isNewSegaPCM) { chan[i].chPanL=chan[i].std.panL.val&127; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; } else { @@ -124,7 +124,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].std.panR.had) { - if (parent->song.newSegaPCM) { + if (chan[i].isNewSegaPCM) { chan[i].chPanR=chan[i].std.panR.val&127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; } else { @@ -144,13 +144,14 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } chan[i].freqChanged=true; } - /*if (chan[i].keyOn || chan[i].keyOff) { - chan[i].keyOff=false; - }*/ - } - for (int i=0; i<16; i++) { - if (chan[i].freqChanged) { + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active) { + chan[i].keyOn=true; + } + } + + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64; if (chan[i].furnacePCM) { double off=1.0; @@ -164,6 +165,56 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } } chan[i].freqChanged=false; + if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].keyOn && !chan[i].keyOff) { + if (dumpWrites) { + addWrite(0x10086+(i<<3),3); + } + chan[i].pcm.pos=0; + if (chan[i].furnacePCM) { + if (dumpWrites) { // Sega PCM writes + DivSample* s=parent->getSample(chan[i].pcm.sample); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + if (actualLength>0xfeff) actualLength=0xfeff; + addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3)); + addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff); + addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff); + addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); + if (loopStart<0 || loopStart>=actualLength) { + addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3)); + } else { + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; + addWrite(0x10004+(i<<3),loopPos&0xff); + addWrite(0x10005+(i<<3),(loopPos>>8)&0xff); + addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3)); + } + } + } else { + if (dumpWrites) { // Sega PCM writes + DivSample* s=parent->getSample(chan[i].pcm.sample); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + if (actualLength>65536) actualLength=65536; + addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3)); + addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff); + addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff); + addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); + if (loopStart<0 || loopStart>=actualLength) { + addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3)); + } else { + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; + addWrite(0x10004+(i<<3),loopPos&0xff); + addWrite(0x10005+(i<<3),(loopPos>>8)&0xff); + addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3)); + } + addWrite(0x10007+(i<<3),chan[i].pcm.freq); + } + } + } + chan[i].keyOn=false; + chan[i].keyOff=false; + } } } } @@ -177,7 +228,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SEGAPCM) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127; + chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM || parent->song.newSegaPCM); chan[c.chan].pcm.sample=ins->amiga.getSample(c.value); if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) { chan[c.chan].pcm.sample=-1; @@ -190,7 +243,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } break; } - chan[c.chan].pcm.pos=0; if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=(c.value<<6); @@ -198,24 +250,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } chan[c.chan].furnacePCM=true; chan[c.chan].macroInit(ins); - if (dumpWrites) { // Sega PCM writes - DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); - if (actualLength>0xfeff) actualLength=0xfeff; - addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); - addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); - addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); - addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (loopStart<0 || loopStart>=actualLength) { - addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); - } else { - int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; - addWrite(0x10004+(c.chan<<3),loopPos&0xff); - addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); - addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); - } - } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { chan[c.chan].macroInit(NULL); if (c.value!=DIV_NOTE_NULL) { @@ -229,28 +265,10 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } break; } - chan[c.chan].pcm.pos=0; chan[c.chan].pcm.freq=MIN(255,(parent->getSample(chan[c.chan].pcm.sample)->rate*255)/31250); chan[c.chan].furnacePCM=false; - if (dumpWrites) { // Sega PCM writes - DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); - if (actualLength>65536) actualLength=65536; - addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); - addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); - addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); - addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (loopStart<0 || loopStart>=actualLength) { - addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); - } else { - int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; - addWrite(0x10004+(c.chan<<3),loopPos&0xff); - addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); - addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); - } - addWrite(0x10007+(c.chan<<3),chan[c.chan].pcm.freq); - } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } break; } @@ -278,7 +296,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (parent->song.newSegaPCM) { + if (chan[c.chan].isNewSegaPCM) { chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127; chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127; } else { @@ -302,7 +320,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].ins=c.value; break; case DIV_CMD_PANNING: { - if (parent->song.newSegaPCM) { + if (chan[c.chan].isNewSegaPCM) { chan[c.chan].chPanL=c.value>>1; chan[c.chan].chPanR=c.value2>>1; chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 6edc85302..4b91a70bb 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -28,13 +28,12 @@ class DivPlatformSegaPCM: public DivDispatch { protected: struct Channel { DivMacroInt std; - unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, note, ins; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, isNewSegaPCM; int vol, outVol; unsigned char chVolL, chVolR; unsigned char chPanL, chPanR; + int macroVolMul; struct PCMChannel { int sample; @@ -48,8 +47,6 @@ class DivPlatformSegaPCM: public DivDispatch { pitch2=0; } Channel(): - freqH(0), - freqL(0), freq(0), baseFreq(0), pitch(0), @@ -64,12 +61,15 @@ class DivPlatformSegaPCM: public DivDispatch { inPorta(false), portaPause(false), furnacePCM(false), + isNewSegaPCM(false), vol(0), outVol(0), chVolL(127), chVolR(127), chPanL(127), - chPanR(127) {} + chPanR(127), + macroVolMul(64), + pcm(PCMChannel()) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index a212c65fe..af088fb57 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -256,12 +256,12 @@ 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 (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->su.useSample)) { - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); + if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); writeControl(c.chan); writeControlUpper(c.chan); } - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 5110d7e15..924e4cabd 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -251,7 +251,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN); if (c.chan==1) { - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { pcm=true; } else if (furnaceDac) { pcm=false; @@ -260,7 +260,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { if (skipRegisterWrites) break; dacPos=0; dacPeriod=0; - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { dacSample=ins->amiga.getSample(c.value); if (dacSample<0 || dacSample>=parent->song.sampleLen) { dacSample=-1; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index fa81afb91..60379d416 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -193,6 +193,25 @@ void DivPlatformVRC6::tick(bool sysTick) { } chan[i].freqChanged=true; } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + if ((i!=2) && (!chan[i].pcm)) { + if (dumpWrites) addWrite(0xffff0002+(i<<8),0); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_VRC6); + chan[i].dacSample=ins->amiga.getSample(chan[i].note); + if (chan[i].dacSample<0 || chan[i].dacSample>=parent->song.sampleLen) { + if (dumpWrites) { + chWrite(i,2,0x80); + chWrite(i,0,isMuted[i]?0:0x80); + addWrite(0xffff0000+(i<<8),chan[i].dacSample); + } + chan[i].dacPos=0; + chan[i].dacPeriod=0; + chan[i].keyOn=true; + } + } + } + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (i==2) { // sawtooth chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,14)-1; @@ -233,14 +252,14 @@ int DivPlatformVRC6::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: if (c.chan!=2) { // pulse wave DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6); - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].pcm=true; } else if (chan[c.chan].furnaceDac) { chan[c.chan].pcm=false; } if (chan[c.chan].pcm) { if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].dacSample=ins->amiga.getSample(c.value); if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) { chan[c.chan].dacSample=-1; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index e2e360b1b..ebb9d6d07 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -23,9 +23,9 @@ #include //#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) if (!skipRegisterWrites) { x1_010->ram_w(a,v); if (dumpWrites) { addWrite(a,v); } } +#define rWrite(a,v) if (!skipRegisterWrites) { x1_010.ram_w(a,v); if (dumpWrites) { addWrite(a,v); } } -#define chRead(c,a) x1_010->ram_r((c<<3)|(a&7)) +#define chRead(c,a) x1_010.ram_r((c<<3)|(a&7)) #define chWrite(c,a,v) rWrite((c<<3)|(a&7),v) #define waveWrite(c,a,v) rWrite(0x1000|(chan[c].waveBank<<11)|(c<<7)|(a&0x7f),(v-128)&0xff) #define envFill(c,a) rWrite(0x800|(c<<7)|(a&0x7f),(chan[c].lvol<<4)|chan[c].rvol) @@ -240,10 +240,10 @@ const char* DivPlatformX1_010::getEffectName(unsigned char effect) { void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; htick(); + x1_010.tick(); - signed int tempL=x1_010->output(0); - signed int tempR=x1_010->output(1); + signed int tempL=x1_010.output(0); + signed int tempR=x1_010.output(1); if (tempL<-32768) tempL=-32768; if (tempL>32767) tempL=32767; @@ -255,11 +255,23 @@ void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t l bufR[h]=stereo?tempR:bufL[h]; for (int i=0; i<16; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=x1_010->chan_out(i); + oscBuf[i]->data[oscBuf[i]->needle++]=x1_010.chan_out(i); } } } +u8 DivPlatformX1_010::read_byte(u32 address) { + if ((sampleMem!=NULL) && (address>17)&7]<<17)|(address&0x1ffff))&0xffffff; + } else { + address&=0xfffff; + } + return sampleMem[address]; + } + return 0; +} + double DivPlatformX1_010::NoteX1_010(int ch, int note) { if (chan[ch].pcm) { // PCM note double off=8192.0; @@ -345,7 +357,7 @@ void DivPlatformX1_010::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol.val))/(chan[i].furnacePCM?64:15); + signed char macroVol=((chan[i].vol&15)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/(chan[i].macroVolMul); if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) { chan[i].outVol=macroVol; chan[i].envChanged=true; @@ -475,6 +487,12 @@ void DivPlatformX1_010::tick(bool sysTick) { if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1; } } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active && chan[i].pcm) { + chWrite(i,0,0); + refreshControl(i); + } + } if (chan[i].active) { if (chan[i].ws.tick()) { updateWave(i); @@ -549,8 +567,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { chWrite(c.chan,0,0); // reset previous note DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010); - if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) { - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:15; + if ((ins->type==DIV_INS_AMIGA || ins->amiga.useSample) || chan[c.chan].pcm) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -562,9 +581,18 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].sample=ins->amiga.getSample(c.value); if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { DivSample* s=parent->getSample(chan[c.chan].sample); - chWrite(c.chan,4,(s->offX1_010>>12)&0xff); - int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded - chWrite(c.chan,5,(0x100-(end>>12))&0xff); + if (isBanked) { + chan[c.chan].bankSlot=ins->x1_010.bankSlot; + bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17; + unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff); + chWrite(c.chan,4,(bankedOffs>>12)&0xff); + int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } else { + chWrite(c.chan,4,(s->offX1_010>>12)&0xff); + int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note); @@ -594,9 +622,17 @@ int DivPlatformX1_010::dispatch(DivCommand c) { break; } DivSample* s=parent->getSample(12*sampleBank+c.value%12); - chWrite(c.chan,4,(s->offX1_010>>12)&0xff); - int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded - chWrite(c.chan,5,(0x100-(end>>12))&0xff); + if (isBanked) { + bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17; + unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff); + chWrite(c.chan,4,(bankedOffs>>12)&0xff); + int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } else { + chWrite(c.chan,4,(s->offX1_010>>12)&0xff); + int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } chan[c.chan].baseFreq=(((unsigned int)s->rate)<<4)/(chipClock/512); chan[c.chan].freqChanged=true; } @@ -813,6 +849,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].autoEnvDen=c.value&15; chan[c.chan].freqChanged=true; break; + case DIV_CMD_X1_010_SAMPLE_BANK_SLOT: + chan[c.chan].bankSlot=c.value&7; + break; case DIV_CMD_GET_VOLMAX: return 15; break; @@ -853,7 +892,7 @@ DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) { unsigned char* DivPlatformX1_010::getRegisterPool() { for (int i=0; i<0x2000; i++) { - regPool[i]=x1_010->ram_r(i); + regPool[i]=x1_010.ram_r(i); } return regPool; } @@ -871,12 +910,16 @@ void DivPlatformX1_010::reset() { chan[i].ws.setEngine(parent); chan[i].ws.init(NULL,128,255,false); } - x1_010->reset(); + x1_010.reset(); sampleBank=0; // set per-channel initial panning for (int i=0; i<16; i++) { chWrite(i,0,0); } + // set initial bank + for (int b=0; b<8; b++) { + bankSlot[b]=b; + } } bool DivPlatformX1_010::isStereo() { @@ -931,15 +974,15 @@ void DivPlatformX1_010::poke(std::vector& wlist) { } const void* DivPlatformX1_010::getSampleMem(int index) { - return index == 0 ? sampleMem : 0; + return index >= 0 ? sampleMem : 0; } size_t DivPlatformX1_010::getSampleMemCapacity(int index) { - return index == 0 ? 1048576 : 0; + return index == 0 ? (isBanked?16777216:1048576):0; } size_t DivPlatformX1_010::getSampleMemUsage(int index) { - return index == 0 ? sampleMemLen : 0; + return index >= 0 ? sampleMemLen : 0; } void DivPlatformX1_010::renderSamples() { @@ -949,12 +992,14 @@ void DivPlatformX1_010::renderSamples() { for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; int paddedLen=(s->length8+4095)&(~0xfff); + if (isBanked) { // fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!) - if (paddedLen>131072) { - paddedLen=131072; - } - if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) { - memPos=(memPos+0x1ffff)&0xfe0000; + if (paddedLen>131072) { + paddedLen=131072; + } + if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) { + memPos=(memPos+0x1ffff)&0xfe0000; + } } if (memPos>=getSampleMemCapacity()) { logW("out of X1-010 memory for sample %d!",i); @@ -972,6 +1017,10 @@ void DivPlatformX1_010::renderSamples() { sampleMemLen=memPos+256; } +void DivPlatformX1_010::setBanked(bool banked) { + isBanked=banked; +} + int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; dumpWrites=false; @@ -984,9 +1033,7 @@ int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned in setFlags(flags); sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; - intf.memory=sampleMem; - x1_010=new x1_010_core(intf); - x1_010->reset(); + x1_010.reset(); reset(); return 16; } @@ -995,7 +1042,6 @@ void DivPlatformX1_010::quit() { for (int i=0; i<16; i++) { delete oscBuf[i]; } - delete x1_010; delete[] sampleMem; } diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 7a85b6336..e75c79495 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -26,18 +26,7 @@ #include "../waveSynth.h" #include "sound/x1_010/x1_010.hpp" -class DivX1_010Interface: public x1_010_mem_intf { - public: - unsigned char* memory; - int sampleBank; - virtual u8 read_byte(u32 address) override { - if (memory==NULL) return 0; - return memory[address & 0xfffff]; - } - DivX1_010Interface(): memory(NULL), sampleBank(0) {} -}; - -class DivPlatformX1_010: public DivDispatch { +class DivPlatformX1_010: public DivDispatch, public x1_010_mem_intf { struct Channel { struct Envelope { struct EnvFlag { @@ -84,7 +73,9 @@ class DivPlatformX1_010: public DivDispatch { unsigned char pan, autoEnvNum, autoEnvDen; bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm; int vol, outVol, lvol, rvol; + int macroVolMul; unsigned char waveBank; + unsigned int bankSlot; Envelope env; DivMacroInt std; DivWaveSynth ws; @@ -109,7 +100,9 @@ class DivPlatformX1_010: public DivDispatch { pan(255), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false), vol(15), outVol(15), lvol(15), rvol(15), - waveBank(0) {} + macroVolMul(15), + waveBank(0), + bankSlot(0) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; @@ -118,14 +111,18 @@ class DivPlatformX1_010: public DivDispatch { unsigned char* sampleMem; size_t sampleMemLen; unsigned char sampleBank; - DivX1_010Interface intf; - x1_010_core* x1_010; + x1_010_core x1_010; + + bool isBanked=false; + unsigned int bankSlot[8]; + unsigned char regPool[0x2000]; double NoteX1_010(int ch, int note); void updateWave(int ch); void updateEnvelope(int ch); friend void putDispatchChan(void*,int,int); public: + u8 read_byte(u32 address); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); @@ -150,8 +147,13 @@ class DivPlatformX1_010: public DivDispatch { void renderSamples(); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); + void setBanked(bool banked); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformX1_010(): + DivDispatch(), + x1_010_mem_intf(), + x1_010(*this) {} ~DivPlatformX1_010(); }; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index c3cf52a06..cfac0f6e1 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -647,12 +647,46 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].keyOff=false; } } + // RSS + for (int i=9; i<15; i++) { + if (chan[i].furnacePCM) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; + } + if (chan[i].std.duty.had) { + if (globalRSSVolume!=(chan[i].std.duty.val&0x3f)) { + globalRSSVolume=chan[i].std.duty.val&0x3f; + immWrite(0x11,globalRSSVolume); + } + } + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + } + if (chan[i].std.phaseReset.had) { + if ((chan[i].std.phaseReset.val==1) && chan[i].active) { + chan[i].keyOn=true; + } + } + if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); + } + if (chan[i].keyOff) { + writeRSSOff|=(1<<(i-9)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + writeRSSOn|=(1<<(i-9)); + chan[i].keyOn=false; + } + } + } // ADPCM-B if (chan[15].furnacePCM) { chan[15].std.next(); if (chan[15].std.vol.had) { - chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64; + chan[15].outVol=(chan[15].vol*MIN(chan[15].macroVolMul,chan[15].std.vol.val))/chan[15].macroVolMul; immWrite(0x10b,chan[15].outVol); } @@ -671,16 +705,42 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[15].freqChanged=true; } } + if (chan[15].std.panL.had) { + if (chan[15].pan!=(chan[15].std.panL.val&3)) { + chan[15].pan=chan[15].std.panL.val&3; + if (!isMuted[15]) { + immWrite(0x101,(isMuted[15]?0:(chan[15].pan<<6))|2); + } + } + } + if (chan[15].std.phaseReset.had) { + if ((chan[15].std.phaseReset.val==1) && chan[15].active) { + chan[15].keyOn=true; + } + } } - if (chan[15].freqChanged) { - if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; - chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off); - } else { - chan[15].freq=0; + if (chan[15].freqChanged || chan[15].keyOn || chan[15].keyOff) { + if (chan[15].furnacePCM) { + if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; + chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off); + } else { + chan[15].freq=0; + } } immWrite(0x109,chan[15].freq&0xff); immWrite(0x10a,(chan[15].freq>>8)&0xff); + if (chan[15].keyOn || chan[15].keyOff) { + immWrite(0x100,0x01); // reset + if (chan[15].active && chan[15].keyOn && !chan[15].keyOff) { + if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[15].sample); + immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat + } + } + chan[15].keyOn=false; + chan[15].keyOff=false; + } chan[15].freqChanged=false; } @@ -740,7 +800,8 @@ int DivPlatformYM2608::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { if (c.chan>14) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -761,7 +822,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) { immWrite(0x104,(end>>5)&0xff); immWrite(0x105,(end>>13)&0xff); immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); - immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -782,6 +842,24 @@ int DivPlatformYM2608::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x102,(s->offB>>5)&0xff); + immWrite(0x103,(s->offB>>13)&0xff); + int end=s->offB+s->lengthB-1; + immWrite(0x104,(end>>5)&0xff); + immWrite(0x105,(end>>13)&0xff); + immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); + int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); + immWrite(0x109,freq&0xff); + immWrite(0x10a,(freq>>8)&0xff); + immWrite(0x10b,chan[c.chan].outVol); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { immWrite(0x100,0x01); // reset immWrite(0x102,0); immWrite(0x103,0); @@ -789,26 +867,31 @@ int DivPlatformYM2608::dispatch(DivCommand c) { immWrite(0x105,0); break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x102,(s->offB>>5)&0xff); - immWrite(0x103,(s->offB>>13)&0xff); - int end=s->offB+s->lengthB-1; - immWrite(0x104,(end>>5)&0xff); - immWrite(0x105,(end>>13)&0xff); - immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); - immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x109,freq&0xff); - immWrite(0x10a,(freq>>8)&0xff); } break; } if (c.chan>8) { // RSS - if (skipRegisterWrites) break; - if (!isMuted[c.chan]) { - writeRSSOn|=(1<<(c.chan-9)); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + chan[c.chan].furnacePCM=true; + } else { + chan[c.chan].furnacePCM=false; } - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (skipRegisterWrites) break; + if (chan[c.chan].furnacePCM) { + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + } + } else { + chan[c.chan].macroInit(NULL); + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); @@ -861,28 +944,12 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan>14) { - immWrite(0x100,0x01); // reset - break; - } - if (c.chan>8) { - writeRSSOff|=1<<(c.chan-9); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan>14) { - immWrite(0x100,0x01); // reset - break; - } - if (c.chan>8) { - writeRSSOff|=1<<(c.chan-9); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; @@ -901,7 +968,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } if (c.chan>8) { // ADPCM-A - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -936,7 +1003,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } if (c.chan>8) { - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); @@ -1205,7 +1272,7 @@ void DivPlatformYM2608::muteChannel(int ch, bool mute) { immWrite(0x101,(isMuted[ch]?0:(chan[ch].pan<<6))|2); } if (ch>8) { // ADPCM-A - immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); + immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol)); return; } if (ch>5) { // PSG @@ -1313,6 +1380,7 @@ void DivPlatformYM2608::reset() { sampleBank=0; writeRSSOff=0; writeRSSOn=0; + globalRSSVolume=0x3f; delay=0; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index ac38a8c08..3a75f863c 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -54,6 +54,7 @@ class DivPlatformYM2608: public DivPlatformOPN { int vol, outVol; int sample; unsigned char pan; + int macroVolMul; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -84,7 +85,8 @@ class DivPlatformYM2608: public DivPlatformOPN { vol(0), outVol(15), sample(-1), - pan(3) {} + pan(3), + macroVolMul(255) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; @@ -99,6 +101,7 @@ class DivPlatformYM2608: public DivPlatformOPN { DivPlatformAY8910* ay; unsigned char sampleBank; unsigned char writeRSSOff, writeRSSOn; + int globalRSSVolume; bool extMode; unsigned char prescale; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 4e01b005c..66bdd8e54 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -18,15 +18,8 @@ */ #include "ym2610.h" -#include "sound/ymfm/ymfm.h" -#include "../engine.h" -#include "../../ta-log.h" -#include #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - const char* regCheatSheetYM2610[]={ // SSG "SSG_FreqL_A", "000", @@ -235,85 +228,6 @@ const char* regCheatSheetYM2610[]={ NULL }; -const void* DivPlatformYM2610Base::getSampleMem(int index) { - return index == 0 ? adpcmAMem : index == 1 ? adpcmBMem : NULL; -} - -size_t DivPlatformYM2610Base::getSampleMemCapacity(int index) { - return index == 0 ? 16777216 : index == 1 ? 16777216 : 0; -} - -size_t DivPlatformYM2610Base::getSampleMemUsage(int index) { - return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0; -} - -void DivPlatformYM2610Base::renderSamples() { - memset(adpcmAMem,0,getSampleMemCapacity(0)); - - size_t memPos=0; - for (int i=0; isong.sampleLen; i++) { - DivSample* s=parent->song.sample[i]; - int paddedLen=(s->lengthA+255)&(~0xff); - if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { - memPos=(memPos+0xfffff)&0xf00000; - } - if (memPos>=getSampleMemCapacity(0)) { - logW("out of ADPCM-A memory for sample %d!",i); - break; - } - if (memPos+paddedLen>=getSampleMemCapacity(0)) { - memcpy(adpcmAMem+memPos,s->dataA,getSampleMemCapacity(0)-memPos); - logW("out of ADPCM-A memory for sample %d!",i); - } else { - memcpy(adpcmAMem+memPos,s->dataA,paddedLen); - } - s->offA=memPos; - memPos+=paddedLen; - } - adpcmAMemLen=memPos+256; - - memset(adpcmBMem,0,getSampleMemCapacity(1)); - - memPos=0; - for (int i=0; isong.sampleLen; i++) { - DivSample* s=parent->song.sample[i]; - int paddedLen=(s->lengthB+255)&(~0xff); - if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { - memPos=(memPos+0xfffff)&0xf00000; - } - if (memPos>=getSampleMemCapacity(1)) { - logW("out of ADPCM-B memory for sample %d!",i); - break; - } - if (memPos+paddedLen>=getSampleMemCapacity(1)) { - memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(1)-memPos); - logW("out of ADPCM-B memory for sample %d!",i); - } else { - memcpy(adpcmBMem+memPos,s->dataB,paddedLen); - } - s->offB=memPos; - memPos+=paddedLen; - } - adpcmBMemLen=memPos+256; -} - -int DivPlatformYM2610Base::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { - parent=p; - adpcmAMem=new unsigned char[getSampleMemCapacity(0)]; - adpcmAMemLen=0; - adpcmBMem=new unsigned char[getSampleMemCapacity(1)]; - adpcmBMemLen=0; - iface.adpcmAMem=adpcmAMem; - iface.adpcmBMem=adpcmBMem; - iface.sampleBank=0; - return 0; -} - -void DivPlatformYM2610Base::quit() { - delete[] adpcmAMem; - delete[] adpcmBMem; -} - const char** DivPlatformYM2610::getRegisterSheet() { return regCheatSheetYM2610; } @@ -438,24 +352,6 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) { return NULL; } -double DivPlatformYM2610::NOTE_OPNB(int ch, int note) { - if (ch>6) { // ADPCM - return NOTE_ADPCMB(note); - } else if (ch>3) { // PSG - return NOTE_PERIODIC(note); - } - // FM - return NOTE_FNUM_BLOCK(note,11); -} - -double DivPlatformYM2610::NOTE_ADPCMB(int note) { - if (chan[13].sample>=0 && chan[13].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/144,off,note,false); - } - return 0; -} - void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; @@ -501,20 +397,20 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l bufL[h]=os[0]; bufR[h]=os[1]; - for (int i=0; i<4; i++) { + for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); } ssge->get_last_out(ssgOut); - for (int i=4; i<7; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-4]; + for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; } - for (int i=7; i<13; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-7]->get_last_out(0)+adpcmAChan[i-7]->get_last_out(1); + for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); } - oscBuf[13]->data[oscBuf[13]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); } } @@ -528,7 +424,7 @@ void DivPlatformYM2610::tick(bool sysTick) { ay->getRegisterWrites().clear(); // FM - for (int i=0; i<4; i++) { + for (int i=0; i=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); + } + chan[i].keyOn=false; } } } - if (chan[13].freqChanged) { - if (chan[13].sample>=0 && chan[13].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0; - chan[13].freq=parent->calcFreq(chan[13].baseFreq,chan[13].pitch,false,4,chan[13].pitch2,(double)chipClock/144,off); - } else { - chan[13].freq=0; + // ADPCM-B + if (chan[adpcmBChanOffs].furnacePCM) { + chan[adpcmBChanOffs].std.next(); + + if (chan[adpcmBChanOffs].std.vol.had) { + chan[adpcmBChanOffs].outVol=(chan[adpcmBChanOffs].vol*MIN(chan[adpcmBChanOffs].macroVolMul,chan[adpcmBChanOffs].std.vol.val))/chan[adpcmBChanOffs].macroVolMul; + immWrite(0x1b,chan[adpcmBChanOffs].outVol); } - immWrite(0x19,chan[13].freq&0xff); - immWrite(0x1a,(chan[13].freq>>8)&0xff); - chan[13].freqChanged=false; + + if (chan[adpcmBChanOffs].std.arp.had) { + if (!chan[adpcmBChanOffs].inPorta) { + if (chan[adpcmBChanOffs].std.arp.mode) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val); + } else { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val); + } + } + chan[adpcmBChanOffs].freqChanged=true; + } else { + if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note); + chan[adpcmBChanOffs].freqChanged=true; + } + } + if (chan[adpcmBChanOffs].std.panL.had) { + if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { + chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; + if (!isMuted[adpcmBChanOffs]) { + immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); + } + } + } + if (chan[adpcmBChanOffs].std.phaseReset.had) { + if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { + chan[adpcmBChanOffs].keyOn=true; + } + } + } + if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].furnacePCM) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0; + chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); + } else { + chan[adpcmBChanOffs].freq=0; + } + immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); + immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); + } + if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + immWrite(0x10,0x01); // reset + if (chan[adpcmBChanOffs].active && chan[adpcmBChanOffs].keyOn && !chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[adpcmBChanOffs].sample); + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat + } + } + chan[adpcmBChanOffs].keyOn=false; + chan[adpcmBChanOffs].keyOff=false; + } + chan[adpcmBChanOffs].freqChanged=false; + } + + if (writeADPCMAOff) { + immWrite(0x100,0x80|writeADPCMAOff); + writeADPCMAOff=0; } for (int i=16; i<512; i++) { @@ -733,7 +696,7 @@ void DivPlatformYM2610::tick(bool sysTick) { } } - for (int i=0; i<4; i++) { + for (int i=0; isong.linearPitch==2) { @@ -761,18 +724,24 @@ void DivPlatformYM2610::tick(bool sysTick) { chan[i].keyOn=false; } } + + if (writeADPCMAOn) { + immWrite(0x100,writeADPCMAOn); + writeADPCMAOn=0; + } } int DivPlatformYM2610::dispatch(DivCommand c) { - if (c.chan>3 && c.chan<7) { - c.chan-=4; + if (c.chan>=psgChanOffs && c.chan<7) { + c.chan-=psgChanOffs; return ay->dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { - if (c.chan>12) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -793,7 +762,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -814,50 +782,104 @@ int DivPlatformYM2610::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x12,(s->offB>>8)&0xff); - immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x19,freq&0xff); - immWrite(0x1a,(freq>>8)&0xff); + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x12,(s->offB>>8)&0xff); + immWrite(0x13,s->offB>>16); + int end=s->offB+s->lengthB-1; + immWrite(0x14,(end>>8)&0xff); + immWrite(0x15,end>>16); + immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); + int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); + immWrite(0x19,freq&0xff); + immWrite(0x1a,(freq>>8)&0xff); + immWrite(0x1b,chan[c.chan].outVol); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + immWrite(0x10,0x01); // reset + immWrite(0x12,0); + immWrite(0x13,0); + immWrite(0x14,0); + immWrite(0x15,0); + break; + } } break; } - if (c.chan>6) { // ADPCM-A - if (skipRegisterWrites) break; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x100,0x80|(1<<(c.chan-7))); - immWrite(0x110+c.chan-7,0); - immWrite(0x118+c.chan-7,0); - immWrite(0x120+c.chan-7,0); - immWrite(0x128+c.chan-7,0); - break; + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + chan[c.chan].furnacePCM=true; + } else { + chan[c.chan].furnacePCM=false; + } + if (skipRegisterWrites) break; + if (chan[c.chan].furnacePCM) { + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + chan[c.chan].sample=ins->amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } + } else { + chan[c.chan].sample=-1; + chan[c.chan].macroInit(NULL); + chan[c.chan].outVol=chan[c.chan].vol; + if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x110+c.chan-7,(s->offA>>8)&0xff); - immWrite(0x118+c.chan-7,s->offA>>16); - int end=s->offA+s->lengthA-1; - immWrite(0x120+c.chan-7,(end>>8)&0xff); - immWrite(0x128+c.chan-7,end>>16); - immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); - immWrite(0x100,0x00|(1<<(c.chan-7))); break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroInit(ins); - if (c.chan<4) { + if (c.chan12) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>6) { - immWrite(0x100,0x80|(1<<(c.chan-7))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan>12) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>6) { - immWrite(0x100,0x80|(1<<(c.chan-7))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; @@ -940,12 +946,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (c.chan>12) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B immWrite(0x1b,chan[c.chan].outVol); break; } - if (c.chan>6) { // ADPCM-A - immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -959,6 +965,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } break; } + case DIV_CMD_ADPCMA_GLOBAL_VOLUME: { + if (globalADPCMAVolume!=(c.value&0x3f)) { + globalADPCMAVolume=c.value&0x3f; + immWrite(0x101,globalADPCMAVolume&0x3f); + } + break; + } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; break; @@ -975,25 +988,25 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } else { chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); } - if (c.chan>12) { + if (c.chan>=adpcmBChanOffs) { immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); break; } - if (c.chan>6) { - immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { - if (c.chan==13 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; } case DIV_CMD_NOTE_PORTA: { - if (c.chan>3 || parent->song.linearPitch==2) { // PSG, ADPCM-B + if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -1027,7 +1040,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { - if (c.chan==13 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; @@ -1044,13 +1057,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; chan[c.chan].state.fb=c.value&7; rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.mult=c.value2&15; @@ -1058,7 +1071,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_FM_TL: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; @@ -1070,7 +1083,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_FM_AR: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; if (c.value<0) { for (int i=0; i<4; i++) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; @@ -1221,13 +1234,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { return 0; break; case DIV_CMD_GET_VOLMAX: - if (c.chan>12) return 255; - if (c.chan>6) return 31; - if (c.chan>3) return 15; + if (c.chan>=adpcmBChanOffs) return 255; + if (c.chan>=adpcmAChanOffs) return 31; + if (c.chan>=psgChanOffs) return 15; return 127; break; case DIV_CMD_PRE_PORTA: - if (c.chan>3) { + if (c.chan>=psgChanOffs) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } @@ -1245,15 +1258,8 @@ int DivPlatformYM2610::dispatch(DivCommand c) { void DivPlatformYM2610::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>12) { // ADPCM-B - immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6)); - } - if (ch>6) { // ADPCM-A - immWrite(0x108+(ch-7),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); - return; - } - if (ch>3) { // PSG - ay->muteChannel(ch-4,mute); + if (ch>=psgChanOffs) { // PSG + DivPlatformYM2610Base::muteChannel(ch,mute); return; } // FM @@ -1261,7 +1267,7 @@ void DivPlatformYM2610::muteChannel(int ch, bool mute) { } void DivPlatformYM2610::forceIns() { - for (int i=0; i<4; i++) { + for (int i=0; i=4 && ch<7) return ay->getChanMacroInt(ch-4); + if (ch>=psgChanOffs && chgetChanMacroInt(ch-psgChanOffs); return &chan[ch].std; } @@ -1336,17 +1342,20 @@ void DivPlatformYM2610::reset() { chan[i]=DivPlatformYM2610::Channel(); chan[i].std.setEngine(parent); } - for (int i=0; i<4; i++) { + for (int i=0; ireset(); - ay->getRegisterWrites().clear(); - ay->flushWrites(); } bool DivPlatformYM2610::isStereo() { @@ -1377,7 +1383,7 @@ bool DivPlatformYM2610::isStereo() { } bool DivPlatformYM2610::keyOffAffectsArp(int ch) { - return (ch>3); + return (ch>=psgChanOffs); } void DivPlatformYM2610::notifyInsChange(int ins) { @@ -1398,46 +1404,13 @@ void DivPlatformYM2610::setSkipRegisterWrites(bool value) { ay->setSkipRegisterWrites(value); } -void DivPlatformYM2610::setFlags(unsigned int flags) { - switch (flags&0xff) { - default: - case 0x00: - chipClock=8000000.0; - break; - case 0x01: - chipClock=24167829/3; - break; - } - rate=chipClock/16; - for (int i=0; i<14; i++) { - oscBuf[i]->rate=rate; - } -} - int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { DivPlatformYM2610Base::init(p, channels, sugRate, flags); - dumpWrites=false; - skipRegisterWrites=false; - for (int i=0; i<14; i++) { - isMuted[i]=false; - oscBuf[i]=new DivDispatchOscBuffer; - } - fm=new ymfm::ym2610(iface); - setFlags(flags); - // YM2149, 2MHz - ay=new DivPlatformAY8910(true,chipClock,32); - ay->init(p,3,sugRate,16); - ay->toggleRegisterDump(true); reset(); return 14; } void DivPlatformYM2610::quit() { - for (int i=0; i<14; i++) { - delete oscBuf[i]; - } - ay->quit(); - delete ay; delete fm; DivPlatformYM2610Base::quit(); } diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index dde7ed105..a1a8f154f 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -19,41 +19,9 @@ #ifndef _YM2610_H #define _YM2610_H -#include "fmshared_OPN.h" -#include "../macroInt.h" -#include "ay.h" -#include "sound/ymfm/ymfm_opn.h" +#include "ym2610shared.h" -class DivYM2610Interface: public ymfm::ymfm_interface { - public: - unsigned char* adpcmAMem; - unsigned char* adpcmBMem; - int sampleBank; - uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); - void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); - DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {} -}; - -class DivPlatformYM2610Base: public DivPlatformOPN { - protected: - unsigned char* adpcmAMem; - size_t adpcmAMemLen; - unsigned char* adpcmBMem; - size_t adpcmBMemLen; - DivYM2610Interface iface; - - public: - const void* getSampleMem(int index); - size_t getSampleMemCapacity(int index); - size_t getSampleMemUsage(int index); - void renderSamples(); - int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); - void quit(); - DivPlatformYM2610Base(): - DivPlatformOPN(9440540.0, 72, 32) {} -}; - -class DivPlatformYM2610: public DivPlatformYM2610Base { +class DivPlatformYM2610: public DivPlatformYM2610Base<14> { protected: const unsigned short chanOffs[4]={ 0x01, 0x02, 0x101, 0x102 @@ -67,64 +35,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { 1, 2, 4, 5 }; - struct Channel { - DivInstrumentFM state; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; - int vol, outVol; - int sample; - unsigned char pan; - DivMacroInt std; - void macroInit(DivInstrument* which) { - std.init(which); - pitch2=0; - } - Channel(): - freqH(0), - freqL(0), - freq(0), - baseFreq(0), - pitch(0), - pitch2(0), - portaPauseFreq(0), - note(0), - ins(-1), - psgMode(1), - autoEnvNum(0), - autoEnvDen(0), - active(false), - insChanged(true), - freqChanged(false), - keyOn(false), - keyOff(false), - portaPause(false), - inPorta(false), - furnacePCM(false), - hardReset(false), - vol(0), - outVol(15), - sample(-1), - pan(3) {} - }; - Channel chan[14]; - DivDispatchOscBuffer* oscBuf[14]; - bool isMuted[14]; - ymfm::ym2610* fm; - ymfm::ym2610::output_data fmout; - - DivPlatformAY8910* ay; - - unsigned char sampleBank; - - bool extMode; - - double NOTE_OPNB(int ch, int note); - double NOTE_ADPCMB(int note); friend void putDispatchChan(void*,int,int); - + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); @@ -146,9 +58,10 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); - void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2610(): + DivPlatformYM2610Base<14>(1,4,7,13) {} ~DivPlatformYM2610(); }; #endif diff --git a/src/engine/platform/ym2610Interface.cpp b/src/engine/platform/ym2610Interface.cpp index d442ce347..1b13b3743 100644 --- a/src/engine/platform/ym2610Interface.cpp +++ b/src/engine/platform/ym2610Interface.cpp @@ -17,9 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "sound/ymfm/ymfm.h" -#include "ym2610.h" -#include "../engine.h" +#include "ym2610shared.h" uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) { switch (type) { diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 1a1f7f0ae..8315e3948 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -18,14 +18,8 @@ */ #include "ym2610b.h" -#include "sound/ymfm/ymfm.h" -#include "../engine.h" -#include #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - const char* regCheatSheetYM2610B[]={ // SSG "SSG_FreqL_A", "000", @@ -422,24 +416,6 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) { return NULL; } -double DivPlatformYM2610B::NOTE_OPNB(int ch, int note) { - if (ch>8) { // ADPCM-B - return NOTE_ADPCMB(note); - } else if (ch>5) { // PSG - return NOTE_PERIODIC(note); - } - // FM - return NOTE_FNUM_BLOCK(note,11); -} - -double DivPlatformYM2610B::NOTE_ADPCMB(int note) { - if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/144,off,note,false); - } - return 0; -} - void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; @@ -484,20 +460,20 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t bufR[h]=os[1]; - for (int i=0; i<6; i++) { + for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); } ssge->get_last_out(ssgOut); - for (int i=6; i<9; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6]; + for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; } - for (int i=9; i<15; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1); + for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); } - oscBuf[15]->data[oscBuf[15]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); } } @@ -511,7 +487,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { ay->getRegisterWrites().clear(); // FM - for (int i=0; i<6; i++) { + for (int i=0; i=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); + } + chan[i].keyOn=false; } } } - if (chan[15].freqChanged) { - if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; - chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off); - } else { - chan[15].freq=0; + // ADPCM-B + if (chan[adpcmBChanOffs].furnacePCM) { + chan[adpcmBChanOffs].std.next(); + + if (chan[adpcmBChanOffs].std.vol.had) { + chan[adpcmBChanOffs].outVol=(chan[adpcmBChanOffs].vol*MIN(chan[adpcmBChanOffs].macroVolMul,chan[adpcmBChanOffs].std.vol.val))/chan[adpcmBChanOffs].macroVolMul; + immWrite(0x1b,chan[adpcmBChanOffs].outVol); } - immWrite(0x19,chan[15].freq&0xff); - immWrite(0x1a,(chan[15].freq>>8)&0xff); - chan[15].freqChanged=false; + + if (chan[adpcmBChanOffs].std.arp.had) { + if (!chan[adpcmBChanOffs].inPorta) { + if (chan[adpcmBChanOffs].std.arp.mode) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val); + } else { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val); + } + } + chan[adpcmBChanOffs].freqChanged=true; + } else { + if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note); + chan[adpcmBChanOffs].freqChanged=true; + } + } + if (chan[adpcmBChanOffs].std.panL.had) { + if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { + chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; + if (!isMuted[adpcmBChanOffs]) { + immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); + } + } + } + if (chan[adpcmBChanOffs].std.phaseReset.had) { + if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { + chan[adpcmBChanOffs].keyOn=true; + } + } + } + if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].furnacePCM) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0; + chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); + } else { + chan[adpcmBChanOffs].freq=0; + } + immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); + immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); + } + if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + immWrite(0x10,0x01); // reset + if (chan[adpcmBChanOffs].active && chan[adpcmBChanOffs].keyOn && !chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[adpcmBChanOffs].sample); + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat + } + } + chan[adpcmBChanOffs].keyOn=false; + chan[adpcmBChanOffs].keyOff=false; + } + chan[adpcmBChanOffs].freqChanged=false; + } + + if (writeADPCMAOff) { + immWrite(0x100,0x80|writeADPCMAOff); + writeADPCMAOff=0; } for (int i=16; i<512; i++) { @@ -715,7 +758,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { } } - for (int i=0; i<6; i++) { + for (int i=0; isong.linearPitch==2) { @@ -743,18 +786,24 @@ void DivPlatformYM2610B::tick(bool sysTick) { chan[i].keyOn=false; } } + + if (writeADPCMAOn) { + immWrite(0x100,writeADPCMAOn); + writeADPCMAOn=0; + } } int DivPlatformYM2610B::dispatch(DivCommand c) { - if (c.chan>5 && c.chan<9) { - c.chan-=6; + if (c.chan>=psgChanOffs && c.chandispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { - if (c.chan>14) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -775,7 +824,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -796,45 +844,99 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x12,(s->offB>>8)&0xff); - immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x19,freq&0xff); - immWrite(0x1a,(freq>>8)&0xff); + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x12,(s->offB>>8)&0xff); + immWrite(0x13,s->offB>>16); + int end=s->offB+s->lengthB-1; + immWrite(0x14,(end>>8)&0xff); + immWrite(0x15,end>>16); + immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); + int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); + immWrite(0x19,freq&0xff); + immWrite(0x1a,(freq>>8)&0xff); + immWrite(0x1b,chan[c.chan].outVol); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + immWrite(0x10,0x01); // reset + immWrite(0x12,0); + immWrite(0x13,0); + immWrite(0x14,0); + immWrite(0x15,0); + break; + } } break; } - if (c.chan>8) { // ADPCM-A - if (skipRegisterWrites) break; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x100,0x80|(1<<(c.chan-9))); - immWrite(0x110+c.chan-9,0); - immWrite(0x118+c.chan-9,0); - immWrite(0x120+c.chan-9,0); - immWrite(0x128+c.chan-9,0); - break; + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + chan[c.chan].furnacePCM=true; + } else { + chan[c.chan].furnacePCM=false; + } + if (skipRegisterWrites) break; + if (chan[c.chan].furnacePCM) { + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + chan[c.chan].sample=ins->amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } + } else { + chan[c.chan].sample=-1; + chan[c.chan].macroInit(NULL); + chan[c.chan].outVol=chan[c.chan].vol; + if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x110+c.chan-9,(s->offA>>8)&0xff); - immWrite(0x118+c.chan-9,s->offA>>16); - int end=s->offA+s->lengthA-1; - immWrite(0x120+c.chan-9,(end>>8)&0xff); - immWrite(0x128+c.chan-9,end>>16); - immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); - immWrite(0x100,0x00|(1<<(c.chan-9))); break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); @@ -887,28 +989,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan>14) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>8) { - immWrite(0x100,0x80|(1<<(c.chan-9))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan>14) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>8) { - immWrite(0x100,0x80|(1<<(c.chan-9))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; @@ -922,12 +1008,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (c.chan>14) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B immWrite(0x1b,chan[c.chan].outVol); break; } - if (c.chan>8) { // ADPCM-A - immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -941,6 +1027,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } break; } + case DIV_CMD_ADPCMA_GLOBAL_VOLUME: { + if (globalADPCMAVolume!=(c.value&0x3f)) { + globalADPCMAVolume=c.value&0x3f; + immWrite(0x101,globalADPCMAVolume&0x3f); + } + break; + } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; break; @@ -957,25 +1050,25 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } else { chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); } - if (c.chan>14) { + if (c.chan>=adpcmBChanOffs) { immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); break; } - if (c.chan>8) { - immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { - if (c.chan==15 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; } case DIV_CMD_NOTE_PORTA: { - if (c.chan>5 || parent->song.linearPitch==2) { // PSG, ADPCM-B + if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -1009,7 +1102,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { - if (c.chan==15 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; @@ -1026,13 +1119,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; chan[c.chan].state.fb=c.value&7; rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.mult=c.value2&15; @@ -1040,7 +1133,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_FM_TL: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; @@ -1052,7 +1145,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_FM_AR: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; if (c.value<0) { for (int i=0; i<4; i++) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; @@ -1203,13 +1296,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { return 0; break; case DIV_CMD_GET_VOLMAX: - if (c.chan>14) return 255; - if (c.chan>8) return 31; - if (c.chan>5) return 15; + if (c.chan>=adpcmBChanOffs) return 255; + if (c.chan>=adpcmAChanOffs) return 31; + if (c.chan>=psgChanOffs) return 15; return 127; break; case DIV_CMD_PRE_PORTA: - if (c.chan>5) { + if (c.chan>=psgChanOffs) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } @@ -1227,15 +1320,8 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { void DivPlatformYM2610B::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>14) { // ADPCM-B - immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6)); - } - if (ch>8) { // ADPCM-A - immWrite(0x108+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); - return; - } - if (ch>5) { // PSG - ay->muteChannel(ch-6,mute); + if (ch>=psgChanOffs) { // PSG + DivPlatformYM2610Base::muteChannel(ch,mute); return; } // FM @@ -1243,7 +1329,7 @@ void DivPlatformYM2610B::muteChannel(int ch, bool mute) { } void DivPlatformYM2610B::forceIns() { - for (int i=0; i<6; i++) { + for (int i=0; i=6 && ch<9) return ay->getChanMacroInt(ch-6); + if (ch>=psgChanOffs && chgetChanMacroInt(ch-psgChanOffs); return &chan[ch].std; } @@ -1318,17 +1404,20 @@ void DivPlatformYM2610B::reset() { chan[i]=DivPlatformYM2610B::Channel(); chan[i].std.setEngine(parent); } - for (int i=0; i<6; i++) { + for (int i=0; i5); + return (ch>=psgChanOffs); } void DivPlatformYM2610B::notifyInsChange(int ins) { @@ -1380,46 +1470,13 @@ void DivPlatformYM2610B::setSkipRegisterWrites(bool value) { ay->setSkipRegisterWrites(value); } -void DivPlatformYM2610B::setFlags(unsigned int flags) { - switch (flags&0xff) { - default: - case 0x00: - chipClock=8000000.0; - break; - case 0x01: - chipClock=24167829/3; - break; - } - rate=chipClock/16; - for (int i=0; i<16; i++) { - oscBuf[i]->rate=rate; - } -} - int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { DivPlatformYM2610Base::init(p, channels, sugRate, flags); - dumpWrites=false; - skipRegisterWrites=false; - for (int i=0; i<16; i++) { - isMuted[i]=false; - oscBuf[i]=new DivDispatchOscBuffer; - } - fm=new ymfm::ym2610b(iface); - setFlags(flags); - // YM2149, 2MHz - ay=new DivPlatformAY8910(true,chipClock,32); - ay->init(p,3,sugRate,16); - ay->toggleRegisterDump(true); reset(); return 16; } void DivPlatformYM2610B::quit() { - for (int i=0; i<16; i++) { - delete oscBuf[i]; - } - ay->quit(); - delete ay; delete fm; DivPlatformYM2610Base::quit(); } diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index fefb06929..38eaa4e3c 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -19,12 +19,9 @@ #ifndef _YM2610B_H #define _YM2610B_H -#include "ym2610.h" -#include "../macroInt.h" -#include "sound/ymfm/ymfm_opn.h" +#include "ym2610shared.h" - -class DivPlatformYM2610B: public DivPlatformYM2610Base { +class DivPlatformYM2610B: public DivPlatformYM2610Base<16> { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 @@ -34,65 +31,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { 0, 1, 2, 4, 5, 6 }; - struct Channel { - DivInstrumentFM state; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; - int vol, outVol; - int sample; - unsigned char pan; - DivMacroInt std; - void macroInit(DivInstrument* which) { - std.init(which); - pitch2=0; - } - Channel(): - freqH(0), - freqL(0), - freq(0), - baseFreq(0), - pitch(0), - pitch2(0), - portaPauseFreq(0), - note(0), - ins(-1), - psgMode(1), - autoEnvNum(0), - autoEnvDen(0), - active(false), - insChanged(true), - freqChanged(false), - keyOn(false), - keyOff(false), - portaPause(false), - inPorta(false), - furnacePCM(false), - hardReset(false), - vol(0), - outVol(15), - sample(-1), - pan(3) {} - }; - Channel chan[16]; - DivDispatchOscBuffer* oscBuf[16]; - bool isMuted[16]; - ymfm::ym2610b* fm; - ymfm::ym2610b::output_data fmout; - - DivPlatformAY8910* ay; - unsigned char sampleBank; - - bool extMode; - double fmFreqBase=9440540; - unsigned char ayDiv=32; - - double NOTE_OPNB(int ch, int note); - double NOTE_ADPCMB(int note); friend void putDispatchChan(void*,int,int); - + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); @@ -114,9 +54,10 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); - void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2610B(): + DivPlatformYM2610Base<16>(2,6,9,15) {} ~DivPlatformYM2610B(); }; #endif diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 7c8247ff8..9f6e528f8 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -18,31 +18,27 @@ */ #include "ym2610bext.h" -#include "../engine.h" #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - int DivPlatformYM2610BExt::dispatch(DivCommand c) { - if (c.chan<2) { + if (c.chan5) { + if (c.chan>(extChanOffs+3)) { c.chan-=3; return DivPlatformYM2610B::dispatch(c); } - int ch=c.chan-2; + int ch=c.chan-extChanOffs; int ordch=orderedOps[ch]; if (!extMode) { - c.chan=2; + c.chan=extChanOffs; return DivPlatformYM2610B::dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; // TODO: how does this work?! if (isOpMuted[ch]) { @@ -61,8 +57,8 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { rWrite(baseAddr+0x90,op.ssgEnv&15); } if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -83,7 +79,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); @@ -115,7 +111,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { opChan[i].pan=opChan[ch].pan; } } - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -165,19 +161,19 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - chan[2].state.fb=c.value&7; - rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + chan[extChanOffs].state.fb=c.value&7; + rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { // TODO - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (isOutput[ins->fm.alg][c.value]) { rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); @@ -189,15 +185,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_AR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } } else { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } break; @@ -205,15 +201,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_RS: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } break; @@ -221,15 +217,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_AM: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -237,15 +233,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_DR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -253,15 +249,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_SL: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -269,15 +265,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_RR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -285,15 +281,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_D2R: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } break; @@ -301,15 +297,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_DT: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dt=c.value&7; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dt=c.value2&7; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } break; @@ -317,15 +313,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_SSG: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } break; @@ -408,31 +404,31 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { } void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) { - if (ch<2) { + if (ch5) { + if (ch>(extChanOffs+3)) { DivPlatformYM2610B::muteChannel(ch-3,mute); return; } - isOpMuted[ch-2]=mute; + isOpMuted[ch-extChanOffs]=mute; - int ordch=orderedOps[ch-2]; - DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + int ordch=orderedOps[ch-extChanOffs]; + DivInstrument* ins=parent->getIns(opChan[ch-extChanOffs].ins,DIV_INS_FM); + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; - if (isOpMuted[ch-2]) { + if (isOpMuted[ch-extChanOffs]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-extChanOffs].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } } void DivPlatformYM2610BExt::forceIns() { - for (int i=0; i<6; i++) { + for (int i=0; iforceIns(); @@ -488,21 +484,21 @@ void DivPlatformYM2610BExt::forceIns() { } void* DivPlatformYM2610BExt::getChanState(int ch) { - if (ch>=6) return &chan[ch-3]; - if (ch>=2) return &opChan[ch-2]; + if (ch>=(extChanOffs+4)) return &chan[ch-3]; + if (ch>=extChanOffs) return &opChan[ch-extChanOffs]; return &chan[ch]; } DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) { - if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9); - if (ch>=6) return &chan[ch-3].std; - if (ch>=2) return NULL; // currently not implemented + if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3); + if (ch>=(extChanOffs+4)) return &chan[ch-3].std; + if (ch>=extChanOffs) return NULL; // currently not implemented return &chan[ch].std; } DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) { - if (ch>=6) return oscBuf[ch-3]; - if (ch<3) return oscBuf[ch]; + if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; + if (ch<(extChanOffs+1)) return oscBuf[ch]; return NULL; } @@ -520,7 +516,7 @@ void DivPlatformYM2610BExt::reset() { } bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) { - return (ch>8); + return (ch>=(psgChanOffs+3)); } void DivPlatformYM2610BExt::notifyInsChange(int ins) { diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index 732678fe5..c54586d36 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -22,19 +22,7 @@ #include "ym2610b.h" class DivPlatformYM2610BExt: public DivPlatformYM2610B { - struct OpChannel { - DivMacroInt std; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; - int vol; - unsigned char pan; - // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} - }; - OpChannel opChan[4]; + DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index b2bd06a8c..ca385f3dc 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -18,31 +18,27 @@ */ #include "ym2610ext.h" -#include "../engine.h" #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - int DivPlatformYM2610Ext::dispatch(DivCommand c) { - if (c.chan<1) { + if (c.chan4) { + if (c.chan>(extChanOffs+3)) { c.chan-=3; return DivPlatformYM2610::dispatch(c); } - int ch=c.chan-1; + int ch=c.chan-extChanOffs; int ordch=orderedOps[ch]; if (!extMode) { - c.chan=2; + c.chan=extChanOffs; return DivPlatformYM2610::dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; // TODO: how does this work?! if (isOpMuted[ch]) { @@ -61,8 +57,8 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x90,op.ssgEnv&15); } if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[1]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[1]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -83,7 +79,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); @@ -115,7 +111,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { opChan[i].pan=opChan[ch].pan; } } - rWrite(chanOffs[1]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -165,19 +161,19 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - chan[1].state.fb=c.value&7; - rWrite(chanOffs[1]+ADDR_FB_ALG,(chan[1].state.alg&7)|(chan[1].state.fb<<3)); + chan[extChanOffs].state.fb=c.value&7; + rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { // TODO - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (isOutput[ins->fm.alg][c.value]) { rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); @@ -189,15 +185,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_AR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } } else { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } break; @@ -205,15 +201,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_RS: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } break; @@ -221,15 +217,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_AM: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -237,15 +233,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_DR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -253,15 +249,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_SL: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -269,15 +265,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_RR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -285,15 +281,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_D2R: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } break; @@ -301,15 +297,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_DT: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dt=c.value&7; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dt=c.value2&7; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } break; @@ -317,15 +313,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_SSG: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } break; @@ -408,31 +404,31 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { } void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { - if (ch<1) { + if (ch4) { + if (ch>(extChanOffs+3)) { DivPlatformYM2610::muteChannel(ch-3,mute); return; } - isOpMuted[ch-1]=mute; + isOpMuted[ch-extChanOffs]=mute; - int ordch=orderedOps[ch-1]; + int ordch=orderedOps[ch-extChanOffs]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-extChanOffs].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } } void DivPlatformYM2610Ext::forceIns() { - for (int i=0; i<4; i++) { + for (int i=0; iforceIns(); @@ -488,21 +484,21 @@ void DivPlatformYM2610Ext::forceIns() { } void* DivPlatformYM2610Ext::getChanState(int ch) { - if (ch>=5) return &chan[ch-3]; - if (ch>=1) return &opChan[ch-1]; + if (ch>=(extChanOffs+4)) return &chan[ch-3]; + if (ch>=extChanOffs) return &opChan[ch-extChanOffs]; return &chan[ch]; } DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) { - if (ch>=7 && ch<10) return ay->getChanMacroInt(ch-7); - if (ch>=5) return &chan[ch-3].std; - if (ch>=1) return NULL; // currently not implemented + if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3); + if (ch>=(extChanOffs+4)) return &chan[ch-3].std; + if (ch>=extChanOffs) return NULL; // currently not implemented return &chan[ch].std; } DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) { - if (ch>=5) return oscBuf[ch-3]; - if (ch<2) return oscBuf[ch]; + if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; + if (ch<(extChanOffs+1)) return oscBuf[ch]; return NULL; } @@ -520,7 +516,7 @@ void DivPlatformYM2610Ext::reset() { } bool DivPlatformYM2610Ext::keyOffAffectsArp(int ch) { - return (ch>7); + return (ch>=(psgChanOffs+3)); } void DivPlatformYM2610Ext::notifyInsChange(int ins) { diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 119d63569..ab7c060ff 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -22,19 +22,7 @@ #include "ym2610.h" class DivPlatformYM2610Ext: public DivPlatformYM2610 { - struct OpChannel { - DivMacroInt std; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; - int vol; - unsigned char pan; - // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} - }; - OpChannel opChan[4]; + DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h new file mode 100644 index 000000000..7fc445d35 --- /dev/null +++ b/src/engine/platform/ym2610shared.h @@ -0,0 +1,315 @@ +/** + * 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 _YM2610SHARED_H +#define _YM2610SHARED_H +#include "fmshared_OPN.h" +#include "../macroInt.h" +#include "../engine.h" +#include "../../ta-log.h" +#include "ay.h" +#include "sound/ymfm/ymfm.h" +#include "sound/ymfm/ymfm_opn.h" +#include + +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + +class DivYM2610Interface: public ymfm::ymfm_interface { + public: + unsigned char* adpcmAMem; + unsigned char* adpcmBMem; + int sampleBank; + uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); + void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); + DivYM2610Interface(): + adpcmAMem(NULL), + adpcmBMem(NULL), + sampleBank(0) {} +}; + +template +class DivPlatformYM2610Base: public DivPlatformOPN { + protected: + struct Channel { + DivInstrumentFM state; + unsigned char freqH, freqL; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; + unsigned char psgMode, autoEnvNum, autoEnvDen; + signed char konCycles; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + int vol, outVol; + int sample; + unsigned char pan; + int macroVolMul; + DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + note(0), + ins(-1), + psgMode(1), + autoEnvNum(0), + autoEnvDen(0), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + furnacePCM(false), + hardReset(false), + vol(0), + outVol(15), + sample(-1), + pan(3), + macroVolMul(255) {} + }; + + struct OpChannel { + DivMacroInt std; + unsigned char freqH, freqL; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; + signed char konCycles; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + int vol; + unsigned char pan; + // UGLY + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + vol(0), + pan(3) {} + }; + Channel chan[ChanNum]; + DivDispatchOscBuffer* oscBuf[ChanNum]; + bool isMuted[ChanNum]; + + ymfm::ym2610b* fm; + ymfm::ym2610b::output_data fmout; + DivPlatformAY8910* ay; + + unsigned char* adpcmAMem; + size_t adpcmAMemLen; + unsigned char* adpcmBMem; + size_t adpcmBMemLen; + DivYM2610Interface iface; + + unsigned char sampleBank; + + bool extMode; + + unsigned char writeADPCMAOff, writeADPCMAOn; + int globalADPCMAVolume; + + const int extChanOffs, psgChanOffs, adpcmAChanOffs, adpcmBChanOffs; + const int chanNum=ChanNum; + + double NOTE_OPNB(int ch, int note) { + if (ch>=adpcmBChanOffs) { // ADPCM + return NOTE_ADPCMB(note); + } else if (ch>=psgChanOffs) { // PSG + return NOTE_PERIODIC(note); + } + // FM + return NOTE_FNUM_BLOCK(note,11); + } + double NOTE_ADPCMB(int note) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0; + return parent->calcBaseFreq((double)chipClock/144,off,note,false); + } + return 0; + } + + public: + void reset() { + writeADPCMAOff=0; + writeADPCMAOn=0; + globalADPCMAVolume=0x3f; + + ay->reset(); + ay->getRegisterWrites().clear(); + ay->flushWrites(); + } + + void muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + if (ch>=adpcmBChanOffs) { // ADPCM-B + immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6)); + } + if (ch>=adpcmAChanOffs) { // ADPCM-A + immWrite(0x108+(ch-adpcmAChanOffs),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol)); + return; + } + if (ch>=psgChanOffs) { // PSG + ay->muteChannel(ch-psgChanOffs,mute); + return; + } + } + + bool isStereo() { + return true; + } + + const void* getSampleMem(int index) { + return index == 0 ? adpcmAMem : index == 1 ? adpcmBMem : NULL; + } + + size_t getSampleMemCapacity(int index) { + return index == 0 ? 16777216 : index == 1 ? 16777216 : 0; + } + + size_t getSampleMemUsage(int index) { + return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0; + } + + void renderSamples() { + memset(adpcmAMem,0,getSampleMemCapacity(0)); + + size_t memPos=0; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + int paddedLen=(s->lengthA+255)&(~0xff); + if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { + memPos=(memPos+0xfffff)&0xf00000; + } + if (memPos>=getSampleMemCapacity(0)) { + logW("out of ADPCM-A memory for sample %d!",i); + break; + } + if (memPos+paddedLen>=getSampleMemCapacity(0)) { + memcpy(adpcmAMem+memPos,s->dataA,getSampleMemCapacity(0)-memPos); + logW("out of ADPCM-A memory for sample %d!",i); + } else { + memcpy(adpcmAMem+memPos,s->dataA,paddedLen); + } + s->offA=memPos; + memPos+=paddedLen; + } + adpcmAMemLen=memPos+256; + + memset(adpcmBMem,0,getSampleMemCapacity(1)); + + memPos=0; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + int paddedLen=(s->lengthB+255)&(~0xff); + if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { + memPos=(memPos+0xfffff)&0xf00000; + } + if (memPos>=getSampleMemCapacity(1)) { + logW("out of ADPCM-B memory for sample %d!",i); + break; + } + if (memPos+paddedLen>=getSampleMemCapacity(1)) { + memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(1)-memPos); + logW("out of ADPCM-B memory for sample %d!",i); + } else { + memcpy(adpcmBMem+memPos,s->dataB,paddedLen); + } + s->offB=memPos; + memPos+=paddedLen; + } + adpcmBMemLen=memPos+256; + } + + void setFlags(unsigned int flags) { + switch (flags&0xff) { + default: + case 0x00: + chipClock=8000000.0; + break; + case 0x01: + chipClock=24167829/3; + break; + } + rate=fm->sample_rate(chipClock); + for (int i=0; irate=rate; + } + } + + int init(DivEngine* p, int channels, int sugRate, unsigned int flags) { + parent=p; + dumpWrites=false; + skipRegisterWrites=false; + for (int i=0; iset_fidelity(ymfm::OPN_FIDELITY_MIN); + setFlags(flags); + // YM2149, 2MHz + ay=new DivPlatformAY8910(true,chipClock,32); + ay->init(p,3,sugRate,16); + ay->toggleRegisterDump(true); + return 0; + } + + void quit() { + for (int i=0; iquit(); + delete ay; + delete[] adpcmAMem; + delete[] adpcmBMem; + } + + DivPlatformYM2610Base(int ext, int psg, int adpcmA, int adpcmB): + DivPlatformOPN(9440540.0, 72, 32), + extChanOffs(ext), + psgChanOffs(psg), + adpcmAChanOffs(adpcmA), + adpcmBChanOffs(adpcmB) {} +}; + +#endif diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index b690d30cb..5003041d3 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -94,7 +94,7 @@ void DivPlatformYMZ280B::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&0xff)*chan[i].std.vol.val)>>6; + chan[i].outVol=((chan[i].vol&0xff)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; writeOutVol(i); } if (chan[i].std.arp.had) { @@ -122,9 +122,19 @@ void DivPlatformYMZ280B::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.panL.had) { // panning - chan[i].panning=MIN((chan[i].std.panL.val*15/16+15)/2+1,15); + if (chan[i].isNewYMZ) { + chan[i].panning=8+chan[i].std.panL.val; + } else { + chan[i].panning=MIN((chan[i].std.panL.val*15/16+15)/2+1,15); + } rWrite(0x03+i*4,chan[i].panning); } + if (chan[i].std.phaseReset.had) { + if ((chan[i].std.phaseReset.val==1) && chan[i].active) { + chan[i].audPos=0; + chan[i].setPos=true; + } + } if (chan[i].setPos) { // force keyon chan[i].keyOn=true; @@ -207,6 +217,8 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].isNewYMZ=ins->type==DIV_INS_YMZ280B; + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index 0d254c088..5ef362ed1 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -32,8 +32,9 @@ class DivPlatformYMZ280B: public DivDispatch { int sample, wave, ins; int note; int panning; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos, isNewYMZ; int vol, outVol; + int macroVolMul; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -56,8 +57,10 @@ class DivPlatformYMZ280B: public DivDispatch { keyOff(false), inPorta(false), setPos(false), + isNewYMZ(false), vol(255), - outVol(255) {} + outVol(255), + macroVolMul(64) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index d3fa252d6..6903c0f04 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -165,6 +165,7 @@ const char* cmdName[]={ "X1_010_ENVELOPE_PERIOD", "X1_010_ENVELOPE_SLIDE", "X1_010_AUTO_ENVELOPE", + "X1_010_SAMPLE_BANK_SLOT", "WS_SWEEP_TIME", "WS_SWEEP_AMOUNT", @@ -189,6 +190,8 @@ const char* cmdName[]={ "DIV_CMD_SU_SYNC_PERIOD_LOW", "DIV_CMD_SU_SYNC_PERIOD_HIGH", + "ADPCMA_GLOBAL_VOLUME", + "ALWAYS_SET_VOLUME" }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index c5541baa3..759ca4ccb 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -944,8 +944,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"}, {"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -956,8 +956,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"}, {"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"}, {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1331,8 +1331,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1343,8 +1343,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1418,6 +1418,7 @@ void DivEngine::registerSystems() { {"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_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} ); @@ -1489,8 +1490,8 @@ void DivEngine::registerSystems() { {"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"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [](int,unsigned char,unsigned char) -> bool {return false;}, segaPCMPostEffectHandler ); @@ -1522,8 +1523,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1630,8 +1631,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1642,8 +1643,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1685,8 +1686,8 @@ void DivEngine::registerSystems() { {"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, + {DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { switch (effect) { case 0x10: // echo feedback @@ -1739,8 +1740,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1751,8 +1752,8 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"}, {"P1", "P2", "P3", "P4", "P5"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [](int,unsigned char,unsigned char) -> bool {return false;}, segaPCMPostEffectHandler ); @@ -1840,7 +1841,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( "Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false, - "a sample chip used in the Gravis Ultrasound, popular in the PC (DOS) demoscene.", + "a sample chip used in the Ensoniq's unique TransWave synthesizers, and SoundScape series PC ISA soundcards (which are yet another (partially) Sound Blaster compatible ones with emulated OPL3 and MIDI ROMpler).", {"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", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, @@ -1853,8 +1854,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_ADPCMB}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, - {}, oplEffectHandler, fmOPLPostEffectHandler ); @@ -1866,7 +1867,7 @@ void DivEngine::registerSystems() { {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_NULL}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, oplEffectHandler, fmOPLPostEffectHandler ); @@ -1966,8 +1967,8 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4"}, {"CH1", "CH2", "CH3", "CH4"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { switch (effect) { case 0x20: // select rate @@ -1986,8 +1987,8 @@ void DivEngine::registerSystems() { {"Sample"}, {"PCM"}, {DIV_CH_PCM}, + {DIV_INS_MSM6258}, {DIV_INS_AMIGA}, - {}, [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { switch (effect) { case 0x20: // select rate @@ -2009,6 +2010,7 @@ void DivEngine::registerSystems() { {"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8"}, {"1", "2", "3", "4", "5", "6", "7", "8"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} ); diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 3a536951f..d6951ffb8 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -318,6 +318,38 @@ void FurnaceGUI::drawInsList() { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]); name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i); break; + case DIV_INS_MSM6258: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6258]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_MSM6295: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6295]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_ADPCMA: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ADPCMA]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_ADPCMB: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ADPCMB]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_SEGAPCM: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SEGAPCM]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_QSOUND: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_QSOUND]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_YMZ280B: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_YMZ280B]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_RF5C68: + 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; default: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 5ae596bcd..641df4d34 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -27,6 +27,7 @@ #include "../engine/platform/nes.h" #include "../engine/platform/c64.h" #include "../engine/platform/arcade.h" +#include "../engine/platform/segapcm.h" #include "../engine/platform/ym2610.h" #include "../engine/platform/ym2610ext.h" #include "../engine/platform/ym2610b.h" @@ -36,9 +37,12 @@ #include "../engine/platform/tia.h" #include "../engine/platform/saa.h" #include "../engine/platform/amiga.h" +#include "../engine/platform/qsound.h" #include "../engine/platform/x1_010.h" #include "../engine/platform/n163.h" #include "../engine/platform/vrc6.h" +#include "../engine/platform/lynx.h" +#include "../engine/platform/pcmdac.h" #include "../engine/platform/dummy.h" #define GENESIS_DEBUG \ @@ -48,6 +52,7 @@ ImGui::Text("* freq: %d",ch->freq); \ ImGui::Text(" - base: %d",ch->baseFreq); \ ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ ImGui::Text("- note: %d",ch->note); \ ImGui::Text("- ins: %d",ch->ins); \ ImGui::Text("- vol: %.2x",ch->vol); \ @@ -68,6 +73,7 @@ ImGui::Text("* freq: %d",ch->freq); \ ImGui::Text(" - base: %d",ch->baseFreq); \ ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ ImGui::Text("- note: %d",ch->note); \ ImGui::Text("- ins: %d",ch->ins); \ ImGui::Text("- vol: %.2x",ch->vol); \ @@ -111,6 +117,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- duty: %d",ch->duty); @@ -133,17 +140,20 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("* DAC:"); ImGui::Text(" - period: %d",ch->dacPeriod); ImGui::Text(" - rate: %d",ch->dacRate); ImGui::Text(" - pos: %d",ch->dacPos); + ImGui::Text(" - out: %d",ch->dacOut); ImGui::Text(" - sample: %d",ch->dacSample); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- pan: %.2x",ch->pan); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- outVol: %.2x",ch->outVol); ImGui::Text("- wave: %d",ch->wave); + ImGui::Text("- macroVolMul: %d",ch->macroVolMul); ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); @@ -161,6 +171,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text(" - prev: %d",ch->prevFreq); ImGui::Text("- note: %d",ch->note); ImGui::Text("- ins: %d",ch->ins); @@ -185,6 +196,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text(" - prev: %d",ch->prevFreq); ImGui::Text("- testWhen: %d",ch->testWhen); ImGui::Text("- note: %d",ch->note); @@ -218,6 +230,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- KOnCycles: %d",ch->konCycles); @@ -231,8 +244,140 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + break; + } + case DIV_SYSTEM_SEGAPCM: + case DIV_SYSTEM_SEGAPCM_COMPAT: { + DivPlatformSegaPCM::Channel* ch=(DivPlatformSegaPCM::Channel*)data; + ImGui::Text("> SegaPCM"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("* PCM:"); + ImGui::Text(" - sample: %d",ch->pcm.sample); + ImGui::Text(" - pos: %d",ch->pcm.pos); + ImGui::Text(" - len: %d",ch->pcm.len); + ImGui::Text(" - freq: %d",ch->pcm.freq); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- chVolL: %.2x",ch->chVolL); + ImGui::Text("- chVolR: %.2x",ch->chVolR); + ImGui::Text("- chPanL: %.2x",ch->chPanL); + ImGui::Text("- chPanR: %.2x",ch->chPanR); + ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->isNewSegaPCM?colorOn:colorOff,">> IsNewSegaPCM"); + break; + } + case DIV_SYSTEM_AY8910: { + DivPlatformAY8910::Channel* ch=(DivPlatformAY8910::Channel*)data; + ImGui::Text("> AY-3-8910"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("* psgMode:"); + ImGui::Text(" - tone: %d",ch->psgMode.tone); + ImGui::Text(" - noise: %d",ch->psgMode.noise); + ImGui::Text(" - envelope: %d",ch->psgMode.envelope); + ImGui::Text(" - dac: %d",ch->psgMode.dac); + ImGui::Text("* DAC:"); + ImGui::Text(" - sample: %d",ch->dac.sample); + ImGui::Text(" - rate: %d",ch->dac.rate); + ImGui::Text(" - period: %d",ch->dac.period); + ImGui::Text(" - pos: %d",ch->dac.pos); + ImGui::Text(" - out: %d",ch->dac.out); + ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum); + ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC"); + break; + } + case DIV_SYSTEM_AY8930: { + DivPlatformAY8930::Channel* ch=(DivPlatformAY8930::Channel*)data; + ImGui::Text("> AY8930"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- duty: %d",ch->duty); + ImGui::Text("* envelope:"); + ImGui::Text(" - mode: %d",ch->envelope.mode); + ImGui::Text(" - period: %d",ch->envelope.period); + ImGui::Text(" * slide: %d",ch->envelope.slide); + ImGui::Text(" - low: %d",ch->envelope.slideLow); + ImGui::Text("* psgMode:"); + ImGui::Text(" - tone: %d",ch->psgMode.tone); + ImGui::Text(" - noise: %d",ch->psgMode.noise); + ImGui::Text(" - envelope: %d",ch->psgMode.envelope); + ImGui::Text(" - dac: %d",ch->psgMode.dac); + ImGui::Text("* DAC:"); + ImGui::Text(" - sample: %d",ch->dac.sample); + ImGui::Text(" - rate: %d",ch->dac.rate); + ImGui::Text(" - period: %d",ch->dac.period); + ImGui::Text(" - pos: %d",ch->dac.pos); + ImGui::Text(" - out: %d",ch->dac.out); + ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum); + ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC"); + break; + } + case DIV_SYSTEM_QSOUND: { + DivPlatformQSound::Channel* ch=(DivPlatformQSound::Channel*)data; + ImGui::Text("> QSound"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- sample: %d",ch->sample); + ImGui::Text("- echo: %d",ch->echo); + ImGui::Text("- panning: %d",ch->panning); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- resVol: %.2x",ch->resVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave"); + ImGui::TextColored(ch->surround?colorOn:colorOff,">> Surround"); + ImGui::TextColored(ch->isNewQSound?colorOn:colorOff,">> IsNewQSound"); break; } case DIV_SYSTEM_X1_010: { @@ -241,6 +386,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %.4x",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- wave: %d",ch->wave); ImGui::Text("- sample: %d",ch->sample); @@ -254,6 +400,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - autoEnvNum: %.2x",ch->autoEnvNum); ImGui::Text(" - autoEnvDen: %.2x",ch->autoEnvDen); ImGui::Text("- WaveBank: %d",ch->waveBank); + ImGui::Text("- bankSlot: %d",ch->bankSlot); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- outVol: %.2x",ch->outVol); ImGui::Text("- Lvol: %.2x",ch->lvol); @@ -282,6 +429,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %.4x",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- wave: %d",ch->wave); ImGui::Text("- wavepos: %d",ch->wavePos); @@ -312,6 +460,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("* DAC:"); ImGui::Text(" - period: %d",ch->dacPeriod); @@ -333,6 +482,71 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); break; } + case DIV_SYSTEM_LYNX: { + DivPlatformLynx::Channel* ch=(DivPlatformLynx::Channel*)data; + ImGui::Text("> Lynx"); + ImGui::Text("* freq:"); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("* FreqDiv:"); + ImGui::Text(" - clockDivider: %d",ch->fd.clockDivider); + ImGui::Text(" - backup: %d",ch->fd.backup); + ImGui::Text("* note: %d",ch->note); + ImGui::Text(" - actualNote: %d",ch->actualNote); + ImGui::Text("* Sample:"); + ImGui::Text(" - sample: %d",ch->sample); + ImGui::Text(" - pos: %d",ch->samplePos); + ImGui::Text(" - accum: %d",ch->sampleAccum); + ImGui::Text(" * freq: %d",ch->sampleFreq); + ImGui::Text(" - base: %d",ch->sampleBaseFreq); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("* duty:"); + ImGui::Text(" - int_feedback7: %d",ch->duty.int_feedback7); + ImGui::Text(" - feedback: %d",ch->duty.feedback); + ImGui::Text("- pan: %.2x",ch->pan); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->pcm?colorOn:colorOff,">> DAC"); + break; + } + case DIV_SYSTEM_PCM_DAC: { + DivPlatformPCMDAC::Channel* ch=(DivPlatformPCMDAC::Channel*)data; + ImGui::Text("> PCM DAC"); + ImGui::Text("* freq:"); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("* note: %d",ch->note); + ImGui::Text("* Sample: %d",ch->sample); + ImGui::Text(" - dir: %d",ch->audDir); + ImGui::Text(" - loc: %d",ch->audLoc); + ImGui::Text(" - len: %d",ch->audLen); + ImGui::Text(" * pos: %d",ch->audPos); + ImGui::Text(" - sub: %d",ch->audSub); + ImGui::Text("- wave: %d",ch->wave); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- panL: %.2x",ch->panL); + ImGui::Text("- panR: %.2x",ch->panR); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- envVol: %.2x",ch->envVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave"); + ImGui::TextColored(ch->setPos?colorOn:colorOff,">> SetPos"); + break; + } default: ImGui::Text("Unimplemented chip! Help!"); break; diff --git a/src/gui/gui.h b/src/gui/gui.h index 0ce4afaee..de72c01ce 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -155,6 +155,14 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, GUI_COLOR_INSTR_OPL_DRUMS, + GUI_COLOR_INSTR_MSM6258, + GUI_COLOR_INSTR_MSM6295, + GUI_COLOR_INSTR_ADPCMA, + GUI_COLOR_INSTR_ADPCMB, + GUI_COLOR_INSTR_SEGAPCM, + GUI_COLOR_INSTR_QSOUND, + GUI_COLOR_INSTR_YMZ280B, + GUI_COLOR_INSTR_RF5C68, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_FM, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index da86ce86a..1be7f9519 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -84,7 +84,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "FM (4-operator)", "Game Boy", "C64", - "Sample", + "Generic Sample", "PC Engine", "AY-3-8910/SSG", "AY8930", @@ -113,6 +113,14 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", + "MSM6258", + "MSM6295", + "ADPCM-A", + "ADPCM-B", + "SegaPCM", + "QSound", + "YMZ280B", + "RF5C68", NULL }; @@ -768,6 +776,14 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)), D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), + D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 55094252f..23ff2261a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -250,6 +250,10 @@ const char* suControlBits[5]={ "ring mod", "low pass", "high pass", "band pass", NULL }; +const char* es5506FilterModes[4]={ + "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", +}; + const char* panBits[3]={ "right", "left", NULL }; @@ -258,6 +262,14 @@ const char* oneBit[2]={ "on", NULL }; +const char* es5506EnvelopeModes[3]={ + "k1 slowdown", "k2 slowdown", NULL +}; + +const char* es5506ControlModes[2]={ + "pause", NULL +}; + const int orderedOps[4]={ 0, 2, 1, 3 }; @@ -314,6 +326,27 @@ String macroHoverLoop(int id, float val) { return ""; } +String macroHoverES5506FilterMode(int id, float val) { + String mode="???"; + switch (((int)val)&3) { + case 0: + mode="HP/K2, HP/K2"; + break; + case 1: + mode="HP/K2, LP/K1"; + break; + case 2: + mode="LP/K2, LP/K2"; + break; + case 3: + mode="LP/K2, LP/K1"; + break; + default: + break; + } + return fmt::sprintf("%d: %s",id,mode); +} + String macroLFOWaves(int id, float val) { switch (((int)val)&3) { case 0: @@ -3174,9 +3207,9 @@ void FurnaceGUI::drawInsEdit() { } } - ImGui::EndChild(); - ImGui::EndDisabled(); } + ImGui::EndChild(); + ImGui::EndDisabled(); ImGui::EndTabItem(); } if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) { @@ -3296,97 +3329,133 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest)); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SU) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { - String sName; - if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { - sName="none selected"; - } else { - sName=e->song.sample[ins->amiga.initSample]->name; - } - if (ins->type==DIV_INS_SU) { - P(ImGui::Checkbox("Use sample",&ins->su.useSample)); - P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles)); - } - if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { - String id; - for (int i=0; isong.sampleLen; i++) { - id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER - ins->amiga.initSample=i; + if (ins->type==DIV_INS_PCE || + ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_MSM6295 || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB || + ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_QSOUND || + ins->type==DIV_INS_YMZ280B || + ins->type==DIV_INS_RF5C68 || + ins->type==DIV_INS_AMIGA || + ins->type==DIV_INS_MULTIPCM || + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_X1_010 || + ins->type==DIV_INS_SWAN || + ins->type==DIV_INS_AY || + ins->type==DIV_INS_AY8930 || + ins->type==DIV_INS_VRC6 || + ins->type==DIV_INS_SU || + ins->type==DIV_INS_SNES || + ins->type==DIV_INS_ES5506) { + if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { + String sName; + if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { + sName="none selected"; + } else { + sName=e->song.sample[ins->amiga.initSample]->name; + } + if (ins->type==DIV_INS_PCE || + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_X1_010 || + ins->type==DIV_INS_SWAN || + ins->type==DIV_INS_AY || + ins->type==DIV_INS_AY8930 || + ins->type==DIV_INS_VRC6 || + ins->type==DIV_INS_SU) { + P(ImGui::Checkbox("Use sample",&ins->amiga.useSample)); + if (ins->type==DIV_INS_SU) { + P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles)); + } + if (ins->type==DIV_INS_X1_010) { + if (ImGui::InputInt("Sample bank slot##BANKSLOT",&ins->x1_010.bankSlot,1,4)) { PARAMETER + if (ins->x1_010.bankSlot<0) ins->x1_010.bankSlot=0; + if (ins->x1_010.bankSlot>=7) ins->x1_010.bankSlot=7; + } } } - ImGui::EndCombo(); - } - if (ins->type==DIV_INS_AMIGA) { - P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); - if (ins->amiga.useWave) { - int len=ins->amiga.waveLen+1; - if (ImGui::InputInt("Width",&len,2,16)) { - if (len<2) len=2; - if (len>256) len=256; - ins->amiga.waveLen=(len&(~1))-1; - PARAMETER + if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { + String id; + for (int i=0; isong.sampleLen; i++) { + id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); + if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER + ins->amiga.initSample=i; + } + } + ImGui::EndCombo(); + } + if (ins->type==DIV_INS_AMIGA) { + P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); + if (ins->amiga.useWave) { + int len=ins->amiga.waveLen+1; + if (ImGui::InputInt("Width",&len,2,16)) { + if (len<2) len=2; + if (len>256) len=256; + ins->amiga.waveLen=(len&(~1))-1; + PARAMETER + } } } - } - ImGui::BeginDisabled(ins->amiga.useWave); - P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); - if (ins->amiga.useNoteMap) { - // TODO: frequency map? - if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); - //ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::BeginDisabled(ins->amiga.useWave); + P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); + if (ins->amiga.useNoteMap) { + // TODO: frequency map? + if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + //ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupScrollFreeze(0,1); + ImGui::TableSetupScrollFreeze(0,1); - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::Text("Sample"); - /*ImGui::TableNextColumn(); - ImGui::Text("Frequency");*/ - for (int i=0; i<120; i++) { - DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; - ImGui::TableNextRow(); - ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); - ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { - sName="-- empty --"; - sampleMap.map=-1; - } else { - sName=e->song.sample[sampleMap.map]->name; - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##SM",sName.c_str())) { - String id; - if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER - sampleMap.map=-1; - } - for (int j=0; jsong.sampleLen; j++) { - id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),sampleMap.map==j)) { PARAMETER - sampleMap.map=j; - if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); - } - } - ImGui::EndCombo(); - } + ImGui::Text("Sample"); /*ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER - if (sampleMap.freq<0) sampleMap.freq=0; - if (sampleMap.freq>262144) sampleMap.freq=262144; - }*/ - ImGui::PopID(); + ImGui::Text("Frequency");*/ + for (int i=0; i<120; i++) { + DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; + ImGui::TableNextRow(); + ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%s",noteNames[60+i]); + ImGui::TableNextColumn(); + if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { + sName="-- empty --"; + sampleMap.map=-1; + } else { + sName=e->song.sample[sampleMap.map]->name; + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##SM",sName.c_str())) { + String id; + if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER + sampleMap.map=-1; + } + for (int j=0; jsong.sampleLen; j++) { + id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); + if (ImGui::Selectable(id.c_str(),sampleMap.map==j)) { PARAMETER + sampleMap.map=j; + if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + } + } + ImGui::EndCombo(); + } + /*ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER + if (sampleMap.freq<0) sampleMap.freq=0; + if (sampleMap.freq>262144) sampleMap.freq=262144; + }*/ + ImGui::PopID(); + } + ImGui::EndTable(); } - ImGui::EndTable(); } + ImGui::EndDisabled(); + ImGui::EndTabItem(); } - ImGui::EndDisabled(); - ImGui::EndTabItem(); } if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem(settings.c163Name.c_str())) { if (ImGui::InputInt("Waveform##WAVE",&ins->n163.wave,1,10)) { PARAMETER @@ -3453,25 +3522,44 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTabItem(); } + if (ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("ES5506")) { + if (ImGui::BeginTable("ESParams",2,ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + // filter + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2",ImGuiDataType_U16,&ins->es5506.filter.k2,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + // envelope + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Envelope count",ImGuiDataType_U16,&ins->es5506.envelope.ecount,&_ZERO,&_FIVE_HUNDRED_ELEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Left Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.lVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Right Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.rVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k1Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k2Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("K1 Ramp Slowdown",&ins->es5506.envelope.k1Slow); + ImGui::TableNextColumn(); + ImGui::Checkbox("K2 Ramp Slowdown",&ins->es5506.envelope.k2Slow); + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_MULTIPCM) { if (ImGui::BeginTabItem("MultiPCM")) { - String sName; - if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { - sName="none selected"; - } else { - sName=e->song.sample[ins->amiga.initSample]->name; - } - if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { - String id; - for (int i=0; isong.sampleLen; i++) { - id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { - ins->amiga.initSample=i; - PARAMETER - } - } - ImGui::EndCombo(); - } ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); if (ImGui::BeginTable("MultiPCMADSRParams",7,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); @@ -3555,14 +3643,110 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } } + if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { + P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv)); + ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); + if (ins->snes.useEnv) { + if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("A"); + ImGui::TextUnformatted("A"); + ImGui::TableNextColumn(); + CENTER_TEXT("D"); + ImGui::TextUnformatted("D"); + ImGui::TableNextColumn(); + CENTER_TEXT("S"); + ImGui::TextUnformatted("S"); + ImGui::TableNextColumn(); + CENTER_TEXT("R"); + ImGui::TextUnformatted("R"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); + ImGui::TableNextColumn(); + drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + + ImGui::EndTable(); + } + } else { + if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("Gain Mode"); + ImGui::TextUnformatted("Gain Mode"); + ImGui::TableNextColumn(); + CENTER_TEXT("Gain"); + ImGui::TextUnformatted("Gain"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; + PARAMETER; + } + if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; + PARAMETER; + } + if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; + PARAMETER; + } + if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; + PARAMETER; + } + if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; + PARAMETER; + } + + ImGui::TableNextColumn(); + unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; + if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; + P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); + + ImGui::TableNextColumn(); + ImGui::Text("Envelope goes here..."); + + ImGui::EndTable(); + } + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_GB || (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || - ins->type==DIV_INS_X1_010 || + (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) || ins->type==DIV_INS_N163 || ins->type==DIV_INS_FDS || - ins->type==DIV_INS_SWAN || - ins->type==DIV_INS_PCE || + (ins->type==DIV_INS_SWAN && !ins->amiga.useSample) || + (ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_SCC || + ins->type==DIV_INS_SNES || ins->type==DIV_INS_NAMCO) { if (ImGui::BeginTabItem("Wavetable")) { if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) { @@ -3725,7 +3909,7 @@ void FurnaceGUI::drawInsEdit() { } } } - if ((ins->type==DIV_INS_PCE || ins->type==DIV_INS_AY8930)) { + if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_AY8930) { volMax=31; } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VERA || ins->type==DIV_INS_VRC6_SAW) { @@ -3734,7 +3918,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { volMax=64; } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { + 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) { volMax=127; } if (ins->type==DIV_INS_GB) { @@ -3750,6 +3934,24 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FDS) { volMax=32; } + if (ins->type==DIV_INS_ES5506) { + volMax=65535; + } + if (ins->type==DIV_INS_MSM6258) { + volMax=0; + } + if (ins->type==DIV_INS_MSM6295) { + volMax=8; + } + if (ins->type==DIV_INS_ADPCMA) { + volMax=31; + } + if (ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68) { + volMax=255; + } + if (ins->type==DIV_INS_QSOUND) { + volMax=16383; + } const char* dutyLabel="Duty/Noise"; int dutyMin=0; @@ -3766,33 +3968,33 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM) { dutyMax=32; } - if ((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)) { - dutyMax=31; + if (ins->type==DIV_INS_AY) { + dutyMax=ins->amiga.useSample?0:31; } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM) { dutyLabel="Noise Freq"; } if (ins->type==DIV_INS_MIKEY) { dutyLabel="Duty/Int"; - dutyMax=10; + dutyMax=ins->amiga.useSample?0:10; } if (ins->type==DIV_INS_BEEPER) { dutyLabel="Pulse Width"; dutyMax=255; } if (ins->type==DIV_INS_AY8930) { - dutyMax=255; + dutyMax=ins->amiga.useSample?0:255; } - if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC) { + if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { dutyMax=0; } - if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) { + if ((ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_NAMCO) { dutyLabel="Noise"; - dutyMax=1; + dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?0:1; } if (ins->type==DIV_INS_SWAN) { dutyLabel="Noise"; - dutyMax=8; + dutyMax=ins->amiga.useSample?0:8; } if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { dutyMax=0; @@ -3807,19 +4009,42 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_VRC6) { dutyLabel="Duty"; - dutyMax=7; + dutyMax=ins->amiga.useSample?0:7; } if (ins->type==DIV_INS_SU) { dutyMax=127; } + if (ins->type==DIV_INS_ES5506) { + dutyLabel="Filter Mode"; + dutyMax=3; + } + if (ins->type==DIV_INS_MSM6258) { + dutyLabel="Frequency Divider"; + dutyMax=2; + } + if (ins->type==DIV_INS_MSM6295) { + dutyLabel="Frequency Divider"; + dutyMax=1; + } + if (ins->type==DIV_INS_ADPCMA) { + dutyLabel="Global Volume"; + dutyMax=63; + } + if (ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68) { + dutyMax=0; + } + if (ins->type==DIV_INS_QSOUND) { + dutyLabel="Echo Level"; + dutyMax=32767; + } const char* waveLabel="Waveform"; - int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255; - bool bitMode=false; - if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) { - bitMode=true; + int waveMax=(ins->type==DIV_INS_VERA)?3:255; + bool waveBitMode=false; + if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_SAA1099) { + waveBitMode=true; } - if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6 || ins->type==DIV_INS_VRC6_SAW) waveMax=0; + if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW) waveMax=0; if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15; if (ins->type==DIV_INS_C64) waveMax=4; if (ins->type==DIV_INS_SAA1099) waveMax=2; @@ -3829,13 +4054,21 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SU) waveMax=7; if (ins->type==DIV_INS_PET) { waveMax=8; - bitMode=true; + waveBitMode=true; + } + if (ins->type==DIV_INS_VRC6) { + waveMax=ins->amiga.useSample?255:0; } if (ins->type==DIV_INS_OPLL) { waveLabel="Patch"; } + if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { + waveMax=ins->amiga.useSample?255:3; + waveBitMode=ins->amiga.useSample?false:true; + } + const char** waveNames=NULL; if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) waveNames=ayShapeBits; if (ins->type==DIV_INS_C64) waveNames=c64ShapeBits; @@ -3850,8 +4083,8 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_X1_010) { dutyMax=0; - ex1Max=7; - ex2Max=255; + ex1Max=ins->amiga.useSample?0:7; + ex2Max=ins->amiga.useSample?0:255; ex2Bit=false; } if (ins->type==DIV_INS_N163) { @@ -3866,7 +4099,18 @@ void FurnaceGUI::drawInsEdit() { ex1Max=16383; ex2Max=255; } + if (ins->type==DIV_INS_MSM6258) { + ex1Max=1; + } + if (ins->type==DIV_INS_QSOUND) { + ex1Max=16383; + ex2Max=2725; + } if (ins->type==DIV_INS_SAA1099) ex1Max=8; + if (ins->type==DIV_INS_ES5506) { + ex1Max=65535; + ex2Max=65535; + } int panMin=0; int panMax=0; @@ -3878,21 +4122,34 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || - ins->type==DIV_INS_VERA) { + ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_VERA || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB) { panMax=1; panSingle=true; } - if (ins->type==DIV_INS_AMIGA) { - panMax=127; - } - if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO) { + if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO || ins->type==DIV_INS_RF5C68) { panMax=15; } - if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { + if (ins->type==DIV_INS_SEGAPCM) { + panMax=127; + } + if (ins->type==DIV_INS_AMIGA) { + if (ins->std.panLMacro.mode) { + panMin=-16; + panMax=16; + } else { + panMin=0; + panMax=127; + } + } + if (ins->type==DIV_INS_QSOUND) { panMin=-16; panMax=16; + panSingleNoBit=true; } - if (ins->type==DIV_INS_MULTIPCM) { + if (ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_YMZ280B) { panMin=-7; panMax=7; panSingleNoBit=true; @@ -3902,6 +4159,9 @@ void FurnaceGUI::drawInsEdit() { panMax=127; panSingleNoBit=true; } + if (ins->type==DIV_INS_ES5506) { + panMax=65535; + } if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); @@ -3910,27 +4170,32 @@ 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_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,¯oHoverES5506FilterMode)); } else { macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER])); } } if (waveMax>0) { - macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); + macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(waveBitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,waveBitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); } if (panMax>0) { if (panSingle) { macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); + } else if (ins->type==DIV_INS_QSOUND) { + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); } } } @@ -3943,14 +4208,25 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_OPZ || ins->type==DIV_INS_PCE || ins->type==DIV_INS_GB || + ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_MSM6295 || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB || + ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_QSOUND || + ins->type==DIV_INS_YMZ280B || + ins->type==DIV_INS_RF5C68 || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SWAN || ins->type==DIV_INS_MULTIPCM || + (ins->type==DIV_INS_VRC6 && ins->amiga.useSample) || ins->type==DIV_INS_SU || - ins->type==DIV_INS_MIKEY) { + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_ES5506 || + (ins->type==DIV_INS_X1_010 && ins->amiga.useSample)) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ex1Max>0) { @@ -3958,7 +4234,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,filtModeBits)); } else if (ins->type==DIV_INS_SAA1099) { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,saaEnvBits)); - } else if (ins->type==DIV_INS_X1_010) { + } else if (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,x1_010EnvBits)); } else if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("Wave Length",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3966,6 +4242,12 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Mod Depth",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode==1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + } else if (ins->type==DIV_INS_MSM6258) { + macroList.push_back(FurnaceGUIMacroDesc("Clock Divider",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_QSOUND) { + macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -3979,6 +4261,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode==1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + } else if (ins->type==DIV_INS_QSOUND) { + macroList.push_back(FurnaceGUIMacroDesc("Echo Buffer Len",&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)); } @@ -3987,7 +4273,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64SpecialBits)); macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } - if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) { + if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample)) { macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Num",&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Den",&ins->std.algMacro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4009,6 +4295,15 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,suControlBits)); macroList.push_back(FurnaceGUIMacroDesc("Phase Reset Timer",&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); // again reuse code from resonance macro but use ex4 instead } + if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Envelope counter",&ins->std.ex3Macro,0,511,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope left volume ramp",&ins->std.ex4Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope right volume ramp",&ins->std.ex5Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope K1 ramp",&ins->std.ex6Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope K2 ramp",&ins->std.ex7Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes)); + } drawMacros(macroList); ImGui::EndTabItem(); diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index 8bee0f88c..9a41486e1 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -31,6 +31,9 @@ const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; const int _ONE_HUNDRED_TWENTY_SEVEN=127; const int _TWO_HUNDRED_FIFTY_FIVE=255; +const int _FIVE_HUNDRED_ELEVEN=511; const int _TWO_THOUSAND_FORTY_SEVEN=2047; const int _FOUR_THOUSAND_NINETY_FIVE=4095; +const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE=65535; const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN=-127; +const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT=-128; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index 98c6c34ff..ff11a4968 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -33,6 +33,9 @@ extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; extern const int _ONE_HUNDRED_TWENTY_SEVEN; extern const int _TWO_HUNDRED_FIFTY_FIVE; +extern const int _FIVE_HUNDRED_ELEVEN; extern const int _TWO_THOUSAND_FORTY_SEVEN; extern const int _FOUR_THOUSAND_NINETY_FIVE; +extern const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE; extern const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN; +extern const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 37d4bfecf..1347c6969 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1485,7 +1485,7 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Sample"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Generic Sample"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_PCE,"PC Engine"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY,"AY-3-8910/SSG"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY8930,"AY8930"); @@ -1517,6 +1517,15 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_NAMCO,"Namco WSG"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL_DRUMS,"FM (OPL Drums)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6258,"MSM6258"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6295,"MSM6295"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMA,"ADPCM-A"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMB,"ADPCM-B"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SEGAPCM,"Sega PCM"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_QSOUND,"QSound"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_YMZ280B,"YMZ280B"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_RF5C68,"RF5C68"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); ImGui::TreePop(); } From 22211a4ef0e72c1cf2773d7bfe04028b42caf387 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 17:28:08 +0900 Subject: [PATCH 306/515] Fix loop --- src/engine/engine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index fb37f4238..cee47e41a 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2764,6 +2764,7 @@ DivSample* DivEngine::sampleFromFile(const char* path) { sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) { + sample->loop=true; sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD); sample->loopStart=inst.loops[0].start; sample->loopEnd=inst.loops[0].end; From c44f03b1a3d4c348bfab1bcb4c4f19265bdf6535 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:11:34 +0900 Subject: [PATCH 307/515] Sync with master --- src/engine/fileOps.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 488878203..dac3c5d18 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2644,10 +2644,6 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (sample[i].len>0) { s->init(sample[i].len*2); } - s->loopStart=sample[i].loopStart*2; - s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; - s->loop=(s->loopStart>=0)&&(s->loopEnd>=0); - reader.read(s->data8,sample[i].len); s->name=fmt::sprintf("Sample %d",i+1); if (sample[i].loopLen>1) { s->loopStart=sample[i].loopStart; From 8f804f6e6b37f2132214789abfed457d3a2f2a67 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:20:33 +0900 Subject: [PATCH 308/515] Correct pitch to sample preview --- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5cb5574b2..de5dd6e78 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -381,7 +381,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { } chan[c.chan].dac.pos=0; chan[c.chan].dac.period=0; - chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate*2048; if (dumpWrites) { rWrite(0x08+c.chan,0); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 5ab9c3489..2dd4ca8de 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -400,7 +400,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } chan[c.chan].dac.pos=0; chan[c.chan].dac.period=0; - chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate*4096; if (dumpWrites) { rWrite(0x08+c.chan,0); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); From 570036ad6ffb9ed9e3b7a12bf77da41c50355942 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:22:36 +0900 Subject: [PATCH 309/515] CONTRIBUTING --- src/engine/platform/ym2610shared.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 7fc445d35..2fee30c7d 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -44,8 +44,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface { sampleBank(0) {} }; -template -class DivPlatformYM2610Base: public DivPlatformOPN { +template class DivPlatformYM2610Base: public DivPlatformOPN { protected: struct Channel { DivInstrumentFM state; From 80c9b0c3f492b0ee8a732db43202f59fe24d325a Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:26:56 +0900 Subject: [PATCH 310/515] Fix compile --- src/engine/vgmOps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 51948f27f..78639cca1 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1559,7 +1559,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p sample->offSegaPCM=memPos; unsigned int readPos=0; for (unsigned int j=0; j=sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { if (sample->isLoopable()) { readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); From 745837c41d51b65aac579488f4f8952e8d50100b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:40:16 +0900 Subject: [PATCH 311/515] Fix compile (2) --- src/engine/platform/ym2610.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index dc5d67b73..143ecb188 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -242,7 +242,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l ymfm::ssg_engine::output_data ssgOut; - ymfm::fm_channel>* fmChan[6]; + ymfm::fm_channel>* fmChan[4]; ymfm::adpcm_a_channel* adpcmAChan[6]; for (int i=0; i<4; i++) { fmChan[i]=fme->debug_channel(bchOffs[i]); From 5d3cecfea6dd1d173173ce98301cb0fd29e327c7 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:58:49 +0900 Subject: [PATCH 312/515] Fix switch case --- src/engine/platform/pcmdac.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 4ce53925f..57f5c0026 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -66,6 +66,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos); chan.audDir=true; } + break; default: if (chan.audPos<0) { chan.sample=-1; @@ -90,6 +91,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos); chan.audDir=true; } + break; default: if (chan.audPos>=s->getEndPosition()) { chan.sample=-1; From f73d1bd82c600fe8a7bbf2c09bfcfeeab123a78b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 28 Aug 2022 01:04:27 +0900 Subject: [PATCH 313/515] Add ADPCM-B instrument support for Y8950 w/drums --- src/engine/sysDef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 241890839..04a598906 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1421,7 +1421,7 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, fmEffectHandlerMap, fmOPLPostEffectHandlerMap From 58853ce5d54b0929fd7f7230ff4489784de37319 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 27 Aug 2022 16:12:00 -0500 Subject: [PATCH 314/515] OPNB-B -> OPNB2 --- src/engine/sysDef.cpp | 4 ++-- src/gui/presets.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 6dc3a8a4e..abfdc3dc1 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1137,7 +1137,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_YM2610B]=new DivSysDef( - "Yamaha YM2610B (OPNB-B)", NULL, 0x9e, 0, 16, true, false, 0x151, false, + "Yamaha YM2610B (OPNB2)", NULL, 0x9e, 0, 16, true, false, 0x151, false, "so Taito asked Yamaha if they could get the two missing FM channels back, and Yamaha gladly provided them with this chip.", {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, @@ -1311,7 +1311,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_YM2610B_EXT]=new DivSysDef( - "Yamaha YM2610B (OPNB-B) Extended Channel 3", NULL, 0xde, 0, 19, true, false, 0x151, false, + "Yamaha YM2610B (OPNB2) Extended Channel 3", NULL, 0xde, 0, 19, true, false, 0x151, false, "so Taito asked Yamaha if they could get the two missing FM channels back, and Yamaha gladly provided them with this chip.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.", {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 04049bdfc..1bd637a23 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -79,7 +79,7 @@ void FurnaceGUI::initSystemPresets() { } )); cat.systems.push_back(FurnaceGUISysDef( - "Yamaha YM2610B (OPNB-B)", { + "Yamaha YM2610B (OPNB2)", { DIV_SYSTEM_YM2610B, 64, 0, 0, 0 } From a411e34a62e6d7b6cd3bf801240f3faad74e63d5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 28 Aug 2022 09:59:56 +0900 Subject: [PATCH 315/515] Performance adjusts --- src/engine/instrument.h | 18 ++++++++++-------- src/engine/platform/amiga.cpp | 4 ++-- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- src/engine/platform/mmc5.cpp | 2 +- src/engine/platform/nes.cpp | 2 +- src/engine/platform/pce.cpp | 2 +- src/engine/platform/pcmdac.cpp | 2 +- src/engine/platform/segapcm.cpp | 2 +- src/engine/platform/swan.cpp | 2 +- src/engine/platform/vera.cpp | 2 +- src/engine/platform/vrc6.cpp | 2 +- src/engine/platform/zxbeeper.cpp | 4 ++-- 13 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 68cd0b3cc..e95ef0b66 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,14 +60,16 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, - DIV_INS_MSM6258=33, - DIV_INS_MSM6295=34, - DIV_INS_ADPCMA=35, - DIV_INS_ADPCMB=36, - DIV_INS_SEGAPCM=37, - DIV_INS_QSOUND=38, - DIV_INS_YMZ280B=39, - DIV_INS_RF5C68=40, + //33 + //34 + DIV_INS_MSM6258=35, + DIV_INS_MSM6295=36, + DIV_INS_ADPCMA=37, + DIV_INS_ADPCMB=38, + DIV_INS_SEGAPCM=39, + DIV_INS_QSOUND=40, + DIV_INS_YMZ280B=41, + DIV_INS_RF5C68=42, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 764c4332c..d229998e2 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -95,8 +95,8 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } } else { DivSample* s=parent->getSample(chan[i].sample); - if (s->getEndPosition()>0) { - if (chan[i].audPos<(unsigned int)s->getEndPosition()) { + if (s->samples>0) { + if (chan[i].audPossamples) { writeAudDat(s->data8[chan[i].audPos++]); } if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index de5dd6e78..b7871b680 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -90,7 +90,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l int prev_out = chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 2dd4ca8de..2943ac177 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -94,7 +94,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l int prev_out = chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 3b9f9b58e..de997a025 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -49,7 +49,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; if (dacPeriod>=rate) { DivSample* s=parent->getSample(dacSample); - if (s->getEndPosition()>0) { + if (s->samples>0) { if (!isMuted[2]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 7827cbac1..fbb7fa3a8 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -76,7 +76,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { dacPeriod+=dacRate; \ if (dacPeriod>=rate) { \ DivSample* s=parent->getSample(dacSample); \ - if (s->getEndPosition()>0) { \ + if (s->samples>0) { \ if (!isMuted[4]) { \ unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \ if (dacAntiClickOn && dacAntiClickrate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dacSample=-1; continue; } diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 57f5c0026..8f1440878 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -50,7 +50,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l output=(chan.ws.output[chan.audPos]^0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); - if (s->getEndPosition()>0) { + if (s->samples>0) { if (chan.audDir) { if (s->isLoopable()) { switch (s->loopMode) { diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 2ff7552d2..93481d94f 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -36,7 +36,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t for (int i=0; i<16; i++) { if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].pcm.sample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].pcm.sample=-1; oscBuf[i]->data[oscBuf[i]->needle++]=0; continue; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 0d264f714..e6242c795 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -57,7 +57,7 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; while (dacPeriod>rate) { DivSample* s=parent->getSample(dacSample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { dacSample=-1; continue; } diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 9d22a854d..22be5e984 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -58,7 +58,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len size_t pos=start; DivSample* s=parent->getSample(chan[16].pcm.sample); while (len>0) { - if (s->getEndPosition()>0) { + if (s->samples>0) { while (pcm_is_fifo_almost_empty(pcm)) { short tmp_l=0; short tmp_r=0; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 2f670bf26..134905479 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -54,7 +54,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>rate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dacSample=-1; chWrite(i,0,0); continue; diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 2869c38aa..5fa3840bb 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -34,9 +34,9 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t if (curSample>=0 && curSamplesong.sampleLen) { if (--curSamplePeriod<0) { DivSample* s=parent->getSample(curSample); - if (s->getEndPosition()>0) { + if (s->samples>0) { sampleOut=(s->data8[curSamplePos++]>0); - if (curSamplePos>=(unsigned int)s->getEndPosition()) curSample=-1; + if (curSamplePos>=s->samples) curSample=-1; // 256 bits if (curSamplePos>2047) curSample=-1; From 3fcccb52ee8bae20864bc08dd3c658f0b1eb7643 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 28 Aug 2022 10:50:57 +0900 Subject: [PATCH 316/515] Reduce performance issue --- src/engine/platform/amiga.cpp | 6 ++--- src/engine/platform/ay.cpp | 6 ++--- src/engine/platform/ay8930.cpp | 6 ++--- src/engine/platform/genesis.cpp | 12 +++++----- src/engine/platform/lynx.cpp | 6 ++--- src/engine/platform/mmc5.cpp | 6 ++--- src/engine/platform/nes.cpp | 6 ++--- src/engine/platform/pce.cpp | 6 ++--- src/engine/platform/pcmdac.cpp | 24 +++++++++---------- src/engine/platform/qsound.cpp | 4 ++-- src/engine/platform/rf5c68.cpp | 2 +- src/engine/platform/segapcm.cpp | 6 ++--- src/engine/platform/su.cpp | 2 +- src/engine/platform/swan.cpp | 6 ++--- src/engine/platform/vera.cpp | 6 ++--- src/engine/platform/vrc6.cpp | 6 ++--- src/engine/playback.cpp | 42 ++++++++++++++++----------------- 17 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index d229998e2..7a49fccfa 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -99,9 +99,9 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le if (chan[i].audPossamples) { writeAudDat(s->data8[chan[i].audPos++]); } - if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) { - chan[i].audPos=s->getLoopStartPosition(); - } else if (chan[i].audPos>=MIN(131071,(unsigned int)s->getEndPosition())) { + if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->loopEnd)) { + chan[i].audPos=s->loopStart; + } else if (chan[i].audPos>=MIN(131071,s->samples)) { chan[i].sample=-1; } } else { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index b7871b680..0b275cb5d 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -104,9 +104,9 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l changed=true; } chan[i].dac.pos++; - if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { - chan[i].dac.pos=s->getLoopStartPosition(); - } else if (chan[i].dac.pos>=s->getEndPosition()) { + if (s->isLoopable() && chan[i].dac.pos>=s->loopEnd) { + chan[i].dac.pos=s->loopStart; + } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 2943ac177..8714f2308 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -108,9 +108,9 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l changed=true; } chan[i].dac.pos++; - if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { - chan[i].dac.pos=s->getLoopStartPosition(); - } else if (chan[i].dac.pos>=s->getEndPosition()) { + if (s->isLoopable() && chan[i].dac.pos>=s->loopEnd) { + chan[i].dac.pos=s->loopStart; + } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index e9e90c4bd..6ae10d0ce 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -52,9 +52,9 @@ void DivPlatformGenesis::processDAC() { if (s->samples>0) { while (chan[i].dacPeriod>=(chipClock/576)) { ++chan[i].dacPos; - if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition())) { - chan[i].dacPos=s->getLoopStartPosition(); - } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { + if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd)) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; chan[i].dacPeriod=0; break; @@ -98,9 +98,9 @@ void DivPlatformGenesis::processDAC() { } } chan[5].dacPos++; - if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->getLoopEndPosition())) { - chan[5].dacPos=s->getLoopStartPosition(); - } else if (chan[5].dacPos>=(unsigned int)s->getEndPosition()) { + if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) { + chan[5].dacPos=s->loopStart; + } else if (chan[5].dacPos>=s->samples) { chan[5].dacSample=-1; if (parent->song.brokenDACMode) { rWrite(0x2b,0); diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 6e9995bea..c67f35234 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -146,9 +146,9 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127)); } - if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) { - chan[i].samplePos=s->getLoopStartPosition(); - } else if (chan[i].samplePos>=s->getEndPosition()) { + if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) { + chan[i].samplePos=s->loopStart; + } else if (chan[i].samplePos>=(int)s->samples) { chan[i].sample=-1; } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index de997a025..7d271046e 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -54,9 +54,9 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } dacPos++; - if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { - dacPos=s->getLoopStartPosition(); - } else if (dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { + dacPos=s->loopStart; + } else if (dacPos>=s->samples) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index fbb7fa3a8..c4376b126 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -88,9 +88,9 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { } \ } \ dacPos++; \ - if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { \ - dacPos=s->getLoopStartPosition(); \ - } else if (dacPos>=(unsigned int)s->getEndPosition()) { \ + if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { \ + dacPos=s->loopStart; \ + } else if (dacPos>=s->samples) { \ dacSample=-1; \ } \ dacPeriod-=rate; \ diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index d9d339e4b..ea6f0e56e 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -76,9 +76,9 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x06,0x10); } chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { - chan[i].dacPos=s->getLoopStartPosition(); - } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; } chan[i].dacPeriod-=rate; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 8f1440878..f7db0ef4c 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -56,14 +56,14 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l switch (s->loopMode) { case DIV_SAMPLE_LOOP_FORWARD: case DIV_SAMPLE_LOOP_PINGPONG: - if (chan.audPosgetLoopStartPosition()) { - chan.audPos=s->getLoopStartPosition()+(s->getLoopStartPosition()-chan.audPos); + if (chan.audPosloopStart) { + chan.audPos=s->loopStart+(s->loopStart-chan.audPos); chan.audDir=false; } break; case DIV_SAMPLE_LOOP_BACKWARD: - if (chan.audPosgetLoopStartPosition()) { - chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos); + if (chan.audPosloopStart) { + chan.audPos=s->loopEnd-1-(s->loopStart-chan.audPos); chan.audDir=true; } break; @@ -73,36 +73,36 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l } break; } - } else if (chan.audPos>=s->getEndPosition()) { + } else if (chan.audPos>=(int)s->samples) { chan.sample=-1; } } else { if (s->isLoopable()) { switch (s->loopMode) { case DIV_SAMPLE_LOOP_FORWARD: - if (chan.audPos>=s->getLoopEndPosition()) { - chan.audPos=(chan.audPos+s->getLoopStartPosition())-s->getLoopEndPosition(); + if (chan.audPos>=s->loopEnd) { + chan.audPos=(chan.audPos+s->loopStart)-s->loopEnd; chan.audDir=false; } break; case DIV_SAMPLE_LOOP_BACKWARD: case DIV_SAMPLE_LOOP_PINGPONG: - if (chan.audPos>=s->getLoopEndPosition()) { - chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos); + if (chan.audPos>=s->loopEnd) { + chan.audPos=s->loopEnd-1-(s->loopEnd-1-chan.audPos); chan.audDir=true; } break; default: - if (chan.audPos>=s->getEndPosition()) { + if (chan.audPos>=(int)s->samples) { chan.sample=-1; } break; } - } else if (chan.audPos>=s->getEndPosition()) { + } else if (chan.audPos>=(int)s->samples) { chan.sample=-1; } } - if (chan.audPos>=0 && chan.audPosgetEndPosition()) { + if (chan.audPos>=0 && chan.audPos<(int)s->samples) { output=s->data16[chan.audPos]; } } else { diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 63985c801..18216f03f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -289,8 +289,8 @@ void DivPlatformQSound::tick(bool sysTick) { qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_addr = s->offQSound & 0xffff; - int loopStart=s->getLoopStartPosition(); - int length = s->getLoopEndPosition(); + int loopStart=s->loopStart; + int length = s->loopEnd; if (length > 65536 - 16) { length = 65536 - 16; } diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 9a0510b05..86d373722 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -136,7 +136,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { start=start+MIN(chan[i].audPos,s->length8); } if (s->isLoopable()) { - loop=start+s->getLoopStartPosition(); + loop=start+s->loopStart; } start=MIN(start,getSampleMemCapacity()-31); loop=MIN(loop,getSampleMemCapacity()-31); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 93481d94f..69e996b8b 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -47,9 +47,9 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); } chan[i].pcm.pos+=chan[i].pcm.freq; - if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->getLoopEndPosition()<<8)) { - chan[i].pcm.pos=s->getLoopStartPosition()<<8; - } else if (chan[i].pcm.pos>=((unsigned int)s->getEndPosition()<<8)) { + if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->loopEnd<<8)) { + chan[i].pcm.pos=s->loopStart<<8; + } else if (chan[i].pcm.pos>=(s->samples<<8)) { chan[i].pcm.sample=-1; } } else { diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index b314ecde6..9a2c4f569 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -552,7 +552,7 @@ void DivPlatformSoundUnit::renderSamples() { for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; if (s->data8==NULL) continue; - int paddedLen=s->getEndPosition(); + int paddedLen=s->length8; if (memPos>=getSampleMemCapacity(0)) { logW("out of PCM memory for sample %d!",i); break; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index e6242c795..6d2954530 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -62,9 +62,9 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len continue; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { - dacPos=s->getLoopStartPosition(); - } else if (dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { + dacPos=s->loopStart; + } else if (dacPos>=s->samples) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 22be5e984..c586cc9fc 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -84,9 +84,9 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len rWritePCMData(tmp_r&0xff); } chan[16].pcm.pos++; - if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->getLoopEndPosition()) { - chan[16].pcm.pos=s->getLoopStartPosition(); - } else if (chan[16].pcm.pos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->loopEnd) { + chan[16].pcm.pos=s->loopStart; + } else if (chan[16].pcm.pos>=s->samples) { chan[16].pcm.sample=-1; break; } diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 134905479..e8cfb99d0 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -65,9 +65,9 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chWrite(i,0,0x80|chan[i].dacOut); } chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { - chan[i].dacPos=s->getLoopStartPosition(); - } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; chWrite(i,0,0); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 9017c40bb..10f544d78 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1334,19 +1334,19 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi samp_prevSample=samp_temp; if (sPreview.dir) { // backward - if (sPreview.posgetLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.posisLoopable() && sPreview.posgetLoopEndPosition()) { + if (sPreview.posloopStart || (sPreview.pBegin>=0 && sPreview.posisLoopable() && sPreview.posloopEnd) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; default: @@ -1355,19 +1355,19 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } else { // forward - if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + if (sPreview.pos>=s->loopEnd || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->loopStart) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; default: @@ -1378,19 +1378,19 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } if (sPreview.dir) { // backward - if (sPreview.pos<=s->getLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) { - if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + if (sPreview.pos<=s->loopStart || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) { + if (s->isLoopable() && sPreview.pos>=s->loopStart) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; default: @@ -1401,25 +1401,25 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } else { // forward - if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + if (sPreview.pos>=s->loopEnd || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->loopStart) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; default: break; } - } else if (sPreview.pos>=s->getEndPosition()) { + } else if (sPreview.pos>=(int)s->samples) { sPreview.sample=-1; } } From 1d5390c0e9b3e984680c9b591e83a2c8c2e11235 Mon Sep 17 00:00:00 2001 From: Lunathir <18320914+lunathir@users.noreply.github.com> Date: Sat, 27 Aug 2022 22:53:47 -0700 Subject: [PATCH 317/515] More in-program text corrections --- src/engine/sysDef.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index abfdc3dc1..1c63431f9 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -957,7 +957,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_OPN_EXT]=new DivSysDef( "Yamaha YM2203 (OPN) Extended Channel 3", NULL, 0xb6, 0, 9, true, true, 0x151, false, - "cost-reduced version of the OPM with a different register layout and no stereo...\n...but it has a built-in AY-3-8910! (actually an YM2149)\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies", + "cost-reduced version of the OPM with a different register layout and no stereo...\n...but it has a built-in AY-3-8910! (actually an YM2149)\nthis one is in Extended Channel mode, which turns the third FM channel into four operators with independent notes/frequencies", {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "PSG 1", "PSG 2", "PSG 3"}, {"F1", "F2", "O1", "O2", "O3", "O4", "S1", "S2", "S3"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, @@ -981,7 +981,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef( "Yamaha YM2608 (OPNA) Extended Channel 3", NULL, 0xb7, 0, 19, true, true, 0x151, false, - "OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies", + "OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.\nthis one is in Extended Channel mode, which turns the third FM channel into four operators with independent notes/frequencies", {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, @@ -1164,7 +1164,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_YM2612_EXT]=new DivSysDef( "Yamaha YM2612 (OPN2) Extended Channel 3", NULL, 0xa0, 0, 9, true, false, 0x150, false, - "this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.", + "this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis one is in Extended Channel mode, which turns the third FM channel into four operators with independent notes/frequencies.", {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, @@ -1312,7 +1312,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_YM2610B_EXT]=new DivSysDef( "Yamaha YM2610B (OPNB2) Extended Channel 3", NULL, 0xde, 0, 19, true, false, 0x151, false, - "so Taito asked Yamaha if they could get the two missing FM channels back, and Yamaha gladly provided them with this chip.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.", + "so Taito asked Yamaha if they could get the two missing FM channels back, and Yamaha gladly provided them with this chip.\nthis one is in Extended Channel mode, which turns the third FM channel into four operators with independent notes/frequencies.", {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, @@ -1566,7 +1566,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_YM2612_FRAC_EXT]=new DivSysDef( "Yamaha YM2612 (OPN2) Extended Channel 3 with DualPCM and CSM", NULL, 0xbd, 0, 11, true, false, 0, false, - "this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis system uses software mixing to provide two sample channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.", + "this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis system uses software mixing to provide two sample channels.\nthis one is in Extended Channel mode, which turns the third FM channel into four operators with independent notes/frequencies.", {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6/PCM 1", "PCM 2", "CSM Timer"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "P1", "P2", "CSM"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE}, From 3e8f248f778591847e67af3d6a31de360ee04044 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Aug 2022 01:03:23 -0500 Subject: [PATCH 318/515] fix saving a pre-24 .dmf song --- src/gui/gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5cb4d520b..86c063e9b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1593,6 +1593,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { int FurnaceGUI::save(String path, int dmfVersion) { SafeWriter* w; if (dmfVersion) { + if (dmfVersion<24) dmfVersion=24; w=e->saveDMF(dmfVersion); } else { w=e->saveFur(); From 82703a165f4bdcf2ad2b8c062fb827d59fe84590 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Aug 2022 01:12:57 -0500 Subject: [PATCH 319/515] fix non-STD instruments in C64/GB/PCE converting to the wrong type --- src/engine/fileOps.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index fe220aae8..a5ce1d095 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -4155,7 +4155,25 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { // safety check if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_FDS) { - i->type=DIV_INS_STD; + switch (song.system[0]) { + case DIV_SYSTEM_GB: + i->type=DIV_INS_GB; + break; + case DIV_SYSTEM_C64_6581: + case DIV_SYSTEM_C64_8580: + i->type=DIV_INS_C64; + break; + case DIV_SYSTEM_PCE: + i->type=DIV_INS_PCE; + break; + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_EXT: + i->type=DIV_INS_AY; + break; + default: + i->type=DIV_INS_STD; + break; + } } if (!isSTDSystem(sys) && i->type!=DIV_INS_FM) { i->type=DIV_INS_FM; From 645dcdf9a04dd5053606ac3acb48c30345e84328 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Aug 2022 02:57:40 -0500 Subject: [PATCH 320/515] fix .dmf and arp macros --- src/engine/fileOps.cpp | 55 ++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index a5ce1d095..0e0ceb8bd 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -4214,56 +4214,79 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } } else { // STD if (sys!=DIV_SYSTEM_GB) { - w->writeC(i->std.volMacro.len); + int realVolMacroLen=i->std.volMacro.len; + if (realVolMacroLen>127) realVolMacroLen=127; + w->writeC(realVolMacroLen); if ((sys==DIV_SYSTEM_C64_6581 || sys==DIV_SYSTEM_C64_8580) && i->c64.volIsCutoff) { - for (int j=0; jstd.volMacro.len; j++) { + for (int j=0; jwriteI(i->std.volMacro.val[j]+18); } } else { - for (int j=0; jstd.volMacro.len; j++) { + for (int j=0; jwriteI(i->std.volMacro.val[j]); } } - if (i->std.volMacro.len>0) { + if (realVolMacroLen>0) { w->writeC(i->std.volMacro.loop); } } // TODO: take care of new arp macro format w->writeC(i->std.arpMacro.len); - if (i->std.arpMacro.mode) { - for (int j=0; jstd.arpMacro.len; j++) { + bool arpMacroMode=false; + int arpMacroHowManyFixed=0; + int realArpMacroLen=i->std.arpMacro.len; + for (int j=0; jstd.arpMacro.len; j++) { + if ((i->std.arpMacro.val[j]&0xc0000000)==0x40000000 || (i->std.arpMacro.val[j]&0xc0000000)==0x80000000) { + arpMacroHowManyFixed++; + } + } + if (arpMacroHowManyFixed>=i->std.arpMacro.len-1) { + arpMacroMode=true; + } + if (i->std.arpMacro.len>0) { + if (arpMacroMode && i->std.arpMacro.val[i->std.arpMacro.len-1]==0 && i->std.arpMacro.loop>=i->std.arpMacro.len) { + realArpMacroLen--; + } + } + + if (arpMacroMode) { + for (int j=0; jwriteI(i->std.arpMacro.val[j]); } } else { - for (int j=0; jstd.arpMacro.len; j++) { + for (int j=0; jwriteI(i->std.arpMacro.val[j]+12); } } - if (i->std.arpMacro.len>0) { + if (realArpMacroLen>0) { w->writeC(i->std.arpMacro.loop); } - w->writeC(i->std.arpMacro.mode); + w->writeC(arpMacroMode); - w->writeC(i->std.dutyMacro.len); + int realDutyMacroLen=i->std.dutyMacro.len; + if (realDutyMacroLen>127) realDutyMacroLen=127; + w->writeC(realDutyMacroLen); if (sys==DIV_SYSTEM_C64_6581 || sys==DIV_SYSTEM_C64_8580) { - for (int j=0; jstd.dutyMacro.len; j++) { + for (int j=0; jwriteI(i->std.dutyMacro.val[j]+12); } } else { - for (int j=0; jstd.dutyMacro.len; j++) { + for (int j=0; jwriteI(i->std.dutyMacro.val[j]); } } - if (i->std.dutyMacro.len>0) { + if (realDutyMacroLen>0) { w->writeC(i->std.dutyMacro.loop); } - w->writeC(i->std.waveMacro.len); - for (int j=0; jstd.waveMacro.len; j++) { + int realWaveMacroLen=i->std.waveMacro.len; + if (realWaveMacroLen>127) realWaveMacroLen=127; + w->writeC(realWaveMacroLen); + for (int j=0; jwriteI(i->std.waveMacro.val[j]); } - if (i->std.waveMacro.len>0) { + if (realWaveMacroLen>0) { w->writeC(i->std.waveMacro.loop); } From c3ced46fa3a3a4420a6a8f5d51ba3d1f2220d87a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Aug 2022 15:10:16 -0500 Subject: [PATCH 321/515] coming soon: reSIDfp core --- CMakeLists.txt | 18 + src/engine/platform/sound/c64_fp/AUTHORS | 6 + src/engine/platform/sound/c64_fp/COPYING | 339 ++++++++++++ src/engine/platform/sound/c64_fp/Dac.cpp | 123 +++++ src/engine/platform/sound/c64_fp/Dac.h | 111 ++++ .../sound/c64_fp/EnvelopeGenerator.cpp | 155 ++++++ .../platform/sound/c64_fp/EnvelopeGenerator.h | 419 +++++++++++++++ .../platform/sound/c64_fp/ExternalFilter.cpp | 68 +++ .../platform/sound/c64_fp/ExternalFilter.h | 125 +++++ src/engine/platform/sound/c64_fp/Filter.cpp | 90 ++++ src/engine/platform/sound/c64_fp/Filter.h | 177 ++++++ .../platform/sound/c64_fp/Filter6581.cpp | 75 +++ src/engine/platform/sound/c64_fp/Filter6581.h | 425 +++++++++++++++ .../platform/sound/c64_fp/Filter8580.cpp | 101 ++++ src/engine/platform/sound/c64_fp/Filter8580.h | 383 +++++++++++++ .../sound/c64_fp/FilterModelConfig.cpp | 79 +++ .../platform/sound/c64_fp/FilterModelConfig.h | 166 ++++++ .../sound/c64_fp/FilterModelConfig6581.cpp | 263 +++++++++ .../sound/c64_fp/FilterModelConfig6581.h | 112 ++++ .../sound/c64_fp/FilterModelConfig8580.cpp | 222 ++++++++ .../sound/c64_fp/FilterModelConfig8580.h | 68 +++ .../platform/sound/c64_fp/Integrator6581.cpp | 25 + .../platform/sound/c64_fp/Integrator6581.h | 285 ++++++++++ .../platform/sound/c64_fp/Integrator8580.cpp | 25 + .../platform/sound/c64_fp/Integrator8580.h | 142 +++++ src/engine/platform/sound/c64_fp/OpAmp.cpp | 84 +++ src/engine/platform/sound/c64_fp/OpAmp.h | 113 ++++ .../platform/sound/c64_fp/Potentiometer.h | 50 ++ src/engine/platform/sound/c64_fp/README | 20 + src/engine/platform/sound/c64_fp/SID.cpp | 504 ++++++++++++++++++ src/engine/platform/sound/c64_fp/SID.h | 372 +++++++++++++ src/engine/platform/sound/c64_fp/Spline.cpp | 119 +++++ src/engine/platform/sound/c64_fp/Spline.h | 78 +++ src/engine/platform/sound/c64_fp/Voice.h | 130 +++++ .../sound/c64_fp/WaveformCalculator.cpp | 204 +++++++ .../sound/c64_fp/WaveformCalculator.h | 128 +++++ .../sound/c64_fp/WaveformGenerator.cpp | 357 +++++++++++++ .../platform/sound/c64_fp/WaveformGenerator.h | 396 ++++++++++++++ src/engine/platform/sound/c64_fp/array.h | 73 +++ .../sound/c64_fp/resample/Resampler.h | 86 +++ .../sound/c64_fp/resample/SincResampler.cpp | 393 ++++++++++++++ .../sound/c64_fp/resample/SincResampler.h | 114 ++++ .../c64_fp/resample/TwoPassSincResampler.h | 83 +++ .../c64_fp/resample/ZeroOrderResampler.h | 88 +++ .../platform/sound/c64_fp/resample/test.cpp | 87 +++ src/engine/platform/sound/c64_fp/sidcxx11.h | 29 + src/engine/platform/sound/c64_fp/sidcxx14.h | 29 + src/engine/platform/sound/c64_fp/siddefs-fp.h | 62 +++ src/engine/platform/sound/c64_fp/version.cc | 21 + src/gui/about.cpp | 2 + src/gui/gui.h | 2 + src/gui/settings.cpp | 12 + src/main.cpp | 1 + 53 files changed, 7639 insertions(+) create mode 100644 src/engine/platform/sound/c64_fp/AUTHORS create mode 100644 src/engine/platform/sound/c64_fp/COPYING create mode 100644 src/engine/platform/sound/c64_fp/Dac.cpp create mode 100644 src/engine/platform/sound/c64_fp/Dac.h create mode 100644 src/engine/platform/sound/c64_fp/EnvelopeGenerator.cpp create mode 100644 src/engine/platform/sound/c64_fp/EnvelopeGenerator.h create mode 100644 src/engine/platform/sound/c64_fp/ExternalFilter.cpp create mode 100644 src/engine/platform/sound/c64_fp/ExternalFilter.h create mode 100644 src/engine/platform/sound/c64_fp/Filter.cpp create mode 100644 src/engine/platform/sound/c64_fp/Filter.h create mode 100644 src/engine/platform/sound/c64_fp/Filter6581.cpp create mode 100644 src/engine/platform/sound/c64_fp/Filter6581.h create mode 100644 src/engine/platform/sound/c64_fp/Filter8580.cpp create mode 100644 src/engine/platform/sound/c64_fp/Filter8580.h create mode 100644 src/engine/platform/sound/c64_fp/FilterModelConfig.cpp create mode 100644 src/engine/platform/sound/c64_fp/FilterModelConfig.h create mode 100644 src/engine/platform/sound/c64_fp/FilterModelConfig6581.cpp create mode 100644 src/engine/platform/sound/c64_fp/FilterModelConfig6581.h create mode 100644 src/engine/platform/sound/c64_fp/FilterModelConfig8580.cpp create mode 100644 src/engine/platform/sound/c64_fp/FilterModelConfig8580.h create mode 100644 src/engine/platform/sound/c64_fp/Integrator6581.cpp create mode 100644 src/engine/platform/sound/c64_fp/Integrator6581.h create mode 100644 src/engine/platform/sound/c64_fp/Integrator8580.cpp create mode 100644 src/engine/platform/sound/c64_fp/Integrator8580.h create mode 100644 src/engine/platform/sound/c64_fp/OpAmp.cpp create mode 100644 src/engine/platform/sound/c64_fp/OpAmp.h create mode 100644 src/engine/platform/sound/c64_fp/Potentiometer.h create mode 100644 src/engine/platform/sound/c64_fp/README create mode 100644 src/engine/platform/sound/c64_fp/SID.cpp create mode 100644 src/engine/platform/sound/c64_fp/SID.h create mode 100644 src/engine/platform/sound/c64_fp/Spline.cpp create mode 100644 src/engine/platform/sound/c64_fp/Spline.h create mode 100644 src/engine/platform/sound/c64_fp/Voice.h create mode 100644 src/engine/platform/sound/c64_fp/WaveformCalculator.cpp create mode 100644 src/engine/platform/sound/c64_fp/WaveformCalculator.h create mode 100644 src/engine/platform/sound/c64_fp/WaveformGenerator.cpp create mode 100644 src/engine/platform/sound/c64_fp/WaveformGenerator.h create mode 100644 src/engine/platform/sound/c64_fp/array.h create mode 100644 src/engine/platform/sound/c64_fp/resample/Resampler.h create mode 100755 src/engine/platform/sound/c64_fp/resample/SincResampler.cpp create mode 100644 src/engine/platform/sound/c64_fp/resample/SincResampler.h create mode 100644 src/engine/platform/sound/c64_fp/resample/TwoPassSincResampler.h create mode 100644 src/engine/platform/sound/c64_fp/resample/ZeroOrderResampler.h create mode 100644 src/engine/platform/sound/c64_fp/resample/test.cpp create mode 100644 src/engine/platform/sound/c64_fp/sidcxx11.h create mode 100644 src/engine/platform/sound/c64_fp/sidcxx14.h create mode 100644 src/engine/platform/sound/c64_fp/siddefs-fp.h create mode 100644 src/engine/platform/sound/c64_fp/version.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b47d2a74c..ff7db42e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,6 +368,24 @@ src/engine/platform/sound/c64/wave8580_PST.cc src/engine/platform/sound/c64/wave8580_P_T.cc src/engine/platform/sound/c64/wave8580__ST.cc +src/engine/platform/sound/c64_fp/Dac.cpp +src/engine/platform/sound/c64_fp/EnvelopeGenerator.cpp +src/engine/platform/sound/c64_fp/ExternalFilter.cpp +src/engine/platform/sound/c64_fp/Filter6581.cpp +src/engine/platform/sound/c64_fp/Filter8580.cpp +src/engine/platform/sound/c64_fp/Filter.cpp +src/engine/platform/sound/c64_fp/FilterModelConfig6581.cpp +src/engine/platform/sound/c64_fp/FilterModelConfig8580.cpp +src/engine/platform/sound/c64_fp/FilterModelConfig.cpp +src/engine/platform/sound/c64_fp/Integrator6581.cpp +src/engine/platform/sound/c64_fp/Integrator8580.cpp +src/engine/platform/sound/c64_fp/OpAmp.cpp +src/engine/platform/sound/c64_fp/SID.cpp +src/engine/platform/sound/c64_fp/Spline.cpp +src/engine/platform/sound/c64_fp/WaveformCalculator.cpp +src/engine/platform/sound/c64_fp/WaveformGenerator.cpp +src/engine/platform/sound/c64_fp/resample/SincResampler.cpp + src/engine/platform/sound/tia/TIASnd.cpp src/engine/platform/sound/ymfm/ymfm_adpcm.cpp diff --git a/src/engine/platform/sound/c64_fp/AUTHORS b/src/engine/platform/sound/c64_fp/AUTHORS new file mode 100644 index 000000000..b04ee0f01 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/AUTHORS @@ -0,0 +1,6 @@ +Authors of reSIDfp. + +Dag Lem: Designed and programmed complete emulation engine. +Antti S. Lankila: Distortion simulation and calculation of combined waveforms +Ken Händel: source code conversion to Java +Leandro Nini: port to c++, merge with reSID 1.0 diff --git a/src/engine/platform/sound/c64_fp/COPYING b/src/engine/platform/sound/c64_fp/COPYING new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/engine/platform/sound/c64_fp/Dac.cpp b/src/engine/platform/sound/c64_fp/Dac.cpp new file mode 100644 index 000000000..0665da817 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Dac.cpp @@ -0,0 +1,123 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2016 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 "Dac.h" + +namespace reSIDfp +{ + +Dac::Dac(unsigned int bits) : + dac(new double[bits]), + dacLength(bits) +{} + +Dac::~Dac() +{ + delete [] dac; +} + +double Dac::getOutput(unsigned int input) const +{ + double dacValue = 0.; + + for (unsigned int i = 0; i < dacLength; i++) + { + if ((input & (1 << i)) != 0) + { + dacValue += dac[i]; + } + } + + return dacValue; +} + +void Dac::kinkedDac(ChipModel chipModel) +{ + const double R_INFINITY = 1e6; + + // Non-linearity parameter, 8580 DACs are perfectly linear + const double _2R_div_R = chipModel == MOS6581 ? 2.20 : 2.00; + + // 6581 DACs are not terminated by a 2R resistor + const bool term = chipModel == MOS8580; + + // Calculate voltage contribution by each individual bit in the R-2R ladder. + for (unsigned int set_bit = 0; set_bit < dacLength; set_bit++) + { + double Vn = 1.; // Normalized bit voltage. + double R = 1.; // Normalized R + const double _2R = _2R_div_R * R; // 2R + double Rn = term ? // Rn = 2R for correct termination, + _2R : R_INFINITY; // INFINITY for missing termination. + + unsigned int bit; + + // Calculate DAC "tail" resistance by repeated parallel substitution. + for (bit = 0; bit < set_bit; bit++) + { + Rn = (Rn == R_INFINITY) ? + R + _2R : + R + (_2R * Rn) / (_2R + Rn); // R + 2R || Rn + } + + // Source transformation for bit voltage. + if (Rn == R_INFINITY) + { + Rn = _2R; + } + else + { + Rn = (_2R * Rn) / (_2R + Rn); // 2R || Rn + Vn = Vn * Rn / _2R; + } + + // Calculate DAC output voltage by repeated source transformation from + // the "tail". + + for (++bit; bit < dacLength; bit++) + { + Rn += R; + const double I = Vn / Rn; + Rn = (_2R * Rn) / (_2R + Rn); // 2R || Rn + Vn = Rn * I; + } + + dac[set_bit] = Vn; + } + + // Normalize to integerish behavior + double Vsum = 0.; + + for (unsigned int i = 0; i < dacLength; i++) + { + Vsum += dac[i]; + } + + Vsum /= 1 << dacLength; + + for (unsigned int i = 0; i < dacLength; i++) + { + dac[i] /= Vsum; + } +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/Dac.h b/src/engine/platform/sound/c64_fp/Dac.h new file mode 100644 index 000000000..35bc0b2ca --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Dac.h @@ -0,0 +1,111 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2016 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 DAC_H +#define DAC_H + +#include "siddefs-fp.h" + +namespace reSIDfp +{ + +/** + * Estimate DAC nonlinearity. + * The SID DACs are built up as R-2R ladder as follows: + * + * n n-1 2 1 0 VGND + * | | | | | | Termination + * 2R 2R 2R 2R 2R 2R only for + * | | | | | | MOS 8580 + * Vo -o-R-o-R-...-o-R-o-R-- --+ + * + * + * All MOS 6581 DACs are missing a termination resistor at bit 0. This causes + * pronounced errors for the lower 4 - 5 bits (e.g. the output for bit 0 is + * actually equal to the output for bit 1), resulting in DAC discontinuities + * for the lower bits. + * In addition to this, the 6581 DACs exhibit further severe discontinuities + * for higher bits, which may be explained by a less than perfect match between + * the R and 2R resistors, or by output impedance in the NMOS transistors + * providing the bit voltages. A good approximation of the actual DAC output is + * achieved for 2R/R ~ 2.20. + * + * The MOS 8580 DACs, on the other hand, do not exhibit any discontinuities. + * These DACs include the correct termination resistor, and also seem to have + * very accurately matched R and 2R resistors (2R/R = 2.00). + * + * On the 6581 the output of the waveform and envelope DACs go through + * a voltage follower built with two NMOS: + * + * Vdd + * + * | + * |-+ + * Vin -------| T1 (enhancement-mode) + * |-+ + * | + * o-------- Vout + * | + * |-+ + * +---| T2 (depletion-mode) + * | |-+ + * | | + * + * GND GND + */ +class Dac +{ +private: + /// analog values + double * const dac; + + /// the dac array length + const unsigned int dacLength; + +public: + /** + * Initialize DAC model. + * + * @param bits the number of input bits + */ + Dac(unsigned int bits); + ~Dac(); + + /** + * Build DAC model for specific chip. + * + * @param chipModel 6581 or 8580 + */ + void kinkedDac(ChipModel chipModel); + + /** + * Get the Vo output for a given combination of input bits. + * + * @param input the digital input + * @return the analog output value + */ + double getOutput(unsigned int input) const; +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/EnvelopeGenerator.cpp b/src/engine/platform/sound/c64_fp/EnvelopeGenerator.cpp new file mode 100644 index 000000000..af636ac7f --- /dev/null +++ b/src/engine/platform/sound/c64_fp/EnvelopeGenerator.cpp @@ -0,0 +1,155 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2018 VICE Project + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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. + */ + +#define ENVELOPEGENERATOR_CPP + +#include "EnvelopeGenerator.h" + +namespace reSIDfp +{ + +/** + * Lookup table to convert from attack, decay, or release value to rate + * counter period. + * + * The rate counter is a 15 bit register which is left shifted each cycle. + * When the counter reaches a specific comparison value, + * the envelope counter is incremented (attack) or decremented + * (decay/release) and the rate counter is resetted. + * + * see [kevtris.org](http://blog.kevtris.org/?p=13) + */ +const unsigned int EnvelopeGenerator::adsrtable[16] = +{ + 0x007f, + 0x3000, + 0x1e00, + 0x0660, + 0x0182, + 0x5573, + 0x000e, + 0x3805, + 0x2424, + 0x2220, + 0x090c, + 0x0ecd, + 0x010e, + 0x23f7, + 0x5237, + 0x64a8 +}; + +void EnvelopeGenerator::reset() +{ + // counter is not changed on reset + envelope_pipeline = 0; + + state_pipeline = 0; + + attack = 0; + decay = 0; + sustain = 0; + release = 0; + + gate = false; + + resetLfsr = true; + + exponential_counter = 0; + exponential_counter_period = 1; + new_exponential_counter_period = 0; + + state = RELEASE; + counter_enabled = true; + rate = adsrtable[release]; +} + +void EnvelopeGenerator::writeCONTROL_REG(unsigned char control) +{ + const bool gate_next = (control & 0x01) != 0; + + if (gate_next != gate) + { + gate = gate_next; + + // The rate counter is never reset, thus there will be a delay before the + // envelope counter starts counting up (attack) or down (release). + + if (gate_next) + { + // Gate bit on: Start attack, decay, sustain. + next_state = ATTACK; + state_pipeline = 2; + + if (resetLfsr || (exponential_pipeline == 2)) + { + envelope_pipeline = (exponential_counter_period == 1) || (exponential_pipeline == 2) ? 2 : 4; + } + else if (exponential_pipeline == 1) + { + state_pipeline = 3; + } + } + else + { + // Gate bit off: Start release. + next_state = RELEASE; + state_pipeline = envelope_pipeline > 0 ? 3 : 2; + } + } +} + +void EnvelopeGenerator::writeATTACK_DECAY(unsigned char attack_decay) +{ + attack = (attack_decay >> 4) & 0x0f; + decay = attack_decay & 0x0f; + + if (state == ATTACK) + { + rate = adsrtable[attack]; + } + else if (state == DECAY_SUSTAIN) + { + rate = adsrtable[decay]; + } +} + +void EnvelopeGenerator::writeSUSTAIN_RELEASE(unsigned char sustain_release) +{ + // From the sustain levels it follows that both the low and high 4 bits + // of the envelope counter are compared to the 4-bit sustain value. + // This has been verified by sampling ENV3. + // + // For a detailed description see: + // http://ploguechipsounds.blogspot.it/2010/11/new-research-on-sid-adsr.html + sustain = (sustain_release & 0xf0) | ((sustain_release >> 4) & 0x0f); + + release = sustain_release & 0x0f; + + if (state == RELEASE) + { + rate = adsrtable[release]; + } +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/EnvelopeGenerator.h b/src/engine/platform/sound/c64_fp/EnvelopeGenerator.h new file mode 100644 index 000000000..f2aab3874 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/EnvelopeGenerator.h @@ -0,0 +1,419 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2018 VICE Project + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 ENVELOPEGENERATOR_H +#define ENVELOPEGENERATOR_H + +#include "siddefs-fp.h" + +namespace reSIDfp +{ + +/** + * A 15 bit [LFSR] is used to implement the envelope rates, in effect dividing + * the clock to the envelope counter by the currently selected rate period. + * + * In addition, another 5 bit counter is used to implement the exponential envelope decay, + * in effect further dividing the clock to the envelope counter. + * The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope counter + * values 255, 93, 54, 26, 14, 6, respectively. + * + * [LFSR]: https://en.wikipedia.org/wiki/Linear_feedback_shift_register + */ +class EnvelopeGenerator +{ +private: + /** + * The envelope state machine's distinct states. In addition to this, + * envelope has a hold mode, which freezes envelope counter to zero. + */ + enum State + { + ATTACK, DECAY_SUSTAIN, RELEASE + }; + +private: + /// XOR shift register for ADSR prescaling. + unsigned int lfsr; + + /// Comparison value (period) of the rate counter before next event. + unsigned int rate; + + /** + * During release mode, the SID approximates envelope decay via piecewise + * linear decay rate. + */ + unsigned int exponential_counter; + + /** + * Comparison value (period) of the exponential decay counter before next + * decrement. + */ + unsigned int exponential_counter_period; + unsigned int new_exponential_counter_period; + + unsigned int state_pipeline; + + /// + unsigned int envelope_pipeline; + + unsigned int exponential_pipeline; + + /// Current envelope state + State state; + State next_state; + + /// Whether counter is enabled. Only switching to ATTACK can release envelope. + bool counter_enabled; + + /// Gate bit + bool gate; + + /// + bool resetLfsr; + + /// The current digital value of envelope output. + unsigned char envelope_counter; + + /// Attack register + unsigned char attack; + + /// Decay register + unsigned char decay; + + /// Sustain register + unsigned char sustain; + + /// Release register + unsigned char release; + + /// The ENV3 value, sampled at the first phase of the clock + unsigned char env3; + +private: + static const unsigned int adsrtable[16]; + +private: + void set_exponential_counter(); + + void state_change(); + +public: + /** + * SID clocking. + */ + void clock(); + + /** + * Get the Envelope Generator digital output. + */ + unsigned int output() const { return envelope_counter; } + + /** + * Constructor. + */ + EnvelopeGenerator() : + lfsr(0x7fff), + rate(0), + exponential_counter(0), + exponential_counter_period(1), + new_exponential_counter_period(0), + state_pipeline(0), + envelope_pipeline(0), + exponential_pipeline(0), + state(RELEASE), + next_state(RELEASE), + counter_enabled(true), + gate(false), + resetLfsr(false), + envelope_counter(0xaa), + attack(0), + decay(0), + sustain(0), + release(0), + env3(0) + {} + + /** + * SID reset. + */ + void reset(); + + /** + * Write control register. + * + * @param control + * control register value + */ + void writeCONTROL_REG(unsigned char control); + + /** + * Write Attack/Decay register. + * + * @param attack_decay + * attack/decay value + */ + void writeATTACK_DECAY(unsigned char attack_decay); + + /** + * Write Sustain/Release register. + * + * @param sustain_release + * sustain/release value + */ + void writeSUSTAIN_RELEASE(unsigned char sustain_release); + + /** + * Return the envelope current value. + * + * @return envelope counter value + */ + unsigned char readENV() const { return env3; } +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(ENVELOPEGENERATOR_CPP) + +namespace reSIDfp +{ + +RESID_INLINE +void EnvelopeGenerator::clock() +{ + env3 = envelope_counter; + + if (unlikely(new_exponential_counter_period > 0)) + { + exponential_counter_period = new_exponential_counter_period; + new_exponential_counter_period = 0; + } + + if (unlikely(state_pipeline)) + { + state_change(); + } + + if (unlikely(envelope_pipeline != 0) && (--envelope_pipeline == 0)) + { + if (likely(counter_enabled)) + { + if (state == ATTACK) + { + if (++envelope_counter==0xff) + { + next_state = DECAY_SUSTAIN; + state_pipeline = 3; + } + } + else if ((state == DECAY_SUSTAIN) || (state == RELEASE)) + { + if (--envelope_counter==0x00) + { + counter_enabled = false; + } + } + + set_exponential_counter(); + } + } + else if (unlikely(exponential_pipeline != 0) && (--exponential_pipeline == 0)) + { + exponential_counter = 0; + + if (((state == DECAY_SUSTAIN) && (envelope_counter != sustain)) + || (state == RELEASE)) + { + // The envelope counter can flip from 0x00 to 0xff by changing state to + // attack, then to release. The envelope counter will then continue + // counting down in the release state. + // This has been verified by sampling ENV3. + + envelope_pipeline = 1; + } + } + else if (unlikely(resetLfsr)) + { + lfsr = 0x7fff; + resetLfsr = false; + + if (state == ATTACK) + { + // The first envelope step in the attack state also resets the exponential + // counter. This has been verified by sampling ENV3. + exponential_counter = 0; // NOTE this is actually delayed one cycle, not modeled + + // The envelope counter can flip from 0xff to 0x00 by changing state to + // release, then to attack. The envelope counter is then frozen at + // zero; to unlock this situation the state must be changed to release, + // then to attack. This has been verified by sampling ENV3. + + envelope_pipeline = 2; + } + else + { + if (counter_enabled && (++exponential_counter == exponential_counter_period)) + exponential_pipeline = exponential_counter_period != 1 ? 2 : 1; + } + } + + // ADSR delay bug. + // If the rate counter comparison value is set below the current value of the + // rate counter, the counter will continue counting up until it wraps around + // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the + // envelope can constly be stepped. + // This has been verified by sampling ENV3. + + // check to see if LFSR matches table value + if (likely(lfsr != rate)) + { + // it wasn't a match, clock the LFSR once + // by performing XOR on last 2 bits + const unsigned int feedback = ((lfsr << 14) ^ (lfsr << 13)) & 0x4000; + lfsr = (lfsr >> 1) | feedback; + } + else + { + resetLfsr = true; + } +} + +/** + * This is what happens on chip during state switching, + * based on die reverse engineering and transistor level + * emulation. + * + * Attack + * + * 0 - Gate on + * 1 - Counting direction changes + * During this cycle the decay rate is "accidentally" activated + * 2 - Counter is being inverted + * Now the attack rate is correctly activated + * Counter is enabled + * 3 - Counter will be counting upward from now on + * + * Decay + * + * 0 - Counter == $ff + * 1 - Counting direction changes + * The attack state is still active + * 2 - Counter is being inverted + * During this cycle the decay state is activated + * 3 - Counter will be counting downward from now on + * + * Release + * + * 0 - Gate off + * 1 - During this cycle the release state is activated if coming from sustain/decay + * *2 - Counter is being inverted, the release state is activated + * *3 - Counter will be counting downward from now on + * + * (* only if coming directly from Attack state) + * + * Freeze + * + * 0 - Counter == $00 + * 1 - Nothing + * 2 - Counter is disabled + */ +RESID_INLINE +void EnvelopeGenerator::state_change() +{ + state_pipeline--; + + switch (next_state) + { + case ATTACK: + if (state_pipeline == 1) + { + // The decay rate is "accidentally" enabled during first cycle of attack phase + rate = adsrtable[decay]; + } + else if (state_pipeline == 0) + { + state = ATTACK; + // The attack rate is correctly enabled during second cycle of attack phase + rate = adsrtable[attack]; + counter_enabled = true; + } + break; + case DECAY_SUSTAIN: + if (state_pipeline == 0) + { + state = DECAY_SUSTAIN; + rate = adsrtable[decay]; + } + break; + case RELEASE: + if (((state == ATTACK) && (state_pipeline == 0)) + || ((state == DECAY_SUSTAIN) && (state_pipeline == 1))) + { + state = RELEASE; + rate = adsrtable[release]; + } + break; + } +} + +RESID_INLINE +void EnvelopeGenerator::set_exponential_counter() +{ + // Check for change of exponential counter period. + // + // For a detailed description see: + // http://ploguechipsounds.blogspot.it/2010/03/sid-6581r3-adsr-tables-up-close.html + switch (envelope_counter) + { + case 0xff: + case 0x00: + new_exponential_counter_period = 1; + break; + + case 0x5d: + new_exponential_counter_period = 2; + break; + + case 0x36: + new_exponential_counter_period = 4; + break; + + case 0x1a: + new_exponential_counter_period = 8; + break; + + case 0x0e: + new_exponential_counter_period = 16; + break; + + case 0x06: + new_exponential_counter_period = 30; + break; + } +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/ExternalFilter.cpp b/src/engine/platform/sound/c64_fp/ExternalFilter.cpp new file mode 100644 index 000000000..eac790b31 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/ExternalFilter.cpp @@ -0,0 +1,68 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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. + */ + +#define EXTERNALFILTER_CPP + +#include "ExternalFilter.h" + +namespace reSIDfp +{ + +/** + * Get the 3 dB attenuation point. + * + * @param res the resistance value in Ohms + * @param cap the capacitance value in Farads + */ +inline double getRC(double res, double cap) +{ + return res * cap; +} + +ExternalFilter::ExternalFilter() : + w0lp_1_s7(0), + w0hp_1_s17(0) +{ + reset(); +} + +void ExternalFilter::setClockFrequency(double frequency) +{ + const double dt = 1. / frequency; + + // Low-pass: R = 10kOhm, C = 1000pF; w0l = dt/(dt+RC) = 1e-6/(1e-6+1e4*1e-9) = 0.091 + // Cutoff 1/2*PI*RC = 1/2*PI*1e4*1e-9 = 15915.5 Hz + w0lp_1_s7 = static_cast((dt / (dt + getRC(10e3, 1000e-12))) * (1 << 7) + 0.5); + + // High-pass: R = 10kOhm, C = 10uF; w0h = dt/(dt+RC) = 1e-6/(1e-6+1e4*1e-5) = 0.00000999 + // Cutoff 1/2*PI*RC = 1/2*PI*1e4*1e-5 = 1.59155 Hz + w0hp_1_s17 = static_cast((dt / (dt + getRC(10e3, 10e-6))) * (1 << 17) + 0.5); +} + +void ExternalFilter::reset() +{ + // State of filter. + Vlp = 0; //1 << (15 + 11); + Vhp = 0; +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/ExternalFilter.h b/src/engine/platform/sound/c64_fp/ExternalFilter.h new file mode 100644 index 000000000..760ee5c22 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/ExternalFilter.h @@ -0,0 +1,125 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 EXTERNALFILTER_H +#define EXTERNALFILTER_H + +#include "siddefs-fp.h" + +namespace reSIDfp +{ + +/** + * The audio output stage in a Commodore 64 consists of two STC networks, a + * low-pass RC filter with 3 dB frequency 16kHz followed by a DC-blocker which + * acts as a high-pass filter with a cutoff dependent on the attached audio + * equipment impedance. Here we suppose an impedance of 10kOhm resulting + * in a 3 dB attenuation at 1.6Hz. + * To operate properly the 6581 audio output needs a pull-down resistor + *(1KOhm recommended, not needed on 8580) + * + * ~~~ + * 9/12V + * -----+ + * audio| 10k | + * +---o----R---o--------o-----(K) +----- + * out | | | | | |audio + * -----+ R 1k C 1000 | | 10 uF | + * | | pF +-C----o-----C-----+ 10k + * 470 | | + * GND GND pF R 1K | amp + * * * | +----- + * + * GND + * ~~~ + * + * The STC networks are connected with a [BJT] based [common collector] + * used as a voltage follower (featuring a 2SC1815 NPN transistor). + * * The C64c board additionally includes a [bootstrap] condenser to increase + * the input impedance of the common collector. + * + * [BJT]: https://en.wikipedia.org/wiki/Bipolar_junction_transistor + * [common collector]: https://en.wikipedia.org/wiki/Common_collector + * [bootstrap]: https://en.wikipedia.org/wiki/Bootstrapping_(electronics) + */ +class ExternalFilter +{ +private: + /// Lowpass filter voltage + int Vlp; + + /// Highpass filter voltage + int Vhp; + + int w0lp_1_s7; + + int w0hp_1_s17; + +public: + /** + * SID clocking. + * + * @param input + */ + int clock(unsigned short input); + + /** + * Constructor. + */ + ExternalFilter(); + + /** + * Setup of the external filter sampling parameters. + * + * @param frequency the main system clock frequency + */ + void setClockFrequency(double frequency); + + /** + * SID reset. + */ + void reset(); +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(EXTERNALFILTER_CPP) + +namespace reSIDfp +{ + +RESID_INLINE +int ExternalFilter::clock(unsigned short input) +{ + const int Vi = (static_cast(input)<<11) - (1 << (11+15)); + const int dVlp = (w0lp_1_s7 * (Vi - Vlp) >> 7); + const int dVhp = (w0hp_1_s17 * (Vlp - Vhp) >> 17); + Vlp += dVlp; + Vhp += dVhp; + return (Vlp - Vhp) >> 11; +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/Filter.cpp b/src/engine/platform/sound/c64_fp/Filter.cpp new file mode 100644 index 000000000..2a2dd24f7 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Filter.cpp @@ -0,0 +1,90 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2013 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 "Filter.h" + +namespace reSIDfp +{ + +void Filter::enable(bool enable) +{ + enabled = enable; + + if (enabled) + { + writeRES_FILT(filt); + } + else + { + filt1 = filt2 = filt3 = filtE = false; + } +} + +void Filter::reset() +{ + writeFC_LO(0); + writeFC_HI(0); + writeMODE_VOL(0); + writeRES_FILT(0); +} + +void Filter::writeFC_LO(unsigned char fc_lo) +{ + fc = (fc & 0x7f8) | (fc_lo & 0x007); + updatedCenterFrequency(); +} + +void Filter::writeFC_HI(unsigned char fc_hi) +{ + fc = (fc_hi << 3 & 0x7f8) | (fc & 0x007); + updatedCenterFrequency(); +} + +void Filter::writeRES_FILT(unsigned char res_filt) +{ + filt = res_filt; + + updateResonance((res_filt >> 4) & 0x0f); + + if (enabled) + { + filt1 = (filt & 0x01) != 0; + filt2 = (filt & 0x02) != 0; + filt3 = (filt & 0x04) != 0; + filtE = (filt & 0x08) != 0; + } + + updatedMixing(); +} + +void Filter::writeMODE_VOL(unsigned char mode_vol) +{ + vol = mode_vol & 0x0f; + lp = (mode_vol & 0x10) != 0; + bp = (mode_vol & 0x20) != 0; + hp = (mode_vol & 0x40) != 0; + voice3off = (mode_vol & 0x80) != 0; + + updatedMixing(); +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/Filter.h b/src/engine/platform/sound/c64_fp/Filter.h new file mode 100644 index 000000000..4b3473369 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Filter.h @@ -0,0 +1,177 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2017 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 FILTER_H +#define FILTER_H + +namespace reSIDfp +{ + +/** + * SID filter base class + */ +class Filter +{ +protected: + /// Current volume amplifier setting. + unsigned short* currentGain; + + /// Current filter/voice mixer setting. + unsigned short* currentMixer; + + /// Filter input summer setting. + unsigned short* currentSummer; + + /// Filter resonance value. + unsigned short* currentResonance; + + /// Filter highpass state. + int Vhp; + + /// Filter bandpass state. + int Vbp; + + /// Filter lowpass state. + int Vlp; + + /// Filter external input. + int ve; + + /// Filter cutoff frequency. + unsigned int fc; + + /// Routing to filter or outside filter + bool filt1, filt2, filt3, filtE; + + /// Switch voice 3 off. + bool voice3off; + + /// Highpass, bandpass, and lowpass filter modes. + bool hp, bp, lp; + + /// Current volume. + unsigned char vol; + +private: + /// Filter enabled. + bool enabled; + + /// Selects which inputs to route through filter. + unsigned char filt; + +protected: + /** + * Set filter cutoff frequency. + */ + virtual void updatedCenterFrequency() = 0; + + /** + * Set filter resonance. + */ + virtual void updateResonance(unsigned char res) = 0; + + /** + * Mixing configuration modified (offsets change) + */ + virtual void updatedMixing() = 0; + +public: + Filter() : + currentGain(nullptr), + currentMixer(nullptr), + currentSummer(nullptr), + currentResonance(nullptr), + Vhp(0), + Vbp(0), + Vlp(0), + ve(0), + fc(0), + filt1(false), + filt2(false), + filt3(false), + filtE(false), + voice3off(false), + hp(false), + bp(false), + lp(false), + vol(0), + enabled(true), + filt(0) {} + + virtual ~Filter() {} + + /** + * SID clocking - 1 cycle + * + * @param v1 voice 1 in + * @param v2 voice 2 in + * @param v3 voice 3 in + * @return filtered output + */ + virtual unsigned short clock(int v1, int v2, int v3) = 0; + + /** + * Enable filter. + * + * @param enable + */ + void enable(bool enable); + + /** + * SID reset. + */ + void reset(); + + /** + * Write Frequency Cutoff Low register. + * + * @param fc_lo Frequency Cutoff Low-Byte + */ + void writeFC_LO(unsigned char fc_lo); + + /** + * Write Frequency Cutoff High register. + * + * @param fc_hi Frequency Cutoff High-Byte + */ + void writeFC_HI(unsigned char fc_hi); + + /** + * Write Resonance/Filter register. + * + * @param res_filt Resonance/Filter + */ + void writeRES_FILT(unsigned char res_filt); + + /** + * Write filter Mode/Volume register. + * + * @param mode_vol Filter Mode/Volume + */ + void writeMODE_VOL(unsigned char mode_vol); + + virtual void input(int input) = 0; +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/Filter6581.cpp b/src/engine/platform/sound/c64_fp/Filter6581.cpp new file mode 100644 index 000000000..c064a8801 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Filter6581.cpp @@ -0,0 +1,75 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2015 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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. + */ + +#define FILTER6581_CPP + +#include "Filter6581.h" + +#include "Integrator6581.h" + +namespace reSIDfp +{ + +Filter6581::~Filter6581() +{ + delete [] f0_dac; +} + +void Filter6581::updatedCenterFrequency() +{ + const unsigned short Vw = f0_dac[fc]; + hpIntegrator->setVw(Vw); + bpIntegrator->setVw(Vw); +} + +void Filter6581::updatedMixing() +{ + currentGain = gain_vol[vol]; + + unsigned int ni = 0; + unsigned int no = 0; + + (filt1 ? ni : no)++; + (filt2 ? ni : no)++; + + if (filt3) ni++; + else if (!voice3off) no++; + + (filtE ? ni : no)++; + + currentSummer = summer[ni]; + + if (lp) no++; + if (bp) no++; + if (hp) no++; + + currentMixer = mixer[no]; +} + +void Filter6581::setFilterCurve(double curvePosition) +{ + delete [] f0_dac; + f0_dac = FilterModelConfig6581::getInstance()->getDAC(curvePosition); + updatedCenterFrequency(); +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/Filter6581.h b/src/engine/platform/sound/c64_fp/Filter6581.h new file mode 100644 index 000000000..7fca331ab --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Filter6581.h @@ -0,0 +1,425 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 FILTER6581_H +#define FILTER6581_H + +#include "siddefs-fp.h" + +#include + +#include "Filter.h" +#include "FilterModelConfig6581.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +class Integrator6581; + +/** + * The SID filter is modeled with a two-integrator-loop biquadratic filter, + * which has been confirmed by Bob Yannes to be the actual circuit used in + * the SID chip. + * + * Measurements show that excellent emulation of the SID filter is achieved, + * except when high resonance is combined with high sustain levels. + * In this case the SID op-amps are performing less than ideally and are + * causing some peculiar behavior of the SID filter. This however seems to + * have more effect on the overall amplitude than on the color of the sound. + * + * The theory for the filter circuit can be found in "Microelectric Circuits" + * by Adel S. Sedra and Kenneth C. Smith. + * The circuit is modeled based on the explanation found there except that + * an additional inverter is used in the feedback from the bandpass output, + * allowing the summer op-amp to operate in single-ended mode. This yields + * filter outputs with levels independent of Q, which corresponds with the + * results obtained from a real SID. + * + * We have been able to model the summer and the two integrators of the circuit + * to form components of an IIR filter. + * Vhp is the output of the summer, Vbp is the output of the first integrator, + * and Vlp is the output of the second integrator in the filter circuit. + * + * According to Bob Yannes, the active stages of the SID filter are not really + * op-amps. Rather, simple NMOS inverters are used. By biasing an inverter + * into its region of quasi-linear operation using a feedback resistor from + * input to output, a MOS inverter can be made to act like an op-amp for + * small signals centered around the switching threshold. + * + * In 2008, Michael Huth facilitated closer investigation of the SID 6581 + * filter circuit by publishing high quality microscope photographs of the die. + * Tommi Lempinen has done an impressive work on re-vectorizing and annotating + * the die photographs, substantially simplifying further analysis of the + * filter circuit. + * + * The filter schematics below are reverse engineered from these re-vectorized + * and annotated die photographs. While the filter first depicted in reSID 0.9 + * is a correct model of the basic filter, the schematics are now completed + * with the audio mixer and output stage, including details on intended + * relative resistor values. Also included are schematics for the NMOS FET + * voltage controlled resistors (VCRs) used to control cutoff frequency, the + * DAC which controls the VCRs, the NMOS op-amps, and the output buffer. + * + * + * SID filter / mixer / output + * --------------------------- + * ~~~ + * +---------------------------------------------------+ + * | | + * | +--1R1-- \--+ D7 | + * | +---R1--+ | | | + * | | | o--2R1-- \--o D6 | + * | +---------o----o--Rw--o--[A>--o--Rw--o--[A>--o + * ve (EXT IN) | | | | + * D3 \ ---------------R8--o | | (CAP2A) | (CAP1A) + * | v3 | | vhp | vbp | vlp + * D2 | \ -----------R8--o +-----+ | | + * | | v2 | | | | + * D1 | | \ -------R8--o | +----------------+ | + * | | | v1 | | | | + * D0 | | | \ ---R8--+ | | +---------------------------+ + * | | | | | | | + * R6 R6 R6 R6 R6 R6 R6 + * | | | | $18 | | | $18 + * | \ | | D7: 1=open \ \ \ D6 - D4: 0=open + * | | | | | | | + * +---o---o---o-------------o---o---+ 12V + * | + * | D3 +--/ --1R2--+ | + * | +---R8--+ | | +---R2--+ | + * | | | D2 o--/ --2R2--o | | ||--+ + * +---o--[A>--o------o o--o--[A>--o--|| + * D1 o--/ --4R2--o (4.25R2) ||--+ + * $18 | | | + * 0=open D0 +--/ --8R2--+ (8.75R2) | + * + * vo (AUDIO + * OUT) + * + * + * v1 - voice 1 + * v2 - voice 2 + * v3 - voice 3 + * ve - ext in + * vhp - highpass output + * vbp - bandpass output + * vlp - lowpass output + * vo - audio out + * [A> - single ended inverting op-amp (self-biased NMOS inverter) + * Rn - "resistors", implemented with custom NMOS FETs + * Rw - cutoff frequency resistor (VCR) + * C - capacitor + * ~~~ + * Notes: + * + * R2 ~ 2.0*R1 + * R6 ~ 6.0*R1 + * R8 ~ 8.0*R1 + * R24 ~ 24.0*R1 + * + * The Rn "resistors" in the circuit are implemented with custom NMOS FETs, + * probably because of space constraints on the SID die. The silicon substrate + * is laid out in a narrow strip or "snake", with a strip length proportional + * to the intended resistance. The polysilicon gate electrode covers the entire + * silicon substrate and is fixed at 12V in order for the NMOS FET to operate + * in triode mode (a.k.a. linear mode or ohmic mode). + * + * Even in "linear mode", an NMOS FET is only an approximation of a resistor, + * as the apparant resistance increases with increasing drain-to-source + * voltage. If the drain-to-source voltage should approach the gate voltage + * of 12V, the NMOS FET will enter saturation mode (a.k.a. active mode), and + * the NMOS FET will not operate anywhere like a resistor. + * + * + * + * NMOS FET voltage controlled resistor (VCR) + * ------------------------------------------ + * ~~~ + * Vw + * + * | + * | + * R1 + * | + * +--R1--o + * | __|__ + * | ----- + * | | | + * vi -----o----+ +--o----- vo + * | | + * +----R24----+ + * + * + * vi - input + * vo - output + * Rn - "resistors", implemented with custom NMOS FETs + * Vw - voltage from 11-bit DAC (frequency cutoff control) + * ~~~ + * Notes: + * + * An approximate value for R24 can be found by using the formula for the + * filter cutoff frequency: + * + * FCmin = 1/(2*pi*Rmax*C) + * + * Assuming that a the setting for minimum cutoff frequency in combination with + * a low level input signal ensures that only negligible current will flow + * through the transistor in the schematics above, values for FCmin and C can + * be substituted in this formula to find Rmax. + * Using C = 470pF and FCmin = 220Hz (measured value), we get: + * + * FCmin = 1/(2*pi*Rmax*C) + * Rmax = 1/(2*pi*FCmin*C) = 1/(2*pi*220*470e-12) ~ 1.5MOhm + * + * From this it follows that: + * R24 = Rmax ~ 1.5MOhm + * R1 ~ R24/24 ~ 64kOhm + * R2 ~ 2.0*R1 ~ 128kOhm + * R6 ~ 6.0*R1 ~ 384kOhm + * R8 ~ 8.0*R1 ~ 512kOhm + * + * Note that these are only approximate values for one particular SID chip, + * due to process variations the values can be substantially different in + * other chips. + * + * + * + * Filter frequency cutoff DAC + * --------------------------- + * + * ~~~ + * 12V 10 9 8 7 6 5 4 3 2 1 0 VGND + * | | | | | | | | | | | | | Missing + * 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R termination + * | | | | | | | | | | | | | + * Vw --o-R-o-R-o-R-o-R-o-R-o-R-o-R-o-R-o-R-o-R-o-R-o- -+ + * + * + * Bit on: 12V + * Bit off: 5V (VGND) + * ~~~ + * As is the case with all MOS 6581 DACs, the termination to (virtual) ground + * at bit 0 is missing. + * + * Furthermore, the control of the two VCRs imposes a load on the DAC output + * which varies with the input signals to the VCRs. This can be seen from the + * VCR figure above. + * + * + * + * "Op-amp" (self-biased NMOS inverter) + * ------------------------------------ + * ~~~ + * + * 12V + * + * | + * +-----------o + * | | + * | +------o + * | | | + * | | ||--+ + * | +--|| + * | ||--+ + * ||--+ | + * vi -----|| o---o----- vo + * ||--+ | | + * | ||--+ | + * |-------|| | + * | ||--+ | + * ||--+ | | + * +--|| | | + * | ||--+ | | + * | | | | + * | +-----------o | + * | | | + * | | + * | GND | + * | | + * +----------------------+ + * + * + * vi - input + * vo - output + * ~~~ + * Notes: + * + * The schematics above are laid out to show that the "op-amp" logically + * consists of two building blocks; a saturated load NMOS inverter (on the + * right hand side of the schematics) with a buffer / bias input stage + * consisting of a variable saturated load NMOS inverter (on the left hand + * side of the schematics). + * + * Provided a reasonably high input impedance and a reasonably low output + * impedance, the "op-amp" can be modeled as a voltage transfer function + * mapping input voltage to output voltage. + * + * + * + * Output buffer (NMOS voltage follower) + * ------------------------------------- + * ~~~ + * + * 12V + * + * | + * | + * ||--+ + * vi -----|| + * ||--+ + * | + * o------ vo + * | (AUDIO + * Rext OUT) + * | + * | + * + * GND + * + * vi - input + * vo - output + * Rext - external resistor, 1kOhm + * ~~~ + * Notes: + * + * The external resistor Rext is needed to complete the NMOS voltage follower, + * this resistor has a recommended value of 1kOhm. + * + * Die photographs show that actually, two NMOS transistors are used in the + * voltage follower. However the two transistors are coupled in parallel (all + * terminals are pairwise common), which implies that we can model the two + * transistors as one. + */ +class Filter6581 final : public Filter +{ +private: + const unsigned short* f0_dac; + + unsigned short** mixer; + unsigned short** summer; + unsigned short** gain_res; + unsigned short** gain_vol; + + const int voiceScaleS11; + const int voiceDC; + + /// VCR + associated capacitor connected to highpass output. + std::unique_ptr const hpIntegrator; + + /// VCR + associated capacitor connected to bandpass output. + std::unique_ptr const bpIntegrator; + +protected: + /** + * Set filter cutoff frequency. + */ + void updatedCenterFrequency() override; + + /** + * Set filter resonance. + * + * In the MOS 6581, 1/Q is controlled linearly by res. + */ + void updateResonance(unsigned char res) override { currentResonance = gain_res[res]; } + + void updatedMixing() override; + +public: + Filter6581() : + f0_dac(FilterModelConfig6581::getInstance()->getDAC(0.5)), + mixer(FilterModelConfig6581::getInstance()->getMixer()), + summer(FilterModelConfig6581::getInstance()->getSummer()), + gain_res(FilterModelConfig6581::getInstance()->getGainRes()), + gain_vol(FilterModelConfig6581::getInstance()->getGainVol()), + voiceScaleS11(FilterModelConfig6581::getInstance()->getVoiceScaleS11()), + voiceDC(FilterModelConfig6581::getInstance()->getNormalizedVoiceDC()), + hpIntegrator(FilterModelConfig6581::getInstance()->buildIntegrator()), + bpIntegrator(FilterModelConfig6581::getInstance()->buildIntegrator()) + { + input(0); + } + + ~Filter6581(); + + unsigned short clock(int voice1, int voice2, int voice3) override; + + void input(int sample) override { ve = (sample * voiceScaleS11 * 3 >> 11) + mixer[0][0]; } + + /** + * Set filter curve type based on single parameter. + * + * @param curvePosition 0 .. 1, where 0 sets center frequency high ("light") and 1 sets it low ("dark"), default is 0.5 + */ + void setFilterCurve(double curvePosition); +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(FILTER6581_CPP) + +#include "Integrator6581.h" + +namespace reSIDfp +{ + +RESID_INLINE +unsigned short Filter6581::clock(int voice1, int voice2, int voice3) +{ + voice1 = (voice1 * voiceScaleS11 >> 15) + voiceDC; + voice2 = (voice2 * voiceScaleS11 >> 15) + voiceDC; + // Voice 3 is silenced by voice3off if it is not routed through the filter. + voice3 = (filt3 || !voice3off) ? (voice3 * voiceScaleS11 >> 15) + voiceDC : 0; + + int Vi = 0; + int Vo = 0; + + (filt1 ? Vi : Vo) += voice1; + (filt2 ? Vi : Vo) += voice2; + (filt3 ? Vi : Vo) += voice3; + (filtE ? Vi : Vo) += ve; + + Vhp = currentSummer[currentResonance[Vbp] + Vlp + Vi]; + Vbp = hpIntegrator->solve(Vhp); + Vlp = bpIntegrator->solve(Vbp); + + if (lp) Vo += Vlp; + if (bp) Vo += Vbp; + if (hp) Vo += Vhp; + + return currentGain[currentMixer[Vo]]; +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/Filter8580.cpp b/src/engine/platform/sound/c64_fp/Filter8580.cpp new file mode 100644 index 000000000..a70285a8a --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Filter8580.cpp @@ -0,0 +1,101 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2019 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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. + */ + +#define FILTER8580_CPP + +#include "Filter8580.h" + +#include "Integrator8580.h" + +namespace reSIDfp +{ + +/** + * W/L ratio of frequency DAC bit 0, + * other bit are proportional. + * When no bit are selected a resistance with half + * W/L ratio is selected. + */ +const double DAC_WL0 = 0.00615; + +Filter8580::~Filter8580() {} + +void Filter8580::updatedCenterFrequency() +{ + double wl; + double dacWL = DAC_WL0; + if (fc) + { + wl = 0.; + for (unsigned int i = 0; i < 11; i++) + { + if (fc & (1 << i)) + { + wl += dacWL; + } + dacWL *= 2.; + } + } + else + { + wl = dacWL/2.; + } + + hpIntegrator->setFc(wl); + bpIntegrator->setFc(wl); +} + +void Filter8580::updatedMixing() +{ + currentGain = gain_vol[vol]; + + unsigned int ni = 0; + unsigned int no = 0; + + (filt1 ? ni : no)++; + (filt2 ? ni : no)++; + + if (filt3) ni++; + else if (!voice3off) no++; + + (filtE ? ni : no)++; + + currentSummer = summer[ni]; + + if (lp) no++; + if (bp) no++; + if (hp) no++; + + currentMixer = mixer[no]; +} + +void Filter8580::setFilterCurve(double curvePosition) +{ + // Adjust cp + // 1.2 <= cp <= 1.8 + cp = 1.8 - curvePosition * 3./5.; + + hpIntegrator->setV(cp); + bpIntegrator->setV(cp); +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/Filter8580.h b/src/engine/platform/sound/c64_fp/Filter8580.h new file mode 100644 index 000000000..2166ec0da --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Filter8580.h @@ -0,0 +1,383 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 FILTER8580_H +#define FILTER8580_H + +#include "siddefs-fp.h" + +#include + +#include "Filter.h" +#include "FilterModelConfig8580.h" +#include "Integrator8580.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +class Integrator8580; + +/** + * Filter for 8580 chip + * -------------------- + * The 8580 filter stage had been redesigned to be more linear and robust + * against temperature change. It also features real op-amps and a + * revisited resonance model. + * The filter schematics below are reverse engineered from re-vectorized + * and annotated die photographs. Credits to Michael Huth for the microscope + * photographs of the die, Tommi Lempinen for re-vectorizating and annotating + * the images and ttlworks from forum.6502.org for the circuit analysis. + * + * ~~~ + * + * +---------------------------------------------------+ + * | $17 +----Rf-+ | + * | | | | + * | D4&!D5 o- \-R3-o | + * | | | $17 | + * | !D4&!D5 o- \-R2-o | + * | | | +---R8-- \--+ !D6&D7 | + * | D4&!D5 o- \-R1-o | | | + * | | | o---RC-- \--o D6&D7 | + * | +---------o----o--Rfc-o--[A>--o--Rfc-o--[A>--o + * ve (EXT IN) | | | | + * D3 \ --------------R12--o | | (CAP2A) | (CAP1A) + * | v3 | | vhp | vbp | vlp + * D2 | \ -----------R7--o +-----+ | | + * | | v2 | | | | + * D1 | | \ -------R7--o | +----------------+ | + * | | | v1 | | | | + * D0 | | | \ ---R7--+ | | +---------------------------+ + * | | | | | | | + * R9 R5 R5 R5 R5 R5 R5 + * | | | | $18 | | | $18 + * | \ | | D7: 1=open \ \ \ D6 - D4: 0=open + * | | | | | | | + * +---o---o---o-------------o---o---+ + * | + * | D3 +--/ --1R4--+ + * | +---R8--+ | | +---R2--+ + * | | | D2 o--/ --2R4--o | | + * +---o--[A>--o------o o--o--[A>--o-- vo (AUDIO OUT) + * D1 o--/ --4R4--o + * $18 | | + * 0=open D0 +--/ --8R4--+ + * + * + * + * Resonance + * --------- + * For resonance, we have two tiny DACs that controls both the input + * and feedback resistances. + * + * The "resistors" are switched in as follows by bits in register $17: + * + * feedback: + * R1: bit4&!bit5 + * R2: !bit4&bit5 + * R3: bit4&bit5 + * Rf: always on + * + * input: + * R4: bit6&!bit7 + * R8: !bit6&bit7 + * RC: bit6&bit7 + * Ri: !(R4|R8|RC) = !(bit6|bit7) = !bit6&!bit7 + * + * + * The relative "resistor" values are approximately (using channel length): + * + * R1 = 15.3*Ri + * R2 = 7.3*Ri + * R3 = 4.7*Ri + * Rf = 1.4*Ri + * R4 = 1.4*Ri + * R8 = 2.0*Ri + * RC = 2.8*Ri + * + * + * Approximate values for 1/Q can now be found as follows (assuming an + * ideal op-amp): + * + * res feedback input -gain (1/Q) + * --- -------- ----- ---------- + * 0 Rf Ri Rf/Ri = 1/(Ri*(1/Rf)) = 1/0.71 + * 1 Rf|R1 Ri (Rf|R1)/Ri = 1/(Ri*(1/Rf+1/R1)) = 1/0.78 + * 2 Rf|R2 Ri (Rf|R2)/Ri = 1/(Ri*(1/Rf+1/R2)) = 1/0.85 + * 3 Rf|R3 Ri (Rf|R3)/Ri = 1/(Ri*(1/Rf+1/R3)) = 1/0.92 + * 4 Rf R4 Rf/R4 = 1/(R4*(1/Rf)) = 1/1.00 + * 5 Rf|R1 R4 (Rf|R1)/R4 = 1/(R4*(1/Rf+1/R1)) = 1/1.10 + * 6 Rf|R2 R4 (Rf|R2)/R4 = 1/(R4*(1/Rf+1/R2)) = 1/1.20 + * 7 Rf|R3 R4 (Rf|R3)/R4 = 1/(R4*(1/Rf+1/R3)) = 1/1.30 + * 8 Rf R8 Rf/R8 = 1/(R8*(1/Rf)) = 1/1.43 + * 9 Rf|R1 R8 (Rf|R1)/R8 = 1/(R8*(1/Rf+1/R1)) = 1/1.56 + * A Rf|R2 R8 (Rf|R2)/R8 = 1/(R8*(1/Rf+1/R2)) = 1/1.70 + * B Rf|R3 R8 (Rf|R3)/R8 = 1/(R8*(1/Rf+1/R3)) = 1/1.86 + * C Rf RC Rf/RC = 1/(RC*(1/Rf)) = 1/2.00 + * D Rf|R1 RC (Rf|R1)/RC = 1/(RC*(1/Rf+1/R1)) = 1/2.18 + * E Rf|R2 RC (Rf|R2)/RC = 1/(RC*(1/Rf+1/R2)) = 1/2.38 + * F Rf|R3 RC (Rf|R3)/RC = 1/(RC*(1/Rf+1/R3)) = 1/2.60 + * + * + * These data indicate that the following function for 1/Q has been + * modeled in the MOS 8580: + * + * 1/Q = 2^(1/2)*2^(-x/8) = 2^(1/2 - x/8) = 2^((4 - x)/8) + * + * + * + * Op-amps + * ------- + * Unlike the 6581, the 8580 has real OpAmps. + * + * Temperature compensated differential amplifier: + * + * 9V + * + * | + * +-------o-o-o-------+ + * | | | | + * | R R | + * +--|| | | ||--+ + * ||---o o---|| + * +--|| | | ||--+ + * | | | | + * o-----+ | | o--- Va + * | | | | | + * +--|| | | | ||--+ + * ||-o-+---+---|| + * +--|| | | ||--+ + * | | | | + * | | + * GND | | GND + * ||--+ +--|| + * in- -----|| ||------ in+ + * ||----o----|| + * | + * 8 Current sink + * | + * + * GND + * + * Inverter + non-inverting output amplifier: + * + * Va ---o---||-------------------o--------------------+ + * | | 9V | + * | +----------+----------+ | | + * | 9V | | 9V | ||--+ | + * | | | 9V | | +-|| | + * | R | | | ||--+ ||--+ | + * | | | ||--+ +--|| o---o--- Vout + * | o---o---|| ||--+ ||--+ + * | | ||--+ o-----|| + * | ||--+ | ||--+ ||--+ + * +-----|| o-----|| | + * ||--+ | ||--+ + * | R | GND + * | + * GND GND + * GND + * + * + * + * Virtual ground + * -------------- + * A PolySi resitive voltage divider provides the voltage + * for the positive input of the filter op-amps. + * + * 5V + * +----------+ + * | | |\ | + * R1 +---|-\ | + * 5V | |A >---o--- Vref + * o-------|+/ + * | | |/ + * R10 R4 + * | | + * o---+ + * | + * R10 + * | + * + * GND + * + * Rn = n*R1 + * + * + * + * Rfc - freq control DAC resistance ladder + * ---------------------------------------- + * The 8580 has 11 bits for frequency control, but 12 bit DACs. + * If those 11 bits would be '0', the impedance of the DACs would be "infinitely high". + * To get around this, there is an 11 input NOR gate below the DACs sensing those 11 bits. + * If all are 0, the NOR gate gives the gate control voltage to the 12 bit DAC LSB. + * + * ----o---o--...--o---o---o--- + * | | | | | + * Rb10 Rb9 ... Rb1 Rb0 R0 + * | | | | | + * ----o---o--...--o---o---o--- + * + * + * + * Crystal stabilized precision switched capacitor voltage divider + * --------------------------------------------------------------- + * There is a FET working as a temperature sensor close to the DACs which changes the gate voltage + * of the frequency control DACs according to the temperature of the DACs, + * to reduce the effects of temperature on the filter curve. + * An asynchronous 3 bit binary counter, running at the speed of PHI2, drives two big capacitors + * whose AC resistance is then used as a voltage divider. + * This implicates that frequency difference between PAL and NTSC might shift the filter curve by 4% or such. + * + * |\ OpAmp has a smaller capacitor than the other OPs + * Vref ---|+\ + * |A >---o--- Vdac + * +-------|-/ | + * | |/ | + * | | + * C1 | C2 | + * +---||---o---+ +---o-----||-------o + * | | | | | | + * o----+ | ----- | | + * | | | ----- +----+ +-----o + * | ----- | | | | + * | ----- | ----- | + * | | | ----- | + * | +-----------+ | | + * | /Q Q | +-------+ + * GND +-----------+ FET close to DAC + * | clk/8 | working as temperature sensor + * +-----------+ + */ +class Filter8580 final : public Filter +{ +private: + unsigned short** mixer; + unsigned short** summer; + unsigned short** gain_res; + unsigned short** gain_vol; + + const int voiceScaleS11; + const int voiceDC; + + double cp; + + /// VCR + associated capacitor connected to highpass output. + std::unique_ptr const hpIntegrator; + + /// VCR + associated capacitor connected to bandpass output. + std::unique_ptr const bpIntegrator; + +protected: + /** + * Set filter cutoff frequency. + */ + void updatedCenterFrequency() override; + + /** + * Set filter resonance. + * + * @param res the new resonance value + */ + void updateResonance(unsigned char res) override { currentResonance = gain_res[res]; } + + void updatedMixing() override; + +public: + Filter8580() : + mixer(FilterModelConfig8580::getInstance()->getMixer()), + summer(FilterModelConfig8580::getInstance()->getSummer()), + gain_res(FilterModelConfig8580::getInstance()->getGainRes()), + gain_vol(FilterModelConfig8580::getInstance()->getGainVol()), + voiceScaleS11(FilterModelConfig8580::getInstance()->getVoiceScaleS11()), + voiceDC(FilterModelConfig8580::getInstance()->getNormalizedVoiceDC()), + cp(0.5), + hpIntegrator(FilterModelConfig8580::getInstance()->buildIntegrator()), + bpIntegrator(FilterModelConfig8580::getInstance()->buildIntegrator()) + { + setFilterCurve(cp); + input(0); + } + + ~Filter8580(); + + unsigned short clock(int voice1, int voice2, int voice3) override; + + void input(int sample) override { ve = (sample * voiceScaleS11 * 3 >> 11) + mixer[0][0]; } + + /** + * Set filter curve type based on single parameter. + * + * @param curvePosition 0 .. 1, where 0 sets center frequency high ("light") and 1 sets it low ("dark"), default is 0.5 + */ + void setFilterCurve(double curvePosition); +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(FILTER8580_CPP) + +namespace reSIDfp +{ + +RESID_INLINE +unsigned short Filter8580::clock(int voice1, int voice2, int voice3) +{ + voice1 = (voice1 * voiceScaleS11 >> 15) + voiceDC; + voice2 = (voice2 * voiceScaleS11 >> 15) + voiceDC; + // Voice 3 is silenced by voice3off if it is not routed through the filter. + voice3 = (filt3 || !voice3off) ? (voice3 * voiceScaleS11 >> 15) + voiceDC : 0; + + int Vi = 0; + int Vo = 0; + + (filt1 ? Vi : Vo) += voice1; + (filt2 ? Vi : Vo) += voice2; + (filt3 ? Vi : Vo) += voice3; + (filtE ? Vi : Vo) += ve; + + Vhp = currentSummer[currentResonance[Vbp] + Vlp + Vi]; + Vbp = hpIntegrator->solve(Vhp); + Vlp = bpIntegrator->solve(Vbp); + + if (lp) Vo += Vlp; + if (bp) Vo += Vbp; + if (hp) Vo += Vhp; + + return currentGain[currentMixer[Vo]]; +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/FilterModelConfig.cpp b/src/engine/platform/sound/c64_fp/FilterModelConfig.cpp new file mode 100644 index 000000000..8fb762382 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/FilterModelConfig.cpp @@ -0,0 +1,79 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 "FilterModelConfig.h" + +#include + +namespace reSIDfp +{ + +FilterModelConfig::FilterModelConfig( + double vvr, + double vdv, + double c, + double vdd, + double vth, + double ucox, + const Spline::Point *opamp_voltage, + int opamp_size +) : + voice_voltage_range(vvr), + voice_DC_voltage(vdv), + C(c), + Vdd(vdd), + Vth(vth), + Ut(26.0e-3), + uCox(ucox), + Vddt(Vdd - Vth), + vmin(opamp_voltage[0].x), + vmax(std::max(Vddt, opamp_voltage[0].y)), + denorm(vmax - vmin), + norm(1.0 / denorm), + N16(norm * ((1 << 16) - 1)), + currFactorCoeff(denorm * (uCox / 2. * 1.0e-6 / C)) +{ + // Convert op-amp voltage transfer to 16 bit values. + + std::vector scaled_voltage(opamp_size); + + for (int i = 0; i < opamp_size; i++) + { + scaled_voltage[i].x = N16 * (opamp_voltage[i].x - opamp_voltage[i].y + denorm) / 2.; + scaled_voltage[i].y = N16 * (opamp_voltage[i].x - vmin); + } + + // Create lookup table mapping capacitor voltage to op-amp input voltage: + + Spline s(scaled_voltage); + + for (int x = 0; x < (1 << 16); x++) + { + const Spline::Point out = s.evaluate(x); + // If Vmax > max opamp_voltage the first elements may be negative + double tmp = out.x > 0. ? out.x : 0.; + assert(tmp < 65535.5); + opamp_rev[x] = static_cast(tmp + 0.5); + } +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/FilterModelConfig.h b/src/engine/platform/sound/c64_fp/FilterModelConfig.h new file mode 100644 index 000000000..d8ae77ab8 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/FilterModelConfig.h @@ -0,0 +1,166 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 FILTERMODELCONFIG_H +#define FILTERMODELCONFIG_H + +#include +#include + +#include "Spline.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +class FilterModelConfig +{ +protected: + const double voice_voltage_range; + const double voice_DC_voltage; + + /// Capacitor value. + const double C; + + /// Transistor parameters. + //@{ + const double Vdd; + const double Vth; ///< Threshold voltage + const double Ut; ///< Thermal voltage: Ut = kT/q = 8.61734315e-5*T ~ 26mV + const double uCox; ///< Transconductance coefficient: u*Cox + const double Vddt; ///< Vdd - Vth + //@} + + // Derived stuff + const double vmin, vmax; + const double denorm, norm; + + /// Fixed point scaling for 16 bit op-amp output. + const double N16; + + /// Current factor coefficient for op-amp integrators. + const double currFactorCoeff; + + /// Lookup tables for gain and summer op-amps in output stage / filter. + //@{ + unsigned short* mixer[8]; //-V730_NOINIT this is initialized in the derived class constructor + unsigned short* summer[5]; //-V730_NOINIT this is initialized in the derived class constructor + unsigned short* gain_vol[16]; //-V730_NOINIT this is initialized in the derived class constructor + unsigned short* gain_res[16]; //-V730_NOINIT this is initialized in the derived class constructor + //@} + + /// Reverse op-amp transfer function. + unsigned short opamp_rev[1 << 16]; //-V730_NOINIT this is initialized in the derived class constructor + +private: + FilterModelConfig (const FilterModelConfig&) DELETE; + FilterModelConfig& operator= (const FilterModelConfig&) DELETE; + +protected: + /** + * @param vvr voice voltage range + * @param vdv voice DC voltage + * @param c capacitor value + * @param vdd Vdd + * @param vth threshold voltage + * @param ucox u*Cox + * @param ominv opamp min voltage + * @param omaxv opamp max voltage + */ + FilterModelConfig( + double vvr, + double vdv, + double c, + double vdd, + double vth, + double ucox, + const Spline::Point *opamp_voltage, + int opamp_size + ); + + ~FilterModelConfig() + { + for (int i = 0; i < 8; i++) + { + delete [] mixer[i]; + } + + for (int i = 0; i < 5; i++) + { + delete [] summer[i]; + } + + for (int i = 0; i < 16; i++) + { + delete [] gain_vol[i]; + delete [] gain_res[i]; + } + } + +public: + unsigned short** getGainVol() { return gain_vol; } + unsigned short** getGainRes() { return gain_res; } + unsigned short** getSummer() { return summer; } + unsigned short** getMixer() { return mixer; } + + /** + * The digital range of one voice is 20 bits; create a scaling term + * for multiplication which fits in 11 bits. + */ + int getVoiceScaleS11() const { return static_cast((norm * ((1 << 11) - 1)) * voice_voltage_range); } + + /** + * The "zero" output level of the voices. + */ + int getNormalizedVoiceDC() const { return static_cast(N16 * (voice_DC_voltage - vmin)); } + + inline unsigned short getOpampRev(int i) const { return opamp_rev[i]; } + inline double getVddt() const { return Vddt; } + inline double getVth() const { return Vth; } + inline double getVoiceDCVoltage() const { return voice_DC_voltage; } + + // helper functions + inline unsigned short getNormalizedValue(double value) const + { + const double tmp = N16 * (value - vmin); + assert(tmp > -0.5 && tmp < 65535.5); + return static_cast(tmp + 0.5); + } + + inline unsigned short getNormalizedCurrentFactor(double wl) const + { + const double tmp = (1 << 13) * currFactorCoeff * wl; + assert(tmp > -0.5 && tmp < 65535.5); + return static_cast(tmp + 0.5); + } + + inline unsigned short getNVmin() const { + const double tmp = N16 * vmin; + assert(tmp > -0.5 && tmp < 65535.5); + return static_cast(tmp + 0.5); + } +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/FilterModelConfig6581.cpp b/src/engine/platform/sound/c64_fp/FilterModelConfig6581.cpp new file mode 100644 index 000000000..3d86bdcf2 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/FilterModelConfig6581.cpp @@ -0,0 +1,263 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2010 Dag Lem + * + * 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 "FilterModelConfig6581.h" + +#include + +#include "Integrator6581.h" +#include "OpAmp.h" + +namespace reSIDfp +{ + +#ifndef HAVE_CXX11 +/** + * Compute log(1+x) without losing precision for small values of x + * + * @note when compiling with -ffastm-math the compiler will + * optimize the expression away leaving a plain log(1. + x) + */ +inline double log1p(double x) +{ + return log(1. + x) - (((1. + x) - 1.) - x) / (1. + x); +} +#endif + +const unsigned int OPAMP_SIZE = 33; + +/** + * This is the SID 6581 op-amp voltage transfer function, measured on + * CAP1B/CAP1A on a chip marked MOS 6581R4AR 0687 14. + * All measured chips have op-amps with output voltages (and thus input + * voltages) within the range of 0.81V - 10.31V. + */ +const Spline::Point opamp_voltage[OPAMP_SIZE] = +{ + { 0.81, 10.31 }, // Approximate start of actual range + { 2.40, 10.31 }, + { 2.60, 10.30 }, + { 2.70, 10.29 }, + { 2.80, 10.26 }, + { 2.90, 10.17 }, + { 3.00, 10.04 }, + { 3.10, 9.83 }, + { 3.20, 9.58 }, + { 3.30, 9.32 }, + { 3.50, 8.69 }, + { 3.70, 8.00 }, + { 4.00, 6.89 }, + { 4.40, 5.21 }, + { 4.54, 4.54 }, // Working point (vi = vo) + { 4.60, 4.19 }, + { 4.80, 3.00 }, + { 4.90, 2.30 }, // Change of curvature + { 4.95, 2.03 }, + { 5.00, 1.88 }, + { 5.05, 1.77 }, + { 5.10, 1.69 }, + { 5.20, 1.58 }, + { 5.40, 1.44 }, + { 5.60, 1.33 }, + { 5.80, 1.26 }, + { 6.00, 1.21 }, + { 6.40, 1.12 }, + { 7.00, 1.02 }, + { 7.50, 0.97 }, + { 8.50, 0.89 }, + { 10.00, 0.81 }, + { 10.31, 0.81 }, // Approximate end of actual range +}; + +std::unique_ptr FilterModelConfig6581::instance(nullptr); + +FilterModelConfig6581* FilterModelConfig6581::getInstance() +{ + if (!instance.get()) + { + instance.reset(new FilterModelConfig6581()); + } + + return instance.get(); +} + +FilterModelConfig6581::FilterModelConfig6581() : + FilterModelConfig( + 1.5, // voice voltage range + 5.075, // voice DC voltage + 470e-12, // capacitor value + 12.18, // Vdd + 1.31, // Vth + 20e-6, // uCox + opamp_voltage, + OPAMP_SIZE + ), + WL_vcr(9.0 / 1.0), + WL_snake(1.0 / 115.0), + dac_zero(6.65), + dac_scale(2.63), + dac(DAC_BITS) +{ + dac.kinkedDac(MOS6581); + + // Create lookup tables for gains / summers. + + OpAmp opampModel(std::vector(std::begin(opamp_voltage), std::end(opamp_voltage)), Vddt); + + // The filter summer operates at n ~ 1, and has 5 fundamentally different + // input configurations (2 - 6 input "resistors"). + // + // Note that all "on" transistors are modeled as one. This is not + // entirely accurate, since the input for each transistor is different, + // and transistors are not linear components. However modeling all + // transistors separately would be extremely costly. + for (int i = 0; i < 5; i++) + { + const int idiv = 2 + i; // 2 - 6 input "resistors". + const int size = idiv << 16; + const double n = idiv; + opampModel.reset(); + summer[i] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16 / idiv; /* vmin .. vmax */ + summer[i][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + // The audio mixer operates at n ~ 8/6, and has 8 fundamentally different + // input configurations (0 - 7 input "resistors"). + // + // All "on", transistors are modeled as one - see comments above for + // the filter summer. + for (int i = 0; i < 8; i++) + { + const int idiv = (i == 0) ? 1 : i; + const int size = (i == 0) ? 1 : i << 16; + const double n = i * 8.0 / 6.0; + opampModel.reset(); + mixer[i] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16 / idiv; /* vmin .. vmax */ + mixer[i][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + // 4 bit "resistor" ladders in the audio + // output gain necessitate 16 gain tables. + // From die photographs of the bandpass and volume "resistor" ladders + // it follows that gain ~ vol/12 (assuming ideal + // op-amps and ideal "resistors"). + for (int n8 = 0; n8 < 16; n8++) + { + const int size = 1 << 16; + const double n = n8 / 12.0; + opampModel.reset(); + gain_vol[n8] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16; /* vmin .. vmax */ + gain_vol[n8][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + // 4 bit "resistor" ladders in the bandpass resonance gain + // necessitate 16 gain tables. + // From die photographs of the bandpass and volume "resistor" ladders + // it follows that 1/Q ~ ~res/8 (assuming ideal + // op-amps and ideal "resistors"). + for (int n8 = 0; n8 < 16; n8++) + { + const int size = 1 << 16; + const double n = (~n8 & 0xf) / 8.0; + opampModel.reset(); + gain_res[n8] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16; /* vmin .. vmax */ + gain_res[n8][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + const double nVddt = N16 * (Vddt - vmin); + + for (unsigned int i = 0; i < (1 << 16); i++) + { + // The table index is right-shifted 16 times in order to fit in + // 16 bits; the argument to sqrt is thus multiplied by (1 << 16). + const double tmp = nVddt - sqrt(static_cast(i << 16)); + assert(tmp > -0.5 && tmp < 65535.5); + vcr_nVg[i] = static_cast(tmp + 0.5); + } + + // EKV model: + // + // Ids = Is * (if - ir) + // Is = (2 * u*Cox * Ut^2)/k * W/L + // if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut)) + // ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut)) + + // moderate inversion characteristic current + const double Is = (2. * uCox * Ut * Ut) * WL_vcr; + + // Normalized current factor for 1 cycle at 1MHz. + const double N15 = norm * ((1 << 15) - 1); + const double n_Is = N15 * 1.0e-6 / C * Is; + + // kVgt_Vx = k*(Vg - Vt) - Vx + // I.e. if k != 1.0, Vg must be scaled accordingly. + for (int kVgt_Vx = 0; kVgt_Vx < (1 << 16); kVgt_Vx++) + { + const double log_term = log1p(exp((kVgt_Vx / N16) / (2. * Ut))); + // Scaled by m*2^15 + const double tmp = n_Is * log_term * log_term; + assert(tmp > -0.5 && tmp < 65535.5); + vcr_n_Ids_term[kVgt_Vx] = static_cast(tmp + 0.5); + } +} + +unsigned short* FilterModelConfig6581::getDAC(double adjustment) const +{ + const double dac_zero = getDacZero(adjustment); + + unsigned short* f0_dac = new unsigned short[1 << DAC_BITS]; + + for (unsigned int i = 0; i < (1 << DAC_BITS); i++) + { + const double fcd = dac.getOutput(i); + f0_dac[i] = getNormalizedValue(dac_zero + fcd * dac_scale / (1 << DAC_BITS)); + } + + return f0_dac; +} + +std::unique_ptr FilterModelConfig6581::buildIntegrator() +{ + return MAKE_UNIQUE(Integrator6581, this, WL_snake); +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/FilterModelConfig6581.h b/src/engine/platform/sound/c64_fp/FilterModelConfig6581.h new file mode 100644 index 000000000..85cbd43fb --- /dev/null +++ b/src/engine/platform/sound/c64_fp/FilterModelConfig6581.h @@ -0,0 +1,112 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 FILTERMODELCONFIG6581_H +#define FILTERMODELCONFIG6581_H + +#include "FilterModelConfig.h" + +#include + +#include "Dac.h" + +#include "sidcxx14.h" + +namespace reSIDfp +{ + +class Integrator6581; + +/** + * Calculate parameters for 6581 filter emulation. + */ +class FilterModelConfig6581 final : public FilterModelConfig +{ +private: + static const unsigned int DAC_BITS = 11; + +private: + static std::unique_ptr instance; + // This allows access to the private constructor +#ifdef HAVE_CXX11 + friend std::unique_ptr::deleter_type; +#else + friend class std::auto_ptr; +#endif + + /// Transistor parameters. + //@{ + const double WL_vcr; ///< W/L for VCR + const double WL_snake; ///< W/L for "snake" + //@} + + /// DAC parameters. + //@{ + const double dac_zero; + const double dac_scale; + //@} + + /// DAC lookup table + Dac dac; + + /// VCR - 6581 only. + //@{ + unsigned short vcr_nVg[1 << 16]; + unsigned short vcr_n_Ids_term[1 << 16]; + //@} + +private: + double getDacZero(double adjustment) const { return dac_zero + (1. - adjustment); } + + FilterModelConfig6581(); + ~FilterModelConfig6581() DEFAULT; + +public: + static FilterModelConfig6581* getInstance(); + + /** + * Construct an 11 bit cutoff frequency DAC output voltage table. + * Ownership is transferred to the requester which becomes responsible + * of freeing the object when done. + * + * @param adjustment + * @return the DAC table + */ + unsigned short* getDAC(double adjustment) const; + + /** + * Construct an integrator solver. + * + * @return the integrator + */ + std::unique_ptr buildIntegrator(); + + inline unsigned short getVcr_nVg(int i) const { return vcr_nVg[i]; } + inline unsigned short getVcr_n_Ids_term(int i) const { return vcr_n_Ids_term[i]; } + // only used if SLOPE_FACTOR is defined + inline double getUt() const { return Ut; } + inline double getN16() const { return N16; } +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/FilterModelConfig8580.cpp b/src/engine/platform/sound/c64_fp/FilterModelConfig8580.cpp new file mode 100644 index 000000000..fd2a16fab --- /dev/null +++ b/src/engine/platform/sound/c64_fp/FilterModelConfig8580.cpp @@ -0,0 +1,222 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2010 Dag Lem + * + * 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 "FilterModelConfig8580.h" + +#include "Integrator8580.h" +#include "OpAmp.h" + +namespace reSIDfp +{ + +/* + * R1 = 15.3*Ri + * R2 = 7.3*Ri + * R3 = 4.7*Ri + * Rf = 1.4*Ri + * R4 = 1.4*Ri + * R8 = 2.0*Ri + * RC = 2.8*Ri + * + * res feedback input + * --- -------- ----- + * 0 Rf Ri + * 1 Rf|R1 Ri + * 2 Rf|R2 Ri + * 3 Rf|R3 Ri + * 4 Rf R4 + * 5 Rf|R1 R4 + * 6 Rf|R2 R4 + * 7 Rf|R3 R4 + * 8 Rf R8 + * 9 Rf|R1 R8 + * A Rf|R2 R8 + * B Rf|R3 R8 + * C Rf RC + * D Rf|R1 RC + * E Rf|R2 RC + * F Rf|R3 RC + */ +const double resGain[16] = +{ + 1.4/1.0, // Rf/Ri 1.4 + ((1.4*15.3)/(1.4+15.3))/1.0, // (Rf|R1)/Ri 1.28263 + ((1.4*7.3)/(1.4+7.3))/1.0, // (Rf|R2)/Ri 1.17471 + ((1.4*4.7)/(1.4+4.7))/1.0, // (Rf|R3)/Ri 1.07869 + 1.4/1.4, // Rf/R4 1 + ((1.4*15.3)/(1.4+15.3))/1.4, // (Rf|R1)/R4 0.916168 + ((1.4*7.3)/(1.4+7.3))/1.4, // (Rf|R2)/R4 0.83908 + ((1.4*4.7)/(1.4+4.7))/1.4, // (Rf|R3)/R4 0.770492 + 1.4/2.0, // Rf/R8 0.7 + ((1.4*15.3)/(1.4+15.3))/2.0, // (Rf|R1)/R8 0.641317 + ((1.4*7.3)/(1.4+7.3))/2.0, // (Rf|R2)/R8 0.587356 + ((1.4*4.7)/(1.4+4.7))/2.0, // (Rf|R3)/R8 0.539344 + 1.4/2.8, // Rf/RC 0.5 + ((1.4*15.3)/(1.4+15.3))/2.8, // (Rf|R1)/RC 0.458084 + ((1.4*7.3)/(1.4+7.3))/2.8, // (Rf|R2)/RC 0.41954 + ((1.4*4.7)/(1.4+4.7))/2.8, // (Rf|R3)/RC 0.385246 +}; + +const unsigned int OPAMP_SIZE = 21; + +/** + * This is the SID 8580 op-amp voltage transfer function, measured on + * CAP1B/CAP1A on a chip marked CSG 8580R5 1690 25. + */ +const Spline::Point opamp_voltage[OPAMP_SIZE] = +{ + { 1.30, 8.91 }, // Approximate start of actual range + { 4.76, 8.91 }, + { 4.77, 8.90 }, + { 4.78, 8.88 }, + { 4.785, 8.86 }, + { 4.79, 8.80 }, + { 4.795, 8.60 }, + { 4.80, 8.25 }, + { 4.805, 7.50 }, + { 4.81, 6.10 }, + { 4.815, 4.05 }, // Change of curvature + { 4.82, 2.27 }, + { 4.825, 1.65 }, + { 4.83, 1.55 }, + { 4.84, 1.47 }, + { 4.85, 1.43 }, + { 4.87, 1.37 }, + { 4.90, 1.34 }, + { 5.00, 1.30 }, + { 5.10, 1.30 }, + { 8.91, 1.30 }, // Approximate end of actual range +}; + +std::unique_ptr FilterModelConfig8580::instance(nullptr); + +FilterModelConfig8580* FilterModelConfig8580::getInstance() +{ + if (!instance.get()) + { + instance.reset(new FilterModelConfig8580()); + } + + return instance.get(); +} + +FilterModelConfig8580::FilterModelConfig8580() : + FilterModelConfig( + 0.25, // voice voltage range FIXME measure + 4.80, // voice DC voltage FIXME was 4.76 + 22e-9, // capacitor value + 9.09, // Vdd + 0.80, // Vth + 100e-6, // uCox + opamp_voltage, + OPAMP_SIZE + ) +{ + // Create lookup tables for gains / summers. + + OpAmp opampModel(std::vector(std::begin(opamp_voltage), std::end(opamp_voltage)), Vddt); + + // The filter summer operates at n ~ 1, and has 5 fundamentally different + // input configurations (2 - 6 input "resistors"). + // + // Note that all "on" transistors are modeled as one. This is not + // entirely accurate, since the input for each transistor is different, + // and transistors are not linear components. However modeling all + // transistors separately would be extremely costly. + for (int i = 0; i < 5; i++) + { + const int idiv = 2 + i; // 2 - 6 input "resistors". + const int size = idiv << 16; + const double n = idiv; + opampModel.reset(); + summer[i] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16 / idiv; /* vmin .. vmax */ + summer[i][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + // The audio mixer operates at n ~ 8/5, and has 8 fundamentally different + // input configurations (0 - 7 input "resistors"). + // + // All "on", transistors are modeled as one - see comments above for + // the filter summer. + for (int i = 0; i < 8; i++) + { + const int idiv = (i == 0) ? 1 : i; + const int size = (i == 0) ? 1 : i << 16; + const double n = i * 8.0 / 5.0; + opampModel.reset(); + mixer[i] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16 / idiv; /* vmin .. vmax */ + mixer[i][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + // 4 bit "resistor" ladders in the audio output gain + // necessitate 16 gain tables. + // From die photographs of the volume "resistor" ladders + // it follows that gain ~ vol/16 (assuming ideal op-amps + for (int n8 = 0; n8 < 16; n8++) + { + const int size = 1 << 16; + const double n = n8 / 16.0; + opampModel.reset(); + gain_vol[n8] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16; /* vmin .. vmax */ + gain_vol[n8][vi] = getNormalizedValue(opampModel.solve(n, vin)); + } + } + + // 4 bit "resistor" ladders in the bandpass resonance gain + // necessitate 16 gain tables. + // From die photographs of the bandpass and volume "resistor" ladders + // it follows that 1/Q ~ 2^((4 - res)/8) (assuming ideal + // op-amps and ideal "resistors"). + for (int n8 = 0; n8 < 16; n8++) + { + const int size = 1 << 16; + opampModel.reset(); + gain_res[n8] = new unsigned short[size]; + + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi / N16; /* vmin .. vmax */ + gain_res[n8][vi] = getNormalizedValue(opampModel.solve(resGain[n8], vin)); + } + } +} + +std::unique_ptr FilterModelConfig8580::buildIntegrator() +{ + return MAKE_UNIQUE(Integrator8580, this); +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/FilterModelConfig8580.h b/src/engine/platform/sound/c64_fp/FilterModelConfig8580.h new file mode 100644 index 000000000..ee2b40087 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/FilterModelConfig8580.h @@ -0,0 +1,68 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 FILTERMODELCONFIG8580_H +#define FILTERMODELCONFIG8580_H + +#include "FilterModelConfig.h" + +#include + +#include "sidcxx14.h" + +namespace reSIDfp +{ + +class Integrator8580; + +/** + * Calculate parameters for 8580 filter emulation. + */ +class FilterModelConfig8580 final : public FilterModelConfig +{ +private: + static std::unique_ptr instance; + // This allows access to the private constructor +#ifdef HAVE_CXX11 + friend std::unique_ptr::deleter_type; +#else + friend class std::auto_ptr; +#endif + +private: + FilterModelConfig8580(); + ~FilterModelConfig8580() DEFAULT; + +public: + static FilterModelConfig8580* getInstance(); + + /** + * Construct an integrator solver. + * + * @return the integrator + */ + std::unique_ptr buildIntegrator(); +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/Integrator6581.cpp b/src/engine/platform/sound/c64_fp/Integrator6581.cpp new file mode 100644 index 000000000..490be9b5c --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Integrator6581.cpp @@ -0,0 +1,25 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2014 Leandro Nini + * + * 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. + */ + +#define INTEGRATOR_CPP + +#include "Integrator6581.h" + +// This is needed when compiling with --disable-inline diff --git a/src/engine/platform/sound/c64_fp/Integrator6581.h b/src/engine/platform/sound/c64_fp/Integrator6581.h new file mode 100644 index 000000000..99ac3bea6 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Integrator6581.h @@ -0,0 +1,285 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004, 2010 Dag Lem + * + * 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 INTEGRATOR6581_H +#define INTEGRATOR6581_H + +#include "FilterModelConfig6581.h" + +#include +#include + +// uncomment to enable use of the slope factor +// in the EKV model +// actually produces worse results, needs investigation +//#define SLOPE_FACTOR + +#ifdef SLOPE_FACTOR +# include +#endif + +#include "siddefs-fp.h" + +namespace reSIDfp +{ + +/** + * Find output voltage in inverting integrator SID op-amp circuits, using a + * single fixpoint iteration step. + * + * A circuit diagram of a MOS 6581 integrator is shown below. + * + * +---C---+ + * | | + * vi --o--Rw--o-o--[A>--o-- vo + * | | vx + * +--Rs--+ + * + * From Kirchoff's current law it follows that + * + * IRw + IRs + ICr = 0 + * + * Using the formula for current through a capacitor, i = C*dv/dt, we get + * + * IRw + IRs + C*(vc - vc0)/dt = 0 + * dt/C*(IRw + IRs) + vc - vc0 = 0 + * vc = vc0 - n*(IRw(vi,vx) + IRs(vi,vx)) + * + * which may be rewritten as the following iterative fixpoint function: + * + * vc = vc0 - n*(IRw(vi,g(vc)) + IRs(vi,g(vc))) + * + * To accurately calculate the currents through Rs and Rw, we need to use + * transistor models. Rs has a gate voltage of Vdd = 12V, and can be + * assumed to always be in triode mode. For Rw, the situation is rather + * more complex, as it turns out that this transistor will operate in + * both subthreshold, triode, and saturation modes. + * + * The Shichman-Hodges transistor model routinely used in textbooks may + * be written as follows: + * + * Ids = 0 , Vgst < 0 (subthreshold mode) + * Ids = K*W/L*(2*Vgst - Vds)*Vds , Vgst >= 0, Vds < Vgst (triode mode) + * Ids = K*W/L*Vgst^2 , Vgst >= 0, Vds >= Vgst (saturation mode) + * + * where + * K = u*Cox/2 (transconductance coefficient) + * W/L = ratio between substrate width and length + * Vgst = Vg - Vs - Vt (overdrive voltage) + * + * This transistor model is also called the quadratic model. + * + * Note that the equation for the triode mode can be reformulated as + * independent terms depending on Vgs and Vgd, respectively, by the + * following substitution: + * + * Vds = Vgst - (Vgst - Vds) = Vgst - Vgdt + * + * Ids = K*W/L*(2*Vgst - Vds)*Vds + * = K*W/L*(2*Vgst - (Vgst - Vgdt)*(Vgst - Vgdt) + * = K*W/L*(Vgst + Vgdt)*(Vgst - Vgdt) + * = K*W/L*(Vgst^2 - Vgdt^2) + * + * This turns out to be a general equation which covers both the triode + * and saturation modes (where the second term is 0 in saturation mode). + * The equation is also symmetrical, i.e. it can calculate negative + * currents without any change of parameters (since the terms for drain + * and source are identical except for the sign). + * + * FIXME: Subthreshold as function of Vgs, Vgd. + * + * Ids = I0*W/L*e^(Vgst/(Ut/k)) , Vgst < 0 (subthreshold mode) + * + * where + * I0 = (2 * uCox * Ut^2) / k + * + * The remaining problem with the textbook model is that the transition + * from subthreshold the triode/saturation is not continuous. + * + * Realizing that the subthreshold and triode/saturation modes may both + * be defined by independent (and equal) terms of Vgs and Vds, + * respectively, the corresponding terms can be blended into (equal) + * continuous functions suitable for table lookup. + * + * The EKV model (Enz, Krummenacher and Vittoz) essentially performs this + * blending using an elegant mathematical formulation: + * + * Ids = Is * (if - ir) + * Is = ((2 * u*Cox * Ut^2)/k) * W/L + * if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut)) + * ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut)) + * + * For our purposes, the EKV model preserves two important properties + * discussed above: + * + * - It consists of two independent terms, which can be represented by + * the same lookup table. + * - It is symmetrical, i.e. it calculates current in both directions, + * facilitating a branch-free implementation. + * + * Rw in the circuit diagram above is a VCR (voltage controlled resistor), + * as shown in the circuit diagram below. + * + * + * Vdd + * | + * Vdd _|_ + * | +---+ +---- Vw + * _|_ | + * +--+ +---o Vg + * | __|__ + * | ----- Rw + * | | | + * vi -----o------+ +-------- vo + * + * + * In order to calculalate the current through the VCR, its gate voltage + * must be determined. + * + * Assuming triode mode and applying Kirchoff's current law, we get the + * following equation for Vg: + * + * u*Cox/2*W/L*((nVddt - Vg)^2 - (nVddt - vi)^2 + (nVddt - Vg)^2 - (nVddt - Vw)^2) = 0 + * 2*(nVddt - Vg)^2 - (nVddt - vi)^2 - (nVddt - Vw)^2 = 0 + * (nVddt - Vg) = sqrt(((nVddt - vi)^2 + (nVddt - Vw)^2)/2) + * + * Vg = nVddt - sqrt(((nVddt - vi)^2 + (nVddt - Vw)^2)/2) + */ +class Integrator6581 +{ +private: + unsigned int nVddt_Vw_2; + mutable int vx; + mutable int vc; + +#ifdef SLOPE_FACTOR + // Slope factor n = 1/k + // where k is the gate coupling coefficient + // k = Cox/(Cox+Cdep) ~ 0.7 (depends on gate voltage) + mutable double n; +#endif + const unsigned short nVddt; + const unsigned short nVt; + const unsigned short nVmin; + const unsigned short nSnake; + + const FilterModelConfig6581* fmc; + +public: + Integrator6581(const FilterModelConfig6581* fmc, + double WL_snake) : + nVddt_Vw_2(0), + vx(0), + vc(0), +#ifdef SLOPE_FACTOR + n(1.4), +#endif + nVddt(fmc->getNormalizedValue(fmc->getVddt())), + nVt(fmc->getNormalizedValue(fmc->getVth())), + nVmin(fmc->getNVmin()), + nSnake(fmc->getNormalizedCurrentFactor(WL_snake)), + fmc(fmc) {} + + void setVw(unsigned short Vw) { nVddt_Vw_2 = ((nVddt - Vw) * (nVddt - Vw)) >> 1; } + + int solve(int vi) const; +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(INTEGRATOR_CPP) + +namespace reSIDfp +{ + +RESID_INLINE +int Integrator6581::solve(int vi) const +{ + // Make sure Vgst>0 so we're not in subthreshold mode + assert(vx < nVddt); + + // Check that transistor is actually in triode mode + // Vds < Vgs - Vth + assert(vi < nVddt); + + // "Snake" voltages for triode mode calculation. + const unsigned int Vgst = nVddt - vx; + const unsigned int Vgdt = nVddt - vi; + + const unsigned int Vgst_2 = Vgst * Vgst; + const unsigned int Vgdt_2 = Vgdt * Vgdt; + + // "Snake" current, scaled by (1/m)*2^13*m*2^16*m*2^16*2^-15 = m*2^30 + const int n_I_snake = nSnake * (static_cast(Vgst_2 - Vgdt_2) >> 15); + + // VCR gate voltage. // Scaled by m*2^16 + // Vg = Vddt - sqrt(((Vddt - Vw)^2 + Vgdt^2)/2) + const int nVg = static_cast(fmc->getVcr_nVg((nVddt_Vw_2 + (Vgdt_2 >> 1)) >> 16)); +#ifdef SLOPE_FACTOR + const double nVp = static_cast(nVg - nVt) / n; // Pinch-off voltage + const int kVg = static_cast(nVp + 0.5) - nVmin; +#else + const int kVg = (nVg - nVt) - nVmin; +#endif + + // VCR voltages for EKV model table lookup. + const int kVgt_Vs = (vx < kVg) ? kVg - vx : 0; + assert(kVgt_Vs < (1 << 16)); + const int kVgt_Vd = (vi < kVg) ? kVg - vi : 0; + assert(kVgt_Vd < (1 << 16)); + + // VCR current, scaled by m*2^15*2^15 = m*2^30 + const unsigned int If = static_cast(fmc->getVcr_n_Ids_term(kVgt_Vs)) << 15; + const unsigned int Ir = static_cast(fmc->getVcr_n_Ids_term(kVgt_Vd)) << 15; +#ifdef SLOPE_FACTOR + const double iVcr = static_cast(If - Ir); + const int n_I_vcr = static_cast((iVcr * n) + 0.5); +#else + const int n_I_vcr = If - Ir; +#endif + +#ifdef SLOPE_FACTOR + // estimate new slope factor based on gate voltage + const double gamma = 1.0; // body effect factor + const double phi = 0.8; // bulk Fermi potential + const double Vp = nVp / fmc->getN16(); + n = 1. + (gamma / (2. * sqrt(Vp + phi + 4. * fmc->getUt()))); + assert((n > 1.2) && (n < 1.8)); +#endif + + // Change in capacitor charge. + vc += n_I_snake + n_I_vcr; + + // vx = g(vc) + const int tmp = (vc >> 15) + (1 << 15); + assert(tmp < (1 << 16)); + vx = fmc->getOpampRev(tmp); + + // Return vo. + return vx - (vc >> 14); +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/Integrator8580.cpp b/src/engine/platform/sound/c64_fp/Integrator8580.cpp new file mode 100644 index 000000000..6fba9521b --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Integrator8580.cpp @@ -0,0 +1,25 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2014-2016 Leandro Nini + * + * 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. + */ + +#define INTEGRATOR8580_CPP + +#include "Integrator8580.h" + +// This is needed when compiling with --disable-inline diff --git a/src/engine/platform/sound/c64_fp/Integrator8580.h b/src/engine/platform/sound/c64_fp/Integrator8580.h new file mode 100644 index 000000000..7137e9407 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Integrator8580.h @@ -0,0 +1,142 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004, 2010 Dag Lem + * + * 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 INTEGRATOR8580_H +#define INTEGRATOR8580_H + +#include "FilterModelConfig8580.h" + +#include +#include + +#include "siddefs-fp.h" + +namespace reSIDfp +{ + +/** + * 8580 integrator + * + * +---C---+ + * | | + * vi -----Rfc---o--[A>--o-- vo + * vx + * + * IRfc + ICr = 0 + * IRfc + C*(vc - vc0)/dt = 0 + * dt/C*(IRfc) + vc - vc0 = 0 + * vc = vc0 - n*(IRfc(vi,vx)) + * vc = vc0 - n*(IRfc(vi,g(vc))) + * + * IRfc = K*W/L*(Vgst^2 - Vgdt^2) = n*((Vddt - vx)^2 - (Vddt - vi)^2) + * + * Rfc gate voltage is generated by an OP Amp and depends on chip temperature. + */ +class Integrator8580 +{ +private: + mutable int vx; + mutable int vc; + + unsigned short nVgt; + unsigned short n_dac; + + const FilterModelConfig8580* fmc; + +public: + Integrator8580(const FilterModelConfig8580* fmc) : + vx(0), + vc(0), + fmc(fmc) + { + setV(1.5); + } + + /** + * Set Filter Cutoff resistor ratio. + */ + void setFc(double wl) + { + // Normalized current factor, 1 cycle at 1MHz. + // Fit in 5 bits. + n_dac = fmc->getNormalizedCurrentFactor(wl); + } + + /** + * Set FC gate voltage multiplier. + */ + void setV(double v) + { + // Gate voltage is controlled by the switched capacitor voltage divider + // Ua = Ue * v = 4.76v 1 1.0 && v < 2.0); + const double Vg = fmc->getVoiceDCVoltage() * v; + const double Vgt = Vg - fmc->getVth(); + + // Vg - Vth, normalized so that translated values can be subtracted: + // Vgt - x = (Vgt - t) - (x - t) + nVgt = fmc->getNormalizedValue(Vgt); + } + + int solve(int vi) const; +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(INTEGRATOR8580_CPP) + +namespace reSIDfp +{ + +RESID_INLINE +int Integrator8580::solve(int vi) const +{ + // Make sure we're not in subthreshold mode + assert(vx < nVgt); + + // DAC voltages + const unsigned int Vgst = nVgt - vx; + const unsigned int Vgdt = (vi < nVgt) ? nVgt - vi : 0; // triode/saturation mode + + const unsigned int Vgst_2 = Vgst * Vgst; + const unsigned int Vgdt_2 = Vgdt * Vgdt; + + // DAC current, scaled by (1/m)*2^13*m*2^16*m*2^16*2^-15 = m*2^30 + const int n_I_dac = n_dac * (static_cast(Vgst_2 - Vgdt_2) >> 15); + + // Change in capacitor charge. + vc += n_I_dac; + + // vx = g(vc) + const int tmp = (vc >> 15) + (1 << 15); + assert(tmp < (1 << 16)); + vx = fmc->getOpampRev(tmp); + + // Return vo. + return vx - (vc >> 14); +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/OpAmp.cpp b/src/engine/platform/sound/c64_fp/OpAmp.cpp new file mode 100644 index 000000000..b26b2efcb --- /dev/null +++ b/src/engine/platform/sound/c64_fp/OpAmp.cpp @@ -0,0 +1,84 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2015 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 "OpAmp.h" + +#include + +#include "siddefs-fp.h" + +namespace reSIDfp +{ + +const double EPSILON = 1e-8; + +double OpAmp::solve(double n, double vi) const +{ + // Start off with an estimate of x and a root bracket [ak, bk]. + // f is decreasing, so that f(ak) > 0 and f(bk) < 0. + double ak = vmin; + double bk = vmax; + + const double a = n + 1.; + const double b = Vddt; + const double b_vi = (b > vi) ? (b - vi) : 0.; + const double c = n * (b_vi * b_vi); + + for (;;) + { + const double xk = x; + + // Calculate f and df. + + Spline::Point out = opamp->evaluate(x); + const double vo = out.x; + const double dvo = out.y; + + const double b_vx = (b > x) ? b - x : 0.; + const double b_vo = (b > vo) ? b - vo : 0.; + + // f = a*(b - vx)^2 - c - (b - vo)^2 + const double f = a * (b_vx * b_vx) - c - (b_vo * b_vo); + + // df = 2*((b - vo)*dvo - a*(b - vx)) + const double df = 2. * (b_vo * dvo - a * b_vx); + + // Newton-Raphson step: xk1 = xk - f(xk)/f'(xk) + x -= f / df; + + if (unlikely(fabs(x - xk) < EPSILON)) + { + out = opamp->evaluate(x); + return out.x; + } + + // Narrow down root bracket. + (f < 0. ? bk : ak) = xk; + + if (unlikely(x <= ak) || unlikely(x >= bk)) + { + // Bisection step (ala Dekker's method). + x = (ak + bk) * 0.5; + } + } +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/OpAmp.h b/src/engine/platform/sound/c64_fp/OpAmp.h new file mode 100644 index 000000000..9d2c8f162 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/OpAmp.h @@ -0,0 +1,113 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2015 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 OPAMP_H +#define OPAMP_H + +#include +#include + +#include "Spline.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +/** + * Find output voltage in inverting gain and inverting summer SID op-amp + * circuits, using a combination of Newton-Raphson and bisection. + * + * +---R2--+ + * | | + * vi ---R1--o--[A>--o-- vo + * vx + * + * From Kirchoff's current law it follows that + * + * IR1f + IR2r = 0 + * + * Substituting the triode mode transistor model K*W/L*(Vgst^2 - Vgdt^2) + * for the currents, we get: + * + * n*((Vddt - vx)^2 - (Vddt - vi)^2) + (Vddt - vx)^2 - (Vddt - vo)^2 = 0 + * + * Our root function f can thus be written as: + * + * f = (n + 1)*(Vddt - vx)^2 - n*(Vddt - vi)^2 - (Vddt - vo)^2 = 0 + * + * Using substitution constants + * + * a = n + 1 + * b = Vddt + * c = n*(Vddt - vi)^2 + * + * the equations for the root function and its derivative can be written as: + * + * f = a*(b - vx)^2 - c - (b - vo)^2 + * df = 2*((b - vo)*dvo - a*(b - vx)) + */ +class OpAmp +{ +private: + /// Current root position (cached as guess to speed up next iteration) + mutable double x; + + const double Vddt; + const double vmin; + const double vmax; + + std::unique_ptr const opamp; + +public: + /** + * Opamp input -> output voltage conversion + * + * @param opamp opamp mapping table as pairs of points (in -> out) + * @param opamplength length of the opamp array + * @param kVddt transistor dt parameter (in volts) + */ + OpAmp(const std::vector &opamp, double Vddt) : + x(0.), + Vddt(Vddt), + vmin(opamp.front().x), + vmax(opamp.back().x), + opamp(new Spline(opamp)) {} + + void reset() const + { + x = vmin; + } + + /** + * Solve the opamp equation for input vi in loading context n + * + * @param n the ratio of input/output loading + * @param vi input + * @return vo + */ + double solve(double n, double vi) const; +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/Potentiometer.h b/src/engine/platform/sound/c64_fp/Potentiometer.h new file mode 100644 index 000000000..8b63df130 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Potentiometer.h @@ -0,0 +1,50 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2013 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright (C) 2004 Dag Lem + * + * 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 POTENTIOMETER_H +#define POTENTIOMETER_H + +namespace reSIDfp +{ + +/** + * Potentiometer representation. + * + * This class will probably never be implemented in any real way. + * + * @author Ken Händel + * @author Dag Lem + */ +class Potentiometer +{ +public: + /** + * Read paddle value. Not modeled. + * + * @return paddle value (always 0xff) + */ + unsigned char readPOT() const { return 0xff; } +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/README b/src/engine/platform/sound/c64_fp/README new file mode 100644 index 000000000..45d4bfb92 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/README @@ -0,0 +1,20 @@ +reSIDfp is a fork of Dag Lem's reSID 0.16, a reverse engineered software emulation +of the MOS6581/8580 SID (Sound Interface Device). + +The project was started by Antti S. Lankila in order to improve SID emulation +with special focus on the 6581 filter. +The codebase has been later on ported to java by Ken Händel within the jsidplay2 project +and has seen further work by Antti Lankila. +It was then ported back to c++ and integrated with improvements from reSID 1.0 by Leandro Nini. + + +Main differences from reSID: + +* combined waveforms are emulated by a parametrized model based on samplings from Kevtris; +* envelope generator is implemented like in the real machine with a shift register; +* high quality resampling is done in two steps to allow computational savings using lower order filters; +* part of the calculations are done with floats instead of fixed point; +* interpolation is accomplished with Fritsch-Carlson method to preserve monotonicity. + + +reSIDfp is free software. See the file COPYING for copying permission. diff --git a/src/engine/platform/sound/c64_fp/SID.cpp b/src/engine/platform/sound/c64_fp/SID.cpp new file mode 100644 index 000000000..a996d2230 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/SID.cpp @@ -0,0 +1,504 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2016 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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. + */ + +#define SID_CPP + +#include "SID.h" + +#include + +#include "array.h" +#include "Dac.h" +#include "Filter6581.h" +#include "Filter8580.h" +#include "Potentiometer.h" +#include "WaveformCalculator.h" +#include "resample/TwoPassSincResampler.h" +#include "resample/ZeroOrderResampler.h" + +namespace reSIDfp +{ + +const unsigned int ENV_DAC_BITS = 8; +const unsigned int OSC_DAC_BITS = 12; + +/** + * The waveform D/A converter introduces a DC offset in the signal + * to the envelope multiplying D/A converter. The "zero" level of + * the waveform D/A converter can be found as follows: + * + * Measure the "zero" voltage of voice 3 on the SID audio output + * pin, routing only voice 3 to the mixer ($d417 = $0b, $d418 = + * $0f, all other registers zeroed). + * + * Then set the sustain level for voice 3 to maximum and search for + * the waveform output value yielding the same voltage as found + * above. This is done by trying out different waveform output + * values until the correct value is found, e.g. with the following + * program: + * + * lda #$08 + * sta $d412 + * lda #$0b + * sta $d417 + * lda #$0f + * sta $d418 + * lda #$f0 + * sta $d414 + * lda #$21 + * sta $d412 + * lda #$01 + * sta $d40e + * + * ldx #$00 + * lda #$38 ; Tweak this to find the "zero" level + *l cmp $d41b + * bne l + * stx $d40e ; Stop frequency counter - freeze waveform output + * brk + * + * The waveform output range is 0x000 to 0xfff, so the "zero" + * level should ideally have been 0x800. In the measured chip, the + * waveform output "zero" level was found to be 0x380 (i.e. $d41b + * = 0x38) at an audio output voltage of 5.94V. + * + * With knowledge of the mixer op-amp characteristics, further estimates + * of waveform voltages can be obtained by sampling the EXT IN pin. + * From EXT IN samples, the corresponding waveform output can be found by + * using the model for the mixer. + * + * Such measurements have been done on a chip marked MOS 6581R4AR + * 0687 14, and the following results have been obtained: + * * The full range of one voice is approximately 1.5V. + * * The "zero" level rides at approximately 5.0V. + * + * + * zero-x did the measuring on the 8580 (https://sourceforge.net/p/vice-emu/bugs/1036/#c5b3): + * When it sits on basic from powerup it's at 4.72 + * Run 1.prg and check the output pin level. + * Then run 2.prg andadjust it until the output level is the same... + * 0x94-0xA8 gives me the same 4.72 1.prg shows. + * On another 8580 it's 0x90-0x9C + * Third chip 0x94-0xA8 + * Fourth chip 0x90-0xA4 + * On the 8580 that plays digis the output is 4.66 and 0x93 is the only value to reach that. + * To me that seems as regular 8580s have somewhat wide 0-level range, + * whereas that digi-compatible 8580 has it very narrow. + * On my 6581R4AR has 0x3A as the only value giving the same output level as 1.prg + */ +//@{ +unsigned int constexpr OFFSET_6581 = 0x380; +unsigned int constexpr OFFSET_8580 = 0x9c0; +//@} + +/** + * Bus value stays alive for some time after each operation. + * Values differs between chip models, the timings used here + * are taken from VICE [1]. + * See also the discussion "How do I reliably detect 6581/8580 sid?" on CSDb [2]. + * + * Results from real C64 (testprogs/SID/bitfade/delayfrq0.prg): + * + * (new SID) (250469/8580R5) (250469/8580R5) + * delayfrq0 ~7a000 ~108000 + * + * (old SID) (250407/6581) + * delayfrq0 ~01d00 + * + * [1]: http://sourceforge.net/p/vice-emu/patches/99/ + * [2]: http://noname.c64.org/csdb/forums/?roomid=11&topicid=29025&showallposts=1 + */ +//@{ +int constexpr BUS_TTL_6581 = 0x01d00; +int constexpr BUS_TTL_8580 = 0xa2000; +//@} + +SID::SID() : + filter6581(new Filter6581()), + filter8580(new Filter8580()), + externalFilter(new ExternalFilter()), + resampler(nullptr), + potX(new Potentiometer()), + potY(new Potentiometer()) +{ + voice[0].reset(new Voice()); + voice[1].reset(new Voice()); + voice[2].reset(new Voice()); + + muted[0] = muted[1] = muted[2] = false; + + reset(); + setChipModel(MOS8580); +} + +SID::~SID() +{ + // Needed to delete auto_ptr with complete type +} + +void SID::setFilter6581Curve(double filterCurve) +{ + filter6581->setFilterCurve(filterCurve); +} + +void SID::setFilter8580Curve(double filterCurve) +{ + filter8580->setFilterCurve(filterCurve); +} + +void SID::enableFilter(bool enable) +{ + filter6581->enable(enable); + filter8580->enable(enable); +} + +void SID::voiceSync(bool sync) +{ + if (sync) + { + // Synchronize the 3 waveform generators. + for (int i = 0; i < 3; i++) + { + voice[i]->wave()->synchronize(voice[(i + 1) % 3]->wave(), voice[(i + 2) % 3]->wave()); + } + } + + // Calculate the time to next voice sync + nextVoiceSync = std::numeric_limits::max(); + + for (int i = 0; i < 3; i++) + { + WaveformGenerator* const wave = voice[i]->wave(); + const unsigned int freq = wave->readFreq(); + + if (wave->readTest() || freq == 0 || !voice[(i + 1) % 3]->wave()->readSync()) + { + continue; + } + + const unsigned int accumulator = wave->readAccumulator(); + const unsigned int thisVoiceSync = ((0x7fffff - accumulator) & 0xffffff) / freq + 1; + + if (thisVoiceSync < nextVoiceSync) + { + nextVoiceSync = thisVoiceSync; + } + } +} + +void SID::setChipModel(ChipModel model) +{ + switch (model) + { + case MOS6581: + filter = filter6581.get(); + modelTTL = BUS_TTL_6581; + break; + + case MOS8580: + filter = filter8580.get(); + modelTTL = BUS_TTL_8580; + break; + + default: + throw SIDError("Unknown chip type"); + } + + this->model = model; + + // calculate waveform-related tables + matrix_t* tables = WaveformCalculator::getInstance()->buildTable(model); + + // calculate envelope DAC table + { + Dac dacBuilder(ENV_DAC_BITS); + dacBuilder.kinkedDac(model); + + for (unsigned int i = 0; i < (1 << ENV_DAC_BITS); i++) + { + envDAC[i] = static_cast(dacBuilder.getOutput(i)); + } + } + + // calculate oscillator DAC table + const bool is6581 = model == MOS6581; + + { + Dac dacBuilder(OSC_DAC_BITS); + dacBuilder.kinkedDac(model); + + const double offset = dacBuilder.getOutput(is6581 ? OFFSET_6581 : OFFSET_8580); + + for (unsigned int i = 0; i < (1 << OSC_DAC_BITS); i++) + { + const double dacValue = dacBuilder.getOutput(i); + oscDAC[i] = static_cast(dacValue - offset); + } + } + + // set voice tables + for (int i = 0; i < 3; i++) + { + voice[i]->setEnvDAC(envDAC); + voice[i]->setWavDAC(oscDAC); + voice[i]->wave()->setModel(is6581); + voice[i]->wave()->setWaveformModels(tables); + } +} + +void SID::reset() +{ + for (int i = 0; i < 3; i++) + { + voice[i]->reset(); + } + + filter6581->reset(); + filter8580->reset(); + externalFilter->reset(); + + if (resampler.get()) + { + resampler->reset(); + } + + busValue = 0; + busValueTtl = 0; + voiceSync(false); +} + +void SID::input(int value) +{ + filter6581->input(value); + filter8580->input(value); +} + +unsigned char SID::read(int offset) +{ + switch (offset) + { + case 0x19: // X value of paddle + busValue = potX->readPOT(); + busValueTtl = modelTTL; + break; + + case 0x1a: // Y value of paddle + busValue = potY->readPOT(); + busValueTtl = modelTTL; + break; + + case 0x1b: // Voice #3 waveform output + busValue = voice[2]->wave()->readOSC(); + busValueTtl = modelTTL; + break; + + case 0x1c: // Voice #3 ADSR output + busValue = voice[2]->envelope()->readENV(); + busValueTtl = modelTTL; + break; + + default: + // Reading from a write-only or non-existing register + // makes the bus discharge faster. + // Emulate this by halving the residual TTL. + busValueTtl /= 2; + break; + } + + return busValue; +} + +void SID::write(int offset, unsigned char value) +{ + busValue = value; + busValueTtl = modelTTL; + + switch (offset) + { + case 0x00: // Voice #1 frequency (Low-byte) + voice[0]->wave()->writeFREQ_LO(value); + break; + + case 0x01: // Voice #1 frequency (High-byte) + voice[0]->wave()->writeFREQ_HI(value); + break; + + case 0x02: // Voice #1 pulse width (Low-byte) + voice[0]->wave()->writePW_LO(value); + break; + + case 0x03: // Voice #1 pulse width (bits #8-#15) + voice[0]->wave()->writePW_HI(value); + break; + + case 0x04: // Voice #1 control register + voice[0]->writeCONTROL_REG(muted[0] ? 0 : value); + break; + + case 0x05: // Voice #1 Attack and Decay length + voice[0]->envelope()->writeATTACK_DECAY(value); + break; + + case 0x06: // Voice #1 Sustain volume and Release length + voice[0]->envelope()->writeSUSTAIN_RELEASE(value); + break; + + case 0x07: // Voice #2 frequency (Low-byte) + voice[1]->wave()->writeFREQ_LO(value); + break; + + case 0x08: // Voice #2 frequency (High-byte) + voice[1]->wave()->writeFREQ_HI(value); + break; + + case 0x09: // Voice #2 pulse width (Low-byte) + voice[1]->wave()->writePW_LO(value); + break; + + case 0x0a: // Voice #2 pulse width (bits #8-#15) + voice[1]->wave()->writePW_HI(value); + break; + + case 0x0b: // Voice #2 control register + voice[1]->writeCONTROL_REG(muted[1] ? 0 : value); + break; + + case 0x0c: // Voice #2 Attack and Decay length + voice[1]->envelope()->writeATTACK_DECAY(value); + break; + + case 0x0d: // Voice #2 Sustain volume and Release length + voice[1]->envelope()->writeSUSTAIN_RELEASE(value); + break; + + case 0x0e: // Voice #3 frequency (Low-byte) + voice[2]->wave()->writeFREQ_LO(value); + break; + + case 0x0f: // Voice #3 frequency (High-byte) + voice[2]->wave()->writeFREQ_HI(value); + break; + + case 0x10: // Voice #3 pulse width (Low-byte) + voice[2]->wave()->writePW_LO(value); + break; + + case 0x11: // Voice #3 pulse width (bits #8-#15) + voice[2]->wave()->writePW_HI(value); + break; + + case 0x12: // Voice #3 control register + voice[2]->writeCONTROL_REG(muted[2] ? 0 : value); + break; + + case 0x13: // Voice #3 Attack and Decay length + voice[2]->envelope()->writeATTACK_DECAY(value); + break; + + case 0x14: // Voice #3 Sustain volume and Release length + voice[2]->envelope()->writeSUSTAIN_RELEASE(value); + break; + + case 0x15: // Filter cut off frequency (bits #0-#2) + filter6581->writeFC_LO(value); + filter8580->writeFC_LO(value); + break; + + case 0x16: // Filter cut off frequency (bits #3-#10) + filter6581->writeFC_HI(value); + filter8580->writeFC_HI(value); + break; + + case 0x17: // Filter control + filter6581->writeRES_FILT(value); + filter8580->writeRES_FILT(value); + break; + + case 0x18: // Volume and filter modes + filter6581->writeMODE_VOL(value); + filter8580->writeMODE_VOL(value); + break; + + default: + break; + } + + // Update voicesync just in case. + voiceSync(false); +} + +void SID::setSamplingParameters(double clockFrequency, SamplingMethod method, double samplingFrequency, double highestAccurateFrequency) +{ + externalFilter->setClockFrequency(clockFrequency); + + switch (method) + { + case DECIMATE: + resampler.reset(new ZeroOrderResampler(clockFrequency, samplingFrequency)); + break; + + case RESAMPLE: + resampler.reset(TwoPassSincResampler::create(clockFrequency, samplingFrequency, highestAccurateFrequency)); + break; + + default: + throw SIDError("Unknown sampling method"); + } +} + +void SID::clockSilent(unsigned int cycles) +{ + ageBusValue(cycles); + + while (cycles != 0) + { + int delta_t = std::min(nextVoiceSync, cycles); + + if (delta_t > 0) + { + for (int i = 0; i < delta_t; i++) + { + // clock waveform generators (can affect OSC3) + voice[0]->wave()->clock(); + voice[1]->wave()->clock(); + voice[2]->wave()->clock(); + + voice[0]->wave()->output(voice[2]->wave()); + voice[1]->wave()->output(voice[0]->wave()); + voice[2]->wave()->output(voice[1]->wave()); + + // clock ENV3 only + voice[2]->envelope()->clock(); + } + + cycles -= delta_t; + nextVoiceSync -= delta_t; + } + + if (nextVoiceSync == 0) + { + voiceSync(true); + } + } +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/SID.h b/src/engine/platform/sound/c64_fp/SID.h new file mode 100644 index 000000000..05ad83c3b --- /dev/null +++ b/src/engine/platform/sound/c64_fp/SID.h @@ -0,0 +1,372 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2016 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 SIDFP_H +#define SIDFP_H + +#include + +#include "siddefs-fp.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +class Filter; +class Filter6581; +class Filter8580; +class ExternalFilter; +class Potentiometer; +class Voice; +class Resampler; + +/** + * SID error exception. + */ +class SIDError +{ +private: + const char* message; + +public: + SIDError(const char* msg) : + message(msg) {} + const char* getMessage() const { return message; } +}; + +/** + * MOS6581/MOS8580 emulation. + */ +class SID +{ +private: + /// Currently active filter + Filter* filter; + + /// Filter used, if model is set to 6581 + std::unique_ptr const filter6581; + + /// Filter used, if model is set to 8580 + std::unique_ptr const filter8580; + + /** + * External filter that provides high-pass and low-pass filtering + * to adjust sound tone slightly. + */ + std::unique_ptr const externalFilter; + + /// Resampler used by audio generation code. + std::unique_ptr resampler; + + /// Paddle X register support + std::unique_ptr const potX; + + /// Paddle Y register support + std::unique_ptr const potY; + + /// SID voices + std::unique_ptr voice[3]; + + /// Time to live for the last written value + int busValueTtl; + + /// Current chip model's bus value TTL + int modelTTL; + + /// Time until #voiceSync must be run. + unsigned int nextVoiceSync; + + /// Currently active chip model. + ChipModel model; + + /// Last written value + unsigned char busValue; + + /// Flags for muted channels + bool muted[3]; + + /** + * Emulated nonlinearity of the envelope DAC. + * + * @See Dac + */ + float envDAC[256]; + + /** + * Emulated nonlinearity of the oscillator DAC. + * + * @See Dac + */ + float oscDAC[4096]; + +private: + /** + * Age the bus value and zero it if it's TTL has expired. + * + * @param n the number of cycles + */ + void ageBusValue(unsigned int n); + + /** + * Get output sample. + * + * @return the output sample + */ + int output() const; + + /** + * Calculate the numebr of cycles according to current parameters + * that it takes to reach sync. + * + * @param sync whether to do the actual voice synchronization + */ + void voiceSync(bool sync); + +public: + SID(); + ~SID(); + + /** + * Set chip model. + * + * @param model chip model to use + * @throw SIDError + */ + void setChipModel(ChipModel model); + + /** + * Get currently emulated chip model. + */ + ChipModel getChipModel() const { return model; } + + /** + * SID reset. + */ + void reset(); + + /** + * 16-bit input (EXT IN). Write 16-bit sample to audio input. NB! The caller + * is responsible for keeping the value within 16 bits. Note that to mix in + * an external audio signal, the signal should be resampled to 1MHz first to + * avoid sampling noise. + * + * @param value input level to set + */ + void input(int value); + + /** + * Read registers. + * + * Reading a write only register returns the last char written to any SID register. + * The individual bits in this value start to fade down towards zero after a few cycles. + * All bits reach zero within approximately $2000 - $4000 cycles. + * It has been claimed that this fading happens in an orderly fashion, + * however sampling of write only registers reveals that this is not the case. + * NOTE: This is not correctly modeled. + * The actual use of write only registers has largely been made + * in the belief that all SID registers are readable. + * To support this belief the read would have to be done immediately + * after a write to the same register (remember that an intermediate write + * to another register would yield that value instead). + * With this in mind we return the last value written to any SID register + * for $2000 cycles without modeling the bit fading. + * + * @param offset SID register to read + * @return value read from chip + */ + unsigned char read(int offset); + + /** + * Write registers. + * + * @param offset chip register to write + * @param value value to write + */ + void write(int offset, unsigned char value); + + /** + * SID voice muting. + * + * @param channel channel to modify + * @param enable is muted? + */ + void mute(int channel, bool enable) { muted[channel] = enable; } + + /** + * Setting of SID sampling parameters. + * + * Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64. + * The default end of passband frequency is pass_freq = 0.9*sample_freq/2 + * for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample frequencies. + * + * For resampling, the ratio between the clock frequency and the sample frequency + * is limited as follows: 125*clock_freq/sample_freq < 16384 + * E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not be set + * lower than ~ 8kHz. A lower sample frequency would make the resampling code + * overfill its 16k sample ring buffer. + * + * The end of passband frequency is also limited: pass_freq <= 0.9*sample_freq/2 + * + * E.g. for a 44.1kHz sampling rate the end of passband frequency + * is limited to slightly below 20kHz. + * This constraint ensures that the FIR table is not overfilled. + * + * @param clockFrequency System clock frequency at Hz + * @param method sampling method to use + * @param samplingFrequency Desired output sampling rate + * @param highestAccurateFrequency + * @throw SIDError + */ + void setSamplingParameters(double clockFrequency, SamplingMethod method, double samplingFrequency, double highestAccurateFrequency); + + /** + * Clock SID forward using chosen output sampling algorithm. + * + * @param cycles c64 clocks to clock + * @param buf audio output buffer + * @return number of samples produced + */ + int clock(unsigned int cycles, short* buf); + + /** + * Clock SID forward with no audio production. + * + * _Warning_: + * You can't mix this method of clocking with the audio-producing + * clock() because components that don't affect OSC3/ENV3 are not + * emulated. + * + * @param cycles c64 clocks to clock. + */ + void clockSilent(unsigned int cycles); + + /** + * Set filter curve parameter for 6581 model. + * + * @see Filter6581::setFilterCurve(double) + */ + void setFilter6581Curve(double filterCurve); + + /** + * Set filter curve parameter for 8580 model. + * + * @see Filter8580::setFilterCurve(double) + */ + void setFilter8580Curve(double filterCurve); + + /** + * Enable filter emulation. + * + * @param enable false to turn off filter emulation + */ + void enableFilter(bool enable); +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(SID_CPP) + +#include + +#include "Filter.h" +#include "ExternalFilter.h" +#include "Voice.h" +#include "resample/Resampler.h" + +namespace reSIDfp +{ + +RESID_INLINE +void SID::ageBusValue(unsigned int n) +{ + if (likely(busValueTtl != 0)) + { + busValueTtl -= n; + + if (unlikely(busValueTtl <= 0)) + { + busValue = 0; + busValueTtl = 0; + } + } +} + +RESID_INLINE +int SID::output() const +{ + const int v1 = voice[0]->output(voice[2]->wave()); + const int v2 = voice[1]->output(voice[0]->wave()); + const int v3 = voice[2]->output(voice[1]->wave()); + + return externalFilter->clock(filter->clock(v1, v2, v3)); +} + + +RESID_INLINE +int SID::clock(unsigned int cycles, short* buf) +{ + ageBusValue(cycles); + int s = 0; + + while (cycles != 0) + { + unsigned int delta_t = std::min(nextVoiceSync, cycles); + + if (likely(delta_t > 0)) + { + for (unsigned int i = 0; i < delta_t; i++) + { + // clock waveform generators + voice[0]->wave()->clock(); + voice[1]->wave()->clock(); + voice[2]->wave()->clock(); + + // clock envelope generators + voice[0]->envelope()->clock(); + voice[1]->envelope()->clock(); + voice[2]->envelope()->clock(); + + if (unlikely(resampler->input(output()))) + { + buf[s++] = resampler->getOutput(); + } + } + + cycles -= delta_t; + nextVoiceSync -= delta_t; + } + + if (unlikely(nextVoiceSync == 0)) + { + voiceSync(true); + } + } + + return s; +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/Spline.cpp b/src/engine/platform/sound/c64_fp/Spline.cpp new file mode 100644 index 000000000..50d55fef1 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Spline.cpp @@ -0,0 +1,119 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2015 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 "Spline.h" + +#include +#include + +namespace reSIDfp +{ + +Spline::Spline(const std::vector &input) : + params(input.size()), + c(¶ms[0]) +{ + assert(input.size() > 2); + + const size_t coeffLength = input.size() - 1; + + std::vector dxs(coeffLength); + std::vector ms(coeffLength); + + // Get consecutive differences and slopes + for (size_t i = 0; i < coeffLength; i++) + { + assert(input[i].x < input[i + 1].x); + + const double dx = input[i + 1].x - input[i].x; + const double dy = input[i + 1].y - input[i].y; + dxs[i] = dx; + ms[i] = dy/dx; + } + + // Get degree-1 coefficients + params[0].c = ms[0]; + for (size_t i = 1; i < coeffLength; i++) + { + const double m = ms[i - 1]; + const double mNext = ms[i]; + if (m * mNext <= 0) + { + params[i].c = 0.0; + } + else + { + const double dx = dxs[i - 1]; + const double dxNext = dxs[i]; + const double common = dx + dxNext; + params[i].c = 3.0 * common / ((common + dxNext) / m + (common + dx) / mNext); + } + } + params[coeffLength].c = ms[coeffLength - 1]; + + // Get degree-2 and degree-3 coefficients + for (size_t i = 0; i < coeffLength; i++) + { + params[i].x1 = input[i].x; + params[i].x2 = input[i + 1].x; + params[i].d = input[i].y; + + const double c1 = params[i].c; + const double m = ms[i]; + const double invDx = 1.0 / dxs[i]; + const double common = c1 + params[i + 1].c - m - m; + params[i].b = (m - c1 - common) * invDx; + params[i].a = common * invDx * invDx; + } + + // Fix the upper range, because we interpolate outside original bounds if necessary. + params[coeffLength - 1].x2 = std::numeric_limits::max(); +} + +Spline::Point Spline::evaluate(double x) const +{ + if ((x < c->x1) || (x > c->x2)) + { + for (size_t i = 0; i < params.size(); i++) + { + if (x <= params[i].x2) + { + c = ¶ms[i]; + break; + } + } + } + + // Interpolate + const double diff = x - c->x1; + + Point out; + + // y = a*x^3 + b*x^2 + c*x + d + out.x = ((c->a * diff + c->b) * diff + c->c) * diff + c->d; + + // dy = 3*a*x^2 + 2*b*x + c + out.y = (3.0 * c->a * diff + 2.0 * c->b) * diff + c->c; + + return out; +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/Spline.h b/src/engine/platform/sound/c64_fp/Spline.h new file mode 100644 index 000000000..6cc2b1edc --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Spline.h @@ -0,0 +1,78 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2015 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 SPLINE_H +#define SPLINE_H + +#include +#include + +namespace reSIDfp +{ + +/** + * Fritsch-Carlson monotone cubic spline interpolation. + * + * Based on the implementation from the [Monotone cubic interpolation] wikipedia page. + * + * [Monotone cubic interpolation]: https://en.wikipedia.org/wiki/Monotone_cubic_interpolation + */ +class Spline +{ +public: + typedef struct + { + double x; + double y; + } Point; + +private: + typedef struct + { + double x1; + double x2; + double a; + double b; + double c; + double d; + } Param; + + typedef std::vector ParamVector; + +private: + /// Interpolation parameters + ParamVector params; + + /// Last used parameters, cached for speed up + mutable ParamVector::const_pointer c; + +public: + Spline(const std::vector &input); + + /** + * Evaluate y and its derivative at given point x. + */ + Point evaluate(double x) const; +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/Voice.h b/src/engine/platform/sound/c64_fp/Voice.h new file mode 100644 index 000000000..fc7ed41b7 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/Voice.h @@ -0,0 +1,130 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 VOICE_H +#define VOICE_H + +#include + +#include "siddefs-fp.h" +#include "WaveformGenerator.h" +#include "EnvelopeGenerator.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +/** + * Representation of SID voice block. + */ +class Voice +{ +private: + std::unique_ptr const waveformGenerator; + + std::unique_ptr const envelopeGenerator; + + /// The DAC LUT for analog waveform output + float* wavDAC; //-V730_NOINIT this is initialized in the SID constructor + + /// The DAC LUT for analog envelope output + float* envDAC; //-V730_NOINIT this is initialized in the SID constructor + +public: + /** + * Amplitude modulated waveform output. + * + * The waveform DAC generates a voltage between virtual ground and Vdd + * (5-12 V for the 6581 and 4.75-9 V for the 8580) + * corresponding to oscillator state 0 .. 4095. + * + * The envelope DAC generates a voltage between waveform gen output and + * the virtual ground level, corresponding to envelope state 0 .. 255. + * + * Ideal range [-2048*255, 2047*255]. + * + * @param ringModulator Ring-modulator for waveform + * @return the voice analog output + */ + RESID_INLINE + int output(const WaveformGenerator* ringModulator) const + { + unsigned int const wav = waveformGenerator->output(ringModulator); + unsigned int const env = envelopeGenerator->output(); + + // DAC imperfections are emulated by using the digital output + // as an index into a DAC lookup table. + return static_cast(wavDAC[wav] * envDAC[env]); + } + + /** + * Constructor. + */ + Voice() : + waveformGenerator(new WaveformGenerator()), + envelopeGenerator(new EnvelopeGenerator()) {} + + /** + * Set the analog DAC emulation for waveform generator. + * Must be called before any operation. + * + * @param dac + */ + void setWavDAC(float* dac) { wavDAC = dac; } + + /** + * Set the analog DAC emulation for envelope. + * Must be called before any operation. + * + * @param dac + */ + void setEnvDAC(float* dac) { envDAC = dac; } + + WaveformGenerator* wave() const { return waveformGenerator.get(); } + + EnvelopeGenerator* envelope() const { return envelopeGenerator.get(); } + + /** + * Write control register. + * + * @param control Control register value. + */ + void writeCONTROL_REG(unsigned char control) + { + waveformGenerator->writeCONTROL_REG(control); + envelopeGenerator->writeCONTROL_REG(control); + } + + /** + * SID reset. + */ + void reset() + { + waveformGenerator->reset(); + envelopeGenerator->reset(); + } +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/WaveformCalculator.cpp b/src/engine/platform/sound/c64_fp/WaveformCalculator.cpp new file mode 100644 index 000000000..fe5030faf --- /dev/null +++ b/src/engine/platform/sound/c64_fp/WaveformCalculator.cpp @@ -0,0 +1,204 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2016 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 "WaveformCalculator.h" + +#include + +namespace reSIDfp +{ + +WaveformCalculator* WaveformCalculator::getInstance() +{ + static WaveformCalculator instance; + return &instance; +} + +/** + * Parameters derived with the Monte Carlo method based on + * samplings by kevtris. Code and data available in the project repository [1]. + * + * The score here reported is the acoustic error + * calculated XORing the estimated and the sampled values. + * In parentheses the number of mispredicted bits + * on a total of 32768. + * + * [1] https://github.com/libsidplayfp/combined-waveforms + */ +const CombinedWaveformConfig config[2][4] = +{ + { /* kevtris chip G (6581 R2) */ + {0.90251f, 0.f, 0.f, 1.9147f, 1.6747f, 0.62376f }, // error 1689 (280) + {0.93088f, 2.4843f, 0.f, 1.0353f, 1.1484f, 0.f }, // error 6128 (130) + {0.90988f, 2.26303f, 1.13126f, 1.0035f, 1.13801f, 0.f }, // error 14243 (632) + {0.91f, 1.192f, 0.f, 1.0169f, 1.2f, 0.637f }, // error 64 (2) + }, + { /* kevtris chip V (8580 R5) */ + {0.9632f, 0.f, 0.975f, 1.7467f, 2.36132f, 0.975395f}, // error 1380 (169) + {0.92886f, 1.67696f, 0.f, 1.1014f, 1.4352f, 0.f }, // error 8007 (218) + {0.94043f, 1.7937f, 0.981f, 1.1213f, 1.4259f, 0.f }, // error 11957 (362) + {0.96211f, 0.98695f, 1.00387f, 1.46499f, 1.98375f, 0.77777f }, // error 2369 (89) + }, +}; + +/** + * Generate bitstate based on emulation of combined waves. + * + * @param config model parameters matrix + * @param waveform the waveform to emulate, 1 .. 7 + * @param accumulator the high bits of the accumulator value + */ +short calculateCombinedWaveform(const CombinedWaveformConfig& config, int waveform, int accumulator) +{ + float o[12]; + + // Saw + for (unsigned int i = 0; i < 12; i++) + { + o[i] = (accumulator & (1 << i)) != 0 ? 1.f : 0.f; + } + + // convert to Triangle + if ((waveform & 3) == 1) + { + const bool top = (accumulator & 0x800) != 0; + + for (int i = 11; i > 0; i--) + { + o[i] = top ? 1.0f - o[i - 1] : o[i - 1]; + } + + o[0] = 0.f; + } + + // or to Saw+Triangle + else if ((waveform & 3) == 3) + { + // bottom bit is grounded via T waveform selector + o[0] *= config.stmix; + + for (int i = 1; i < 12; i++) + { + /* + * Enabling the S waveform pulls the XOR circuit selector transistor down + * (which would normally make the descending ramp of the triangle waveform), + * so ST does not actually have a sawtooth and triangle waveform combined, + * but merely combines two sawtooths, one rising double the speed the other. + * + * http://www.lemon64.com/forum/viewtopic.php?t=25442&postdays=0&postorder=asc&start=165 + */ + o[i] = o[i - 1] * (1.f - config.stmix) + o[i] * config.stmix; + } + } + + // topbit for Saw + if ((waveform & 2) == 2) + { + o[11] *= config.topbit; + } + + // ST, P* waveforms + if (waveform == 3 || waveform > 4) + { + float distancetable[12 * 2 + 1]; + distancetable[12] = 1.f; + for (int i = 12; i > 0; i--) + { + distancetable[12-i] = 1.0f / pow(config.distance1, i); + distancetable[12+i] = 1.0f / pow(config.distance2, i); + } + + float tmp[12]; + + for (int i = 0; i < 12; i++) + { + float avg = 0.f; + float n = 0.f; + + for (int j = 0; j < 12; j++) + { + const float weight = distancetable[i - j + 12]; + avg += o[j] * weight; + n += weight; + } + + // pulse control bit + if (waveform > 4) + { + const float weight = distancetable[i - 12 + 12]; + avg += config.pulsestrength * weight; + n += weight; + } + + tmp[i] = (o[i] + avg / n) * 0.5f; + } + + for (int i = 0; i < 12; i++) + { + o[i] = tmp[i]; + } + } + + short value = 0; + + for (unsigned int i = 0; i < 12; i++) + { + if (o[i] > config.bias) + { + value |= 1 << i; + } + } + + return value; +} + +matrix_t* WaveformCalculator::buildTable(ChipModel model) +{ + const CombinedWaveformConfig* cfgArray = config[model == MOS6581 ? 0 : 1]; + + cw_cache_t::iterator lb = CACHE.lower_bound(cfgArray); + + if (lb != CACHE.end() && !(CACHE.key_comp()(cfgArray, lb->first))) + { + return &(lb->second); + } + + matrix_t wftable(8, 4096); + + for (unsigned int idx = 0; idx < 1 << 12; idx++) + { + wftable[0][idx] = 0xfff; + wftable[1][idx] = static_cast((idx & 0x800) == 0 ? idx << 1 : (idx ^ 0xfff) << 1); + wftable[2][idx] = static_cast(idx); + wftable[3][idx] = calculateCombinedWaveform(cfgArray[0], 3, idx); + wftable[4][idx] = 0xfff; + wftable[5][idx] = calculateCombinedWaveform(cfgArray[1], 5, idx); + wftable[6][idx] = calculateCombinedWaveform(cfgArray[2], 6, idx); + wftable[7][idx] = calculateCombinedWaveform(cfgArray[3], 7, idx); + } +#ifdef HAVE_CXX11 + return &(CACHE.emplace_hint(lb, cw_cache_t::value_type(cfgArray, wftable))->second); +#else + return &(CACHE.insert(lb, cw_cache_t::value_type(cfgArray, wftable))->second); +#endif +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/WaveformCalculator.h b/src/engine/platform/sound/c64_fp/WaveformCalculator.h new file mode 100644 index 000000000..f9183c5d5 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/WaveformCalculator.h @@ -0,0 +1,128 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2016 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 WAVEFORMCALCULATOR_h +#define WAVEFORMCALCULATOR_h + +#include + +#include "array.h" +#include "sidcxx11.h" +#include "siddefs-fp.h" + + +namespace reSIDfp +{ + +/** + * Combined waveform model parameters. + */ +typedef struct +{ + float bias; + float pulsestrength; + float topbit; + float distance1; + float distance2; + float stmix; +} CombinedWaveformConfig; + +/** + * Combined waveform calculator for WaveformGenerator. + * By combining waveforms, the bits of each waveform are effectively short + * circuited. A zero bit in one waveform will result in a zero output bit + * (thus the infamous claim that the waveforms are AND'ed). + * However, a zero bit in one waveform may also affect the neighboring bits + * in the output. + * + * Example: + * + * 1 1 + * Bit # 1 0 9 8 7 6 5 4 3 2 1 0 + * ----------------------- + * Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0 + * + * Triangle 0 0 1 1 1 1 1 1 0 0 0 0 + * + * AND 0 0 0 1 1 1 1 1 0 0 0 0 + * + * Output 0 0 0 0 1 1 1 0 0 0 0 0 + * + * + * Re-vectorized die photographs reveal the mechanism behind this behavior. + * Each waveform selector bit acts as a switch, which directly connects + * internal outputs into the waveform DAC inputs as follows: + * + * - Noise outputs the shift register bits to DAC inputs as described above. + * Each output is also used as input to the next bit when the shift register + * is shifted. Lower four bits are grounded. + * - Pulse connects a single line to all DAC inputs. The line is connected to + * either 5V (pulse on) or 0V (pulse off) at bit 11, and ends at bit 0. + * - Triangle connects the upper 11 bits of the (MSB EOR'ed) accumulator to the + * DAC inputs, so that DAC bit 0 = 0, DAC bit n = accumulator bit n - 1. + * - Sawtooth connects the upper 12 bits of the accumulator to the DAC inputs, + * so that DAC bit n = accumulator bit n. Sawtooth blocks out the MSB from + * the EOR used to generate the triangle waveform. + * + * We can thus draw the following conclusions: + * + * - The shift register may be written to by combined waveforms. + * - The pulse waveform interconnects all bits in combined waveforms via the + * pulse line. + * - The combination of triangle and sawtooth interconnects neighboring bits + * of the sawtooth waveform. + * + * Also in the 6581 the MSB of the oscillator, used as input for the + * triangle xor logic and the pulse adder's last bit, is connected directly + * to the waveform selector, while in the 8580 it is latched at sid_clk2 + * before being forwarded to the selector. Thus in the 6581 if the sawtooth MSB + * is pulled down it might affect the oscillator's adder + * driving the top bit low. + * + */ +class WaveformCalculator +{ +private: + typedef std::map cw_cache_t; + +private: + cw_cache_t CACHE; + + WaveformCalculator() DEFAULT; + +public: + /** + * Get the singleton instance. + */ + static WaveformCalculator* getInstance(); + + /** + * Build waveform tables for use by WaveformGenerator. + * + * @param model Chip model to use + * @return Waveform table + */ + matrix_t* buildTable(ChipModel model); +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp b/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp new file mode 100644 index 000000000..16a9eb6b6 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp @@ -0,0 +1,357 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2021 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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. + */ + +#define WAVEFORMGENERATOR_CPP + +#include "WaveformGenerator.h" + +/* + * This fixes tests + * SID/wb_testsuite/noise_writeback_check_8_to_C_old + * SID/wb_testsuite/noise_writeback_check_9_to_C_old + * SID/wb_testsuite/noise_writeback_check_A_to_C_old + * SID/wb_testsuite/noise_writeback_check_C_to_C_old + * + * but breaks SID/wf12nsr/wf12nsr + * + * needs more digging... + */ +//#define NO_WB_NOI_PUL + +namespace reSIDfp +{ + +/** + * Number of cycles after which the waveform output fades to 0 when setting + * the waveform register to 0. + * Values measured on warm chips (6581R3/R4 and 8580R5) + * checking OSC3. + * Times vary wildly with temperature and may differ + * from chip to chip so the numbers here represent + * only the big difference between the old and new models. + * + * See [VICE Bug #290](http://sourceforge.net/p/vice-emu/bugs/290/) + * and [VICE Bug #1128](http://sourceforge.net/p/vice-emu/bugs/1128/) + */ +// ~95ms +const unsigned int FLOATING_OUTPUT_TTL_6581R3 = 54000; +const unsigned int FLOATING_OUTPUT_FADE_6581R3 = 1400; +// ~1s +const unsigned int FLOATING_OUTPUT_TTL_6581R4 = 1000000; +// ~1s +const unsigned int FLOATING_OUTPUT_TTL_8580R5 = 800000; +const unsigned int FLOATING_OUTPUT_FADE_8580R5 = 50000; + +/** + * Number of cycles after which the shift register is reset + * when the test bit is set. + * Values measured on warm chips (6581R3/R4 and 8580R5) + * checking OSC3. + * Times vary wildly with temperature and may differ + * from chip to chip so the numbers here represent + * only the big difference between the old and new models. + */ +// ~210ms +const unsigned int SHIFT_REGISTER_RESET_6581R3 = 50000; +const unsigned int SHIFT_REGISTER_FADE_6581R3 = 15000; +// ~2.15s +const unsigned int SHIFT_REGISTER_RESET_6581R4 = 2150000; +// ~2.8s +const unsigned int SHIFT_REGISTER_RESET_8580R5 = 986000; +const unsigned int SHIFT_REGISTER_FADE_8580R5 = 314300; + +/* + * This is what happens when the lfsr is clocked: + * + * cycle 0: bit 19 of the accumulator goes from low to high, the noise register acts normally, + * the output may overwrite a bit; + * + * cycle 1: first phase of the shift, the bits are interconnected and the output of each bit + * is latched into the following. The output may overwrite the latched value. + * + * cycle 2: second phase of the shift, the latched value becomes active in the first + * half of the clock and from the second half the register returns to normal operation. + * + * When the test or reset lines are active the first phase is executed at every cyle + * until the signal is released triggering the second phase. + */ +void WaveformGenerator::clock_shift_register(unsigned int bit0) +{ + shift_register = (shift_register >> 1) | bit0; + + // New noise waveform output. + set_noise_output(); +} + +unsigned int WaveformGenerator::get_noise_writeback() +{ + return + ~( + (1 << 2) | // Bit 20 + (1 << 4) | // Bit 18 + (1 << 8) | // Bit 14 + (1 << 11) | // Bit 11 + (1 << 13) | // Bit 9 + (1 << 17) | // Bit 5 + (1 << 20) | // Bit 2 + (1 << 22) // Bit 0 + ) | + ((waveform_output & (1 << 11)) >> 9) | // Bit 11 -> bit 20 + ((waveform_output & (1 << 10)) >> 6) | // Bit 10 -> bit 18 + ((waveform_output & (1 << 9)) >> 1) | // Bit 9 -> bit 14 + ((waveform_output & (1 << 8)) << 3) | // Bit 8 -> bit 11 + ((waveform_output & (1 << 7)) << 6) | // Bit 7 -> bit 9 + ((waveform_output & (1 << 6)) << 11) | // Bit 6 -> bit 5 + ((waveform_output & (1 << 5)) << 15) | // Bit 5 -> bit 2 + ((waveform_output & (1 << 4)) << 18); // Bit 4 -> bit 0 +} + +void WaveformGenerator::write_shift_register() +{ + if (unlikely(waveform > 0x8) && likely(!test) && likely(shift_pipeline != 1)) + { + // Write changes to the shift register output caused by combined waveforms + // back into the shift register. This happens only when the register is clocked + // (see $D1+$81_wave_test [1]) or when the test bit is falling. + // A bit once set to zero cannot be changed, hence the and'ing. + // + // [1] ftp://ftp.untergrund.net/users/nata/sid_test/$D1+$81_wave_test.7z + // + // FIXME: Write test program to check the effect of 1 bits and whether + // neighboring bits are affected. + +#ifdef NO_WB_NOI_PUL + if (waveform == 0xc) + return; +#endif + shift_register &= get_noise_writeback(); + + noise_output &= waveform_output; + set_no_noise_or_noise_output(); + } +} + +void WaveformGenerator::set_noise_output() +{ + noise_output = + ((shift_register & (1 << 2)) << 9) | // Bit 20 -> bit 11 + ((shift_register & (1 << 4)) << 6) | // Bit 18 -> bit 10 + ((shift_register & (1 << 8)) << 1) | // Bit 14 -> bit 9 + ((shift_register & (1 << 11)) >> 3) | // Bit 11 -> bit 8 + ((shift_register & (1 << 13)) >> 6) | // Bit 9 -> bit 7 + ((shift_register & (1 << 17)) >> 11) | // Bit 5 -> bit 6 + ((shift_register & (1 << 20)) >> 15) | // Bit 2 -> bit 5 + ((shift_register & (1 << 22)) >> 18); // Bit 0 -> bit 4 + + set_no_noise_or_noise_output(); +} + +void WaveformGenerator::setWaveformModels(matrix_t* models) +{ + model_wave = models; +} + +void WaveformGenerator::synchronize(WaveformGenerator* syncDest, const WaveformGenerator* syncSource) const +{ + // A special case occurs when a sync source is synced itself on the same + // cycle as when its MSB is set high. In this case the destination will + // not be synced. This has been verified by sampling OSC3. + if (unlikely(msb_rising) && syncDest->sync && !(sync && syncSource->msb_rising)) + { + syncDest->accumulator = 0; + } +} + +bool do_pre_writeback(unsigned int waveform_prev, unsigned int waveform, bool is6581) +{ + // no writeback without combined waveforms + if (likely(waveform_prev <= 0x8)) + return false; + // no writeback when changing to noise + if (waveform == 8) + return false; + // What's happening here? + if (is6581 && + ((((waveform_prev & 0x3) == 0x1) && ((waveform & 0x3) == 0x2)) + || (((waveform_prev & 0x3) == 0x2) && ((waveform & 0x3) == 0x1)))) + return false; + if (waveform_prev == 0xc) + { + if (is6581) + return false; + else if ((waveform != 0x9) && (waveform != 0xe)) + return false; + } +#ifdef NO_WB_NOI_PUL + if (waveform == 0xc) + return false; +#endif + // ok do the writeback + return true; +} + +/* + * When noise and pulse are combined all the bits are + * connected and the four lower ones are grounded. + * This causes the adjacent bits to be pulled down, + * with different strength depending on model. + * + * This is just a rough attempt at modelling the effect. + */ + +static unsigned int noise_pulse6581(unsigned int noise) +{ + return (noise < 0xf00) ? 0x000 : noise & (noise << 1) & (noise << 2); +} + +static unsigned int noise_pulse8580(unsigned int noise) +{ + return (noise < 0xfc0) ? noise & (noise << 1) : 0xfc0; +} + +void WaveformGenerator::set_no_noise_or_noise_output() +{ + no_noise_or_noise_output = no_noise | noise_output; + + // pulse+noise + if (unlikely((waveform & 0xc) == 0xc)) + no_noise_or_noise_output = is6581 + ? noise_pulse6581(no_noise_or_noise_output) + : noise_pulse8580(no_noise_or_noise_output); + +} + +void WaveformGenerator::writeCONTROL_REG(unsigned char control) +{ + const unsigned int waveform_prev = waveform; + const bool test_prev = test; + + waveform = (control >> 4) & 0x0f; + test = (control & 0x08) != 0; + sync = (control & 0x02) != 0; + + // Substitution of accumulator MSB when sawtooth = 0, ring_mod = 1. + ring_msb_mask = ((~control >> 5) & (control >> 2) & 0x1) << 23; + + if (waveform != waveform_prev) + { + // Set up waveform table. + wave = (*model_wave)[waveform & 0x7]; + + // no_noise and no_pulse are used in set_waveform_output() as bitmasks to + // only let the noise or pulse influence the output when the noise or pulse + // waveforms are selected. + no_noise = (waveform & 0x8) != 0 ? 0x000 : 0xfff; + set_no_noise_or_noise_output(); + no_pulse = (waveform & 0x4) != 0 ? 0x000 : 0xfff; + + if (waveform == 0) + { + // Change to floating DAC input. + // Reset fading time for floating DAC input. + floating_output_ttl = is6581 ? FLOATING_OUTPUT_TTL_6581R3 : FLOATING_OUTPUT_TTL_8580R5; + } + } + + if (test != test_prev) + { + if (test) + { + // Reset accumulator. + accumulator = 0; + + // Flush shift pipeline. + shift_pipeline = 0; + + // Set reset time for shift register. + shift_register_reset = is6581 ? SHIFT_REGISTER_RESET_6581R3 : SHIFT_REGISTER_RESET_8580R5; + } + else + { + // When the test bit is falling, the second phase of the shift is + // completed by enabling SRAM write. + + // During first phase of the shift the bits are interconnected + // and the output of each bit is latched into the following. + // The output may overwrite the latched value. + if (do_pre_writeback(waveform_prev, waveform, is6581)) + { + shift_register &= get_noise_writeback(); + } + + // bit0 = (bit22 | test) ^ bit17 = 1 ^ bit17 = ~bit17 + clock_shift_register((~shift_register << 17) & (1 << 22)); + } + } +} + +void WaveformGenerator::waveBitfade() +{ + waveform_output &= waveform_output >> 1; + osc3 = waveform_output; + if (waveform_output != 0) + floating_output_ttl = is6581 ? FLOATING_OUTPUT_FADE_6581R3 : FLOATING_OUTPUT_FADE_8580R5; +} + +void WaveformGenerator::shiftregBitfade() +{ + shift_register |= shift_register >> 1; + shift_register |= 0x400000; + if (shift_register != 0x7fffff) + shift_register_reset = is6581 ? SHIFT_REGISTER_FADE_6581R3 : SHIFT_REGISTER_FADE_8580R5; +} + +void WaveformGenerator::reset() +{ + // accumulator is not changed on reset + freq = 0; + pw = 0; + + msb_rising = false; + + waveform = 0; + osc3 = 0; + + test = false; + sync = false; + + wave = model_wave ? (*model_wave)[0] : nullptr; + + ring_msb_mask = 0; + no_noise = 0xfff; + no_pulse = 0xfff; + pulse_output = 0xfff; + + shift_register_reset = 0; + shift_register = 0x7fffff; + // when reset is released the shift register is clocked once + // so the lower bit is zeroed out + // bit0 = (bit22 | test) ^ bit17 = 1 ^ 1 = 0 + clock_shift_register(0); + + shift_pipeline = 0; + + waveform_output = 0; + floating_output_ttl = 0; +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/WaveformGenerator.h b/src/engine/platform/sound/c64_fp/WaveformGenerator.h new file mode 100644 index 000000000..9fd617f6b --- /dev/null +++ b/src/engine/platform/sound/c64_fp/WaveformGenerator.h @@ -0,0 +1,396 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2022 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004,2010 Dag Lem + * + * 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 WAVEFORMGENERATOR_H +#define WAVEFORMGENERATOR_H + +#include "siddefs-fp.h" +#include "array.h" + +#include "sidcxx11.h" + +namespace reSIDfp +{ + +/** + * A 24 bit accumulator is the basis for waveform generation. + * FREQ is added to the lower 16 bits of the accumulator each cycle. + * The accumulator is set to zero when TEST is set, and starts counting + * when TEST is cleared. + * + * Waveforms are generated as follows: + * + * - No waveform: + * When no waveform is selected, the DAC input is floating. + * + * + * - Triangle: + * The upper 12 bits of the accumulator are used. + * The MSB is used to create the falling edge of the triangle by inverting + * the lower 11 bits. The MSB is thrown away and the lower 11 bits are + * left-shifted (half the resolution, full amplitude). + * Ring modulation substitutes the MSB with MSB EOR NOT sync_source MSB. + * + * + * - Sawtooth: + * The output is identical to the upper 12 bits of the accumulator. + * + * + * - Pulse: + * The upper 12 bits of the accumulator are used. + * These bits are compared to the pulse width register by a 12 bit digital + * comparator; output is either all one or all zero bits. + * The pulse setting is delayed one cycle after the compare. + * The test bit, when set to one, holds the pulse waveform output at 0xfff + * regardless of the pulse width setting. + * + * + * - Noise: + * The noise output is taken from intermediate bits of a 23-bit shift register + * which is clocked by bit 19 of the accumulator. + * The shift is delayed 2 cycles after bit 19 is set high. + * + * Operation: Calculate EOR result, shift register, set bit 0 = result. + * + * reset +--------------------------------------------+ + * | | | + * test--OR-->EOR<--+ | + * | | | + * 2 2 2 1 1 1 1 1 1 1 1 1 1 | + * Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <---+ + * | | | | | | | | + * Waveform bits: 1 1 9 8 7 6 5 4 + * 1 0 + * + * The low 4 waveform bits are zero (grounded). + */ +class WaveformGenerator +{ +private: + matrix_t* model_wave; + + short* wave; + + // PWout = (PWn/40.95)% + unsigned int pw; + + unsigned int shift_register; + + /// Emulation of pipeline causing bit 19 to clock the shift register. + int shift_pipeline; + + unsigned int ring_msb_mask; + unsigned int no_noise; + unsigned int noise_output; + unsigned int no_noise_or_noise_output; + unsigned int no_pulse; + unsigned int pulse_output; + + /// The control register right-shifted 4 bits; used for output function table lookup. + unsigned int waveform; + + unsigned int waveform_output; + + /// Current accumulator value. + unsigned int accumulator; + + // Fout = (Fn*Fclk/16777216)Hz + unsigned int freq; + + /// 8580 tri/saw pipeline + unsigned int tri_saw_pipeline; + + /// The OSC3 value + unsigned int osc3; + + /// Remaining time to fully reset shift register. + unsigned int shift_register_reset; + + // The wave signal TTL when no waveform is selected + unsigned int floating_output_ttl; + + /// The control register bits. Gate is handled by EnvelopeGenerator. + //@{ + bool test; + bool sync; + //@} + + /// Tell whether the accumulator MSB was set high on this cycle. + bool msb_rising; + + bool is6581; //-V730_NOINIT this is initialized in the SID constructor + +private: + void clock_shift_register(unsigned int bit0); + + unsigned int get_noise_writeback(); + + void write_shift_register(); + + void set_noise_output(); + + void set_no_noise_or_noise_output(); + + void waveBitfade(); + + void shiftregBitfade(); + +public: + void setWaveformModels(matrix_t* models); + + /** + * Set the chip model. + * Must be called before any operation. + * + * @param is6581 true if MOS6581, false if CSG8580 + */ + void setModel(bool is6581) { this->is6581 = is6581; } + + /** + * SID clocking. + */ + void clock(); + + /** + * Synchronize oscillators. + * This must be done after all the oscillators have been clock()'ed, + * so that they are in the same state. + * + * @param syncDest The oscillator that will be synced + * @param syncSource The sync source oscillator + */ + void synchronize(WaveformGenerator* syncDest, const WaveformGenerator* syncSource) const; + + /** + * Constructor. + */ + WaveformGenerator() : + model_wave(nullptr), + wave(nullptr), + pw(0), + shift_register(0), + shift_pipeline(0), + ring_msb_mask(0), + no_noise(0), + noise_output(0), + no_noise_or_noise_output(0), + no_pulse(0), + pulse_output(0), + waveform(0), + waveform_output(0), + accumulator(0x555555), // Accumulator's even bits are high on powerup + freq(0), + tri_saw_pipeline(0x555), + osc3(0), + shift_register_reset(0), + floating_output_ttl(0), + test(false), + sync(false), + msb_rising(false) {} + + /** + * Write FREQ LO register. + * + * @param freq_lo low 8 bits of frequency + */ + void writeFREQ_LO(unsigned char freq_lo) { freq = (freq & 0xff00) | (freq_lo & 0xff); } + + /** + * Write FREQ HI register. + * + * @param freq_hi high 8 bits of frequency + */ + void writeFREQ_HI(unsigned char freq_hi) { freq = (freq_hi << 8 & 0xff00) | (freq & 0xff); } + + /** + * Write PW LO register. + * + * @param pw_lo low 8 bits of pulse width + */ + void writePW_LO(unsigned char pw_lo) { pw = (pw & 0xf00) | (pw_lo & 0x0ff); } + + /** + * Write PW HI register. + * + * @param pw_hi high 8 bits of pulse width + */ + void writePW_HI(unsigned char pw_hi) { pw = (pw_hi << 8 & 0xf00) | (pw & 0x0ff); } + + /** + * Write CONTROL REGISTER register. + * + * @param control control register value + */ + void writeCONTROL_REG(unsigned char control); + + /** + * SID reset. + */ + void reset(); + + /** + * 12-bit waveform output. + * + * @param ringModulator The oscillator ring-modulating current one. + * @return the waveform generator digital output + */ + unsigned int output(const WaveformGenerator* ringModulator); + + /** + * Read OSC3 value. + */ + unsigned char readOSC() const { return static_cast(osc3 >> 4); } + + /** + * Read accumulator value. + */ + unsigned int readAccumulator() const { return accumulator; } + + /** + * Read freq value. + */ + unsigned int readFreq() const { return freq; } + + /** + * Read test value. + */ + bool readTest() const { return test; } + + /** + * Read sync value. + */ + bool readSync() const { return sync; } +}; + +} // namespace reSIDfp + +#if RESID_INLINING || defined(WAVEFORMGENERATOR_CPP) + +namespace reSIDfp +{ + +RESID_INLINE +void WaveformGenerator::clock() +{ + if (unlikely(test)) + { + if (unlikely(shift_register_reset != 0) && unlikely(--shift_register_reset == 0)) + { + shiftregBitfade(); + + // New noise waveform output. + set_noise_output(); + } + + // The test bit sets pulse high. + pulse_output = 0xfff; + } + else + { + // Calculate new accumulator value; + const unsigned int accumulator_old = accumulator; + accumulator = (accumulator + freq) & 0xffffff; + + // Check which bit have changed + const unsigned int accumulator_bits_set = ~accumulator_old & accumulator; + + // Check whether the MSB is set high. This is used for synchronization. + msb_rising = (accumulator_bits_set & 0x800000) != 0; + + // Shift noise register once for each time accumulator bit 19 is set high. + // The shift is delayed 2 cycles. + if (unlikely((accumulator_bits_set & 0x080000) != 0)) + { + // Pipeline: Detect rising bit, shift phase 1, shift phase 2. + shift_pipeline = 2; + } + else if (unlikely(shift_pipeline != 0) && --shift_pipeline == 0) + { + // bit0 = (bit22 | test) ^ bit17 + clock_shift_register(((shift_register << 22) ^ (shift_register << 17)) & (1 << 22)); + } + } +} + +RESID_INLINE +unsigned int WaveformGenerator::output(const WaveformGenerator* ringModulator) +{ + // Set output value. + if (likely(waveform != 0)) + { + const unsigned int ix = (accumulator ^ (~ringModulator->accumulator & ring_msb_mask)) >> 12; + + // The bit masks no_pulse and no_noise are used to achieve branch-free + // calculation of the output value. + waveform_output = wave[ix] & (no_pulse | pulse_output) & no_noise_or_noise_output; + + // Triangle/Sawtooth output is delayed half cycle on 8580. + // This will appear as a one cycle delay on OSC3 as it is latched first phase of the clock. + if ((waveform & 3) && !is6581) + { + osc3 = tri_saw_pipeline & (no_pulse | pulse_output) & no_noise_or_noise_output; + tri_saw_pipeline = wave[ix]; + } + else + { + osc3 = waveform_output; + } + + // In the 6581 the top bit of the accumulator may be driven low by combined waveforms + // when the sawtooth is selected + // FIXME doesn't seem to always happen + if ((waveform & 2) && unlikely(waveform & 0xd) && is6581) + accumulator &= (waveform_output << 12) | 0x7fffff; + + write_shift_register(); + } + else + { + // Age floating DAC input. + if (likely(floating_output_ttl != 0) && unlikely(--floating_output_ttl == 0)) + { + waveBitfade(); + } + } + + // The pulse level is defined as (accumulator >> 12) >= pw ? 0xfff : 0x000. + // The expression -((accumulator >> 12) >= pw) & 0xfff yields the same + // results without any branching (and thus without any pipeline stalls). + // NB! This expression relies on that the result of a boolean expression + // is either 0 or 1, and furthermore requires two's complement integer. + // A few more cycles may be saved by storing the pulse width left shifted + // 12 bits, and dropping the and with 0xfff (this is valid since pulse is + // used as a bit mask on 12 bit values), yielding the expression + // -(accumulator >= pw24). However this only results in negligible savings. + + // The result of the pulse width compare is delayed one cycle. + // Push next pulse level into pulse level pipeline. + pulse_output = ((accumulator >> 12) >= pw) ? 0xfff : 0x000; + + return waveform_output; +} + +} // namespace reSIDfp + +#endif + +#endif diff --git a/src/engine/platform/sound/c64_fp/array.h b/src/engine/platform/sound/c64_fp/array.h new file mode 100644 index 000000000..5291938c0 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/array.h @@ -0,0 +1,73 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright (C) 2011-2014 Leandro Nini + * + * 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 ARRAY_H +#define ARRAY_H + +/** + * Counter. + */ +class counter +{ +private: + unsigned int c; + +public: + counter() : c(1) {} + void increase() { ++c; } + unsigned int decrease() { return --c; } +}; + +/** + * Reference counted pointer to matrix wrapper, for use with standard containers. + */ +template +class matrix +{ +private: + T* data; + counter* count; + const unsigned int x, y; + +public: + matrix(unsigned int x, unsigned int y) : + data(new T[x * y]), + count(new counter()), + x(x), + y(y) {} + + matrix(const matrix& p) : + data(p.data), + count(p.count), + x(p.x), + y(p.y) { count->increase(); } + + ~matrix() { if (count->decrease() == 0) { delete count; delete [] data; } } + + unsigned int length() const { return x * y; } + + T* operator[](unsigned int a) { return &data[a * y]; } + + T const* operator[](unsigned int a) const { return &data[a * y]; } +}; + +typedef matrix matrix_t; + +#endif diff --git a/src/engine/platform/sound/c64_fp/resample/Resampler.h b/src/engine/platform/sound/c64_fp/resample/Resampler.h new file mode 100644 index 000000000..904f65458 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/resample/Resampler.h @@ -0,0 +1,86 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 RESAMPLER_H +#define RESAMPLER_H + +#include + +#include "../sidcxx11.h" + +#include "../siddefs-fp.h" + +namespace reSIDfp +{ + +/** + * Abstraction of a resampling process. Given enough input, produces output. + * Constructors take additional arguments that configure these objects. + */ +class Resampler +{ +protected: + inline short softClip(int x) const + { + constexpr int threshold = 28000; + if (likely(x < threshold)) + return x; + + constexpr double t = threshold / 32768.; + constexpr double a = 1. - t; + constexpr double b = 1. / a; + + double value = static_cast(x - threshold) / 32768.; + value = t + a * tanh(b * value); + return static_cast(value * 32768.); + } + + virtual int output() const = 0; + + Resampler() {} + +public: + virtual ~Resampler() {} + + /** + * Input a sample into resampler. Output "true" when resampler is ready with new sample. + * + * @param sample input sample + * @return true when a sample is ready + */ + virtual bool input(int sample) = 0; + + /** + * Output a sample from resampler. + * + * @return resampled sample + */ + short getOutput() const + { + return softClip(output()); + } + + virtual void reset() = 0; +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/resample/SincResampler.cpp b/src/engine/platform/sound/c64_fp/resample/SincResampler.cpp new file mode 100755 index 000000000..adb17f9e9 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/resample/SincResampler.cpp @@ -0,0 +1,393 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2020 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 "SincResampler.h" + +#include +#include +#include +#include +#include + +#include "../siddefs-fp.h" + +#ifdef HAVE_EMMINTRIN_H +# include +#elif defined HAVE_MMINTRIN_H +# include +#elif defined(HAVE_ARM_NEON_H) +# include +#endif + +namespace reSIDfp +{ + +typedef std::map fir_cache_t; + +/// Cache for the expensive FIR table computation results. +fir_cache_t FIR_CACHE; + +/// Maximum error acceptable in I0 is 1e-6, or ~96 dB. +const double I0E = 1e-6; + +const int BITS = 16; + +/** + * Compute the 0th order modified Bessel function of the first kind. + * This function is originally from resample-1.5/filterkit.c by J. O. Smith. + * It is used to build the Kaiser window for resampling. + * + * @param x evaluate I0 at x + * @return value of I0 at x. + */ +double I0(double x) +{ + double sum = 1.; + double u = 1.; + double n = 1.; + const double halfx = x / 2.; + + do + { + const double temp = halfx / n; + u *= temp * temp; + sum += u; + n += 1.; + } + while (u >= I0E * sum); + + return sum; +} + +/** + * Calculate convolution with sample and sinc. + * + * @param a sample buffer input + * @param b sinc buffer + * @param bLength length of the sinc buffer + * @return convolved result + */ +int convolve(const short* a, const short* b, int bLength) +{ +#ifdef HAVE_EMMINTRIN_H + int out = 0; + + const uintptr_t offset = (uintptr_t)(a) & 0x0f; + + // check for aligned accesses + if (offset == ((uintptr_t)(b) & 0x0f)) + { + if (offset) + { + const int l = (0x10 - offset)/2; + + for (int i = 0; i < l; i++) + { + out += *a++ * *b++; + } + + bLength -= offset; + } + + __m128i acc = _mm_setzero_si128(); + + const int n = bLength / 8; + + for (int i = 0; i < n; i++) + { + const __m128i tmp = _mm_madd_epi16(*(__m128i*)a, *(__m128i*)b); + acc = _mm_add_epi16(acc, tmp); + a += 8; + b += 8; + } + + __m128i vsum = _mm_add_epi32(acc, _mm_srli_si128(acc, 8)); + vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4)); + out += _mm_cvtsi128_si32(vsum); + + bLength &= 7; + } +#elif defined HAVE_MMINTRIN_H + __m64 acc = _mm_setzero_si64(); + + const int n = bLength / 4; + + for (int i = 0; i < n; i++) + { + const __m64 tmp = _mm_madd_pi16(*(__m64*)a, *(__m64*)b); + acc = _mm_add_pi16(acc, tmp); + a += 4; + b += 4; + } + + int out = _mm_cvtsi64_si32(acc) + _mm_cvtsi64_si32(_mm_srli_si64(acc, 32)); + _mm_empty(); + + bLength &= 3; +#elif defined(HAVE_ARM_NEON_H) +#if (defined(__arm64__) && defined(__APPLE__)) || defined(__aarch64__) + int32x4_t acc1Low = vdupq_n_s32(0); + int32x4_t acc1High = vdupq_n_s32(0); + int32x4_t acc2Low = vdupq_n_s32(0); + int32x4_t acc2High = vdupq_n_s32(0); + + const int n = bLength / 16; + + for (int i = 0; i < n; i++) + { + int16x8_t v11 = vld1q_s16(a); + int16x8_t v12 = vld1q_s16(a + 8); + int16x8_t v21 = vld1q_s16(b); + int16x8_t v22 = vld1q_s16(b + 8); + + acc1Low = vmlal_s16(acc1Low, vget_low_s16(v11), vget_low_s16(v21)); + acc1High = vmlal_high_s16(acc1High, v11, v21); + acc2Low = vmlal_s16(acc2Low, vget_low_s16(v12), vget_low_s16(v22)); + acc2High = vmlal_high_s16(acc2High, v12, v22); + + a += 16; + b += 16; + } + + bLength &= 15; + + if (bLength >= 8) + { + int16x8_t v1 = vld1q_s16(a); + int16x8_t v2 = vld1q_s16(b); + + acc1Low = vmlal_s16(acc1Low, vget_low_s16(v1), vget_low_s16(v2)); + acc1High = vmlal_high_s16(acc1High, v1, v2); + + a += 8; + b += 8; + } + + bLength &= 7; + + if (bLength >= 4) + { + int16x4_t v1 = vld1_s16(a); + int16x4_t v2 = vld1_s16(b); + + acc1Low = vmlal_s16(acc1Low, v1, v2); + + a += 4; + b += 4; + } + + int32x4_t accSumsNeon = vaddq_s32(acc1Low, acc1High); + accSumsNeon = vaddq_s32(accSumsNeon, acc2Low); + accSumsNeon = vaddq_s32(accSumsNeon, acc2High); + + int out = vaddvq_s32(accSumsNeon); + + bLength &= 3; +#else + int32x4_t acc = vdupq_n_s32(0); + + const int n = bLength / 4; + + for (int i = 0; i < n; i++) + { + const int16x4_t h_vec = vld1_s16(a); + const int16x4_t x_vec = vld1_s16(b); + acc = vmlal_s16(acc, h_vec, x_vec); + a += 4; + b += 4; + } + + int out = vgetq_lane_s32(acc, 0) + + vgetq_lane_s32(acc, 1) + + vgetq_lane_s32(acc, 2) + + vgetq_lane_s32(acc, 3); + + bLength &= 3; +#endif +#else + int out = 0; +#endif + + for (int i = 0; i < bLength; i++) + { + out += *a++ * *b++; + } + + return (out + (1 << 14)) >> 15; +} + +int SincResampler::fir(int subcycle) +{ + // Find the first of the nearest fir tables close to the phase + int firTableFirst = (subcycle * firRES >> 10); + const int firTableOffset = (subcycle * firRES) & 0x3ff; + + // Find firN most recent samples, plus one extra in case the FIR wraps. + int sampleStart = sampleIndex - firN + RINGSIZE - 1; + + const int v1 = convolve(sample + sampleStart, (*firTable)[firTableFirst], firN); + + // Use next FIR table, wrap around to first FIR table using + // previous sample. + if (unlikely(++firTableFirst == firRES)) + { + firTableFirst = 0; + ++sampleStart; + } + + const int v2 = convolve(sample + sampleStart, (*firTable)[firTableFirst], firN); + + // Linear interpolation between the sinc tables yields good + // approximation for the exact value. + return v1 + (firTableOffset * (v2 - v1) >> 10); +} + +SincResampler::SincResampler(double clockFrequency, double samplingFrequency, double highestAccurateFrequency) : + sampleIndex(0), + cyclesPerSample(static_cast(clockFrequency / samplingFrequency * 1024.)), + sampleOffset(0), + outputValue(0) +{ + // 16 bits -> -96dB stopband attenuation. + const double A = -20. * log10(1.0 / (1 << BITS)); + // A fraction of the bandwidth is allocated to the transition band, which we double + // because we design the filter to transition halfway at nyquist. + const double dw = (1. - 2.*highestAccurateFrequency / samplingFrequency) * M_PI * 2.; + + // For calculation of beta and N see the reference for the kaiserord + // function in the MATLAB Signal Processing Toolbox: + // http://www.mathworks.com/help/signal/ref/kaiserord.html + const double beta = 0.1102 * (A - 8.7); + const double I0beta = I0(beta); + const double cyclesPerSampleD = clockFrequency / samplingFrequency; + + { + // The filter order will maximally be 124 with the current constraints. + // N >= (96.33 - 7.95)/(2 * pi * 2.285 * (maxfreq - passbandfreq) >= 123 + // The filter order is equal to the number of zero crossings, i.e. + // it should be an even number (sinc is symmetric with respect to x = 0). + int N = static_cast((A - 7.95) / (2.285 * dw) + 0.5); + N += N & 1; + + // The filter length is equal to the filter order + 1. + // The filter length must be an odd number (sinc is symmetric with respect to + // x = 0). + firN = static_cast(N * cyclesPerSampleD) + 1; + firN |= 1; + + // Check whether the sample ring buffer would overflow. + assert(firN < RINGSIZE); + + // Error is bounded by err < 1.234 / L^2, so L = sqrt(1.234 / (2^-16)) = sqrt(1.234 * 2^16). + firRES = static_cast(ceil(sqrt(1.234 * (1 << BITS)) / cyclesPerSampleD)); + + // firN*firRES represent the total resolution of the sinc sampling. JOS + // recommends a length of 2^BITS, but we don't quite use that good a filter. + // The filter test program indicates that the filter performs well, though. + } + + // Create the map key + std::ostringstream o; + o << firN << "," << firRES << "," << cyclesPerSampleD; + const std::string firKey = o.str(); + fir_cache_t::iterator lb = FIR_CACHE.lower_bound(firKey); + + // The FIR computation is expensive and we set sampling parameters often, but + // from a very small set of choices. Thus, caching is used to speed initialization. + if (lb != FIR_CACHE.end() && !(FIR_CACHE.key_comp()(firKey, lb->first))) + { + firTable = &(lb->second); + } + else + { + // Allocate memory for FIR tables. + matrix_t tempTable(firRES, firN); +#ifdef HAVE_CXX11 + firTable = &(FIR_CACHE.emplace_hint(lb, fir_cache_t::value_type(firKey, tempTable))->second); +#else + firTable = &(FIR_CACHE.insert(lb, fir_cache_t::value_type(firKey, tempTable))->second); +#endif + + // The cutoff frequency is midway through the transition band, in effect the same as nyquist. + const double wc = M_PI; + + // Calculate the sinc tables. + const double scale = 32768.0 * wc / cyclesPerSampleD / M_PI; + + // we're not interested in the fractional part + // so use int division before converting to double + const int tmp = firN / 2; + const double firN_2 = static_cast(tmp); + + for (int i = 0; i < firRES; i++) + { + const double jPhase = (double) i / firRES + firN_2; + + for (int j = 0; j < firN; j++) + { + const double x = j - jPhase; + + const double xt = x / firN_2; + const double kaiserXt = fabs(xt) < 1. ? I0(beta * sqrt(1. - xt * xt)) / I0beta : 0.; + + const double wt = wc * x / cyclesPerSampleD; + const double sincWt = fabs(wt) >= 1e-8 ? sin(wt) / wt : 1.; + + (*firTable)[i][j] = static_cast(scale * sincWt * kaiserXt); + } + } + } +} + +bool SincResampler::input(int input) +{ + bool ready = false; + + /* + * Clip the input as it may overflow the 16 bit range. + * + * Approximate measured input ranges: + * 6581: [-24262,+25080] (Kawasaki_Synthesizer_Demo) + * 8580: [-21514,+35232] (64_Forever, Drum_Fool) + */ + sample[sampleIndex] = sample[sampleIndex + RINGSIZE] = softClip(input); + sampleIndex = (sampleIndex + 1) & (RINGSIZE - 1); + + if (sampleOffset < 1024) + { + outputValue = fir(sampleOffset); + ready = true; + sampleOffset += cyclesPerSample; + } + + sampleOffset -= 1024; + + return ready; +} + +void SincResampler::reset() +{ + memset(sample, 0, sizeof(sample)); + sampleOffset = 0; +} + +} // namespace reSIDfp diff --git a/src/engine/platform/sound/c64_fp/resample/SincResampler.h b/src/engine/platform/sound/c64_fp/resample/SincResampler.h new file mode 100644 index 000000000..7502d96fd --- /dev/null +++ b/src/engine/platform/sound/c64_fp/resample/SincResampler.h @@ -0,0 +1,114 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2013 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * Copyright 2004 Dag Lem + * + * 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 SINCRESAMPLER_H +#define SINCRESAMPLER_H + +#include "Resampler.h" + +#include +#include + +#include "../array.h" + +#include "../sidcxx11.h" + +namespace reSIDfp +{ + +/** + * This is the theoretically correct (and computationally intensive) audio sample generation. + * The samples are generated by resampling to the specified sampling frequency. + * The work rate is inversely proportional to the percentage of the bandwidth + * allocated to the filter transition band. + * + * This implementation is based on the paper "A Flexible Sampling-Rate Conversion Method", + * by J. O. Smith and P. Gosset, or rather on the expanded tutorial on the + * [Digital Audio Resampling Home Page](http://www-ccrma.stanford.edu/~jos/resample/). + * + * By building shifted FIR tables with samples according to the sampling frequency, + * this implementation dramatically reduces the computational effort in the + * filter convolutions, without any loss of accuracy. + * The filter convolutions are also vectorizable on current hardware. + */ +class SincResampler final : public Resampler +{ +private: + /// Size of the ring buffer, must be a power of 2 + static const int RINGSIZE = 2048; + +private: + /// Table of the fir filter coefficients + matrix_t* firTable; + + int sampleIndex; + + /// Filter resolution + int firRES; + + /// Filter length + int firN; + + const int cyclesPerSample; + + int sampleOffset; + + int outputValue; + + short sample[RINGSIZE * 2]; + +private: + int fir(int subcycle); + +public: + /** + * Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64. + * The default end of passband frequency is pass_freq = 0.9*sample_freq/2 + * for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample frequencies. + * + * For resampling, the ratio between the clock frequency and the sample frequency + * is limited as follows: 125*clock_freq/sample_freq < 16384 + * E.g. provided a clock frequency of ~ 1MHz, the sample frequency + * can not be set lower than ~ 8kHz. + * A lower sample frequency would make the resampling code overfill its 16k sample ring buffer. + * + * The end of passband frequency is also limited: pass_freq <= 0.9*sample_freq/2 + * + * E.g. for a 44.1kHz sampling rate the end of passband frequency is limited + * to slightly below 20kHz. This constraint ensures that the FIR table is not overfilled. + * + * @param clockFrequency System clock frequency at Hz + * @param samplingFrequency Desired output sampling rate + * @param highestAccurateFrequency + */ + SincResampler(double clockFrequency, double samplingFrequency, double highestAccurateFrequency); + + bool input(int input) override; + + int output() const override { return outputValue; } + + void reset() override; +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/resample/TwoPassSincResampler.h b/src/engine/platform/sound/c64_fp/resample/TwoPassSincResampler.h new file mode 100644 index 000000000..81659193a --- /dev/null +++ b/src/engine/platform/sound/c64_fp/resample/TwoPassSincResampler.h @@ -0,0 +1,83 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2015 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 TWOPASSSINCRESAMPLER_H +#define TWOPASSSINCRESAMPLER_H + +#include + +#include + +#include "Resampler.h" +#include "SincResampler.h" + +#include "../sidcxx11.h" + +namespace reSIDfp +{ + +/** + * Compose a more efficient SINC from chaining two other SINCs. + */ +class TwoPassSincResampler final : public Resampler +{ +private: + std::unique_ptr const s1; + std::unique_ptr const s2; + +private: + TwoPassSincResampler(double clockFrequency, double samplingFrequency, double highestAccurateFrequency, double intermediateFrequency) : + s1(new SincResampler(clockFrequency, intermediateFrequency, highestAccurateFrequency)), + s2(new SincResampler(intermediateFrequency, samplingFrequency, highestAccurateFrequency)) + {} + +public: + // Named constructor + static TwoPassSincResampler* create(double clockFrequency, double samplingFrequency, double highestAccurateFrequency) + { + // Calculation according to Laurent Ganier. It evaluates to about 120 kHz at typical settings. + // Some testing around the chosen value seems to confirm that this does work. + double const intermediateFrequency = 2. * highestAccurateFrequency + + sqrt(2. * highestAccurateFrequency * clockFrequency + * (samplingFrequency - 2. * highestAccurateFrequency) / samplingFrequency); + return new TwoPassSincResampler(clockFrequency, samplingFrequency, highestAccurateFrequency, intermediateFrequency); + } + + bool input(int sample) override + { + return s1->input(sample) && s2->input(s1->output()); + } + + int output() const override + { + return s2->output(); + } + + void reset() override + { + s1->reset(); + s2->reset(); + } +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/resample/ZeroOrderResampler.h b/src/engine/platform/sound/c64_fp/resample/ZeroOrderResampler.h new file mode 100644 index 000000000..2bc80cded --- /dev/null +++ b/src/engine/platform/sound/c64_fp/resample/ZeroOrderResampler.h @@ -0,0 +1,88 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2011-2013 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 ZEROORDER_RESAMPLER_H +#define ZEROORDER_RESAMPLER_H + +#include "Resampler.h" + +#include "../sidcxx11.h" + +namespace reSIDfp +{ + +/** + * Return sample with linear interpolation. + * + * @author Antti Lankila + */ +class ZeroOrderResampler final : public Resampler +{ + +private: + /// Last sample + int cachedSample; + + /// Number of cycles per sample + const int cyclesPerSample; + + int sampleOffset; + + /// Calculated sample + int outputValue; + +public: + ZeroOrderResampler(double clockFrequency, double samplingFrequency) : + cachedSample(0), + cyclesPerSample(static_cast(clockFrequency / samplingFrequency * 1024.)), + sampleOffset(0), + outputValue(0) {} + + bool input(int sample) override + { + bool ready = false; + + if (sampleOffset < 1024) + { + outputValue = cachedSample + (sampleOffset * (sample - cachedSample) >> 10); + ready = true; + sampleOffset += cyclesPerSample; + } + + sampleOffset -= 1024; + + cachedSample = sample; + + return ready; + } + + int output() const override { return outputValue; } + + void reset() override + { + sampleOffset = 0; + cachedSample = 0; + } +}; + +} // namespace reSIDfp + +#endif diff --git a/src/engine/platform/sound/c64_fp/resample/test.cpp b/src/engine/platform/sound/c64_fp/resample/test.cpp new file mode 100644 index 000000000..5e5026fff --- /dev/null +++ b/src/engine/platform/sound/c64_fp/resample/test.cpp @@ -0,0 +1,87 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2012-2013 Leandro Nini + * Copyright 2007-2010 Antti Lankila + * + * 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 +#include +#include +#include +#include +#include + +#include "siddefs-fp.h" + +#include "Resampler.h" +#include "TwoPassSincResampler.h" + +/** + * Simple sin waveform in, power output measurement function. + * It would be far better to use FFT. + */ +int main(int argc, const char* argv[]) +{ + const double RATE = 985248.4; + const int RINGSIZE = 2048; + + std::auto_ptr r(reSIDfp::TwoPassSincResampler::create(RATE, 48000.0, 20000.0)); + + std::map results; + clock_t start = clock(); + + for (double freq = 1000.; freq < RATE / 2.; freq *= 1.01) + { + /* prefill resampler buffer */ + int k = 0; + double omega = 2 * M_PI * freq / RATE; + + for (int j = 0; j < RINGSIZE; j ++) + { + int signal = static_cast(32768.0 * sin(k++ * omega) * sqrt(2)); + r->input(signal); + } + + int n = 0; + float pwr = 0; + + /* Now, during measurement stage, put 100 cycles of waveform through filter. */ + for (int j = 0; j < 100000; j ++) + { + int signal = static_cast(32768.0 * sin(k++ * omega) * sqrt(2)); + + if (r->input(signal)) + { + float out = r->output(); + pwr += out * out; + n += 1; + } + } + + results.insert(std::make_pair(freq, 10 * log10(pwr / n))); + } + + clock_t end = clock(); + + for (std::map::iterator it = results.begin(); it != results.end(); ++it) + { + std::cout << std::fixed << std::setprecision(0) << std::setw(6) << (*it).first << " Hz " << (*it).second << " dB" << std::endl; + } + + std::cout << "Filtering time " << (end - start) * 1000. / CLOCKS_PER_SEC << " ms" << std::endl; +} diff --git a/src/engine/platform/sound/c64_fp/sidcxx11.h b/src/engine/platform/sound/c64_fp/sidcxx11.h new file mode 100644 index 000000000..18eadf4ae --- /dev/null +++ b/src/engine/platform/sound/c64_fp/sidcxx11.h @@ -0,0 +1,29 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2014-2015 Leandro Nini + * + * 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 SIDCXX11_H +#define SIDCXX11_H + +#define DEFAULT = default +#define DELETE = delete + +#define HAVE_CXX11 + +#endif diff --git a/src/engine/platform/sound/c64_fp/sidcxx14.h b/src/engine/platform/sound/c64_fp/sidcxx14.h new file mode 100644 index 000000000..5078a0b1a --- /dev/null +++ b/src/engine/platform/sound/c64_fp/sidcxx14.h @@ -0,0 +1,29 @@ +/* + * This file is part of libsidplayfp, a SID player engine. + * + * Copyright 2014-2015 Leandro Nini + * + * 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 SIDCXX14_H +#define SIDCXX14_H + +#include "sidcxx11.h" + +#define MAKE_UNIQUE(type, ...) std::make_unique(__VA_ARGS__) +#define HAVE_CXX14 + +#endif diff --git a/src/engine/platform/sound/c64_fp/siddefs-fp.h b/src/engine/platform/sound/c64_fp/siddefs-fp.h new file mode 100644 index 000000000..439008621 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/siddefs-fp.h @@ -0,0 +1,62 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// 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 SIDDEFS_FP_H +#define SIDDEFS_FP_H + +// Compilation configuration. +#define RESID_BRANCH_HINTS 0 + +// Compiler specifics. +#define HAVE_BUILTIN_EXPECT 0 + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +// Branch prediction macros, lifted off the Linux kernel. +#if RESID_BRANCH_HINTS && HAVE_BUILTIN_EXPECT +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + +namespace reSIDfp { + +typedef enum { MOS6581=1, MOS8580 } ChipModel; + +typedef enum { DECIMATE=1, RESAMPLE } SamplingMethod; +} + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* residfp_version_string; +#else +const char* residfp_version_string = "furnace"; +#endif +} + +// Inlining on/off. +#define RESID_INLINING 1 +#define RESID_INLINE inline + +#endif // SIDDEFS_FP_H diff --git a/src/engine/platform/sound/c64_fp/version.cc b/src/engine/platform/sound/c64_fp/version.cc new file mode 100644 index 000000000..3ed8b4490 --- /dev/null +++ b/src/engine/platform/sound/c64_fp/version.cc @@ -0,0 +1,21 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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. +// --------------------------------------------------------------------------- + +#define __VERSION_CC__ +#include "siddefs-fp.h" diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 65baf4fd3..a79948b93 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -133,6 +133,8 @@ const char* aboutLine[]={ "puNES (NES, MMC5 and FDS) by FHorse", "NSFPlay (NES and FDS) by Brad Smith and Brezza", "reSID by Dag Lem", + "reSIDfp by Dag Lem, Antti Lankila", + "and Leandro Nini", "Stella by Stella Team", "QSound emulator by superctr and Valley Bell", "VICE VIC-20 sound core by Rami Rasanen and viznut", diff --git a/src/gui/gui.h b/src/gui/gui.h index 48b8e12cb..2cd850204 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1049,6 +1049,7 @@ class FurnaceGUI { int snCore; int nesCore; int fdsCore; + int c64Core; int pcSpeakerOutMethod; String yrw801Path; String tg100Path; @@ -1168,6 +1169,7 @@ class FurnaceGUI { snCore(0), nesCore(0), fdsCore(0), + c64Core(1), pcSpeakerOutMethod(0), yrw801Path(""), tg100Path(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1e9a14457..27720112a 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -97,6 +97,11 @@ const char* nesCores[]={ "NSFplay" }; +const char* c64Cores[]={ + "reSID", + "reSIDfp" +}; + const char* pcspkrOutMethods[]={ "evdev SND_TONE", "KIOCSOUND on /dev/tty1", @@ -972,6 +977,10 @@ void FurnaceGUI::drawSettings() { ImGui::SameLine(); ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2); + ImGui::Text("SID core"); + ImGui::SameLine(); + ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,2); + ImGui::Separator(); ImGui::Text("PC Speaker strategy"); @@ -2155,6 +2164,7 @@ void FurnaceGUI::syncSettings() { settings.snCore=e->getConfInt("snCore",0); settings.nesCore=e->getConfInt("nesCore",0); settings.fdsCore=e->getConfInt("fdsCore",0); + settings.c64Core=e->getConfInt("c64Core",1); settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0); settings.yrw801Path=e->getConfString("yrw801Path",""); settings.tg100Path=e->getConfString("tg100Path",""); @@ -2267,6 +2277,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.snCore,0,1); clampSetting(settings.nesCore,0,1); clampSetting(settings.fdsCore,0,1); + clampSetting(settings.c64Core,0,1); clampSetting(settings.pcSpeakerOutMethod,0,4); clampSetting(settings.mainFont,0,6); clampSetting(settings.patFont,0,6); @@ -2402,6 +2413,7 @@ void FurnaceGUI::commitSettings() { e->setConf("snCore",settings.snCore); e->setConf("nesCore",settings.nesCore); e->setConf("fdsCore",settings.fdsCore); + e->setConf("c64Core",settings.c64Core); e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod); e->setConf("yrw801Path",settings.yrw801Path); e->setConf("tg100Path",settings.tg100Path); diff --git a/src/main.cpp b/src/main.cpp index 39c9e6ca2..a18560926 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -181,6 +181,7 @@ TAParamResult pVersion(String) { printf("- puNES by FHorse (GPLv2)\n"); printf("- NSFPlay by Brad Smith and Brezza (unknown open-source license)\n"); printf("- reSID by Dag Lem (GPLv2)\n"); + printf("- reSIDfp by Dag Lem, Antti Lankila and Leandro Nini (GPLv2)\n"); printf("- Stella by Stella Team (GPLv2)\n"); printf("- vgsound_emu (first version) by cam900 (BSD 3-clause)\n"); return TA_PARAM_QUIT; From d485af439db9f71daf699dae2601a88965151355 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Aug 2022 15:36:12 -0500 Subject: [PATCH 322/515] fix macOS build --- src/engine/platform/sound/c64_fp/WaveformGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp b/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp index 16a9eb6b6..e5e544e7b 100644 --- a/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp +++ b/src/engine/platform/sound/c64_fp/WaveformGenerator.cpp @@ -56,7 +56,7 @@ namespace reSIDfp const unsigned int FLOATING_OUTPUT_TTL_6581R3 = 54000; const unsigned int FLOATING_OUTPUT_FADE_6581R3 = 1400; // ~1s -const unsigned int FLOATING_OUTPUT_TTL_6581R4 = 1000000; +//const unsigned int FLOATING_OUTPUT_TTL_6581R4 = 1000000; // ~1s const unsigned int FLOATING_OUTPUT_TTL_8580R5 = 800000; const unsigned int FLOATING_OUTPUT_FADE_8580R5 = 50000; @@ -74,7 +74,7 @@ const unsigned int FLOATING_OUTPUT_FADE_8580R5 = 50000; const unsigned int SHIFT_REGISTER_RESET_6581R3 = 50000; const unsigned int SHIFT_REGISTER_FADE_6581R3 = 15000; // ~2.15s -const unsigned int SHIFT_REGISTER_RESET_6581R4 = 2150000; +//const unsigned int SHIFT_REGISTER_RESET_6581R4 = 2150000; // ~2.8s const unsigned int SHIFT_REGISTER_RESET_8580R5 = 986000; const unsigned int SHIFT_REGISTER_FADE_8580R5 = 314300; From 6041b8f14f366104a7f231086e81fb5025ecc266 Mon Sep 17 00:00:00 2001 From: Lunathir <18320914+lunathir@users.noreply.github.com> Date: Sun, 28 Aug 2022 13:54:05 -0700 Subject: [PATCH 323/515] Change references to some chips (#658) * Update sysDef.cpp * Update sysDef.cpp * Update sysDef.cpp * Update sysDef.cpp --- src/engine/sysDef.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 1c63431f9..78af262a4 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1370,7 +1370,7 @@ void DivEngine::registerSystems() { // to Grauw: feel free to change this to 24 during development of OPL4's PCM part. sysDefs[DIV_SYSTEM_OPL4]=new DivSysDef( - "Yamaha OPL4", NULL, 0xae, 0, 42, true, true, 0, false, + "Yamaha YMF278B (OPL4)", NULL, 0xae, 0, 42, true, true, 0, false, "like OPL3, but this time it also has a 24-channel version of MultiPCM.", {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18", "PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "PCM 17", "PCM 18", "PCM 19", "PCM 20", "PCM 21", "PCM 22", "PCM 23", "PCM 24"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"}, @@ -1379,7 +1379,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_OPL4_DRUMS]=new DivSysDef( - "Yamaha OPL4 with drums", NULL, 0xaf, 0, 44, true, true, 0, false, + "Yamaha YMF278B (OPL4) with drums", NULL, 0xaf, 0, 44, true, true, 0, false, "the OPL4 but with drums mode turned on.", {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick/FM 16", "Snare", "Tom", "Top", "HiHat", "PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "PCM 17", "PCM 18", "PCM 19", "PCM 20", "PCM 21", "PCM 22", "PCM 23", "PCM 24"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "BD", "SD", "TM", "TP", "HH", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"}, From 32050a211ff17ac57c705825a886ac145f08c3c7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Aug 2022 15:54:21 -0500 Subject: [PATCH 324/515] GUI: update credits --- src/gui/about.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index a79948b93..39cb1192e 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -102,6 +102,7 @@ const char* aboutLine[]={ "fd", "GENATARi", "host12prog", + "lunathir", "plane", "TheEssem", "", From c2a7bdd19460ed8d91f932e1ba0a06e495479227 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 29 Aug 2022 11:45:18 +0900 Subject: [PATCH 325/515] Match this to actual channel count --- src/engine/platform/su.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 136503457..730f8d892 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -581,7 +581,7 @@ int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, unsigned su=new SoundUnit(); setFlags(flags); reset(); - return 6; + return 8; } void DivPlatformSoundUnit::quit() { From 8d280fd9a32496bc53870a5142fbc7af714edc87 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 29 Aug 2022 03:26:49 -0500 Subject: [PATCH 326/515] C64: bind reSIDfp --- src/engine/dispatchContainer.cpp | 2 ++ src/engine/platform/c64.cpp | 59 +++++++++++++++++++++++++------- src/engine/platform/c64.h | 8 +++++ 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 8d8db5c5a..158bce4ef 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -218,10 +218,12 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_C64_6581: dispatch=new DivPlatformC64; + ((DivPlatformC64*)dispatch)->setFP(eng->getConfInt("c64Core",1)==1); ((DivPlatformC64*)dispatch)->setChipModel(true); break; case DIV_SYSTEM_C64_8580: dispatch=new DivPlatformC64; + ((DivPlatformC64*)dispatch)->setFP(eng->getConfInt("c64Core",1)==1); ((DivPlatformC64*)dispatch)->setChipModel(false); break; case DIV_SYSTEM_YM2151: diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 9825f189e..5d1eb53cc 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -19,9 +19,10 @@ #include "c64.h" #include "../engine.h" +#include "sound/c64_fp/siddefs-fp.h" #include -#define rWrite(a,v) if (!skipRegisterWrites) {sid.write(a,v); regPool[(a)&0x1f]=v; if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {if (isFP) {sid_fp.write(a,v);} else {sid.write(a,v);}; regPool[(a)&0x1f]=v; if (dumpWrites) {addWrite(a,v);} } #define CHIP_FREQBASE 524288 @@ -63,15 +64,19 @@ const char** DivPlatformC64::getRegisterSheet() { } void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) { - int dcOff=sid.get_dc(0); + int dcOff=isFP?0:sid.get_dc(0); for (size_t i=start; i=8) { - writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=(sid.last_chan_out[0]-dcOff)>>5; - oscBuf[1]->data[oscBuf[1]->needle++]=(sid.last_chan_out[1]-dcOff)>>5; - oscBuf[2]->data[oscBuf[2]->needle++]=(sid.last_chan_out[2]-dcOff)>>5; + if (isFP) { + sid_fp.clock(4,&bufL[i]); + } else { + sid.clock(); + bufL[i]=sid.output(); + if (++writeOscBuf>=8) { + writeOscBuf=0; + oscBuf[0]->data[oscBuf[0]->needle++]=(sid.last_chan_out[0]-dcOff)>>5; + oscBuf[1]->data[oscBuf[1]->needle++]=(sid.last_chan_out[1]-dcOff)>>5; + oscBuf[2]->data[oscBuf[2]->needle++]=(sid.last_chan_out[2]-dcOff)>>5; + } } } } @@ -405,7 +410,11 @@ int DivPlatformC64::dispatch(DivCommand c) { void DivPlatformC64::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - sid.set_is_muted(ch,mute); + if (isFP) { + sid_fp.mute(ch,mute); + } else { + sid.set_is_muted(ch,mute); + } } void DivPlatformC64::forceIns() { @@ -462,13 +471,21 @@ bool DivPlatformC64::getWantPreNote() { return true; } +float DivPlatformC64::getPostAmp() { + return isFP?3.0f:1.0f; +} + void DivPlatformC64::reset() { for (int i=0; i<3; i++) { chan[i]=DivPlatformC64::Channel(); chan[i].std.setEngine(parent); } - sid.reset(); + if (isFP) { + sid_fp.reset(); + } else { + sid.reset(); + } memset(regPool,0,32); rWrite(0x18,0x0f); @@ -490,12 +507,24 @@ void DivPlatformC64::poke(std::vector& wlist) { void DivPlatformC64::setChipModel(bool is6581) { if (is6581) { - sid.set_chip_model(MOS6581); + if (isFP) { + sid_fp.setChipModel(reSIDfp::MOS6581); + } else { + sid.set_chip_model(MOS6581); + } } else { - sid.set_chip_model(MOS8580); + if (isFP) { + sid_fp.setChipModel(reSIDfp::MOS8580); + } else { + sid.set_chip_model(MOS8580); + } } } +void DivPlatformC64::setFP(bool fp) { + isFP=fp; +} + void DivPlatformC64::setFlags(unsigned int flags) { switch (flags&0xf) { case 0x0: // NTSC C64 @@ -513,6 +542,10 @@ void DivPlatformC64::setFlags(unsigned int flags) { for (int i=0; i<3; i++) { oscBuf[i]->rate=rate/16; } + if (isFP) { + rate/=4; + sid_fp.setSamplingParameters(chipClock,reSIDfp::DECIMATE,rate,0); + } } int DivPlatformC64::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index 799635977..7587730b0 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -23,6 +23,7 @@ #include "../dispatch.h" #include "../macroInt.h" #include "sound/c64/sid.h" +#include "sound/c64_fp/SID.h" class DivPlatformC64: public DivDispatch { struct Channel { @@ -76,12 +77,17 @@ class DivPlatformC64: public DivDispatch { unsigned char filtControl, filtRes, vol; unsigned char writeOscBuf; int filtCut, resetTime; + bool isFP; SID sid; + reSIDfp::SID sid_fp; unsigned char regPool[32]; friend void putDispatchChan(void*,int,int); + void acquire_classic(short* bufL, short* bufR, size_t start, size_t len); + void acquire_fp(short* bufL, short* bufR, size_t start, size_t len); + void updateFilter(); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); @@ -98,6 +104,7 @@ class DivPlatformC64: public DivDispatch { void notifyInsChange(int ins); bool getDCOffRequired(); bool getWantPreNote(); + float getPostAmp(); DivMacroInt* getChanMacroInt(int ch); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); @@ -105,6 +112,7 @@ class DivPlatformC64: public DivDispatch { const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void setChipModel(bool is6581); + void setFP(bool fp); void quit(); ~DivPlatformC64(); }; From 4b4a2540646460ca0dd4777aff24344cc8233563 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 29 Aug 2022 03:54:55 -0500 Subject: [PATCH 327/515] C64: reSIDfp per-chan osc --- src/engine/platform/c64.cpp | 8 +++++++- src/engine/platform/sound/c64_fp/SID.h | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 5d1eb53cc..ad1113470 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -68,10 +68,16 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) for (size_t i=start; i=4) { + writeOscBuf=0; + oscBuf[0]->data[oscBuf[0]->needle++]=(sid_fp.lastChanOut[0]-dcOff)>>5; + oscBuf[1]->data[oscBuf[1]->needle++]=(sid_fp.lastChanOut[1]-dcOff)>>5; + oscBuf[2]->data[oscBuf[2]->needle++]=(sid_fp.lastChanOut[2]-dcOff)>>5; + } } else { sid.clock(); bufL[i]=sid.output(); - if (++writeOscBuf>=8) { + if (++writeOscBuf>=16) { writeOscBuf=0; oscBuf[0]->data[oscBuf[0]->needle++]=(sid.last_chan_out[0]-dcOff)>>5; oscBuf[1]->data[oscBuf[1]->needle++]=(sid.last_chan_out[1]-dcOff)>>5; diff --git a/src/engine/platform/sound/c64_fp/SID.h b/src/engine/platform/sound/c64_fp/SID.h index 05ad83c3b..85b6a4e4d 100644 --- a/src/engine/platform/sound/c64_fp/SID.h +++ b/src/engine/platform/sound/c64_fp/SID.h @@ -132,7 +132,7 @@ private: * * @return the output sample */ - int output() const; + int output(); /** * Calculate the numebr of cycles according to current parameters @@ -146,6 +146,8 @@ public: SID(); ~SID(); + int lastChanOut[3]; + /** * Set chip model. * @@ -312,12 +314,16 @@ void SID::ageBusValue(unsigned int n) } RESID_INLINE -int SID::output() const +int SID::output() { const int v1 = voice[0]->output(voice[2]->wave()); const int v2 = voice[1]->output(voice[0]->wave()); const int v3 = voice[2]->output(voice[1]->wave()); + lastChanOut[0]=v1; + lastChanOut[1]=v2; + lastChanOut[2]=v3; + return externalFilter->clock(filter->clock(v1, v2, v3)); } From 3af287cf9de2bba751244954b303b324c6009b53 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 29 Aug 2022 04:15:53 -0500 Subject: [PATCH 328/515] AY: fix per-chan osc in Sunsoft 5B mode --- src/engine/platform/ay.cpp | 44 ++++++++++++++++++---------- src/engine/platform/sound/ay8910.cpp | 2 ++ src/engine/platform/sound/ay8910.h | 2 ++ 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index f45c51ea7..23f20c2a0 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -69,6 +69,14 @@ const char* regCheatSheetAY8914[]={ NULL }; +// taken from ay8910.cpp +const int sunsoftVolTable[32]={ + 103350, 73770, 52657, 37586, 32125, 27458, 24269, 21451, + 18447, 15864, 14009, 12371, 10506, 8922, 7787, 6796, + 5689, 4763, 4095, 3521, 2909, 2403, 2043, 1737, + 1397, 1123, 925, 762, 578, 438, 332, 251 +}; + const char** DivPlatformAY8910::getRegisterSheet() { return intellivision?regCheatSheetAY8914:regCheatSheetAY; } @@ -93,27 +101,33 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l regPool[w.addr&0x0f]=w.val; writes.pop(); } - ay->sound_stream_update(ayBuf,len); if (sunsoft) { for (size_t i=0; isound_stream_update(ayBuf,1); + bufL[i+start]=ayBuf[0][0]; bufR[i+start]=bufL[i+start]; - } - } else if (stereo) { - for (size_t i=0; idata[oscBuf[0]->needle++]=sunsoftVolTable[31-(ay->lastIndx&31)]>>3; + oscBuf[1]->data[oscBuf[1]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>5)&31)]>>3; + oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]>>3; } } else { - for (size_t i=0; isound_stream_update(ayBuf,len); + if (stereo) { + for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]; + for (int ch=0; ch<3; ch++) { + for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]; + } } } } diff --git a/src/engine/platform/sound/ay8910.cpp b/src/engine/platform/sound/ay8910.cpp index 2c11b6e3f..c7be503e7 100644 --- a/src/engine/platform/sound/ay8910.cpp +++ b/src/engine/platform/sound/ay8910.cpp @@ -924,6 +924,7 @@ float ay8910_device::mix_3D() indx |= tone_mask | (m_vol_enabled[chan] ? tone_volume(tone) << (chan*5) : 0); } } + lastIndx=indx; return m_vol3d_table[indx]; } @@ -1359,6 +1360,7 @@ unsigned char ay8910_device::ay8910_read_ym() void ay8910_device::device_reset() { + lastIndx=0; ay8910_reset_ym(); } diff --git a/src/engine/platform/sound/ay8910.h b/src/engine/platform/sound/ay8910.h index 314383f57..6f4c6f318 100644 --- a/src/engine/platform/sound/ay8910.h +++ b/src/engine/platform/sound/ay8910.h @@ -146,6 +146,8 @@ public: double m_Kn[32]; }; + int lastIndx; + // internal interface for PSG component of YM device // FIXME: these should be private, but vector06 accesses them directly From e1deee40547d45bd1299f5fbdff9cc1559b741e5 Mon Sep 17 00:00:00 2001 From: Alexis <99325922+ActualNK358@users.noreply.github.com> Date: Mon, 29 Aug 2022 11:12:44 -0500 Subject: [PATCH 329/515] Add a Pseudo-GBA demo song Song is "Godot - The Fragrance of Dark Colored Coffee" from the Phoenix Wright: Ace Attorney - Trials & Tribulations OST. :) --- demos/pseudogba_pwaa_godot.fur | Bin 0 -> 157205 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/pseudogba_pwaa_godot.fur diff --git a/demos/pseudogba_pwaa_godot.fur b/demos/pseudogba_pwaa_godot.fur new file mode 100644 index 0000000000000000000000000000000000000000..5bb97a2f8630b974c5edc79771c249e956e95ec0 GIT binary patch literal 157205 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

    ZThxWM`* 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

    7PNOn^-U^GCS=lR6Z=} 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 Date: Tue, 30 Aug 2022 15:47:12 -0500 Subject: [PATCH 330/515] NES: #655 --- src/engine/platform/nes.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index ab466f1b5..50fcd5ca6 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -115,11 +115,11 @@ void DivPlatformNES::acquire_puNES(short* bufL, short* bufR, size_t start, size_ bufL[i]=sample; if (++writeOscBuf>=32) { writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=nes->S1.output<<11; - oscBuf[1]->data[oscBuf[1]->needle++]=nes->S2.output<<11; - oscBuf[2]->data[oscBuf[2]->needle++]=nes->TR.output<<11; - oscBuf[3]->data[oscBuf[3]->needle++]=nes->NS.output<<11; - oscBuf[4]->data[oscBuf[4]->needle++]=nes->DMC.output<<8; + oscBuf[0]->data[oscBuf[0]->needle++]=isMuted[0]?0:(nes->S1.output<<11); + oscBuf[1]->data[oscBuf[1]->needle++]=isMuted[1]?0:(nes->S2.output<<11); + oscBuf[2]->data[oscBuf[2]->needle++]=isMuted[2]?0:(nes->TR.output<<11); + oscBuf[3]->data[oscBuf[3]->needle++]=isMuted[3]?0:(nes->NS.output<<11); + oscBuf[4]->data[oscBuf[4]->needle++]=isMuted[4]?0:(nes->DMC.output<<8); } } } From 95db5624144503a7a8f38e38b7560868f2da8359 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 30 Aug 2022 16:28:05 -0500 Subject: [PATCH 331/515] fix Android build --- src/engine/config.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/engine/config.cpp b/src/engine/config.cpp index f404c0a4f..862cd4c03 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -36,12 +36,20 @@ #define CONFIG_FILE "/furnace.cfg" #endif +#ifdef IS_MOBILE +#ifdef HAVE_SDL2 +#include +#else +#error "Furnace mobile requires SDL2!" +#endif +#endif + void DivEngine::initConfDir() { #ifdef _WIN32 // maybe move this function in here instead? configPath=getWinConfigPath(); -#elif defined (IS_MOBILE) - configPath=SDL_GetPrefPath(); +#elif defined(IS_MOBILE) + configPath=SDL_GetPrefPath("tildearrow","furnace"); #else #ifdef __HAIKU__ char userSettingsDir[PATH_MAX]; From 7f01eaec9d0b08966eaab2c3179d282c3c933f4b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 30 Aug 2022 23:59:38 -0500 Subject: [PATCH 332/515] convert note/macro rel to note off on .dmf save --- src/engine/fileOps.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 0e0ceb8bd..66ca9d468 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -4342,14 +4342,25 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } } + bool relWarning=false; + for (int i=0; iwriteC(curPat[i].effectCols); for (int j=0; jordersLen; j++) { DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][j],false); for (int k=0; kpatLen; k++) { - w->writeS(pat->data[k][0]); // note - w->writeS(pat->data[k][1]); // octave + if ((pat->data[k][0]==101 || pat->data[k][0]==102) && pat->data[k][1]==0) { + w->writeS(100); + w->writeS(0); + if (!relWarning) { + relWarning=true; + addWarning("note/macro release will be converted to note off!"); + } + } else { + w->writeS(pat->data[k][0]); // note + w->writeS(pat->data[k][1]); // octave + } w->writeS(pat->data[k][3]); // volume #ifdef TA_BIG_ENDIAN for (int l=0; l Date: Wed, 31 Aug 2022 00:51:08 -0500 Subject: [PATCH 333/515] WonderSwan: fix possible hang when seeking --- src/engine/platform/swan.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 7f1e10a02..7ac266299 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -59,7 +59,8 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len DivSample* s=parent->getSample(dacSample); if (s->samples<=0) { dacSample=-1; - continue; + dacPeriod=0; + break; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); if (s->isLoopable() && dacPos>=s->getEndPosition()) { From f3c3d82e4d8321684346c4f8ab92c591ec2305fe Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 31 Aug 2022 02:52:35 -0500 Subject: [PATCH 334/515] fix hang when swapping chips fixes #660 --- src/engine/engine.cpp | 47 ++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 1230cb599..bee077511 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1140,7 +1140,7 @@ void DivEngine::swapChannels(int src, int dest) { String prevChanName=curSubSong->chanName[src]; String prevChanShortName=curSubSong->chanShortName[src]; bool prevChanShow=curSubSong->chanShow[src]; - bool prevChanCollapse=curSubSong->chanCollapse[src]; + unsigned char prevChanCollapse=curSubSong->chanCollapse[src]; curSubSong->chanName[src]=curSubSong->chanName[dest]; curSubSong->chanShortName[src]=curSubSong->chanShortName[dest]; @@ -1445,25 +1445,44 @@ bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) { } } + // swap channels logV("swap list:"); for (int i=0; i %d",unswappedChannels[i],swappedChannels[i]); } - // swap channels - bool allComplete=false; - while (!allComplete) { - logD("doing swap..."); - allComplete=true; - for (int i=0; i %d -> %d",unswappedChannels[i],unswappedChannels[swappedChannels[i]]); - unswappedChannels[i]^=unswappedChannels[swappedChannels[i]]; - unswappedChannels[swappedChannels[i]]^=unswappedChannels[i]; - unswappedChannels[i]^=unswappedChannels[swappedChannels[i]]; + for (size_t i=0; iorders; + DivPattern* prevPat[DIV_MAX_CHANS][256]; + unsigned char prevEffectCols[DIV_MAX_CHANS]; + String prevChanName[DIV_MAX_CHANS]; + String prevChanShortName[DIV_MAX_CHANS]; + bool prevChanShow[DIV_MAX_CHANS]; + unsigned char prevChanCollapse[DIV_MAX_CHANS]; + + for (int j=0; jpat[j].data[k]; } + prevEffectCols[j]=song.subsong[i]->pat[j].effectCols; + + prevChanName[j]=song.subsong[i]->chanName[j]; + prevChanShortName[j]=song.subsong[i]->chanShortName[j]; + prevChanShow[j]=song.subsong[i]->chanShow[j]; + prevChanCollapse[j]=song.subsong[i]->chanCollapse[j]; + } + + for (int j=0; jorders.ord[j][k]=prevOrders.ord[swappedChannels[j]][k]; + song.subsong[i]->pat[j].data[k]=prevPat[swappedChannels[j]][k]; + } + + song.subsong[i]->pat[j].effectCols=prevEffectCols[swappedChannels[j]]; + song.subsong[i]->chanName[j]=prevChanName[swappedChannels[j]]; + song.subsong[i]->chanShortName[j]=prevChanShortName[swappedChannels[j]]; + song.subsong[i]->chanShow[j]=prevChanShow[swappedChannels[j]]; + song.subsong[i]->chanCollapse[j]=prevChanCollapse[swappedChannels[j]]; } } } From 820b23ecdbb9f902f279a233a8efc1291e6722ea Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 31 Aug 2022 03:05:06 -0500 Subject: [PATCH 335/515] fix macros sometimes being out of sync when seekin --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bee077511..4a8b7f5b2 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1666,7 +1666,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { } } int oldOrder=curOrder; - while (playing && curRow1)) { if (nextTick(preserveDrift)) { skipping=false; return; From 16eba9ec96fbbd29daaaa15dfddd64284bb61e8e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 31 Aug 2022 03:11:02 -0500 Subject: [PATCH 336/515] fix macro delay not working on first note --- src/engine/macroInt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index ad761ba53..5208dc542 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -50,7 +50,7 @@ struct DivMacroStruct { finished(false), will(false), linger(false), - began(false), + began(true), mode(0) {} }; From a33e6e3989f6cd12f3ca9b3ab39d42bd33f8c4d7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 31 Aug 2022 03:34:13 -0500 Subject: [PATCH 337/515] GUI: add "create wave from selection" option in sample editor --- src/gui/doAction.cpp | 26 ++++++++++++++++++++++++++ src/gui/gui.h | 1 + src/gui/guiConst.cpp | 1 + src/gui/sampleEdit.cpp | 3 +++ 4 files changed, 31 insertions(+) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index e0f0ca30a..919166699 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -1295,6 +1295,32 @@ void FurnaceGUI::doAction(int what) { MARK_MODIFIED; break; } + case GUI_ACTION_SAMPLE_CREATE_WAVE: { + if (curSample<0 || curSample>=(int)e->song.sample.size()) break; + DivSample* sample=e->song.sample[curSample]; + SAMPLE_OP_BEGIN; + if (end-start<1) { + showError("select at least one sample!"); + } else if (end-start>256) { + showError("maximum size is 256 samples!"); + } else { + curWave=e->addWave(); + if (curWave==-1) { + showError("too many wavetables!"); + } else { + DivWavetable* wave=e->song.wave[curWave]; + wave->min=0; + wave->max=255; + wave->len=end-start; + for (unsigned int i=start; idata[i-start]=(sample->data8[i]&0xff)^0x80; + } + nextWindow=GUI_WINDOW_WAVE_EDIT; + MARK_MODIFIED; + } + } + break; + } case GUI_ACTION_ORDERS_UP: if (curOrder>0) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 2cd850204..9938e3cc3 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -525,6 +525,7 @@ enum FurnaceGUIActions { GUI_ACTION_SAMPLE_ZOOM_AUTO, GUI_ACTION_SAMPLE_MAKE_INS, GUI_ACTION_SAMPLE_SET_LOOP, + GUI_ACTION_SAMPLE_CREATE_WAVE, GUI_ACTION_SAMPLE_MAX, GUI_ACTION_ORDERS_MIN, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index d1ef835c9..bf075f2f3 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -641,6 +641,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("SAMPLE_ZOOM_AUTO", "Toggle auto-zoom", FURKMOD_CMD|SDLK_0), D("SAMPLE_MAKE_INS", "Create instrument from sample", 0), D("SAMPLE_SET_LOOP", "Set loop to selection", FURKMOD_CMD|SDLK_l), + D("SAMPLE_CREATE_WAVE", "Create wavetable from selection", FURKMOD_CMD|SDLK_w), D("SAMPLE_MAX", "", NOT_AN_ACTION), D("ORDERS_MIN", "---Orders", NOT_AN_ACTION), diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index e9b5cfb35..0ce1500e9 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1293,6 +1293,9 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::MenuItem("set loop to selection",BIND_FOR(GUI_ACTION_SAMPLE_SET_LOOP))) { doAction(GUI_ACTION_SAMPLE_SET_LOOP); } + if (ImGui::MenuItem("create wavetable from selection",BIND_FOR(GUI_ACTION_SAMPLE_CREATE_WAVE))) { + doAction(GUI_ACTION_SAMPLE_CREATE_WAVE); + } ImGui::EndPopup(); } From b213368d034b5aa9bbf92248b570d4c7dadd1949 Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Wed, 31 Aug 2022 14:05:47 -0700 Subject: [PATCH 338/515] New instrument proposal --- instruments/FM/guitar/Banjo (Muted).opni | Bin 0 -> 83 bytes instruments/FM/guitar/Banjo.opni | Bin 0 -> 83 bytes instruments/FM/guitar/Koto.opni | Bin 0 -> 83 bytes instruments/FM/guitar/Oud.opni | Bin 0 -> 83 bytes .../FM/guitar/Shamisen (Regular Pluck).opni | Bin 0 -> 83 bytes instruments/FM/guitar/Shamisen (Tsugaru Slap).opni | Bin 0 -> 83 bytes instruments/FM/guitar/Sitar.opni | Bin 0 -> 83 bytes instruments/FM/guitar/Tamboura (Bass Sitar).opni | Bin 0 -> 83 bytes 8 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/FM/guitar/Banjo (Muted).opni create mode 100644 instruments/FM/guitar/Banjo.opni create mode 100644 instruments/FM/guitar/Koto.opni create mode 100644 instruments/FM/guitar/Oud.opni create mode 100644 instruments/FM/guitar/Shamisen (Regular Pluck).opni create mode 100644 instruments/FM/guitar/Shamisen (Tsugaru Slap).opni create mode 100644 instruments/FM/guitar/Sitar.opni create mode 100644 instruments/FM/guitar/Tamboura (Bass Sitar).opni diff --git a/instruments/FM/guitar/Banjo (Muted).opni b/instruments/FM/guitar/Banjo (Muted).opni new file mode 100644 index 0000000000000000000000000000000000000000..1bf6e88fb38b7fc55ccf6a4f4cb209884906fa1a GIT binary patch literal 83 zcmWId5AZY6_4G3eVPIll@GUJ#O;K=4%*)DWzyXvP0_El9h1eMaRpc2M*csfkQa`|Y E0fsCIE&u=k literal 0 HcmV?d00001 diff --git a/instruments/FM/guitar/Shamisen (Regular Pluck).opni b/instruments/FM/guitar/Shamisen (Regular Pluck).opni new file mode 100644 index 0000000000000000000000000000000000000000..c25acca1e7b9529b36934355efc0f36d3a44d26a GIT binary patch literal 83 zcmWId5AZY6_4G3eVPIll2+l~%%`8sMQ}D|#%1z8+zyg>UQibEiI3pR1)Z{rCeli$o S$a67#XE0)r=jY1=s|Ns}I1Qfw literal 0 HcmV?d00001 diff --git a/instruments/FM/guitar/Shamisen (Tsugaru Slap).opni b/instruments/FM/guitar/Shamisen (Tsugaru Slap).opni new file mode 100644 index 0000000000000000000000000000000000000000..ed9c9497dc5669a04da0d1ead6d9eb352ad2a91e GIT binary patch literal 83 zcmWId5AZY6_4G3eVPIll2+l~%%`8sMQwYvUEMUM2m>5!d;>9>C8I08AIT?O37-`6J QF??q*Vvy(O%LMBH0CS%V-v9sr literal 0 HcmV?d00001 diff --git a/instruments/FM/guitar/Sitar.opni b/instruments/FM/guitar/Sitar.opni new file mode 100644 index 0000000000000000000000000000000000000000..3427fe2a7054ddeafd2eabe054e6806468dbd017 GIT binary patch literal 83 zcmWId5AZY6_4G3eVPIll2+k}?EMmY5m>8s#1bBF>7zE|y**OFmQdLB_d7>B$ndG^7 HG{HInm~02N literal 0 HcmV?d00001 diff --git a/instruments/FM/guitar/Tamboura (Bass Sitar).opni b/instruments/FM/guitar/Tamboura (Bass Sitar).opni new file mode 100644 index 0000000000000000000000000000000000000000..e6514b73c2bbbc08c049d16baf4959512c49ec8a GIT binary patch literal 83 zcmWId5AZY6_4G3eVPIll2uaLM$}cTSWWWuW8MM{7*f=a0L=?rDSTq Date: Wed, 31 Aug 2022 14:11:10 -0700 Subject: [PATCH 339/515] One last instrument proposal --- instruments/FM/percussion/Kalimba.fui | Bin 0 -> 1893 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/FM/percussion/Kalimba.fui diff --git a/instruments/FM/percussion/Kalimba.fui b/instruments/FM/percussion/Kalimba.fui new file mode 100644 index 0000000000000000000000000000000000000000..128deca3fd33b48c86e15a69a110d7b9bfeb23c2 GIT binary patch literal 1893 zcmdOOD=o@POioqE%quP_($g(qU|>)HVi@rB3l6bmXJ9B`U}W%4%*o76N@QRLN-}{I z$TKi8^D8od1z;MGX?b2YPJVaX^5SAlT>MHvL)egYA=vV4jGX*HyFeCV0sIV14nSuy zFmOOIkU|3TNNj@4|3DS^Fg63w)q|WuEc{UO<8(n@R*oE%r;m#+NPAT<2 zA@gDKqxPVdJFsv8mcpz7tOpnw{sRGn0*(?8p&D=DMNA+g8AS#YZ$ZQlEW<$ Date: Thu, 1 Sep 2022 10:49:49 -0700 Subject: [PATCH 340/515] Update brickblock369 Harpsichord I realized this one was outdated, I'm uploading a much better version --- instruments/FM/keys/brickblock369 Harpsichord.dmp | Bin 51 -> 51 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/instruments/FM/keys/brickblock369 Harpsichord.dmp b/instruments/FM/keys/brickblock369 Harpsichord.dmp index a2aba1f2d7b3b99cfa540071d1c49d4e34639f15..0f5ea587d338e30c838daa10db612ee6662f2bb8 100644 GIT binary patch literal 51 xcmd;PVq^dUZeDo_Hg*OEW(Ec}d3jbwpdgURDkd+($OdGxF)%X7bMkY7MFAzI0cHRI literal 51 xcmd;PVq{=vU|`acXW?gNU;rXcd3jbwMlh3AR9=RW1;}J$U}TWz Date: Sun, 4 Sep 2022 02:26:29 -0500 Subject: [PATCH 341/515] GUI: work around .dmf/.dmp saving issue --- src/gui/dataList.cpp | 32 ++++++++- src/gui/doAction.cpp | 9 +++ src/gui/gui.cpp | 158 ++++++++++++++++++++++++++----------------- src/gui/gui.h | 7 ++ src/gui/guiConst.cpp | 3 + 5 files changed, 144 insertions(+), 65 deletions(-) diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 10dda6aaf..0ef1f183b 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -121,16 +121,30 @@ void FurnaceGUI::drawInsList() { if (ImGui::MenuItem("instrument")) { doAction(GUI_ACTION_INS_LIST_SAVE); } + if (ImGui::MenuItem("instrument (.dmp)")) { + doAction(GUI_ACTION_INS_LIST_SAVE_DMP); + } if (ImGui::MenuItem("wavetable")) { doAction(GUI_ACTION_WAVE_LIST_SAVE); } + if (ImGui::MenuItem("wavetable (.dmw)")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE_DMW); + } + if (ImGui::MenuItem("wavetable (raw)")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE_RAW); + } if (ImGui::MenuItem("sample")) { doAction(GUI_ACTION_SAMPLE_LIST_SAVE); } ImGui::EndPopup(); } - } - if (!settings.unifiedDataView) { + } else { + if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) { + if (ImGui::MenuItem("save as .dmp...")) { + doAction(GUI_ACTION_INS_LIST_SAVE_DMP); + } + ImGui::EndPopup(); + } ImGui::SameLine(); if (ImGui::ArrowButton("InsUp",ImGuiDir_Up)) { doAction(GUI_ACTION_INS_LIST_MOVE_UP); @@ -359,6 +373,9 @@ void FurnaceGUI::drawInsList() { if (ImGui::MenuItem("save")) { doAction(GUI_ACTION_INS_LIST_SAVE); } + if (ImGui::MenuItem("save (.dmp)")) { + doAction(GUI_ACTION_INS_LIST_SAVE_DMP); + } if (ImGui::MenuItem("delete")) { doAction(GUI_ACTION_INS_LIST_DELETE); } @@ -430,6 +447,17 @@ void FurnaceGUI::drawWaveList() { if (ImGui::Button(ICON_FA_FLOPPY_O "##WaveSave")) { doAction(GUI_ACTION_WAVE_LIST_SAVE); } + if (!settings.unifiedDataView) { + if (ImGui::BeginPopupContextItem("WaveSaveFormats",ImGuiMouseButton_Right)) { + if (ImGui::MenuItem("save as .dmw...")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE_DMW); + } + if (ImGui::MenuItem("save raw...")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE_RAW); + } + ImGui::EndPopup(); + } + } ImGui::SameLine(); if (ImGui::ArrowButton("WaveUp",ImGuiDir_Up)) { doAction(GUI_ACTION_WAVE_LIST_MOVE_UP); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 919166699..92e12a742 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -599,6 +599,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_INS_LIST_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE); break; + case GUI_ACTION_INS_LIST_SAVE_DMP: + if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_DMP); + break; case GUI_ACTION_INS_LIST_MOVE_UP: if (e->moveInsUp(curIns)) { curIns--; @@ -666,6 +669,12 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WAVE_LIST_SAVE: if (curWave>=0 && curWave<(int)e->song.wave.size()) openFileDialog(GUI_FILE_WAVE_SAVE); break; + case GUI_ACTION_WAVE_LIST_SAVE_DMW: + if (curWave>=0 && curWave<(int)e->song.wave.size()) openFileDialog(GUI_FILE_WAVE_SAVE_DMW); + break; + case GUI_ACTION_WAVE_LIST_SAVE_RAW: + if (curWave>=0 && curWave<(int)e->song.wave.size()) openFileDialog(GUI_FILE_WAVE_SAVE_RAW); + break; case GUI_ACTION_WAVE_LIST_MOVE_UP: if (e->moveWaveUp(curWave)) { curWave--; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 86c063e9b..b0ccd3a36 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1258,9 +1258,18 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirSong)) workingDirSong=getHomeDir(); hasOpened=fileDialog->openSave( "Save File", - {"Furnace song", "*.fur", - "DefleMask 1.1.3 module", "*.dmf"}, - "Furnace song{.fur},DefleMask 1.1.3 module{.dmf}", + {"Furnace song", "*.fur"}, + "Furnace song{.fur}", + workingDirSong, + dpiScale + ); + break; + case GUI_FILE_SAVE_DMF: + if (!dirExists(workingDirSong)) workingDirSong=getHomeDir(); + hasOpened=fileDialog->openSave( + "Save File", + {"DefleMask 1.1.3 module", "*.dmf"}, + "DefleMask 1.1.3 module{.dmf}", workingDirSong, dpiScale ); @@ -1335,9 +1344,18 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); hasOpened=fileDialog->openSave( "Save Instrument", - {"Furnace instrument", "*.fui", - "DefleMask preset", "*.dmp"}, - "Furnace instrument{.fui},DefleMask preset{.dmp}", + {"Furnace instrument", "*.fui"}, + "Furnace instrument{.fui}", + workingDirIns, + dpiScale + ); + break; + case GUI_FILE_INS_SAVE_DMP: + if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); + hasOpened=fileDialog->openSave( + "Save Instrument", + {"DefleMask preset", "*.dmp"}, + "DefleMask preset{.dmp}", workingDirIns, dpiScale ); @@ -1358,10 +1376,28 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirWave)) workingDirWave=getHomeDir(); hasOpened=fileDialog->openSave( "Save Wavetable", - {"Furnace wavetable", ".fuw", - "DefleMask wavetable", ".dmw", - "raw data", ".raw"}, - "Furnace wavetable{.fuw},DefleMask wavetable{.dmw},raw data{.raw}", + {"Furnace wavetable", ".fuw"}, + "Furnace wavetable{.fuw}", + workingDirWave, + dpiScale + ); + break; + case GUI_FILE_WAVE_SAVE_DMW: + if (!dirExists(workingDirWave)) workingDirWave=getHomeDir(); + hasOpened=fileDialog->openSave( + "Save Wavetable", + {"DefleMask wavetable", ".dmw"}, + "DefleMask wavetable{.dmw}", + workingDirWave, + dpiScale + ); + break; + case GUI_FILE_WAVE_SAVE_RAW: + if (!dirExists(workingDirWave)) workingDirWave=getHomeDir(); + hasOpened=fileDialog->openSave( + "Save Wavetable", + {"raw data", ".raw"}, + "raw data{.raw}", workingDirWave, dpiScale ); @@ -2944,6 +2980,9 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("save as...",BIND_FOR(GUI_ACTION_SAVE_AS))) { openFileDialog(GUI_FILE_SAVE); } + if (ImGui::MenuItem("save as .dmf (1.1.3+)...",BIND_FOR(GUI_ACTION_SAVE_AS))) { + openFileDialog(GUI_FILE_SAVE_DMF); + } if (ImGui::MenuItem("save as .dmf (1.0/legacy)...",BIND_FOR(GUI_ACTION_SAVE_AS))) { openFileDialog(GUI_FILE_SAVE_DMF_LEGACY); } @@ -3335,17 +3374,21 @@ bool FurnaceGUI::loop() { switch (curFileDialog) { case GUI_FILE_OPEN: case GUI_FILE_SAVE: + case GUI_FILE_SAVE_DMF: case GUI_FILE_SAVE_DMF_LEGACY: workingDirSong=fileDialog->getPath()+DIR_SEPARATOR_STR; break; case GUI_FILE_INS_OPEN: case GUI_FILE_INS_OPEN_REPLACE: case GUI_FILE_INS_SAVE: + case GUI_FILE_INS_SAVE_DMP: workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR; break; case GUI_FILE_WAVE_OPEN: case GUI_FILE_WAVE_OPEN_REPLACE: case GUI_FILE_WAVE_SAVE: + case GUI_FILE_WAVE_SAVE_DMW: + case GUI_FILE_WAVE_SAVE_RAW: workingDirWave=fileDialog->getPath()+DIR_SEPARATOR_STR; break; case GUI_FILE_SAMPLE_OPEN: @@ -3409,9 +3452,10 @@ bool FurnaceGUI::loop() { } if (fileName!="") { if (curFileDialog==GUI_FILE_SAVE) { - // we can't tell whether the user chose .dmf or .fur in the system file picker - const char* fallbackExt=(settings.sysFileDialog || ImGuiFileDialog::Instance()->GetCurrentFilter()=="Furnace song")?".fur":".dmf"; - checkExtensionDual(".fur",".dmf",fallbackExt); + checkExtension(".fur"); + } + if (curFileDialog==GUI_FILE_SAVE_DMF) { + checkExtension(".dmf"); } if (curFileDialog==GUI_FILE_SAVE_DMF_LEGACY) { checkExtension(".dmf"); @@ -3423,21 +3467,19 @@ bool FurnaceGUI::loop() { checkExtension(".wav"); } if (curFileDialog==GUI_FILE_INS_SAVE) { - // we can't tell whether the user chose .fui or .dmp in the system file picker - const char* fallbackExt=(settings.sysFileDialog || ImGuiFileDialog::Instance()->GetCurrentFilter()=="Furnace instrument")?".fui":".dmp"; - checkExtensionDual(".fui",".dmp",fallbackExt); + checkExtension(".fui"); + } + if (curFileDialog==GUI_FILE_INS_SAVE_DMP) { + checkExtension(".dmp"); } if (curFileDialog==GUI_FILE_WAVE_SAVE) { - // same thing here - const char* fallbackExt=".fuw"; - if (!settings.sysFileDialog) { - if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="raw data") { - fallbackExt=".raw"; - } else if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="DefleMask wavetable") { - fallbackExt=".dmw"; - } - } - checkExtensionTriple(".fuw",".dmw",".raw",fallbackExt); + checkExtension(".fuw"); + } + if (curFileDialog==GUI_FILE_WAVE_SAVE_DMW) { + checkExtension(".dmw"); + } + if (curFileDialog==GUI_FILE_WAVE_SAVE_RAW) { + checkExtension(".raw"); } if (curFileDialog==GUI_FILE_EXPORT_VGM) { checkExtension(".vgm"); @@ -3465,21 +3507,10 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_SAVE: { logD("saving: %s",copyOfName.c_str()); - String lowerCase=fileName; - for (char& i: lowerCase) { - if (i>='A' && i<='Z') i+='a'-'A'; - } bool saveWasSuccessful=true; - if ((lowerCase.size()<4 || lowerCase.rfind(".dmf")!=lowerCase.size()-4)) { - if (save(copyOfName,0)>0) { - showError(fmt::sprintf("Error while saving file! (%s)",lastError)); - saveWasSuccessful=false; - } - } else { - if (save(copyOfName,26)>0) { - showError(fmt::sprintf("Error while saving file! (%s)",lastError)); - saveWasSuccessful=false; - } + if (save(copyOfName,0)>0) { + showError(fmt::sprintf("Error while saving file! (%s)",lastError)); + saveWasSuccessful=false; } if (saveWasSuccessful && postWarnAction!=GUI_WARN_GENERIC) { switch (postWarnAction) { @@ -3512,6 +3543,12 @@ bool FurnaceGUI::loop() { } break; } + case GUI_FILE_SAVE_DMF: + logD("saving: %s",copyOfName.c_str()); + if (save(copyOfName,26)>0) { + showError(fmt::sprintf("Error while saving file! (%s)",lastError)); + } + break; case GUI_FILE_SAVE_DMF_LEGACY: logD("saving: %s",copyOfName.c_str()); if (save(copyOfName,24)>0) { @@ -3520,34 +3557,29 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_INS_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { - String lowerCase=fileName; - for (char& i: lowerCase) { - if (i>='A' && i<='Z') i+='a'-'A'; - } - if ((lowerCase.size()<4 || lowerCase.rfind(".dmp")!=lowerCase.size()-4)) { - e->song.ins[curIns]->save(copyOfName.c_str()); - } else { - if (!e->song.ins[curIns]->saveDMP(copyOfName.c_str())) { - showError("error while saving instrument! make sure your instrument is compatible."); - } + e->song.ins[curIns]->save(copyOfName.c_str()); + } + break; + case GUI_FILE_INS_SAVE_DMP: + if (curIns>=0 && curIns<(int)e->song.ins.size()) { + if (!e->song.ins[curIns]->saveDMP(copyOfName.c_str())) { + showError("error while saving instrument! make sure your instrument is compatible."); } } break; case GUI_FILE_WAVE_SAVE: if (curWave>=0 && curWave<(int)e->song.wave.size()) { - String lowerCase=fileName; - for (char& i: lowerCase) { - if (i>='A' && i<='Z') i+='a'-'A'; - } - if (lowerCase.size()<4) { - e->song.wave[curWave]->save(copyOfName.c_str()); - } else if (lowerCase.rfind(".dmw")==lowerCase.size()-4) { - e->song.wave[curWave]->saveDMW(copyOfName.c_str()); - } else if (lowerCase.rfind(".raw")==lowerCase.size()-4) { - e->song.wave[curWave]->saveRaw(copyOfName.c_str()); - } else { - e->song.wave[curWave]->save(copyOfName.c_str()); - } + e->song.wave[curWave]->save(copyOfName.c_str()); + } + break; + case GUI_FILE_WAVE_SAVE_DMW: + if (curWave>=0 && curWave<(int)e->song.wave.size()) { + e->song.wave[curWave]->saveDMW(copyOfName.c_str()); + } + break; + case GUI_FILE_WAVE_SAVE_RAW: + if (curWave>=0 && curWave<(int)e->song.wave.size()) { + e->song.wave[curWave]->saveRaw(copyOfName.c_str()); } break; case GUI_FILE_SAMPLE_OPEN: { diff --git a/src/gui/gui.h b/src/gui/gui.h index 9938e3cc3..5950ab94a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -263,13 +263,17 @@ enum FurnaceGUIWindows { enum FurnaceGUIFileDialogs { GUI_FILE_OPEN, GUI_FILE_SAVE, + GUI_FILE_SAVE_DMF, GUI_FILE_SAVE_DMF_LEGACY, GUI_FILE_INS_OPEN, GUI_FILE_INS_OPEN_REPLACE, GUI_FILE_INS_SAVE, + GUI_FILE_INS_SAVE_DMP, GUI_FILE_WAVE_OPEN, GUI_FILE_WAVE_OPEN_REPLACE, GUI_FILE_WAVE_SAVE, + GUI_FILE_WAVE_SAVE_DMW, + GUI_FILE_WAVE_SAVE_RAW, GUI_FILE_SAMPLE_OPEN, GUI_FILE_SAMPLE_OPEN_RAW, GUI_FILE_SAMPLE_OPEN_REPLACE, @@ -455,6 +459,7 @@ enum FurnaceGUIActions { GUI_ACTION_INS_LIST_OPEN, GUI_ACTION_INS_LIST_OPEN_REPLACE, GUI_ACTION_INS_LIST_SAVE, + GUI_ACTION_INS_LIST_SAVE_DMP, GUI_ACTION_INS_LIST_MOVE_UP, GUI_ACTION_INS_LIST_MOVE_DOWN, GUI_ACTION_INS_LIST_DELETE, @@ -469,6 +474,8 @@ enum FurnaceGUIActions { GUI_ACTION_WAVE_LIST_OPEN, GUI_ACTION_WAVE_LIST_OPEN_REPLACE, GUI_ACTION_WAVE_LIST_SAVE, + GUI_ACTION_WAVE_LIST_SAVE_DMW, + GUI_ACTION_WAVE_LIST_SAVE_RAW, GUI_ACTION_WAVE_LIST_MOVE_UP, GUI_ACTION_WAVE_LIST_MOVE_DOWN, GUI_ACTION_WAVE_LIST_DELETE, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index bf075f2f3..e79de4106 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -571,6 +571,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("INS_LIST_OPEN", "Open", 0), D("INS_LIST_OPEN_REPLACE", "Open (replace current)", 0), D("INS_LIST_SAVE", "Save", 0), + D("INS_LIST_SAVE_DMP", "Save (.dmp)", 0), D("INS_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP), D("INS_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN), D("INS_LIST_DELETE", "Delete", 0), @@ -585,6 +586,8 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WAVE_LIST_OPEN", "Open", 0), D("WAVE_LIST_OPEN_REPLACE", "Open (replace current)", 0), D("WAVE_LIST_SAVE", "Save", 0), + D("WAVE_LIST_SAVE_DMW", "Save (.dmw)", 0), + D("WAVE_LIST_SAVE_RAW", "Save (raw)", 0), D("WAVE_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP), D("WAVE_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN), D("WAVE_LIST_DELETE", "Delete", 0), From 90a0db06f8cb82c121f01b0037d4749f23a62fdc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 4 Sep 2022 02:27:00 -0500 Subject: [PATCH 342/515] GUI: one tiny fix --- src/gui/gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b0ccd3a36..f0e501422 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2980,10 +2980,10 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("save as...",BIND_FOR(GUI_ACTION_SAVE_AS))) { openFileDialog(GUI_FILE_SAVE); } - if (ImGui::MenuItem("save as .dmf (1.1.3+)...",BIND_FOR(GUI_ACTION_SAVE_AS))) { + if (ImGui::MenuItem("save as .dmf (1.1.3+)...")) { openFileDialog(GUI_FILE_SAVE_DMF); } - if (ImGui::MenuItem("save as .dmf (1.0/legacy)...",BIND_FOR(GUI_ACTION_SAVE_AS))) { + if (ImGui::MenuItem("save as .dmf (1.0/legacy)...")) { openFileDialog(GUI_FILE_SAVE_DMF_LEGACY); } ImGui::Separator(); From f7bca46a4a6969b9dca80ca20d8c827050436436 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 4 Sep 2022 02:37:43 -0500 Subject: [PATCH 343/515] GUI: implement save as format in editors as well --- src/gui/insEdit.cpp | 6 ++++++ src/gui/waveEdit.cpp | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index c89652a37..662448dfc 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1608,6 +1608,12 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Button(ICON_FA_FLOPPY_O "##IESave")) { doAction(GUI_ACTION_INS_LIST_SAVE); } + if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) { + if (ImGui::MenuItem("save as .dmp...")) { + doAction(GUI_ACTION_INS_LIST_SAVE_DMP); + } + ImGui::EndPopup(); + } ImGui::TableNextColumn(); ImGui::Text("Type"); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 7e453ef58..01f678624 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -138,6 +138,15 @@ void FurnaceGUI::drawWaveEdit() { if (ImGui::Button(ICON_FA_FLOPPY_O "##WESave")) { doAction(GUI_ACTION_WAVE_LIST_SAVE); } + if (ImGui::BeginPopupContextItem("WaveSaveFormats",ImGuiMouseButton_Right)) { + if (ImGui::MenuItem("save as .dmw...")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE_DMW); + } + if (ImGui::MenuItem("save raw...")) { + doAction(GUI_ACTION_WAVE_LIST_SAVE_RAW); + } + ImGui::EndPopup(); + } ImGui::SameLine(); if (ImGui::RadioButton("Steps",waveEditStyle==0)) { From 9435ab12b0cb9c9d4d8443216561b45067db82ae Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 4 Sep 2022 04:00:56 -0500 Subject: [PATCH 344/515] GUI: wave generator, part 4 prepare FM --- src/gui/waveEdit.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 01f678624..9fea53c0c 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -104,6 +104,9 @@ void FurnaceGUI::doGenerateWave() { } } +#define CENTER_TEXT(text) \ + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(text).x)); + void FurnaceGUI::drawWaveEdit() { if (nextWindow==GUI_WINDOW_WAVE_EDIT) { waveEditOpen=true; @@ -321,7 +324,109 @@ void FurnaceGUI::drawWaveEdit() { if (ImGui::BeginTabItem("FM")) { waveGenFM=true; - ImGui::Text("FM stuff here"); + if (ImGui::BeginTable("WGFMProps",4)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize("Op").x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.25); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.25); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Op"); + ImGui::TableNextColumn(); + ImGui::Text("Level"); + ImGui::TableNextColumn(); + ImGui::Text("Mult"); + ImGui::TableNextColumn(); + ImGui::Text("FB"); + + for (int i=0; i<4; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d",i+1); + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::PushID(i); + if (CWSliderFloat("##WGTL",&waveGenTL[i],0.0f,1.0f)) { + doGenerateWave(); + } + ImGui::PopID(); + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::PushID(i); + if (CWSliderInt("##WGMULT",&waveGenMult[i],0,15)) { + doGenerateWave(); + } + ImGui::PopID(); + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::PushID(i); + if (CWSliderFloat("##WGFB",&waveGenFB[i],0.0f,7.0f)) { + doGenerateWave(); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + } + + CENTER_TEXT("Connection Diagram"); + ImGui::Text("Connection Diagram"); + + if (ImGui::BeginTable("WGFMCon",5)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(">>"); + ImGui::TableNextColumn(); + ImGui::Text("2"); + ImGui::TableNextColumn(); + ImGui::Text("3"); + ImGui::TableNextColumn(); + ImGui::Text("4"); + ImGui::TableNextColumn(); + ImGui::Text("Out"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("1"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con12",&waveGenFMCon1[0]); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con13",&waveGenFMCon1[1]); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con14",&waveGenFMCon1[2]); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con1O",&waveGenFMCon1[3]); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("2"); + ImGui::TableNextColumn(); + // blank + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con23",&waveGenFMCon2[0]); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con24",&waveGenFMCon2[1]); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con2O",&waveGenFMCon2[2]); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("3"); + ImGui::TableNextColumn(); + // blank + ImGui::TableNextColumn(); + // blank + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con34",&waveGenFMCon3[0]); + ImGui::TableNextColumn(); + ImGui::Checkbox("##Con3O",&waveGenFMCon3[1]); + + ImGui::EndTable(); + } ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Mangle")) { From 17f7647ae7a3064d15f4b377f79b722219c4e438 Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Sun, 4 Sep 2022 13:47:27 -0700 Subject: [PATCH 345/515] Update soundunit.md Clarified that the Sound Unit is able to have 64 KB depending on the configuration. --- papers/doc/7-systems/soundunit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/soundunit.md b/papers/doc/7-systems/soundunit.md index 8c3863b96..34cc16b4e 100644 --- a/papers/doc/7-systems/soundunit.md +++ b/papers/doc/7-systems/soundunit.md @@ -1,5 +1,5 @@ # tildearrow Sound Unit -This is a fantasy sound chip, used in the specs2 fantasy computer designed by tildearrow. It includes native support for sample playback, but with only 8KB of sample data. Since 0.6pre1, this sound chip is no longer hidden by default and can be accessed through the module creation screen and can be added or removed. +This is a fantasy sound chip, used in the specs2 fantasy computer designed by tildearrow. It includes native support for sample playback, but with only 8KB or 64KB of sample data, depending on the configuration used. Since 0.6pre1, this sound chip is no longer hidden by default and can be accessed through the module creation screen and can be added or removed. # effects From dc58043835ccbd0eec0009cfe099473384ad8151 Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Sun, 4 Sep 2022 13:50:14 -0700 Subject: [PATCH 346/515] Fixing the .dmp files as SMS/NES instead of FM These were oddly loaded as FM instruments while having data intended for SN7 - I've fixed them to load the correct type. --- instruments/other/(SMS) 2-Arp Chord High.dmp | Bin 30 -> 30 bytes instruments/other/(SMS) 2-Arp Major Low.dmp | Bin 30 -> 30 bytes instruments/other/(SMS) 2-Arp Minor Low.dmp | Bin 30 -> 30 bytes instruments/other/(SMS) 3-Arp High.dmp | Bin 26 -> 26 bytes instruments/other/(SMS) 3-Arp Major.dmp | Bin 26 -> 26 bytes instruments/other/(SMS) 3-Arp Minor.dmp | Bin 26 -> 26 bytes instruments/other/(SMS) Arp Snare.dmp | Bin 102 -> 102 bytes instruments/other/(SMS) Attack.dmp | Bin 25 -> 25 bytes instruments/other/(SMS) Buzz Noise.dmp | Bin 142 -> 142 bytes instruments/other/(SMS) Crash.dmp | Bin 306 -> 306 bytes instruments/other/(SMS) Decay Noise.dmp | Bin 158 -> 158 bytes instruments/other/(SMS) Decay.dmp | Bin 21 -> 21 bytes instruments/other/(SMS) Down Slider.dmp | Bin 162 -> 162 bytes instruments/other/(SMS) Hi-Hat & Note.dmp | Bin 39 -> 39 bytes instruments/other/(SMS) Hi-Hat Closed.dmp | Bin 29 -> 29 bytes instruments/other/(SMS) Hi-Hat Open.dmp | Bin 181 -> 181 bytes instruments/other/(SMS) Kick Noise.dmp | Bin 39 -> 39 bytes instruments/other/(SMS) Multi Slider.dmp | Bin 162 -> 162 bytes instruments/other/(SMS) Obvious Crash.dmp | Bin 383 -> 383 bytes instruments/other/(SMS) Record Scratch Down.dmp | Bin 94 -> 94 bytes instruments/other/(SMS) Record Scratch Up.dmp | Bin 94 -> 94 bytes instruments/other/(SMS) Retrig.dmp | Bin 49 -> 49 bytes instruments/other/(SMS) Ride.dmp | Bin 367 -> 367 bytes instruments/other/(SMS) Snare.dmp | Bin 86 -> 86 bytes instruments/other/(SMS) Splash.dmp | Bin 517 -> 517 bytes instruments/other/(SMS) Thump & Note.dmp | Bin 46 -> 46 bytes .../other/(SMS) Tim Follin 6-Arp Fast Major.dmp | Bin 38 -> 38 bytes .../other/(SMS) Tim Follin 6-Arp Fast Minor.dmp | Bin 38 -> 38 bytes .../other/(SMS) Tim Follin 6-Arp Slow Major.dmp | Bin 50 -> 50 bytes .../other/(SMS) Tim Follin 6-Arp Slow Minor.dmp | Bin 50 -> 50 bytes instruments/other/(SMS) Tim Follin Lead.dmp | Bin 26 -> 26 bytes instruments/other/(SMS) Tom A.dmp | Bin 62 -> 62 bytes instruments/other/(SMS) Tom B.dmp | Bin 98 -> 98 bytes instruments/other/(SMS) Up Slider.dmp | Bin 162 -> 162 bytes instruments/other/(SMS) Variable.dmp | Bin 13 -> 13 bytes instruments/other/(SMS) Whistle.dmp | Bin 22 -> 22 bytes 36 files changed, 0 insertions(+), 0 deletions(-) diff --git a/instruments/other/(SMS) 2-Arp Chord High.dmp b/instruments/other/(SMS) 2-Arp Chord High.dmp index 9340173621f7e3df55d0eedca9a936478cbbc9ab..845babb2e886dbbfe7dfe065fbe14b25f9c9638f 100644 GIT binary patch literal 30 acmd;PW?!Gj diff --git a/instruments/other/(SMS) 2-Arp Major Low.dmp b/instruments/other/(SMS) 2-Arp Major Low.dmp index 532c24565f97ed0028b999de53319f0a88748956..f65623f0de3f25178ae4232b3f3ff89c4cdb0965 100644 GIT binary patch literal 30 acmd;PW?Xl literal 30 acmd;PVqoNDU|{&q!UH5hSOAKF6axSpJpoq$ diff --git a/instruments/other/(SMS) 2-Arp Minor Low.dmp b/instruments/other/(SMS) 2-Arp Minor Low.dmp index 608e5483246b3a0aea887d7dd45f030bf9ffbfb8..5345dd459587d2fef6326c6a167011c3a45adfcf 100644 GIT binary patch literal 30 acmd;PW?-IP6axSpDFIag diff --git a/instruments/other/(SMS) 3-Arp High.dmp b/instruments/other/(SMS) 3-Arp High.dmp index a5ebf9759321339d37f27d0e167aa9747d651f19..d0fab8e515c705a17b95645caef854bd3a3b9ccd 100644 GIT binary patch literal 26 acmd;PW?z?5i2;iM literal 26 acmd;PVqoNDU|{&q%mXAPfLH~HK>z?3zyW3e diff --git a/instruments/other/(SMS) 3-Arp Major.dmp b/instruments/other/(SMS) 3-Arp Major.dmp index 3d284983e9765b93b28bdf09b9704b62a00c8fbd..d9f9e3a7d2184580ed42d601256280b53703374b 100644 GIT binary patch literal 26 acmd;PW?z?4p#gFL literal 26 acmd;PVqoNDU|{&q%mX9^fLIuaK>z?2*a1xd diff --git a/instruments/other/(SMS) 3-Arp Minor.dmp b/instruments/other/(SMS) 3-Arp Minor.dmp index a28275fb7769b55277b10f51232e1d7aa1a56c47..f36e80e97089ac614fbc2710e26ca4b3c4b2122f 100644 GIT binary patch literal 26 acmd;PW?z?4l>u=8 literal 26 acmd;PVqoNDU|{&q%mXC(fmj%bK>z?2%mGXQ diff --git a/instruments/other/(SMS) Arp Snare.dmp b/instruments/other/(SMS) Arp Snare.dmp index fa5734d4a977e64978bc583dff2cb0e9396be153..7135954297d16b18671a43bccb37fab9390d02a8 100644 GIT binary patch delta 25 acmYdGW8!9>$P^;L$H2fK2E-CT3<3Zu7y=Lg delta 25 acmYdGW8!9-$P^;L#K6G71;ji+3<3ZsQvvG$ diff --git a/instruments/other/(SMS) Attack.dmp b/instruments/other/(SMS) Attack.dmp index 0be930625decb07ad10b738d1b2fdc8325ef4fc8..ac5d24fffcce3acf2eab543fbc65b013f4c2c202 100644 GIT binary patch literal 25 acmd;PW?*4sU|`?|Vtydz1>*le%m4rhH~~KZ literal 25 acmd;PVqjroU|`?|Vtydz1>*le%m4rhAOSuA diff --git a/instruments/other/(SMS) Buzz Noise.dmp b/instruments/other/(SMS) Buzz Noise.dmp index 8b7dfd97dc9c98035b493acf4aa29439ef4a1f6d..d1bc39212d813f895bcd72ad77c2b0c58718a049 100644 GIT binary patch literal 142 Zcmd;PW>DZ~U|<+X{GWk=5oA9D0|2sy10DbX literal 142 acmd;PVo=~`U|<+X{GWk=ks0U)1_l7Ju>%nR diff --git a/instruments/other/(SMS) Crash.dmp b/instruments/other/(SMS) Crash.dmp index f9855bde354ec99718132f753200ae33c698db0e..6f05ff8020edf2094429d2a4f899eac176254203 100644 GIT binary patch delta 43 ncmdnQw26s@o0-9NqJY6f1)hlxw3?}CW=)XjeW_awqbSVpQ2qC;r&)!&ZVZn(R2PW(ovB8(EKidS` Z4z?|98`##ctzcWiwt#I8+YGkx_W^Km0}lWI diff --git a/instruments/other/(SMS) Hi-Hat & Note.dmp b/instruments/other/(SMS) Hi-Hat & Note.dmp index 3f92dc68e44f20be7565640baac423094d562952..cff02382ff3d2e1785f600462a0f97fecba79eb6 100644 GIT binary patch literal 39 icmd;PW?<%KU|?VaVtye0&y)ouLHIud6G(s$%me^ELc0R delta 10 RcmdnWxRsHKn`t7`W&jU~0>S_Q diff --git a/instruments/other/(SMS) Kick Noise.dmp b/instruments/other/(SMS) Kick Noise.dmp index 8f2d3cbf9a4afe32ff867b34df5da03d0dbe6934..b76fb88614620a661ef038fdb7d14724a36086e3 100644 GIT binary patch literal 39 hcmd;PW?<%LU|;}YJ|O|?3uN{tG`G?atIxT|Nox{NW<`d21aHe_df#wLs|;d diff --git a/instruments/other/(SMS) Record Scratch Down.dmp b/instruments/other/(SMS) Record Scratch Down.dmp index 8e28c41800ba5555b93ec5fbb67d7dc3aeb8f951..b3f4b07fa5820b2dd9592d89e33dad421e0326e1 100644 GIT binary patch literal 94 wcma*dxe)*$48*{jA;SSFn7{ubjY=R`MY1F-l76r$@}&nG3ljq!j)scB1BGM*)c^nh literal 94 wcma*fxe)*$34)c^nh literal 94 vcma*exe)*$3$mGGp&%nSS0mT1-7yu$90?GgY delta 21 ZcmWFwW8!9-$mGGp%)r3F1H}J<7yuz70fLI2IHGo(ih_!(j1OPA~0qg(( literal 38 hcmd;PVqoNDU|{&q#sefJfLH*CWq?>1h~fLI!c)qz+Zh_!(j1OPAm0qOt% literal 38 hcmd;PVqoNDU|{&q#sefJfS4bMrGZ!&h~0igf@ diff --git a/instruments/other/(SMS) Tim Follin 6-Arp Slow Major.dmp b/instruments/other/(SMS) Tim Follin 6-Arp Slow Major.dmp index 9536150c65ce3590c7022fec86b4d24542fc3524..11eeafb4a40accc6ca5787c962c0f447befa57f7 100644 GIT binary patch literal 50 jcmd;PW?pjZP)%R{j?kOlz&N#g=S literal 50 jcmd;PVqoNDU|{&q$pa)oSOSOzpjZY-3q!FykOlz&Kav5} diff --git a/instruments/other/(SMS) Tim Follin 6-Arp Slow Minor.dmp b/instruments/other/(SMS) Tim Follin 6-Arp Slow Minor.dmp index 166a1cb3af789baa0b4d0323a05c5fe50ba2d2dd..3cbc3f380aec5cd7d58b1b968e46bd3f6538ddb4 100644 GIT binary patch literal 50 jcmd;PW?$Yj97!@$5G0mT1-7yumD0)GGi delta 21 XcmcDsW8!9-$Yj9700bc7KM(@|8`lD6 diff --git a/instruments/other/(SMS) Tom B.dmp b/instruments/other/(SMS) Tom B.dmp index 664021f6d7446ed81feb56bdf873736f4a45146c..e06cccb81e19cbb5be00da1fa17108d1f1d286a9 100644 GIT binary patch delta 57 vcmYdFV&Z0=$Yfxk#K6Fy2*e6NEDywTKr9QyGC(X1#8N;k3B(dW{2zz`huj1P delta 57 tcmWN=$qfJ?2mnFC*9*@&sELlOSa*_%(4<%0kBDq8P7Zb&8!HPlA3u3F1Azbl diff --git a/instruments/other/(SMS) Up Slider.dmp b/instruments/other/(SMS) Up Slider.dmp index 765f156e824e56bd8cd569c561fd8f997d44551b..b57cfffeaccb7921c8c89b6586aadec4e56bdca5 100644 GIT binary patch literal 162 zcmWm5Hx7VM5X8`rD9JfzasMNNUA!q)-XsoD7DD*mkxfya*xs;x5a9>1ngpl- literal 162 zcmWm8*A0L$3;wuCU!;yTkT??Fripwl{1a_>UhaIRfhd diff --git a/instruments/other/(SMS) Variable.dmp b/instruments/other/(SMS) Variable.dmp index 7ed3209f5ce5f3d2b5bd4fd152b26b8870ee7b00..16a5c0f76e0c3289edb3a860f03eebb5ddbaa915 100644 GIT binary patch literal 13 Scmd;PW?9 diff --git a/instruments/other/(SMS) Whistle.dmp b/instruments/other/(SMS) Whistle.dmp index 0fd9127c031a0eb3668ed18eaf435e5c45d32936..1ed679bb83c880eb1f94f6bcbdfd2993af8ecc12 100644 GIT binary patch literal 22 Xcmd;PW? Date: Sun, 4 Sep 2022 13:56:18 -0700 Subject: [PATCH 347/515] Adding additional PSG instruments --- instruments/other/2A03 Noise Hi-Hat Closed.fui | Bin 0 -> 1937 bytes instruments/other/2A03 Noise Hi-Hat Open.fui | Bin 0 -> 2019 bytes instruments/other/2A03 Noise Kick.fui | Bin 0 -> 1928 bytes instruments/other/2A03 Noise Snare.fui | Bin 0 -> 2013 bytes instruments/other/2A03 Triangle Kick+Bass.fui | Bin 0 -> 1926 bytes instruments/other/2A03 Triangle Kick.fui | Bin 0 -> 1951 bytes instruments/other/2A03 Triangle Snare+Bass.fui | Bin 0 -> 1931 bytes instruments/other/2A03 Triangle Snare.fui | Bin 0 -> 1944 bytes instruments/other/AY kick.fui | Bin 0 -> 1799 bytes instruments/other/AY snare.fui | Bin 0 -> 2056 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/other/2A03 Noise Hi-Hat Closed.fui create mode 100644 instruments/other/2A03 Noise Hi-Hat Open.fui create mode 100644 instruments/other/2A03 Noise Kick.fui create mode 100644 instruments/other/2A03 Noise Snare.fui create mode 100644 instruments/other/2A03 Triangle Kick+Bass.fui create mode 100644 instruments/other/2A03 Triangle Kick.fui create mode 100644 instruments/other/2A03 Triangle Snare+Bass.fui create mode 100644 instruments/other/2A03 Triangle Snare.fui create mode 100644 instruments/other/AY kick.fui create mode 100644 instruments/other/AY snare.fui diff --git a/instruments/other/2A03 Noise Hi-Hat Closed.fui b/instruments/other/2A03 Noise Hi-Hat Closed.fui new file mode 100644 index 0000000000000000000000000000000000000000..a24dff830d17e67e06962ae403631f671aca32af GIT binary patch literal 1937 zcmeHHU24KW5dOv_Mys&k1+vdViboI%MPEeF3rNjFK(rWr_G;eD&L&y1E=wXUC|C!+ z%>UmKCjLC`x2vy2rrYeWe~-TbNQS2AY_Uv3K-p)zG)v?pjVG&v{MhWWWDWR0O9e-r zz!O6t(3uvGe4^f{#{WjX7+6V$8g;2F@=k`a5(Qdg5bK>1%nXVQIUmt84VHXio!5fm zE~s$9XfxDAs;#0PFz%NqEY;VpLprGnxmmJnHR(m+-!*KiZTtU2FMH=_*PDLKzwX~u zU;AHuuJ4h47rxlRJUA0BOptY_tw_1oLskQtQtcrUd{`A~$;%flLkK4kh9C#Iia5fY I13fD42lAWZrT_o{ literal 0 HcmV?d00001 diff --git a/instruments/other/2A03 Noise Hi-Hat Open.fui b/instruments/other/2A03 Noise Hi-Hat Open.fui new file mode 100644 index 0000000000000000000000000000000000000000..26889b0ad7e2b9d8bb07187c9a9ccac4b9cedf44 GIT binary patch literal 2019 zcmeHI%}T>S5dNk~Ow+0hJ$lKWg@}*PlhjKU+7~D#hg@Q5>)8kM;+xf(Bumz1NkqYd z?ZDUh+4(0-vxnDhxmxGCD0lnqUA6(B8HOI`i{*O^h<*N2>~cLTve{~{pEh|3gup;t z(_s{-TOcxV4o^d(@qNeph(a}Sf-E&nC{a}<%h-wvgDHshVFP9srIw5vRs!4L$OqPW zEC}~O+*N~X=7OsRm(0hE5hGzpJG?wxFl03X$u0F=$aDrWiV)|Ta?T31rTuk#BNNoR zd|PsJ_33rupB3!O?Y^HvEqCVsuJ?VIzn#A?zj;5``Fi8bUid#CdX7E_2PWvQb6JP{ l)gs#lZK?ARDL&SMP710)8yCWxier$6d`UcR-iD6l_X*Jl;^Y7T literal 0 HcmV?d00001 diff --git a/instruments/other/2A03 Noise Kick.fui b/instruments/other/2A03 Noise Kick.fui new file mode 100644 index 0000000000000000000000000000000000000000..7cf815e1a9eb2931b503248ae3ed8b909770a790 GIT binary patch literal 1928 zcmeHHOA5j;5Pj1RwTcA1K)V(y9>J9$f(Uv5MY<@0O4YSj^JY4!24e`VC@81{ubI!A znM^2?^!NE{zDVP2wcX{NWCI{(C>e|<(^&vW|7e|U(|DLImVgI1k`vW@SF{0NB^YPq z5jDCc@j7{;Wh7~46jCUPPMY(k3OGFw+qEnB&?M6I;)<^BF!U4KJQn0>gQN>a$dEkQ zRtnp_2BXO+9NNdMLn=w*JgS9idzhNr4SAx2tXFG6|vB)7y1cE$s*`1l4S;EY&pSyN>-&Cu1{nTB~9syLu%FTRn_nHH`KYv)Qn`+T6y9P*skvf&* zEHM{AW+S|{Ohu+wk@Jb9=FAIn%(9Te^fx)1d(~i6Luik8aB-w`bez*j+zn6P(2k+* zhMbZUa!jUVLJFcK@Tq!^xayNAe5xQ?i=y2r+J>US_?kIu=C1n<=i}EXHpub$tm@|) zvbTA^cHvNN|NJl9<@fyC?ViNoN)m7j7IY}TcN9b70ssI2 literal 0 HcmV?d00001 diff --git a/instruments/other/2A03 Triangle Kick+Bass.fui b/instruments/other/2A03 Triangle Kick+Bass.fui new file mode 100644 index 0000000000000000000000000000000000000000..9beaea86258dc329a57a0fbfeba950520da00370 GIT binary patch literal 1926 zcmdOOD=o@POioqE%quP_($g(qU|>)HVi@rB3l526XJ7z{hZJQd=B4MPDtKomXDetc zI3*SrGcd3)Fff5s%X6?Y^J_6Mu)?&W(ef;ejNArzYxh5ia;z2#2_(rfUcJj zg$uBlW({CHz{v0) z2pANY5#l&l^a@Dq*5fUR`1u(aKo~Dz2745$gpr}1pPik75evX(2o_~n9W+qt0KZt{ AWB>pF literal 0 HcmV?d00001 diff --git a/instruments/other/2A03 Triangle Kick.fui b/instruments/other/2A03 Triangle Kick.fui new file mode 100644 index 0000000000000000000000000000000000000000..f226301058a8ca894539476d70fc0ae1f89aef2b GIT binary patch literal 1951 zcmdOOD=o@POioqE%quP_($g(qU|>)HVi@rB3l1q~XJ7z{hZJQd=B4MPDtKomXEQLc zFfcHIl*x0jGV^OOFtEb(pwaRyjEvj{c;vYlS@?y}G$C>2IT<bF!@n?P|GM-xB$y<)&SN6 zj12#QfI)#7A&!GZuYkmEJ>G(dA6VFeFkZk6_9#>dBSSquJ39j-7J$tVEXuGtXrR;q E0Al9ing9R* literal 0 HcmV?d00001 diff --git a/instruments/other/2A03 Triangle Snare+Bass.fui b/instruments/other/2A03 Triangle Snare+Bass.fui new file mode 100644 index 0000000000000000000000000000000000000000..e91831c8a49de1ffd4332efc1a9feee9edc53a99 GIT binary patch literal 1931 zcmdOOD=o@POioqE%quP_($g(qU|>)HVi@rB3l2$UXJ7z{hZJQd=B4MPDg@^x7Nsg^ zD>x+<7c(%hFfcHIl*@ClGV^OOFtEb(qS5j!jEvj{c;vYlS@?y}G$C>2IT<Et@=o1G$Al3n5psyX&ffyu?4$#eE z1i6t+fNmBcKExXGEF@$$y8KA63*FDdolhv4QtE#~=ELMi?LjS%VBrERt62kB4=^(P z2Lc8KW`sBn7QF%zyY+YrB7S}b1`x&zn86-}Dq&=(=VxbUV8jBj8G=O_RtF7~Isl16 B)HVi@rB3l1q@XJ7z{hZJQd=B4MPDg@^x7Ns&U zurM$%fz-)!url*&F)*;gG@;S*ER2lY26*JT7+Ls*&@>@&W5Xad{8%tZ9Oy#_Js{QrVqj=EXaF%t92uaS z$p~^cnE>4^LVSodCZdhdZB8GNsi2gv^J@kJ^J;Ho?LLSa7ojupVG! z_zwgO3d{&`94vYTBzEiZ7DW8OLKcMa0%ovBp-LDT>iOB(85pquY=&S_hSfm>r49hQ C(Bjzu literal 0 HcmV?d00001 diff --git a/instruments/other/AY kick.fui b/instruments/other/AY kick.fui new file mode 100644 index 0000000000000000000000000000000000000000..111f1da7eef5c11230b2bdd186367113a5042685 GIT binary patch literal 1799 zcmdOOD=o@POioqE%quP_($mdiU|>)HVi@rB3l6!@#=wxpz{ZeNl$o5Jl#`#FZER+# z;25cp4dgR0urM$%ft1U0url*&F)*;g^rF%7ER2lY26*JT7+Ls*&@>@&(x{!h(<>K0gxX1+qbA zasn~POi&Oo12IS)2xtQ_NDT-J1F;AYivzJF5X%BFy8S>Q6tLni#68G@$nF8L89@M9 z0SRn$vk37aMw4e7A+yotM}l4Geje_8LP?WS{}VDFCO>KqY6!r>1y~2L2CyDr1Q&V? g3ZSA4KR`8xbRK@w3CSWCM96HgK7L?94Z?T<00z7EGE?*P;W0bzFNsJ2W239_&1*=sq&7{nd9s+^-6xCF zvkP^3tH$Xhn-Td$EzXZSfhUiM0`sxsV_%5gNzHy&_;T0z$O_{~L{e9>URFy>2?HD1+k}dd6umO6Y3nIX}=$x*>EkT Date: Mon, 5 Sep 2022 05:48:20 -0500 Subject: [PATCH 348/515] GUI: wave generator, part 5 completely untested FM generation --- src/gui/waveEdit.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 9fea53c0c..2767911a8 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -32,6 +32,25 @@ const char* waveGenBaseShapes[4]={ "Pulse" }; +const float multFactors[16]={ + M_PI, + 2*M_PI, + 4*M_PI, + 6*M_PI, + 8*M_PI, + 10*M_PI, + 12*M_PI, + 14*M_PI, + 16*M_PI, + 18*M_PI, + 20*M_PI, + 22*M_PI, + 24*M_PI, + 26*M_PI, + 28*M_PI, + 30*M_PI, +}; + void FurnaceGUI::doGenerateWave() { float finalResult[256]; if (curWave<0 || curWave>=(int)e->song.wave.size()) return; @@ -42,7 +61,18 @@ void FurnaceGUI::doGenerateWave() { if (wave->len<2) return; if (waveGenFM) { + for (int i=0; ilen; i++) { + float pos=(float)i/(float)wave->len; + float s0=sin(pos*multFactors[waveGenMult[0]])*waveGenTL[0]; + float s1=sin((pos+(waveGenFMCon1[0]?s0:0.0f))*multFactors[waveGenMult[1]])*waveGenTL[1]; + float s2=sin((pos+(waveGenFMCon1[1]?s0:0.0f)+(waveGenFMCon2[0]?s1:0.0f))*multFactors[waveGenMult[2]])*waveGenTL[2]; + float s3=sin((pos+(waveGenFMCon1[2]?s0:0.0f)+(waveGenFMCon2[1]?s1:0.0f)+(waveGenFMCon3[0]?s2:0.0f))*multFactors[waveGenMult[3]])*waveGenTL[3]; + if (waveGenFMCon1[3]) finalResult[i]+=s0; + if (waveGenFMCon2[2]) finalResult[i]+=s1; + if (waveGenFMCon3[1]) finalResult[i]+=s2; + finalResult[i]+=s3; + } } else { switch (waveGenBaseShape) { case 0: // sine From a59ed84322577e8c25e5751c2a93f4f17f196c4e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 6 Sep 2022 14:28:57 -0500 Subject: [PATCH 349/515] GUI: fix wave gen FM con checkboxes doing nothing --- src/gui/waveEdit.cpp | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 2767911a8..9842d808b 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -423,13 +423,21 @@ void FurnaceGUI::drawWaveEdit() { ImGui::TableNextColumn(); ImGui::Text("1"); ImGui::TableNextColumn(); - ImGui::Checkbox("##Con12",&waveGenFMCon1[0]); + if (ImGui::Checkbox("##Con12",&waveGenFMCon1[0])) { + doGenerateWave(); + } ImGui::TableNextColumn(); - ImGui::Checkbox("##Con13",&waveGenFMCon1[1]); + if (ImGui::Checkbox("##Con13",&waveGenFMCon1[1])) { + doGenerateWave(); + } ImGui::TableNextColumn(); - ImGui::Checkbox("##Con14",&waveGenFMCon1[2]); + if (ImGui::Checkbox("##Con14",&waveGenFMCon1[2])) { + doGenerateWave(); + } ImGui::TableNextColumn(); - ImGui::Checkbox("##Con1O",&waveGenFMCon1[3]); + if (ImGui::Checkbox("##Con1O",&waveGenFMCon1[3])) { + doGenerateWave(); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -437,11 +445,17 @@ void FurnaceGUI::drawWaveEdit() { ImGui::TableNextColumn(); // blank ImGui::TableNextColumn(); - ImGui::Checkbox("##Con23",&waveGenFMCon2[0]); + if (ImGui::Checkbox("##Con23",&waveGenFMCon2[0])) { + doGenerateWave(); + } ImGui::TableNextColumn(); - ImGui::Checkbox("##Con24",&waveGenFMCon2[1]); + if (ImGui::Checkbox("##Con24",&waveGenFMCon2[1])) { + doGenerateWave(); + } ImGui::TableNextColumn(); - ImGui::Checkbox("##Con2O",&waveGenFMCon2[2]); + if (ImGui::Checkbox("##Con2O",&waveGenFMCon2[2])) { + doGenerateWave(); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -451,9 +465,13 @@ void FurnaceGUI::drawWaveEdit() { ImGui::TableNextColumn(); // blank ImGui::TableNextColumn(); - ImGui::Checkbox("##Con34",&waveGenFMCon3[0]); + if (ImGui::Checkbox("##Con34",&waveGenFMCon3[0])) { + doGenerateWave(); + } ImGui::TableNextColumn(); - ImGui::Checkbox("##Con3O",&waveGenFMCon3[1]); + if (ImGui::Checkbox("##Con3O",&waveGenFMCon3[1])) { + doGenerateWave(); + } ImGui::EndTable(); } From 56ba47408cc5a6682524531c0f860df40b2cd4b8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 01:37:16 -0500 Subject: [PATCH 350/515] GUI: initialize variables --- src/gui/gui.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6dc86420f..1911ceb1c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" @@ -4870,6 +4871,13 @@ FurnaceGUI::FurnaceGUI(): fileDialog(NULL), scrW(1280), scrH(800), + scrConfW(1280), + scrConfH(800), + scrX(SDL_WINDOWPOS_CENTERED), + scrY(SDL_WINDOWPOS_CENTERED), + scrConfX(SDL_WINDOWPOS_CENTERED), + scrConfY(SDL_WINDOWPOS_CENTERED), + scrMax(false), dpiScale(1), aboutScroll(0), aboutSin(0), From 21baf2e27255b99b8e68fc3b8ced41663600766d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 01:45:05 -0500 Subject: [PATCH 351/515] GUI: typo fixing --- src/gui/settings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index ed0e66f99..53ce0cdeb 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -515,11 +515,11 @@ void FurnaceGUI::drawSettings() { } bool saveWindowPosB=settings.saveWindowPos; - if (ImGui::Checkbox("Remember window location",&saveWindowPosB)) { + if (ImGui::Checkbox("Remember window position",&saveWindowPosB)) { settings.saveWindowPos=saveWindowPosB; } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("remembers where window was last located on start-up. When disabled, window will start in a defaul location."); + ImGui::SetTooltip("remembers the window's last position on startup."); } bool blankInsB=settings.blankIns; From 4ad324bfedd4e08a65f613debe91f95e80f233c1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 01:49:36 -0500 Subject: [PATCH 352/515] screw you clangd extension --- src/gui/gui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 1911ceb1c..fb197e314 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,7 +17,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include +// I hate you clangd extension! +// how about you DON'T insert random headers before this freaking important +// define!!!!!! #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" From 7de165fd88057588ad807bb2f9cd78f7591c9888 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 03:01:22 -0500 Subject: [PATCH 353/515] N163: fix channel count change glitch, part 1 --- src/engine/platform/n163.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 7da2e0a16..bc985b42b 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -642,6 +642,9 @@ void DivPlatformN163::setFlags(unsigned int flags) { for (int i=0; i<8; i++) { oscBuf[i]->rate=rate/(initChanMax+1); } + + // needed to make sure changing channel count won't trigger glitches + reset(); } int DivPlatformN163::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { From 773b63b8102f174292dae1f6963f0e8535e6a862 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 13:16:57 -0500 Subject: [PATCH 354/515] GUI: don't save layout periodically --- src/gui/gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index fb197e314..9bd20333c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2382,7 +2382,7 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) { if (mobileUI) { ImGui::GetIO().IniFilename=NULL; } else { - ImGui::GetIO().IniFilename=finalLayoutPath; + ImGui::GetIO().IniFilename=NULL; ImGui::LoadIniSettingsFromDisk(finalLayoutPath); } } From ae6e956f06d328ec06e3f4885e305a814d95fb4f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 17:04:38 -0500 Subject: [PATCH 355/515] GUI: some mobile view work --- src/gui/editControls.cpp | 4 ++++ src/gui/gui.cpp | 32 ++++++++++++++++++-------------- src/gui/gui.h | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 912bd1c09..a2014a30d 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -23,12 +23,16 @@ void FurnaceGUI::drawMobileControls() { if (ImGui::Begin("Mobile Controls",NULL,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { + ImGui::SetWindowPos(ImVec2(0.0f,0.0f)); + ImGui::SetWindowSize(portrait?ImVec2(scrW*dpiScale,0.1*scrW*dpiScale):ImVec2(0.1*scrH*dpiScale,scrH*dpiScale)); float availX=ImGui::GetContentRegionAvail().x; ImVec2 buttonSize=ImVec2(availX,availX); if (ImGui::Button(ICON_FA_CHEVRON_RIGHT "##MobileMenu",buttonSize)) { } + ImGui::Text("I put here"); + ImGui::Separator(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(e->isPlaying())); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9bd20333c..c74f077f0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2595,24 +2595,24 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { #define OOB_PIXELS_SAFETY 25 bool FurnaceGUI::detectOutOfBoundsWindow() { - int count = SDL_GetNumVideoDisplays(); - if(count < 1) { - logW("bounds check: error %s", SDL_GetError()); + int count=SDL_GetNumVideoDisplays(); + if (count<1) { + logW("bounds check: error %s",SDL_GetError()); return false; } SDL_Rect rect; - for(int i = 0;i < count;i ++) { - if(SDL_GetDisplayUsableBounds(i, &rect) != 0) { - logW("bounds check: error %s", SDL_GetError()); + for (int i=0; i= scrX; - bool ybound = (rect.y + OOB_PIXELS_SAFETY) <= (scrY + scrH) && (rect.y + rect.h - OOB_PIXELS_SAFETY) >= scrY; - logD("bounds check: display %d is at %dx%dx%dx%d: %s%s", i, rect.x + OOB_PIXELS_SAFETY, rect.y + OOB_PIXELS_SAFETY, rect.x + rect.w - OOB_PIXELS_SAFETY, rect.y + rect.h - OOB_PIXELS_SAFETY, xbound ? "x" : "", ybound ? "y" : ""); + bool xbound=((rect.x+OOB_PIXELS_SAFETY)<=(scrX+scrW)) && ((rect.x+rect.w-OOB_PIXELS_SAFETY)>=scrX); + bool ybound=((rect.y+OOB_PIXELS_SAFETY)<=(scrY+scrH)) && ((rect.y+rect.h-OOB_PIXELS_SAFETY)>=scrY); + logD("bounds check: display %d is at %dx%dx%dx%d: %s%s",i,rect.x+OOB_PIXELS_SAFETY,rect.y+OOB_PIXELS_SAFETY,rect.x+rect.w-OOB_PIXELS_SAFETY,rect.y+rect.h-OOB_PIXELS_SAFETY,xbound?"x":"",ybound?"y":""); - if(xbound && ybound) { + if (xbound && ybound) { return true; } } @@ -2746,6 +2746,7 @@ bool FurnaceGUI::loop() { scrW=ev.window.data1/dpiScale; scrH=ev.window.data2/dpiScale; #endif + portrait=(scrWgetConfInt("lastWindowX",SDL_WINDOWPOS_CENTERED); scrY=scrConfY=e->getConfInt("lastWindowY",SDL_WINDOWPOS_CENTERED); scrMax=e->getConfBool("lastWindowMax",false); + portrait=(scrWdisplaySize.w/dpiScale) scrW=(displaySize.w/dpiScale)-32; if (scrH>displaySize.h/dpiScale) scrH=(displaySize.h/dpiScale)-32; + portrait=(scrW sysSearchResults; std::vector newSongSearchResults; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints, portrait; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; bool displayPendingIns, pendingInsSingle, displayPendingRawSample; From 06845210925da94ae62096d942b140cc0492675e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 17:04:52 -0500 Subject: [PATCH 356/515] update Android ver num --- android/app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index cb4b3c59d..f332e6f58 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,8 +15,8 @@ android { } minSdkVersion 21 targetSdkVersion 26 - versionCode 93 - versionName "0.6pre1" + versionCode 112 + versionName "dev112" externalNativeBuild { cmake { arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static" From 2c18fe1051f7625109ab10d34c2703990d3e158f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 19:15:19 -0500 Subject: [PATCH 357/515] GUI: lots of mobile UI progress --- src/gui/editControls.cpp | 130 +++++++++++++++++++++++++++++++++++---- src/gui/gui.cpp | 10 ++- src/gui/gui.h | 4 +- src/gui/pattern.cpp | 13 +++- src/log.cpp | 4 ++ 5 files changed, 144 insertions(+), 17 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index a2014a30d..5307163e8 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -22,27 +22,54 @@ #include void FurnaceGUI::drawMobileControls() { + float timeScale=1.0f/(60.0f*ImGui::GetIO().DeltaTime); + if (mobileMenuOpen) { + if (mobileMenuPos<0.999f) { + WAKE_UP; + mobileMenuPos+=MIN(0.1,(1.0-mobileMenuPos)*0.65)*timeScale; + } else { + mobileMenuPos=1.0f; + } + } else { + if (mobileMenuPos>0.001f) { + WAKE_UP; + mobileMenuPos-=MIN(0.1,mobileMenuPos*0.65)*timeScale; + } else { + mobileMenuPos=0.0f; + } + } + ImGui::SetNextWindowPos(portrait?ImVec2(0.0f,((1.0-mobileMenuPos*0.65)*scrH*dpiScale)-(0.16*scrW*dpiScale)):ImVec2(0.5*scrW*dpiScale*mobileMenuPos,0.0f)); + ImGui::SetNextWindowSize(portrait?ImVec2(scrW*dpiScale,0.16*scrW*dpiScale):ImVec2(0.16*scrH*dpiScale,scrH*dpiScale)); if (ImGui::Begin("Mobile Controls",NULL,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { - ImGui::SetWindowPos(ImVec2(0.0f,0.0f)); - ImGui::SetWindowSize(portrait?ImVec2(scrW*dpiScale,0.1*scrW*dpiScale):ImVec2(0.1*scrH*dpiScale,scrH*dpiScale)); - float availX=ImGui::GetContentRegionAvail().x; - ImVec2 buttonSize=ImVec2(availX,availX); + float avail=portrait?ImGui::GetContentRegionAvail().y:ImGui::GetContentRegionAvail().x; + ImVec2 buttonSize=ImVec2(avail,avail); - if (ImGui::Button(ICON_FA_CHEVRON_RIGHT "##MobileMenu",buttonSize)) { + const char* mobButtonName=ICON_FA_CHEVRON_RIGHT "##MobileMenu"; + if (portrait) mobButtonName=ICON_FA_CHEVRON_UP "##MobileMenu"; + if (mobileMenuOpen) { + if (portrait) { + mobButtonName=ICON_FA_CHEVRON_DOWN "##MobileMenu"; + } else { + mobButtonName=ICON_FA_CHEVRON_LEFT "##MobileMenu"; + } + } + if (ImGui::Button(mobButtonName,buttonSize)) { + mobileMenuOpen=!mobileMenuOpen; } - ImGui::Text("I put here"); - - ImGui::Separator(); + if (!portrait) ImGui::Separator(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(e->isPlaying())); + if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_PLAY "##Play",buttonSize)) { play(); } ImGui::PopStyleColor(); + if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_STOP "##Stop",buttonSize)) { stop(); } + if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROW_DOWN "##StepOne",buttonSize)) { e->stepOne(cursor.y); pendingStepUpdate=true; @@ -50,12 +77,14 @@ void FurnaceGUI::drawMobileControls() { bool repeatPattern=e->getRepeatPattern(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(repeatPattern)); + if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern",buttonSize)) { e->setRepeatPattern(!repeatPattern); } ImGui::PopStyleColor(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(edit)); + if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_CIRCLE "##Edit",buttonSize)) { edit=!edit; } @@ -63,17 +92,94 @@ void FurnaceGUI::drawMobileControls() { bool metro=e->getMetronome(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(metro)); + if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_BELL_O "##Metronome",buttonSize)) { e->setMetronome(!metro); } ImGui::PopStyleColor(); - - if (ImGui::Button("Get me out of here")) { - toggleMobileUI(false); - } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); + + ImGui::SetNextWindowPos(portrait?ImVec2(0.0f,((1.0-mobileMenuPos*0.65)*scrH*dpiScale)):ImVec2(0.5*scrW*dpiScale*(mobileMenuPos-1.0),0.0f)); + ImGui::SetNextWindowSize(portrait?ImVec2(scrW*dpiScale,0.65*scrH*dpiScale):ImVec2(0.5*scrW*dpiScale,scrH*dpiScale)); + if (ImGui::Begin("Mobile Menu",NULL,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { + ImGui::Button("Pattern"); + ImGui::SameLine(); + ImGui::Button("Ins"); + ImGui::SameLine(); + ImGui::Button("Wave"); + ImGui::SameLine(); + ImGui::Button("Sample"); + + ImGui::Text("Data list goes here..."); + + if (ImGui::Button("New")) { + mobileMenuOpen=false; + //doAction(GUI_ACTION_NEW); + if (modified) { + showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW); + } else { + displayNew=true; + } + } + ImGui::SameLine(); + if (ImGui::Button("Open")) { + mobileMenuOpen=false; + doAction(GUI_ACTION_OPEN); + } + ImGui::SameLine(); + if (ImGui::Button("Save")) { + mobileMenuOpen=false; + doAction(GUI_ACTION_SAVE); + } + ImGui::SameLine(); + if (ImGui::Button("Save as...")) { + mobileMenuOpen=false; + doAction(GUI_ACTION_SAVE_AS); + } + + ImGui::Button("1.1+ .dmf"); + ImGui::SameLine(); + ImGui::Button("Legacy .dmf"); + ImGui::SameLine(); + ImGui::Button("Export Audio"); + ImGui::SameLine(); + ImGui::Button("Export VGM"); + + ImGui::Button("CmdStream"); + ImGui::SameLine(); + ImGui::Button("Panic"); + ImGui::SameLine(); + if (ImGui::Button("Settings")) { + mobileMenuOpen=false; + } + ImGui::SameLine(); + if (ImGui::Button("About")) { + mobileMenuOpen=false; + mobileMenuPos=0.0f; + aboutOpen=true; + } + + ImGui::Separator(); + + if (ImGui::Button("Osc")) { + oscOpen=!oscOpen; + } + ImGui::SameLine(); + if (ImGui::Button("ChanOsc")) { + chanOscOpen=!chanOscOpen; + } + ImGui::SameLine(); + if (ImGui::Button("RegView")) { + regViewOpen=!regViewOpen; + } + ImGui::SameLine(); + if (ImGui::Button("Stats")) { + statsOpen=!statsOpen; + } + } + ImGui::End(); } void FurnaceGUI::drawEditControls() { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c74f077f0..a353308e9 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2581,7 +2581,7 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { if (point.id==0) { ImGui::GetIO().AddMouseButtonEvent(ImGuiMouseButton_Left,false); - ImGui::GetIO().AddMousePosEvent(-FLT_MAX,-FLT_MAX); + //ImGui::GetIO().AddMousePosEvent(-FLT_MAX,-FLT_MAX); } break; } @@ -2747,6 +2747,7 @@ bool FurnaceGUI::loop() { scrH=ev.window.data2/dpiScale; #endif portrait=(scrWgetConfInt("lastWindowY",SDL_WINDOWPOS_CENTERED); scrMax=e->getConfBool("lastWindowMax",false); portrait=(scrWdisplaySize.w/dpiScale) scrW=(displaySize.w/dpiScale)-32; if (scrH>displaySize.h/dpiScale) scrH=(displaySize.h/dpiScale)-32; portrait=(scrW sysSearchResults; std::vector newSongSearchResults; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints, portrait; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; + bool portrait, mobileMenuOpen; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; bool displayPendingIns, pendingInsSingle, displayPendingRawSample; @@ -996,6 +997,7 @@ class FurnaceGUI { int drawHalt; int macroPointSize; int waveEditStyle; + float mobileMenuPos; const int* curSysSection; String pendingRawSample; diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 254c53bed..5081d6ef4 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -372,10 +372,17 @@ void FurnaceGUI::drawPattern() { sel2.xFine^=sel1.xFine; } ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0.0f,0.0f)); + if (mobileUI) { + patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale)); + ImGui::SetNextWindowPos(patWindowPos); + ImGui::SetNextWindowSize(patWindowSize); + } if (ImGui::Begin("Pattern",&patternOpen,globalWinFlags|(settings.avoidRaisingPattern?ImGuiWindowFlags_NoBringToFrontOnFocus:0))) { - //ImGui::SetWindowSize(ImVec2(scrW*dpiScale,scrH*dpiScale)); - patWindowPos=ImGui::GetWindowPos(); - patWindowSize=ImGui::GetWindowSize(); + if (!mobileUI) { + patWindowPos=ImGui::GetWindowPos(); + patWindowSize=ImGui::GetWindowSize(); + } //char id[32]; ImGui::PushFont(patFont); int ord=oldOrder; diff --git a/src/log.cpp b/src/log.cpp index 89602b422..ef2750a2e 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -19,7 +19,11 @@ #include "ta-log.h" +#ifdef IS_MOBILE +int logLevel=LOGLEVEL_TRACE; +#else int logLevel=LOGLEVEL_INFO; +#endif std::atomic logPosition; From 0fd72c53efe13c0cc3fff3222e82e0169f3ff69a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 23:20:33 -0500 Subject: [PATCH 358/515] GUI: and more mobile UI progress --- src/gui/gui.cpp | 3 +++ src/gui/gui.h | 9 +++++++++ src/gui/pattern.cpp | 2 +- src/gui/piano.cpp | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a353308e9..d9e8ffa0f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3349,6 +3349,8 @@ bool FurnaceGUI::loop() { if (mobileUI) { globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; //globalWinFlags=ImGuiWindowFlags_NoTitleBar; + // scene handling goes here! + pianoOpen=true; drawMobileControls(); drawPattern(); drawPiano(); @@ -4882,6 +4884,7 @@ FurnaceGUI::FurnaceGUI(): curFileDialog(GUI_FILE_OPEN), warnAction(GUI_WARN_OPEN), postWarnAction(GUI_WARN_GENERIC), + mobScene(GUI_SCENE_PATTERN), fileDialog(NULL), scrW(1280), scrH(800), diff --git a/src/gui/gui.h b/src/gui/gui.h index 280ec76b7..797f9fd71 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -260,6 +260,14 @@ enum FurnaceGUIWindows { GUI_WINDOW_SPOILER }; +enum FurnaceGUIMobileScenes { + GUI_SCENE_PATTERN, + GUI_SCENE_ORDERS, + GUI_SCENE_INSTRUMENT, + GUI_SCENE_WAVETABLE, + GUI_SCENE_SAMPLE +}; + enum FurnaceGUIFileDialogs { GUI_FILE_OPEN, GUI_FILE_SAVE, @@ -1009,6 +1017,7 @@ class FurnaceGUI { FurnaceGUIFileDialogs curFileDialog; FurnaceGUIWarnings warnAction; FurnaceGUIWarnings postWarnAction; + FurnaceGUIMobileScenes mobScene; FurnaceGUIFileDialog* fileDialog; diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 5081d6ef4..002cabd90 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -374,7 +374,7 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0.0f,0.0f)); if (mobileUI) { patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); - patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale)); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.3*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); ImGui::SetNextWindowPos(patWindowPos); ImGui::SetNextWindowSize(patWindowSize); } diff --git a/src/gui/piano.cpp b/src/gui/piano.cpp index 0e0063bb2..27d8bbeda 100644 --- a/src/gui/piano.cpp +++ b/src/gui/piano.cpp @@ -52,6 +52,10 @@ void FurnaceGUI::drawPiano() { nextWindow=GUI_WINDOW_NOTHING; } if (!pianoOpen) return; + if (mobileUI) { + ImGui::SetNextWindowPos(ImVec2(patWindowPos.x,patWindowPos.y+patWindowSize.y)); + ImGui::SetNextWindowSize(portrait?ImVec2(scrW*dpiScale,0.5*scrW*dpiScale):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),0.3*scrH*dpiScale)); + } if (ImGui::Begin("Piano",&pianoOpen,((pianoOptions)?0:ImGuiWindowFlags_NoTitleBar)|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { bool oldPianoKeyPressed[180]; memcpy(oldPianoKeyPressed,pianoKeyPressed,180*sizeof(bool)); From ffcef2ac735b7b4279f99b34b6a9ac7d33a90f9a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 8 Sep 2022 23:48:39 -0500 Subject: [PATCH 359/515] fix .opni TL loading --- src/engine/fileOpsIns.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 62c3a1d8a..c8dbb57fd 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -805,7 +805,7 @@ void DivEngine::loadOPNI(SafeReader& reader, std::vector& ret, S op.mult = dtMul & 0xF; op.dt = ((dtMul >> 4) & 0x7); - op.tl = totalLevel & 0x3F; + op.tl = totalLevel & 0x7F; op.rs = ((arRateScale >> 6) & 0x3); op.ar = arRateScale & 0x1F; op.dr = drAmpEnable & 0x1F; @@ -1643,7 +1643,7 @@ void DivEngine::loadWOPN(SafeReader& reader, std::vector& ret, S total += (op.mult = dtMul & 0xF); total += (op.dt = ((dtMul >> 4) & 0x7)); - total += (op.tl = totalLevel & 0x3F); + total += (op.tl = totalLevel & 0x7F); total += (op.rs = ((arRateScale >> 6) & 0x3)); total += (op.ar = arRateScale & 0x1F); total += (op.dr = drAmpEnable & 0x1F); From 0c8cde9f85706bd46d5af43a6e16668486e75750 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 00:02:43 -0500 Subject: [PATCH 360/515] GUI: mark modified upon order val change --- src/gui/gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index d9e8ffa0f..6ad37fff4 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1154,6 +1154,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { e->lockSave([this,num]() { e->curOrders->ord[orderCursor][curOrder]=((e->curOrders->ord[orderCursor][curOrder]<<4)|num); }); + MARK_MODIFIED; if (orderEditMode==2 || orderEditMode==3) { curNibble=!curNibble; if (!curNibble) { From 9a3c81d90ac04895a3d56f858f70b5083947f1ff Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 03:23:18 -0500 Subject: [PATCH 361/515] GUI: wave generator, part 6 FM now with feedback! --- src/gui/gui.cpp | 12 +++++++++--- src/gui/gui.h | 2 +- src/gui/waveEdit.cpp | 29 ++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6ad37fff4..55569a620 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5235,9 +5235,15 @@ FurnaceGUI::FurnaceGUI(): memset(waveGenAmp,0,sizeof(float)*16); memset(waveGenPhase,0,sizeof(float)*16); - memset(waveGenTL,0,sizeof(float)*4); - memset(waveGenMult,0,sizeof(int)*4); - memset(waveGenFB,0,sizeof(float)*4); + waveGenTL[0]=0.0f; + waveGenTL[1]=0.0f; + waveGenTL[2]=0.0f; + waveGenTL[3]=1.0f; + waveGenMult[0]=1; + waveGenMult[1]=1; + waveGenMult[2]=1; + waveGenMult[3]=1; + memset(waveGenFB,0,sizeof(int)*4); memset(waveGenFMCon1,0,sizeof(bool)*4); memset(waveGenFMCon2,0,sizeof(bool)*3); memset(waveGenFMCon3,0,sizeof(bool)*2); diff --git a/src/gui/gui.h b/src/gui/gui.h index 797f9fd71..7a67ac374 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1566,7 +1566,7 @@ class FurnaceGUI { float waveGenPhase[16]; float waveGenTL[4]; int waveGenMult[4]; - float waveGenFB[4]; + int waveGenFB[4]; bool waveGenFMCon1[4]; bool waveGenFMCon2[3]; bool waveGenFMCon3[2]; diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 9842d808b..80f3a3419 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -61,12 +61,31 @@ void FurnaceGUI::doGenerateWave() { if (wave->len<2) return; if (waveGenFM) { + float s0fb0=0; + float s0fb1=0; + float s1fb0=0; + float s1fb1=0; + float s2fb0=0; + float s2fb1=0; + float s3fb0=0; + float s3fb1=0; for (int i=0; ilen; i++) { float pos=(float)i/(float)wave->len; - float s0=sin(pos*multFactors[waveGenMult[0]])*waveGenTL[0]; - float s1=sin((pos+(waveGenFMCon1[0]?s0:0.0f))*multFactors[waveGenMult[1]])*waveGenTL[1]; - float s2=sin((pos+(waveGenFMCon1[1]?s0:0.0f)+(waveGenFMCon2[0]?s1:0.0f))*multFactors[waveGenMult[2]])*waveGenTL[2]; - float s3=sin((pos+(waveGenFMCon1[2]?s0:0.0f)+(waveGenFMCon2[1]?s1:0.0f)+(waveGenFMCon3[0]?s2:0.0f))*multFactors[waveGenMult[3]])*waveGenTL[3]; + float s0=sin((pos+(waveGenFB[0]?((s0fb0+s0fb1)*pow(2.0f,waveGenFB[0]-8)):0.0f))*multFactors[waveGenMult[0]])*waveGenTL[0]; + s0fb0=s0fb1; + s0fb1=s0; + + float s1=sin((pos+(waveGenFB[1]?((s1fb0+s1fb1)*pow(2.0f,waveGenFB[1]-8)):0.0f)+(waveGenFMCon1[0]?s0:0.0f))*multFactors[waveGenMult[1]])*waveGenTL[1]; + s1fb0=s1fb1; + s1fb1=s1; + + float s2=sin((pos+(waveGenFB[2]?((s2fb0+s2fb1)*pow(2.0f,waveGenFB[2]-8)):0.0f)+(waveGenFMCon1[1]?s0:0.0f)+(waveGenFMCon2[0]?s1:0.0f))*multFactors[waveGenMult[2]])*waveGenTL[2]; + s2fb0=s2fb1; + s2fb1=s2; + + float s3=sin((pos+(waveGenFB[3]?((s3fb0+s3fb1)*pow(2.0f,waveGenFB[3]-8)):0.0f)+(waveGenFMCon1[2]?s0:0.0f)+(waveGenFMCon2[1]?s1:0.0f)+(waveGenFMCon3[0]?s2:0.0f))*multFactors[waveGenMult[3]])*waveGenTL[3]; + s3fb0=s3fb1; + s3fb1=s3; if (waveGenFMCon1[3]) finalResult[i]+=s0; if (waveGenFMCon2[2]) finalResult[i]+=s1; @@ -394,7 +413,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::PushID(i); - if (CWSliderFloat("##WGFB",&waveGenFB[i],0.0f,7.0f)) { + if (CWSliderInt("##WGFB",&waveGenFB[i],0,7)) { doGenerateWave(); } ImGui::PopID(); From 7e065e4cfea0ddfde34e2a49657cfdbc56080634 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 15:31:29 -0500 Subject: [PATCH 362/515] GUI: more mobile UI things --- src/gui/editControls.cpp | 40 ++++++++++++++++++++++++++++------ src/gui/gui.cpp | 46 ++++++++++++++++++++++++++++++++++++++-- src/gui/insEdit.cpp | 9 +++++++- src/gui/sampleEdit.cpp | 6 ++++++ src/gui/waveEdit.cpp | 9 +++++++- 5 files changed, 99 insertions(+), 11 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 5307163e8..91db32f52 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -104,13 +104,39 @@ void FurnaceGUI::drawMobileControls() { ImGui::SetNextWindowPos(portrait?ImVec2(0.0f,((1.0-mobileMenuPos*0.65)*scrH*dpiScale)):ImVec2(0.5*scrW*dpiScale*(mobileMenuPos-1.0),0.0f)); ImGui::SetNextWindowSize(portrait?ImVec2(scrW*dpiScale,0.65*scrH*dpiScale):ImVec2(0.5*scrW*dpiScale,scrH*dpiScale)); if (ImGui::Begin("Mobile Menu",NULL,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { - ImGui::Button("Pattern"); - ImGui::SameLine(); - ImGui::Button("Ins"); - ImGui::SameLine(); - ImGui::Button("Wave"); - ImGui::SameLine(); - ImGui::Button("Sample"); + if (ImGui::BeginTable("SceneSel",5)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,1.0f); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,1.0f); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,1.0f); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,1.0f); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,1.0f); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImVec2 buttonSize=ImGui::GetContentRegionAvail(); + buttonSize.y=30.0f*dpiScale; + + if (ImGui::Button("Pattern",buttonSize)) { + mobScene=GUI_SCENE_PATTERN; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Orders",buttonSize)) { + mobScene=GUI_SCENE_ORDERS; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Ins",buttonSize)) { + mobScene=GUI_SCENE_INSTRUMENT; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Wave",buttonSize)) { + mobScene=GUI_SCENE_WAVETABLE; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Sample",buttonSize)) { + mobScene=GUI_SCENE_SAMPLE; + } + ImGui::EndTable(); + } ImGui::Text("Data list goes here..."); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 55569a620..4aff36574 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3353,8 +3353,32 @@ bool FurnaceGUI::loop() { // scene handling goes here! pianoOpen=true; drawMobileControls(); - drawPattern(); - drawPiano(); + switch (mobScene) { + case GUI_SCENE_PATTERN: + patternOpen=true; + drawPattern(); + drawPiano(); + break; + case GUI_SCENE_ORDERS: + ordersOpen=true; + drawOrders(); + break; + case GUI_SCENE_INSTRUMENT: + insEditOpen=true; + drawInsEdit(); + drawPiano(); + break; + case GUI_SCENE_WAVETABLE: + waveEditOpen=true; + drawWaveEdit(); + drawPiano(); + break; + case GUI_SCENE_SAMPLE: + sampleEditOpen=true; + drawSampleEdit(); + drawPiano(); + break; + } } else { globalWinFlags=0; ImGui::DockSpaceOverViewport(NULL,lockLayout?(ImGuiDockNodeFlags_NoWindowMenuButton|ImGuiDockNodeFlags_NoMove|ImGuiDockNodeFlags_NoResize|ImGuiDockNodeFlags_NoCloseButton|ImGuiDockNodeFlags_NoDocking|ImGuiDockNodeFlags_NoDockingSplitMe|ImGuiDockNodeFlags_NoDockingSplitOther):0); @@ -3397,6 +3421,13 @@ bool FurnaceGUI::loop() { if (firstFrame) { firstFrame=false; +#ifdef IS_MOBILE + SDL_GetWindowSize(sdlWin,&scrW,&scrH); + scrW/=dpiScale; + scrH/=dpiScale; + portrait=(scrWgetConfInt("lastWindowWidth",1280); scrH=scrConfH=e->getConfInt("lastWindowHeight",800); scrX=scrConfX=e->getConfInt("lastWindowX",SDL_WINDOWPOS_CENTERED); scrY=scrConfY=e->getConfInt("lastWindowY",SDL_WINDOWPOS_CENTERED); scrMax=e->getConfBool("lastWindowMax",false); +#endif portrait=(scrW((displaySize.w/dpiScale)-48) && scrH>((displaySize.h/dpiScale)-64)) { diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 662448dfc..84b70d771 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1560,7 +1560,14 @@ void FurnaceGUI::drawInsEdit() { nextWindow=GUI_WINDOW_NOTHING; } if (!insEditOpen) return; - ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); + if (mobileUI) { + patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.3*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); + ImGui::SetNextWindowPos(patWindowPos); + ImGui::SetNextWindowSize(patWindowSize); + } else { + ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); + } if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking))) { if (curIns<0 || curIns>=(int)e->song.ins.size()) { ImGui::Text("no instrument selected"); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 0ce1500e9..18579e716 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -35,6 +35,12 @@ void FurnaceGUI::drawSampleEdit() { nextWindow=GUI_WINDOW_NOTHING; } if (!sampleEditOpen) return; + if (mobileUI) { + patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.3*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); + ImGui::SetNextWindowPos(patWindowPos); + ImGui::SetNextWindowSize(patWindowSize); + } if (ImGui::Begin("Sample Editor",&sampleEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking))) { if (curSample<0 || curSample>=(int)e->song.sample.size()) { ImGui::Text("no sample selected"); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 80f3a3419..1132b9ea0 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -164,7 +164,14 @@ void FurnaceGUI::drawWaveEdit() { } if (!waveEditOpen) return; float wavePreview[257]; - ImGui::SetNextWindowSizeConstraints(ImVec2(300.0f*dpiScale,300.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); + if (mobileUI) { + patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.3*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); + ImGui::SetNextWindowPos(patWindowPos); + ImGui::SetNextWindowSize(patWindowSize); + } else { + ImGui::SetNextWindowSizeConstraints(ImVec2(300.0f*dpiScale,300.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); + } if (ImGui::Begin("Wavetable Editor",&waveEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking))) { if (curWave<0 || curWave>=(int)e->song.wave.size()) { ImGui::Text("no wavetable selected"); From 84b0ffbac324899126a8240c2f1b44ba1883a7a4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 15:31:38 -0500 Subject: [PATCH 363/515] VRC6: possibly bring solution to #671 --- src/engine/platform/vrc6.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 2500ce190..6e5e0d731 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -195,7 +195,7 @@ void DivPlatformVRC6::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].keyOff) { chWrite(i,2,0); - } else { + } else if (chan[i].active) { chWrite(i,1,chan[i].freq&0xff); chWrite(i,2,0x80|((chan[i].freq>>8)&0xf)); } From d021005f26d518482418d63983bbc9d84bf4722a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 16:41:00 -0500 Subject: [PATCH 364/515] GUI: fix arp macro hover --- src/gui/editControls.cpp | 4 ++++ src/gui/gui.cpp | 2 +- src/gui/gui.h | 8 +++++--- src/gui/insEdit.cpp | 26 +++++++++++++++----------- src/gui/plot_nolerp.cpp | 10 +++++----- src/gui/plot_nolerp.h | 2 +- src/gui/waveEdit.cpp | 4 ++-- 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 91db32f52..f7e40c39e 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -138,6 +138,10 @@ void FurnaceGUI::drawMobileControls() { ImGui::EndTable(); } + if (ImGui::Button("Create Ins")) { + doAction(GUI_ACTION_INS_LIST_ADD); + } + ImGui::Text("Data list goes here..."); if (ImGui::Button("New")) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4aff36574..9a49dd48b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4669,7 +4669,6 @@ bool FurnaceGUI::init() { SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); } } -#endif if (SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(sdlWin),&displaySize)==0) { if (scrW>((displaySize.w/dpiScale)-48) && scrH>((displaySize.h/dpiScale)-64)) { @@ -4684,6 +4683,7 @@ bool FurnaceGUI::init() { SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); } } +#endif } #endif diff --git a/src/gui/gui.h b/src/gui/gui.h index 7a67ac374..c4a3e18c3 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -887,9 +887,10 @@ struct FurnaceGUIMacroDesc { ImVec4 color; unsigned int bitOffset; bool isBitfield, blockMode, bit30; - String (*hoverFunc)(int,float); + String (*hoverFunc)(int,float,void*); + void* hoverFuncUser; - FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0, bool bit30Special=false): + FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float,void*)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0, bool bit30Special=false, void* hfu=NULL): macro(m), height(macroHeight), displayName(name), @@ -900,7 +901,8 @@ struct FurnaceGUIMacroDesc { isBitfield(bitfield), blockMode(block), bit30(bit30Special), - hoverFunc(hf) { + hoverFunc(hf), + hoverFuncUser(hfu) { // MSVC -> hell this->min=macroMin; this->max=macroMax; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 84b70d771..b8427ee45 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -316,27 +316,31 @@ const char* macroRelativeMode="Relative"; const char* macroQSoundMode="QSound"; const char* macroDummyMode="Bug"; -String macroHoverNote(int id, float val) { - if (val<-60 || val>=120) return "???"; - return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]); +String macroHoverNote(int id, float val, void* u) { + int* macroVal=(int*)u; + if ((macroVal[id]&0xc0000000)==0x40000000 || (macroVal[id]&0xc0000000)==0x80000000) { + if (val<-60 || val>=120) return "???"; + return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]); + } + return fmt::sprintf("%d: %d",id,(int)val); } -String macroHover(int id, float val) { +String macroHover(int id, float val, void* u) { return fmt::sprintf("%d: %d",id,val); } -String macroHoverLoop(int id, float val) { +String macroHoverLoop(int id, float val, void* u) { if (val>1) return "Release"; if (val>0) return "Loop"; return ""; } -String macroHoverBit30(int id, float val) { +String macroHoverBit30(int id, float val, void* u) { if (val>0) return "Fixed"; return "Relative"; } -String macroHoverES5506FilterMode(int id, float val) { +String macroHoverES5506FilterMode(int id, float val, void* u) { String mode="???"; switch (((int)val)&3) { case 0: @@ -357,7 +361,7 @@ String macroHoverES5506FilterMode(int id, float val) { return fmt::sprintf("%d: %s",id,mode); } -String macroLFOWaves(int id, float val) { +String macroLFOWaves(int id, float val, void* u) { switch (((int)val)&3) { case 0: return "Saw"; @@ -1355,7 +1359,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (i.isBitfield) { PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight); } else { - PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.blockMode,i.macro->open?genericGuide:NULL,doHighlight); + PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,i.macro->open?genericGuide:NULL,doHighlight); } if (i.macro->open && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { macroDragStart=ImGui::GetItemRectMin(); @@ -3613,7 +3617,7 @@ void FurnaceGUI::drawInsEdit() { modTable[i]=ins->fds.modTable[i]; } ImVec2 modTableSize=ImVec2(ImGui::GetContentRegionAvail().x,96.0f*dpiScale); - PlotCustom("ModTable",modTable,32,0,NULL,-4,3,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,true); + PlotCustom("ModTable",modTable,32,0,NULL,-4,3,modTableSize,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=modTableSize; @@ -4232,7 +4236,7 @@ void FurnaceGUI::drawInsEdit() { if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } - macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,NULL,false,NULL,0,true)); + macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,0,true,ins->std.arpMacro.val)); 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)); diff --git a/src/gui/plot_nolerp.cpp b/src/gui/plot_nolerp.cpp index d802cbc52..b75bda4f0 100644 --- a/src/gui/plot_nolerp.cpp +++ b/src/gui/plot_nolerp.cpp @@ -293,7 +293,7 @@ void PlotBitfield(const char* label, const int* values, int values_count, int va PlotBitfieldEx(label, &Plot_IntArrayGetter, (void*)&data, values_count, values_offset, overlay_text, bits, graph_size, values_highlight, highlightColor); } -int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor) +int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float,void*), void* hoverFuncUser, bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor) { ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindow(); @@ -359,7 +359,7 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett const float v0 = values_getter(data, (v_idx) % values_count); const float v1 = values_getter(data, (v_idx + 1) % values_count); if (hoverFunc) { - std::string hoverText=hoverFunc(v_idx+values_display_offset,v0); + std::string hoverText=hoverFunc(v_idx+values_display_offset,v0,hoverFuncUser); if (!hoverText.empty()) { ImGui::SetTooltip("%s",hoverText.c_str()); } @@ -459,8 +459,8 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett return idx_hovered; } -void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor) +void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float,void*), void* hoverFuncUser, bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor) { FurnacePlotArrayGetterData data(values, stride); - PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, blockMode, guideFunc, values_highlight, highlightColor); -} \ No newline at end of file + PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, hoverFuncUser, blockMode, guideFunc, values_highlight, highlightColor); +} diff --git a/src/gui/plot_nolerp.h b/src/gui/plot_nolerp.h index b353e6f8b..48332b339 100644 --- a/src/gui/plot_nolerp.h +++ b/src/gui/plot_nolerp.h @@ -22,4 +22,4 @@ void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); -void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL, bool blockMode=false, std::string (*guideFunc)(float) = NULL, const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); \ No newline at end of file +void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float,void*) = NULL, void* hoverFuncUser=NULL, bool blockMode=false, std::string (*guideFunc)(float) = NULL, const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 1132b9ea0..f26f45833 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -271,7 +271,7 @@ void FurnaceGUI::drawWaveEdit() { if (waveEditStyle) { PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion); } else { - PlotCustom("##Waveform",wavePreview,wave->len,0,NULL,0,wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,true); + PlotCustom("##Waveform",wavePreview,wave->len,0,NULL,0,wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true); } if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { waveDragStart=ImGui::GetItemRectMin(); @@ -412,7 +412,7 @@ void FurnaceGUI::drawWaveEdit() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::PushID(i); - if (CWSliderInt("##WGMULT",&waveGenMult[i],0,15)) { + if (CWSliderInt("##WGMULT",&waveGenMult[i],1,16)) { doGenerateWave(); } ImGui::PopID(); From 0ac92209d034e7209085cf52114b75e68cb3dd43 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 18:53:20 -0500 Subject: [PATCH 365/515] GUI: even more mobile work --- CONTRIBUTING.md | 2 +- android/app/src/main/AndroidManifest.xml | 14 +- src/gui/dataList.cpp | 60 +++- src/gui/editControls.cpp | 18 +- src/gui/gui.cpp | 171 ++++++----- src/gui/gui.h | 10 +- src/gui/insEdit.cpp | 2 +- src/gui/pattern.cpp | 2 +- src/gui/piano.cpp | 347 ++++++++++++----------- src/gui/sampleEdit.cpp | 2 +- src/gui/waveEdit.cpp | 2 +- 11 files changed, 353 insertions(+), 277 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6931ce8f..853020f94 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ bug fixes, improvements and several other things accepted. the coding style is described here: -- indentation: two spaces +- indentation: two spaces. **strictly** spaces. do NOT use tabs. - modified 1TBS style: - no spaces in function calls - spaces between arguments in function declarations diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5f7a06efc..e28b7fd14 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ @@ -83,13 +83,17 @@ - diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 0ef1f183b..0519fca3d 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -29,14 +29,20 @@ const char* sampleNote[12]={ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; -void FurnaceGUI::drawInsList() { +void FurnaceGUI::drawInsList(bool asChild) { if (nextWindow==GUI_WINDOW_INS_LIST) { insListOpen=true; ImGui::SetNextWindowFocus(); nextWindow=GUI_WINDOW_NOTHING; } - if (!insListOpen) return; - if (ImGui::Begin("Instruments",&insListOpen,globalWinFlags)) { + if (!insListOpen && !asChild) return; + bool began=false; + if (asChild) { + began=ImGui::BeginChild("Instruments"); + } else { + began=ImGui::Begin("Instruments",&insListOpen,globalWinFlags); + } + if (began) { if (settings.unifiedDataView) settings.horizontalDataView=0; if (ImGui::Button(ICON_FA_PLUS "##InsAdd")) { if (!settings.unifiedDataView) doAction(GUI_ACTION_INS_LIST_ADD); @@ -409,11 +415,15 @@ void FurnaceGUI::drawInsList() { ImGui::EndTable(); } } - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_LIST; - ImGui::End(); + if (asChild) { + ImGui::EndChild(); + } else { + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_LIST; + ImGui::End(); + } } -void FurnaceGUI::drawWaveList() { +void FurnaceGUI::drawWaveList(bool asChild) { if (nextWindow==GUI_WINDOW_WAVE_LIST) { waveListOpen=true; if (settings.unifiedDataView) { @@ -424,8 +434,14 @@ void FurnaceGUI::drawWaveList() { nextWindow=GUI_WINDOW_NOTHING; } if (settings.unifiedDataView) return; - if (!waveListOpen) return; - if (ImGui::Begin("Wavetables",&waveListOpen,globalWinFlags)) { + if (!waveListOpen && !asChild) return; + bool began=false; + if (asChild) { + began=ImGui::BeginChild("Wavetables"); + } else { + began=ImGui::Begin("Wavetables",&waveListOpen,globalWinFlags); + } + if (began) { if (ImGui::Button(ICON_FA_PLUS "##WaveAdd")) { doAction(GUI_ACTION_WAVE_LIST_ADD); } @@ -476,11 +492,15 @@ void FurnaceGUI::drawWaveList() { ImGui::EndTable(); } } - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_WAVE_LIST; - ImGui::End(); + if (asChild) { + ImGui::EndChild(); + } else { + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_WAVE_LIST; + ImGui::End(); + } } -void FurnaceGUI::drawSampleList() { +void FurnaceGUI::drawSampleList(bool asChild) { if (nextWindow==GUI_WINDOW_SAMPLE_LIST) { sampleListOpen=true; if (settings.unifiedDataView) { @@ -491,8 +511,14 @@ void FurnaceGUI::drawSampleList() { nextWindow=GUI_WINDOW_NOTHING; } if (settings.unifiedDataView) return; - if (!sampleListOpen) return; - if (ImGui::Begin("Samples",&sampleListOpen,globalWinFlags)) { + if (!sampleListOpen && !asChild) return; + bool began=false; + if (asChild) { + began=ImGui::BeginChild("Samples"); + } else { + began=ImGui::Begin("Samples",&sampleListOpen,globalWinFlags); + } + if (began) { if (ImGui::Button(ICON_FA_FILE "##SampleAdd")) { doAction(GUI_ACTION_SAMPLE_LIST_ADD); } @@ -548,8 +574,12 @@ void FurnaceGUI::drawSampleList() { } ImGui::Unindent(); } - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SAMPLE_LIST; - ImGui::End(); + if (asChild) { + ImGui::EndChild(); + } else { + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SAMPLE_LIST; + ImGui::End(); + } } void FurnaceGUI::actualWaveList() { diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index f7e40c39e..ab3cc688d 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -138,12 +138,22 @@ void FurnaceGUI::drawMobileControls() { ImGui::EndTable(); } - if (ImGui::Button("Create Ins")) { - doAction(GUI_ACTION_INS_LIST_ADD); + if (settings.unifiedDataView) { + drawInsList(true); + } else { + switch (mobScene) { + case GUI_SCENE_WAVETABLE: + drawWaveList(true); + break; + case GUI_SCENE_SAMPLE: + drawSampleList(true); + break; + default: + drawInsList(true); + break; + } } - ImGui::Text("Data list goes here..."); - if (ImGui::Button("New")) { mobileMenuOpen=false; //doAction(GUI_ACTION_NEW); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9a49dd48b..4c1fc5c48 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2544,12 +2544,15 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { TouchPoint* point=NULL; FIND_POINT(point,ev.tfinger.fingerId); if (point!=NULL) { + float prevX=point->x; + float prevY=point->y; point->x=ev.tfinger.x*scrW*dpiScale; point->y=ev.tfinger.y*scrH*dpiScale; point->z=ev.tfinger.pressure; if (point->id==0) { ImGui::GetIO().AddMousePosEvent(point->x,point->y); + pointMotion(point->x,point->y,point->x-prevX,point->y-prevY); } } break; @@ -2570,6 +2573,7 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { if (newPoint.id==0) { ImGui::GetIO().AddMousePosEvent(newPoint.x,newPoint.y); ImGui::GetIO().AddMouseButtonEvent(ImGuiMouseButton_Left,true); + pointDown(newPoint.x,newPoint.y,0); } break; } @@ -2577,13 +2581,15 @@ void FurnaceGUI::processPoint(SDL_Event& ev) { for (size_t i=0; irenderSamplesP(); + } else { + if (sampleSelStart>sampleSelEnd) { + sampleSelStart^=sampleSelEnd; + sampleSelEnd^=sampleSelStart; + sampleSelStart^=sampleSelEnd; + } + } + } + sampleDragActive=false; + if (selecting) { + if (!selectingFull) cursor=selEnd; + finishSelection(); + demandScrollX=true; + if (cursor.xCoarse==selStart.xCoarse && cursor.xFine==selStart.xFine && cursor.y==selStart.y && + cursor.xCoarse==selEnd.xCoarse && cursor.xFine==selEnd.xFine && cursor.y==selEnd.y) { + if (!settings.cursorMoveNoScroll) { + updateScroll(cursor.y); + } + } + } +} + +void FurnaceGUI::pointMotion(int x, int y, int xrel, int yrel) { + if (selecting) { + // detect whether we have to scroll + if (ypatWindowPos.y+patWindowSize.y-2.0f*dpiScale) { + addScroll(1); + } + } + if (macroDragActive || macroLoopDragActive || waveDragActive || sampleDragActive) { + int distance=fabs((double)xrel); + if (distance<1) distance=1; + float start=x-xrel; + float end=x; + float startY=y-yrel; + float endY=y; + for (int i=0; i<=distance; i++) { + float fraction=(float)i/(float)distance; + float x=start+(end-start)*fraction; + float y=startY+(endY-startY)*fraction; + processDrags(x,y); + } + } +} + // how many pixels should be visible at least at x/y dir #define OOB_PIXELS_SAFETY 25 @@ -2640,7 +2724,7 @@ bool FurnaceGUI::loop() { if (settings.powerSave) SDL_WaitEventTimeout(NULL,500); } eventTimeBegin=SDL_GetPerformanceCounter(); - bool updateWindow = false; + bool updateWindow=false; while (SDL_PollEvent(&ev)) { WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); @@ -2658,80 +2742,14 @@ bool FurnaceGUI::loop() { motionXrel*=dpiScale; motionYrel*=dpiScale; #endif - if (selecting) { - // detect whether we have to scroll - if (motionYpatWindowPos.y+patWindowSize.y-2.0f*dpiScale) { - addScroll(1); - } - } - if (macroDragActive || macroLoopDragActive || waveDragActive || sampleDragActive) { - int distance=fabs((double)motionXrel); - if (distance<1) distance=1; - float start=motionX-motionXrel; - float end=motionX; - float startY=motionY-motionYrel; - float endY=motionY; - for (int i=0; i<=distance; i++) { - float fraction=(float)i/(float)distance; - float x=start+(end-start)*fraction; - float y=startY+(endY-startY)*fraction; - processDrags(x,y); - } - } + pointMotion(motionX,motionY,motionXrel,motionYrel); break; } case SDL_MOUSEBUTTONUP: - if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode)) { - MARK_MODIFIED; - } - if (macroDragActive && macroDragLineMode && !macroDragMouseMoved) { - displayMacroMenu=true; - } - macroDragActive=false; - macroDragBitMode=false; - macroDragInitialValue=false; - macroDragInitialValueSet=false; - macroDragLastX=-1; - macroDragLastY=-1; - macroLoopDragActive=false; - waveDragActive=false; - if (sampleDragActive) { - logD("stopping sample drag"); - if (sampleDragMode) { - e->renderSamplesP(); - } else { - if (sampleSelStart>sampleSelEnd) { - sampleSelStart^=sampleSelEnd; - sampleSelEnd^=sampleSelStart; - sampleSelStart^=sampleSelEnd; - } - } - } - sampleDragActive=false; - if (selecting) { - if (!selectingFull) cursor=selEnd; - finishSelection(); - demandScrollX=true; - if (cursor.xCoarse==selStart.xCoarse && cursor.xFine==selStart.xFine && cursor.y==selStart.y && - cursor.xCoarse==selEnd.xCoarse && cursor.xFine==selEnd.xFine && cursor.y==selEnd.y) { - if (!settings.cursorMoveNoScroll) { - updateScroll(cursor.y); - } - } - } + pointUp(ev.button.x,ev.button.y,ev.button.button); break; case SDL_MOUSEBUTTONDOWN: - aboutOpen=false; - if (bindSetActive) { - bindSetActive=false; - bindSetPending=false; - actionKeys[bindSetTarget]=bindSetPrevValue; - bindSetTarget=0; - bindSetPrevValue=0; - } + pointDown(ev.button.x,ev.button.y,ev.button.button); break; case SDL_MOUSEWHEEL: wheelX+=ev.wheel.x; @@ -3356,25 +3374,30 @@ bool FurnaceGUI::loop() { switch (mobScene) { case GUI_SCENE_PATTERN: patternOpen=true; + curWindow=GUI_WINDOW_PATTERN; drawPattern(); drawPiano(); break; case GUI_SCENE_ORDERS: ordersOpen=true; + curWindow=GUI_WINDOW_ORDERS; drawOrders(); break; case GUI_SCENE_INSTRUMENT: insEditOpen=true; + curWindow=GUI_WINDOW_INS_EDIT; drawInsEdit(); drawPiano(); break; case GUI_SCENE_WAVETABLE: waveEditOpen=true; + curWindow=GUI_WINDOW_WAVE_EDIT; drawWaveEdit(); drawPiano(); break; case GUI_SCENE_SAMPLE: sampleEditOpen=true; + curWindow=GUI_WINDOW_SAMPLE_EDIT; drawSampleEdit(); drawPiano(); break; @@ -4628,7 +4651,7 @@ bool FurnaceGUI::init() { portrait=(scrW0)?1:0),ImGuiTableFlags_BordersInnerV)) { + if (ImGui::BeginTable("PianoLayout",((pianoOptions && (!mobileUI || !portrait))?2:1),ImGuiTableFlags_BordersInnerV)) { int& off=(e->isPlaying() || pianoSharePosition)?pianoOffset:pianoOffsetEdit; int& oct=(e->isPlaying() || pianoSharePosition)?pianoOctaves:pianoOctavesEdit; bool view=(pianoView==2)?(!e->isPlaying()):pianoView; - if (pianoOptions) { + if (pianoOptions && (!mobileUI || !portrait)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); } - if (pianoInputPadMode==1 && cursor.xFine>0) { - ImGui::TableSetupColumn("c0s",ImGuiTableColumnFlags_WidthStretch,2.0f); - } ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,1.0f); ImGui::TableNextRow(); if (pianoOptions) { ImGui::TableNextColumn(); - float optionSizeY=ImGui::GetContentRegionAvail().y*0.5-ImGui::GetStyle().ItemSpacing.y; - ImVec2 optionSize=ImVec2(1.2f*optionSizeY,optionSizeY); + float optionSizeY=ImGui::GetContentRegionAvail().y*((mobileUI && portrait)?0.3:0.5)-ImGui::GetStyle().ItemSpacing.y; + ImVec2 optionSize=ImVec2((mobileUI && portrait)?((ImGui::GetContentRegionAvail().x-ImGui::GetStyle().ItemSpacing.x*5.0f)/6.0f):(1.2f*optionSizeY),optionSizeY); if (pianoOptionsSet) { if (ImGui::Button("OFF##PianoNOff",optionSize)) { if (edit) noteInput(0,100); @@ -126,6 +123,10 @@ void FurnaceGUI::drawPiano() { ImGui::EndPopup(); } + if (mobileUI && portrait) { + ImGui::SameLine(); + } + if (pianoOptionsSet) { if (ImGui::Button("REL##PianoNMRel",optionSize)) { if (edit) noteInput(0,102); @@ -152,6 +153,10 @@ void FurnaceGUI::drawPiano() { } } + if (mobileUI && portrait) { + ImGui::TableNextRow(); + } + ImGui::TableNextColumn(); if (pianoInputPadMode==1 && cursor.xFine>0) { ImVec2 buttonSize=ImGui::GetContentRegionAvail(); @@ -199,192 +204,192 @@ void FurnaceGUI::drawPiano() { ImGui::EndTable(); } - ImGui::TableNextColumn(); - } - ImGuiWindow* window=ImGui::GetCurrentWindow(); - ImVec2 size=ImGui::GetContentRegionAvail(); - ImDrawList* dl=ImGui::GetWindowDrawList(); + } else { + ImGuiWindow* window=ImGui::GetCurrentWindow(); + ImVec2 size=ImGui::GetContentRegionAvail(); + ImDrawList* dl=ImGui::GetWindowDrawList(); - ImVec2 minArea=window->DC.CursorPos; - ImVec2 maxArea=ImVec2( - minArea.x+size.x, - minArea.y+size.y - ); - ImRect rect=ImRect(minArea,maxArea); + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); - // render piano - //ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); - if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) { - ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay")); - if (view) { - int notes=oct*12; - // evaluate input - for (TouchPoint& i: activePoints) { - if (rect.Contains(ImVec2(i.x,i.y))) { - int note=(((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*notes)+12*off; - if (note<0) continue; - if (note>=180) continue; - pianoKeyPressed[note]=true; - } - } - - for (int i=0; i=180) continue; - float pkh=pianoKeyHit[note]; - ImVec4 color=isTopKey[i%12]?uiColors[GUI_COLOR_PIANO_KEY_TOP]:uiColors[GUI_COLOR_PIANO_KEY_BOTTOM]; - if (pianoKeyPressed[note]) { - color=isTopKey[i%12]?uiColors[GUI_COLOR_PIANO_KEY_TOP_ACTIVE]:uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE]; - } else { - ImVec4 colorHit=isTopKey[i%12]?uiColors[GUI_COLOR_PIANO_KEY_TOP_HIT]:uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_HIT]; - color.x+=(colorHit.x-color.x)*pkh; - color.y+=(colorHit.y-color.y)*pkh; - color.z+=(colorHit.z-color.z)*pkh; - color.w+=(colorHit.w-color.w)*pkh; - } - ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/notes,0.0f)); - ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/notes,1.0f)); - p1.x-=dpiScale; - dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); - if ((i%12)==0) { - String label=fmt::sprintf("%d",(note-60)/12); - ImVec2 pText=ImLerp(p0,p1,ImVec2(0.5f,1.0f)); - ImVec2 labelSize=ImGui::CalcTextSize(label.c_str()); - pText.x-=labelSize.x*0.5f; - pText.y-=labelSize.y+ImGui::GetStyle().ItemSpacing.y; - dl->AddText(pText,0xff404040,label.c_str()); - } - } - } else { - int bottomNotes=7*oct; - // evaluate input - for (TouchPoint& i: activePoints) { - if (rect.Contains(ImVec2(i.x,i.y))) { - // top - int o=((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*oct; - ImVec2 op0=ImLerp(rect.Min,rect.Max,ImVec2((float)o/oct,0.0f)); - ImVec2 op1=ImLerp(rect.Min,rect.Max,ImVec2((float)(o+1)/oct,1.0f)); - bool foundTopKey=false; - - for (int j=0; j<5; j++) { - int note=topKeyNotes[j]+12*(o+off); + // render piano + //ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) { + ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay")); + if (view) { + int notes=oct*12; + // evaluate input + for (TouchPoint& i: activePoints) { + if (rect.Contains(ImVec2(i.x,i.y))) { + int note=(((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*notes)+12*off; if (note<0) continue; if (note>=180) continue; - ImRect keyRect=ImRect( - ImLerp(op0,op1,ImVec2(topKeyStarts[j]-0.05f,0.0f)), - ImLerp(op0,op1,ImVec2(topKeyStarts[j]+0.05f,0.64f)) - ); - if (keyRect.Contains(ImVec2(i.x,i.y))) { - pianoKeyPressed[note]=true; - foundTopKey=true; - break; - } + pianoKeyPressed[note]=true; } - if (foundTopKey) continue; - - // bottom - int n=((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*bottomNotes; - int note=bottomKeyNotes[n%7]+12*((n/7)+off); - if (note<0) continue; - if (note>=180) continue; - pianoKeyPressed[note]=true; - } - } - - for (int i=0; i=180) continue; - - float pkh=pianoKeyHit[note]; - ImVec4 color=uiColors[GUI_COLOR_PIANO_KEY_BOTTOM]; - if (pianoKeyPressed[note]) { - color=uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE]; - } else { - ImVec4 colorHit=uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_HIT]; - color.x+=(colorHit.x-color.x)*pkh; - color.y+=(colorHit.y-color.y)*pkh; - color.z+=(colorHit.z-color.z)*pkh; - color.w+=(colorHit.w-color.w)*pkh; } - ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/bottomNotes,0.0f)); - ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/bottomNotes,1.0f)); - p1.x-=dpiScale; - - dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); - if ((i%7)==0) { - String label=fmt::sprintf("%d",(note-60)/12); - ImVec2 pText=ImLerp(p0,p1,ImVec2(0.5f,1.0f)); - ImVec2 labelSize=ImGui::CalcTextSize(label.c_str()); - pText.x-=labelSize.x*0.5f; - pText.y-=labelSize.y+ImGui::GetStyle().ItemSpacing.y; - dl->AddText(pText,0xff404040,label.c_str()); - } - } - - for (int i=0; i=180) continue; float pkh=pianoKeyHit[note]; - ImVec4 color=uiColors[GUI_COLOR_PIANO_KEY_TOP]; + ImVec4 color=isTopKey[i%12]?uiColors[GUI_COLOR_PIANO_KEY_TOP]:uiColors[GUI_COLOR_PIANO_KEY_BOTTOM]; if (pianoKeyPressed[note]) { - color=uiColors[GUI_COLOR_PIANO_KEY_TOP_ACTIVE]; + color=isTopKey[i%12]?uiColors[GUI_COLOR_PIANO_KEY_TOP_ACTIVE]:uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE]; } else { - ImVec4 colorHit=uiColors[GUI_COLOR_PIANO_KEY_TOP_HIT]; + ImVec4 colorHit=isTopKey[i%12]?uiColors[GUI_COLOR_PIANO_KEY_TOP_HIT]:uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_HIT]; color.x+=(colorHit.x-color.x)*pkh; color.y+=(colorHit.y-color.y)*pkh; color.z+=(colorHit.z-color.z)*pkh; color.w+=(colorHit.w-color.w)*pkh; } - ImVec2 p0=ImLerp(op0,op1,ImVec2(topKeyStarts[j]-0.05f,0.0f)); - ImVec2 p1=ImLerp(op0,op1,ImVec2(topKeyStarts[j]+0.05f,0.64f)); - dl->AddRectFilled(p0,p1,ImGui::GetColorU32(uiColors[GUI_COLOR_PIANO_BACKGROUND])); - p0.x+=dpiScale; + ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/notes,0.0f)); + ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/notes,1.0f)); p1.x-=dpiScale; - p1.y-=dpiScale; dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); + if ((i%12)==0) { + String label=fmt::sprintf("%d",(note-60)/12); + ImVec2 pText=ImLerp(p0,p1,ImVec2(0.5f,1.0f)); + ImVec2 labelSize=ImGui::CalcTextSize(label.c_str()); + pText.x-=labelSize.x*0.5f; + pText.y-=labelSize.y+ImGui::GetStyle().ItemSpacing.y; + dl->AddText(pText,0xff404040,label.c_str()); + } + } + } else { + int bottomNotes=7*oct; + // evaluate input + for (TouchPoint& i: activePoints) { + if (rect.Contains(ImVec2(i.x,i.y))) { + // top + int o=((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*oct; + ImVec2 op0=ImLerp(rect.Min,rect.Max,ImVec2((float)o/oct,0.0f)); + ImVec2 op1=ImLerp(rect.Min,rect.Max,ImVec2((float)(o+1)/oct,1.0f)); + bool foundTopKey=false; + + for (int j=0; j<5; j++) { + int note=topKeyNotes[j]+12*(o+off); + if (note<0) continue; + if (note>=180) continue; + ImRect keyRect=ImRect( + ImLerp(op0,op1,ImVec2(topKeyStarts[j]-0.05f,0.0f)), + ImLerp(op0,op1,ImVec2(topKeyStarts[j]+0.05f,0.64f)) + ); + if (keyRect.Contains(ImVec2(i.x,i.y))) { + pianoKeyPressed[note]=true; + foundTopKey=true; + break; + } + } + if (foundTopKey) continue; + + // bottom + int n=((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*bottomNotes; + int note=bottomKeyNotes[n%7]+12*((n/7)+off); + if (note<0) continue; + if (note>=180) continue; + pianoKeyPressed[note]=true; + } + } + + for (int i=0; i=180) continue; + + float pkh=pianoKeyHit[note]; + ImVec4 color=uiColors[GUI_COLOR_PIANO_KEY_BOTTOM]; + if (pianoKeyPressed[note]) { + color=uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE]; + } else { + ImVec4 colorHit=uiColors[GUI_COLOR_PIANO_KEY_BOTTOM_HIT]; + color.x+=(colorHit.x-color.x)*pkh; + color.y+=(colorHit.y-color.y)*pkh; + color.z+=(colorHit.z-color.z)*pkh; + color.w+=(colorHit.w-color.w)*pkh; + } + + ImVec2 p0=ImLerp(rect.Min,rect.Max,ImVec2((float)i/bottomNotes,0.0f)); + ImVec2 p1=ImLerp(rect.Min,rect.Max,ImVec2((float)(i+1)/bottomNotes,1.0f)); + p1.x-=dpiScale; + + dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); + if ((i%7)==0) { + String label=fmt::sprintf("%d",(note-60)/12); + ImVec2 pText=ImLerp(p0,p1,ImVec2(0.5f,1.0f)); + ImVec2 labelSize=ImGui::CalcTextSize(label.c_str()); + pText.x-=labelSize.x*0.5f; + pText.y-=labelSize.y+ImGui::GetStyle().ItemSpacing.y; + dl->AddText(pText,0xff404040,label.c_str()); + } + } + + for (int i=0; i=180) continue; + float pkh=pianoKeyHit[note]; + ImVec4 color=uiColors[GUI_COLOR_PIANO_KEY_TOP]; + if (pianoKeyPressed[note]) { + color=uiColors[GUI_COLOR_PIANO_KEY_TOP_ACTIVE]; + } else { + ImVec4 colorHit=uiColors[GUI_COLOR_PIANO_KEY_TOP_HIT]; + color.x+=(colorHit.x-color.x)*pkh; + color.y+=(colorHit.y-color.y)*pkh; + color.z+=(colorHit.z-color.z)*pkh; + color.w+=(colorHit.w-color.w)*pkh; + } + ImVec2 p0=ImLerp(op0,op1,ImVec2(topKeyStarts[j]-0.05f,0.0f)); + ImVec2 p1=ImLerp(op0,op1,ImVec2(topKeyStarts[j]+0.05f,0.64f)); + dl->AddRectFilled(p0,p1,ImGui::GetColorU32(uiColors[GUI_COLOR_PIANO_BACKGROUND])); + p0.x+=dpiScale; + p1.x-=dpiScale; + p1.y-=dpiScale; + dl->AddRectFilled(p0,p1,ImGui::ColorConvertFloat4ToU32(color)); + } + } + } + + const float reduction=ImGui::GetIO().DeltaTime*60.0f*0.12; + for (int i=0; i<180; i++) { + pianoKeyHit[i]-=reduction; + if (pianoKeyHit[i]<0) pianoKeyHit[i]=0; + } + } + + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + pianoOptions=!pianoOptions; + } + + // first check released keys + for (int i=0; i<180; i++) { + int note=i-60; + if (!pianoKeyPressed[i]) { + if (pianoKeyPressed[i]!=oldPianoKeyPressed[i]) { + e->synchronized([this,note]() { + e->autoNoteOff(-1,note); + }); } } } - - const float reduction=ImGui::GetIO().DeltaTime*60.0f*0.12; + // then pressed ones for (int i=0; i<180; i++) { - pianoKeyHit[i]-=reduction; - if (pianoKeyHit[i]<0) pianoKeyHit[i]=0; - } - } - - if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - pianoOptions=!pianoOptions; - } - - // first check released keys - for (int i=0; i<180; i++) { - int note=i-60; - if (!pianoKeyPressed[i]) { - if (pianoKeyPressed[i]!=oldPianoKeyPressed[i]) { - e->synchronized([this,note]() { - e->autoNoteOff(-1,note); - }); - } - } - } - // then pressed ones - for (int i=0; i<180; i++) { - int note=i-60; - if (pianoKeyPressed[i]) { - if (pianoKeyPressed[i]!=oldPianoKeyPressed[i]) { - e->synchronized([this,note]() { - e->autoNoteOn(-1,curIns,note); - }); - if (edit) noteInput(note,0); + int note=i-60; + if (pianoKeyPressed[i]) { + if (pianoKeyPressed[i]!=oldPianoKeyPressed[i]) { + e->synchronized([this,note]() { + e->autoNoteOn(-1,curIns,note); + }); + if (edit) noteInput(note,0); + } } } } diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 18579e716..76f654c16 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -37,7 +37,7 @@ void FurnaceGUI::drawSampleEdit() { if (!sampleEditOpen) return; if (mobileUI) { patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); - patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.3*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.4*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); ImGui::SetNextWindowPos(patWindowPos); ImGui::SetNextWindowSize(patWindowSize); } diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index f26f45833..c46e2ec0c 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -166,7 +166,7 @@ void FurnaceGUI::drawWaveEdit() { float wavePreview[257]; if (mobileUI) { patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*scrH*dpiScale)):ImVec2((0.16*scrH*dpiScale)+0.5*scrW*dpiScale*mobileMenuPos,0.0f)); - patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.3*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); + patWindowSize=(portrait?ImVec2(scrW*dpiScale,scrH*dpiScale-(0.16*scrW*dpiScale)-(pianoOpen?(0.4*scrW*dpiScale):0.0f)):ImVec2(scrW*dpiScale-(0.16*scrH*dpiScale),scrH*dpiScale-(pianoOpen?(0.3*scrH*dpiScale):0.0f))); ImGui::SetNextWindowPos(patWindowPos); ImGui::SetNextWindowSize(patWindowSize); } else { From f2e519d71e80e8057ce6569d4874aef079c672a2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 19:23:53 -0500 Subject: [PATCH 366/515] GUI: add an option to exit mobile UI --- src/gui/editControls.cpp | 172 ++++++++++++++++++++++++--------------- src/gui/gui.cpp | 17 ++-- src/gui/gui.h | 6 +- 3 files changed, 121 insertions(+), 74 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index ab3cc688d..9d6c0d008 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -135,89 +135,127 @@ void FurnaceGUI::drawMobileControls() { if (ImGui::Button("Sample",buttonSize)) { mobScene=GUI_SCENE_SAMPLE; } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Button("Song",buttonSize)) { + mobScene=GUI_SCENE_SONG; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Channels",buttonSize)) { + mobScene=GUI_SCENE_CHANNELS; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Chips",buttonSize)) { + mobScene=GUI_SCENE_CHIPS; + } + ImGui::TableNextColumn(); + if (ImGui::Button("Other",buttonSize)) { + mobScene=GUI_SCENE_OTHER; + } ImGui::EndTable(); } + ImGui::Separator(); + if (settings.unifiedDataView) { drawInsList(true); } else { switch (mobScene) { + case GUI_SCENE_PATTERN: + case GUI_SCENE_ORDERS: + case GUI_SCENE_INSTRUMENT: + drawInsList(true); + break; case GUI_SCENE_WAVETABLE: drawWaveList(true); break; case GUI_SCENE_SAMPLE: drawSampleList(true); break; - default: - drawInsList(true); + case GUI_SCENE_SONG: { + if (ImGui::Button("New")) { + mobileMenuOpen=false; + //doAction(GUI_ACTION_NEW); + if (modified) { + showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW); + } else { + displayNew=true; + } + } + ImGui::SameLine(); + if (ImGui::Button("Open")) { + mobileMenuOpen=false; + doAction(GUI_ACTION_OPEN); + } + ImGui::SameLine(); + if (ImGui::Button("Save")) { + mobileMenuOpen=false; + doAction(GUI_ACTION_SAVE); + } + ImGui::SameLine(); + if (ImGui::Button("Save as...")) { + mobileMenuOpen=false; + doAction(GUI_ACTION_SAVE_AS); + } + + ImGui::Button("1.1+ .dmf"); + ImGui::SameLine(); + ImGui::Button("Legacy .dmf"); + ImGui::SameLine(); + ImGui::Button("Export Audio"); + ImGui::SameLine(); + ImGui::Button("Export VGM"); + + ImGui::Button("CmdStream"); + + ImGui::Separator(); + + ImGui::Text("Song info here..."); break; + } + case GUI_SCENE_CHANNELS: + ImGui::Text("Channels here..."); + break; + case GUI_SCENE_CHIPS: + ImGui::Text("Chips here..."); + break; + case GUI_SCENE_OTHER: { + if (ImGui::Button("Osc")) { + oscOpen=!oscOpen; + } + ImGui::SameLine(); + if (ImGui::Button("ChanOsc")) { + chanOscOpen=!chanOscOpen; + } + ImGui::SameLine(); + if (ImGui::Button("RegView")) { + regViewOpen=!regViewOpen; + } + ImGui::SameLine(); + if (ImGui::Button("Stats")) { + statsOpen=!statsOpen; + } + + ImGui::Separator(); + + ImGui::Button("Panic"); + ImGui::SameLine(); + if (ImGui::Button("Settings")) { + mobileMenuOpen=false; + } + ImGui::SameLine(); + if (ImGui::Button("About")) { + mobileMenuOpen=false; + mobileMenuPos=0.0f; + aboutOpen=true; + } + if (ImGui::Button("Switch to Desktop Mode")) { + toggleMobileUI(!mobileUI); + } + break; + } } } - - if (ImGui::Button("New")) { - mobileMenuOpen=false; - //doAction(GUI_ACTION_NEW); - if (modified) { - showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW); - } else { - displayNew=true; - } - } - ImGui::SameLine(); - if (ImGui::Button("Open")) { - mobileMenuOpen=false; - doAction(GUI_ACTION_OPEN); - } - ImGui::SameLine(); - if (ImGui::Button("Save")) { - mobileMenuOpen=false; - doAction(GUI_ACTION_SAVE); - } - ImGui::SameLine(); - if (ImGui::Button("Save as...")) { - mobileMenuOpen=false; - doAction(GUI_ACTION_SAVE_AS); - } - - ImGui::Button("1.1+ .dmf"); - ImGui::SameLine(); - ImGui::Button("Legacy .dmf"); - ImGui::SameLine(); - ImGui::Button("Export Audio"); - ImGui::SameLine(); - ImGui::Button("Export VGM"); - - ImGui::Button("CmdStream"); - ImGui::SameLine(); - ImGui::Button("Panic"); - ImGui::SameLine(); - if (ImGui::Button("Settings")) { - mobileMenuOpen=false; - } - ImGui::SameLine(); - if (ImGui::Button("About")) { - mobileMenuOpen=false; - mobileMenuPos=0.0f; - aboutOpen=true; - } - - ImGui::Separator(); - - if (ImGui::Button("Osc")) { - oscOpen=!oscOpen; - } - ImGui::SameLine(); - if (ImGui::Button("ChanOsc")) { - chanOscOpen=!chanOscOpen; - } - ImGui::SameLine(); - if (ImGui::Button("RegView")) { - regViewOpen=!regViewOpen; - } - ImGui::SameLine(); - if (ImGui::Button("Stats")) { - statsOpen=!statsOpen; - } } ImGui::End(); } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4c1fc5c48..65e982c73 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3245,6 +3245,11 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("reset layout")) { showWarning("Are you sure you want to reset the workspace layout?",GUI_WARN_RESET_LAYOUT); } +#ifdef IS_MOBILE + if (ImGui::MenuItem("switch to mobile view")) { + toggleMobileUI(!mobileUI); + } +#endif if (ImGui::MenuItem("settings...",BIND_FOR(GUI_ACTION_WINDOW_SETTINGS))) { syncSettings(); settingsOpen=true; @@ -3372,12 +3377,6 @@ bool FurnaceGUI::loop() { pianoOpen=true; drawMobileControls(); switch (mobScene) { - case GUI_SCENE_PATTERN: - patternOpen=true; - curWindow=GUI_WINDOW_PATTERN; - drawPattern(); - drawPiano(); - break; case GUI_SCENE_ORDERS: ordersOpen=true; curWindow=GUI_WINDOW_ORDERS; @@ -3401,6 +3400,12 @@ bool FurnaceGUI::loop() { drawSampleEdit(); drawPiano(); break; + default: + patternOpen=true; + curWindow=GUI_WINDOW_PATTERN; + drawPattern(); + drawPiano(); + break; } } else { globalWinFlags=0; diff --git a/src/gui/gui.h b/src/gui/gui.h index 380141e31..180013dfa 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -265,7 +265,11 @@ enum FurnaceGUIMobileScenes { GUI_SCENE_ORDERS, GUI_SCENE_INSTRUMENT, GUI_SCENE_WAVETABLE, - GUI_SCENE_SAMPLE + GUI_SCENE_SAMPLE, + GUI_SCENE_SONG, + GUI_SCENE_CHANNELS, + GUI_SCENE_CHIPS, + GUI_SCENE_OTHER, }; enum FurnaceGUIFileDialogs { From ce4c0b4291159ccd44640c8e188fc8e978b1d55a Mon Sep 17 00:00:00 2001 From: Waverider <33787286+liaminventions@users.noreply.github.com> Date: Fri, 9 Sep 2022 20:28:06 -0400 Subject: [PATCH 367/515] New Demo Music 010 Editor: https://youtu.be/l-7PsOxffYE her11 VERA edit: https://youtu.be/SDpDUQ2A6k0 chaostune: https://youtu.be/coJDJDpAG7M --- demos/Cafe - 010 Editor 2.0crk.fur | Bin 0 -> 13323 bytes demos/ChaosTune.fur | Bin 0 -> 3048 bytes demos/her11_veraedit.fur | Bin 0 -> 8604 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Cafe - 010 Editor 2.0crk.fur create mode 100644 demos/ChaosTune.fur create mode 100644 demos/her11_veraedit.fur diff --git a/demos/Cafe - 010 Editor 2.0crk.fur b/demos/Cafe - 010 Editor 2.0crk.fur new file mode 100644 index 0000000000000000000000000000000000000000..339e7238f3795d7ed3c013bed685eaf0d67b7ffe GIT binary patch literal 13323 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 sl9A&C*r;1yEP7+A7jTVP5=M^ literal 0 HcmV?d00001 diff --git a/demos/her11_veraedit.fur b/demos/her11_veraedit.fur new file mode 100644 index 0000000000000000000000000000000000000000..1cfabac199e79e68e92f72f3e175116dfc6c582e GIT binary patch literal 8604 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 Date: Fri, 9 Sep 2022 20:28:27 -0700 Subject: [PATCH 368/515] Demo song request (Equinox Intro) --- demos/GEN Equinox Intro.fur | Bin 0 -> 51233 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/GEN Equinox Intro.fur diff --git a/demos/GEN Equinox Intro.fur b/demos/GEN Equinox Intro.fur new file mode 100644 index 0000000000000000000000000000000000000000..04a5bb051a29944822656c90aabe18dc44b29caf GIT binary patch literal 51233 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 literal 0 HcmV?d00001 From fcefbb490916f5b5dda36a545d685fa3e36c7f07 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 23:21:45 -0500 Subject: [PATCH 369/515] TIA: update to latest Stella core --- CMakeLists.txt | 3 +- src/engine/platform/sound/tia/Audio.cpp | 137 +++++++ src/engine/platform/sound/tia/Audio.h | 71 ++++ .../platform/sound/tia/AudioChannel.cpp | 140 +++++++ src/engine/platform/sound/tia/AudioChannel.h | 61 +++ src/engine/platform/sound/tia/TIASnd.cpp | 377 ------------------ src/engine/platform/sound/tia/TIASnd.h | 186 --------- src/engine/platform/sound/tia/TIATables.h | 219 ---------- src/engine/platform/tia.cpp | 14 +- src/engine/platform/tia.h | 4 +- 10 files changed, 421 insertions(+), 791 deletions(-) create mode 100644 src/engine/platform/sound/tia/Audio.cpp create mode 100644 src/engine/platform/sound/tia/Audio.h create mode 100644 src/engine/platform/sound/tia/AudioChannel.cpp create mode 100644 src/engine/platform/sound/tia/AudioChannel.h delete mode 100644 src/engine/platform/sound/tia/TIASnd.cpp delete mode 100644 src/engine/platform/sound/tia/TIASnd.h delete mode 100644 src/engine/platform/sound/tia/TIATables.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ff7db42e6..6e213dcb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,7 +386,8 @@ src/engine/platform/sound/c64_fp/WaveformCalculator.cpp src/engine/platform/sound/c64_fp/WaveformGenerator.cpp src/engine/platform/sound/c64_fp/resample/SincResampler.cpp -src/engine/platform/sound/tia/TIASnd.cpp +src/engine/platform/sound/tia/AudioChannel.cpp +src/engine/platform/sound/tia/Audio.cpp src/engine/platform/sound/ymfm/ymfm_adpcm.cpp src/engine/platform/sound/ymfm/ymfm_opm.cpp diff --git a/src/engine/platform/sound/tia/Audio.cpp b/src/engine/platform/sound/tia/Audio.cpp new file mode 100644 index 000000000..a90aee5a3 --- /dev/null +++ b/src/engine/platform/sound/tia/Audio.cpp @@ -0,0 +1,137 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#define _USE_MATH_DEFINES +#include "Audio.h" + +#include + +namespace { + constexpr double R_MAX = 30.; + constexpr double R = 1.; + + short mixingTableEntry(unsigned char v, unsigned char vMax) + { + return static_cast( + floor(0x7fff * double(v) / double(vMax) * (R_MAX + R * double(vMax)) / (R_MAX + R * double(v))) + ); + } +} + +namespace TIA { + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Audio::Audio() +{ + for (unsigned char i = 0; i <= 0x1e; ++i) myMixingTableSum[i] = mixingTableEntry(i, 0x1e); + for (unsigned char i = 0; i <= 0x0f; ++i) myMixingTableIndividual[i] = mixingTableEntry(i, 0x0f); + + reset(false); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Audio::reset(bool st) +{ + myCounter = 0; + mySampleIndex = 0; + stereo = st; + + myCurrentSample[0]=0; + myCurrentSample[1]=0; + + myChannel0.reset(); + myChannel1.reset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Audio::tick() +{ + switch (myCounter) { + case 9: + case 81: + myChannel0.phase0(); + myChannel1.phase0(); + + break; + + case 37: + case 149: + phase1(); + break; + } + + if (++myCounter == 228) myCounter = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Audio::write(unsigned char addr, unsigned char val) { + switch (addr&0x3f) { + case 0x15: + myChannel0.audc(val); + break; + case 0x16: + myChannel1.audc(val); + break; + case 0x17: + myChannel0.audf(val); + break; + case 0x18: + myChannel1.audf(val); + break; + case 0x19: + myChannel0.audv(val); + break; + case 0x1a: + myChannel1.audv(val); + break; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Audio::phase1() +{ + unsigned char sample0 = myChannel0.phase1(); + unsigned char sample1 = myChannel1.phase1(); + + addSample(sample0, sample1); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Audio::addSample(unsigned char sample0, unsigned char sample1) +{ + if(stereo) { + myCurrentSample[0] = myMixingTableIndividual[sample0]; + myCurrentSample[1] = myMixingTableIndividual[sample1]; + } + else { + myCurrentSample[0] = myMixingTableSum[sample0 + sample1]; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AudioChannel& Audio::channel0() +{ + return myChannel0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AudioChannel& Audio::channel1() +{ + return myChannel1; +} + +} \ No newline at end of file diff --git a/src/engine/platform/sound/tia/Audio.h b/src/engine/platform/sound/tia/Audio.h new file mode 100644 index 000000000..ff3888074 --- /dev/null +++ b/src/engine/platform/sound/tia/Audio.h @@ -0,0 +1,71 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef TIA_AUDIO_HXX +#define TIA_AUDIO_HXX + +#include "AudioChannel.h" +#include + +namespace TIA { + class Audio + { + public: + Audio(); + + void reset(bool stereo); + + void tick(); + + void write(unsigned char addr, unsigned char val); + + AudioChannel& channel0(); + + AudioChannel& channel1(); + + short myCurrentSample[2]; + + private: + void phase1(); + void addSample(unsigned char sample0, unsigned char sample1); + + private: + unsigned char myCounter{0}; + + AudioChannel myChannel0; + AudioChannel myChannel1; + + bool stereo; + + std::array myMixingTableSum; + std::array myMixingTableIndividual; + + unsigned int mySampleIndex{0}; + #ifdef GUI_SUPPORT + bool myRewindMode{false}; + mutable ByteArray mySamples; + #endif + + private: + Audio(const Audio&) = delete; + Audio(Audio&&) = delete; + Audio& operator=(const Audio&) = delete; + Audio& operator=(Audio&&) = delete; + }; +} + +#endif // TIA_AUDIO_HXX diff --git a/src/engine/platform/sound/tia/AudioChannel.cpp b/src/engine/platform/sound/tia/AudioChannel.cpp new file mode 100644 index 000000000..c780c172c --- /dev/null +++ b/src/engine/platform/sound/tia/AudioChannel.cpp @@ -0,0 +1,140 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "AudioChannel.h" + +namespace TIA { + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AudioChannel::reset() +{ + myAudc = myAudv = myAudf = 0; + myClockEnable = myNoiseFeedback = myNoiseCounterBit4 = myPulseCounterHold = false; + myDivCounter = myPulseCounter = myNoiseCounter = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AudioChannel::phase0() +{ + if (myClockEnable) { + myNoiseCounterBit4 = myNoiseCounter & 0x01; + + switch (myAudc & 0x03) { + case 0x00: + case 0x01: + myPulseCounterHold = false; + break; + + case 0x02: + myPulseCounterHold = (myNoiseCounter & 0x1e) != 0x02; + break; + + case 0x03: + myPulseCounterHold = !myNoiseCounterBit4; + break; + } + + switch (myAudc & 0x03) { + case 0x00: + myNoiseFeedback = + ((myPulseCounter ^ myNoiseCounter) & 0x01) || + !(myNoiseCounter || (myPulseCounter != 0x0a)) || + !(myAudc & 0x0c); + + break; + + default: + myNoiseFeedback = + (((myNoiseCounter & 0x04) ? 1 : 0) ^ (myNoiseCounter & 0x01)) || + myNoiseCounter == 0; + + break; + } + } + + myClockEnable = myDivCounter == myAudf; + + if (myDivCounter == myAudf || myDivCounter == 0x1f) { + myDivCounter = 0; + } else { + ++myDivCounter; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +unsigned char AudioChannel::phase1() +{ + if (myClockEnable) { + bool pulseFeedback = false; + switch (myAudc >> 2) { + case 0x00: + pulseFeedback = + (((myPulseCounter & 0x02) ? 1 : 0) ^ (myPulseCounter & 0x01)) && + (myPulseCounter != 0x0a) && + (myAudc & 0x03); + + break; + + case 0x01: + pulseFeedback = !(myPulseCounter & 0x08); + break; + + case 0x02: + pulseFeedback = !myNoiseCounterBit4; + break; + + case 0x03: + pulseFeedback = !((myPulseCounter & 0x02) || !(myPulseCounter & 0x0e)); + break; + } + + myNoiseCounter >>= 1; + if (myNoiseFeedback) { + myNoiseCounter |= 0x10; + } + + if (!myPulseCounterHold) { + myPulseCounter = ~(myPulseCounter >> 1) & 0x07; + + if (pulseFeedback) { + myPulseCounter |= 0x08; + } + } + } + + return (myPulseCounter & 0x01) * myAudv; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AudioChannel::audc(unsigned char value) +{ + myAudc = value & 0x0f; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AudioChannel::audv(unsigned char value) +{ + myAudv = value & 0x0f; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void AudioChannel::audf(unsigned char value) +{ + myAudf = value & 0x1f; +} + +} \ No newline at end of file diff --git a/src/engine/platform/sound/tia/AudioChannel.h b/src/engine/platform/sound/tia/AudioChannel.h new file mode 100644 index 000000000..942e101ab --- /dev/null +++ b/src/engine/platform/sound/tia/AudioChannel.h @@ -0,0 +1,61 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef TIA_AUDIO_CHANNEL_HXX +#define TIA_AUDIO_CHANNEL_HXX + +namespace TIA { + class AudioChannel + { + public: + AudioChannel() = default; + + void reset(); + + void phase0(); + + unsigned char phase1(); + + void audc(unsigned char value); + + void audf(unsigned char value); + + void audv(unsigned char value); + + private: + unsigned char myAudc{0}; + unsigned char myAudv{0}; + unsigned char myAudf{0}; + + bool myClockEnable{false}; + bool myNoiseFeedback{false}; + bool myNoiseCounterBit4{false}; + bool myPulseCounterHold{false}; + + unsigned char myDivCounter{0}; + unsigned char myPulseCounter{0}; + unsigned char myNoiseCounter{0}; + + private: + AudioChannel(const AudioChannel&) = delete; + AudioChannel(AudioChannel&&) = delete; + AudioChannel& operator=(const AudioChannel&) = delete; + AudioChannel& operator=(AudioChannel&&) = delete; + }; +} + +#endif // TIA_AUDIO_CHANNEL_HXX diff --git a/src/engine/platform/sound/tia/TIASnd.cpp b/src/engine/platform/sound/tia/TIASnd.cpp deleted file mode 100644 index e2d0568c4..000000000 --- a/src/engine/platform/sound/tia/TIASnd.cpp +++ /dev/null @@ -1,377 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id: TIASnd.cxx 3239 2015-12-29 19:22:46Z stephena $ -//============================================================================ - -#include "TIATables.h" -#include "TIASnd.h" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIASound::TIASound(int outputFrequency) - : myChannelMode(Hardware2Stereo), - myOutputFrequency(outputFrequency), - myVolumePercentage(100) -{ - reset(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::reset() -{ - // Fill the polynomials - polyInit(Bit4, 4, 4, 3); - polyInit(Bit5, 5, 5, 3); - polyInit(Bit9, 9, 9, 5); - - // Initialize instance variables - for(int chan = 0; chan <= 1; ++chan) - { - myVolume[chan] = 0; - myDivNCnt[chan] = 0; - myDivNMax[chan] = 0; - myDiv3Cnt[chan] = 3; - myAUDC[chan] = 0; - myAUDF[chan] = 0; - myAUDV[chan] = 0; - myP4[chan] = 0; - myP5[chan] = 0; - myP9[chan] = 0; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::outputFrequency(int freq) -{ - myOutputFrequency = freq; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -std::string TIASound::channels(unsigned int hardware, bool stereo) -{ - if(hardware == 1) - myChannelMode = Hardware1; - else - myChannelMode = stereo ? Hardware2Stereo : Hardware2Mono; - - switch(myChannelMode) - { - case Hardware1: return "Hardware1"; - case Hardware2Mono: return "Hardware2Mono"; - case Hardware2Stereo: return "Hardware2Stereo"; - default: return ""; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::set(unsigned short address, unsigned char value) -{ - int chan = ~address & 0x1; - switch(address) - { - case TIARegister::AUDC0: - case TIARegister::AUDC1: - myAUDC[chan] = value & 0x0f; - break; - - case TIARegister::AUDF0: - case TIARegister::AUDF1: - myAUDF[chan] = value & 0x1f; - break; - - case TIARegister::AUDV0: - case TIARegister::AUDV1: - myAUDV[chan] = (value & 0x0f) << AUDV_SHIFT; - break; - - default: - return; - } - - unsigned short newVal = 0; - - // An AUDC value of 0 is a special case - if (myAUDC[chan] == SET_TO_1 || myAUDC[chan] == POLY5_POLY5) - { - // Indicate the clock is zero so no processing will occur, - // and set the output to the selected volume - newVal = 0; - myVolume[chan] = (myAUDV[chan] * myVolumePercentage) / 100; - } - else - { - // Otherwise calculate the 'divide by N' value - newVal = myAUDF[chan] + 1; - - // If bits 2 & 3 are set, then multiply the 'div by n' count by 3 - if((myAUDC[chan] & DIV3_MASK) == DIV3_MASK && myAUDC[chan] != POLY5_DIV3) - newVal *= 3; - } - - // Only reset those channels that have changed - if(newVal != myDivNMax[chan]) - { - // Reset the divide by n counters - myDivNMax[chan] = newVal; - - // If the channel is now volume only or was volume only, - // reset the counter (otherwise let it complete the previous) - if ((myDivNCnt[chan] == 0) || (newVal == 0)) - myDivNCnt[chan] = newVal; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -unsigned char TIASound::get(unsigned short address) const -{ - switch(address) - { - case TIARegister::AUDC0: return myAUDC[0]; - case TIARegister::AUDC1: return myAUDC[1]; - case TIARegister::AUDF0: return myAUDF[0]; - case TIARegister::AUDF1: return myAUDF[1]; - case TIARegister::AUDV0: return myAUDV[0] >> AUDV_SHIFT; - case TIARegister::AUDV1: return myAUDV[1] >> AUDV_SHIFT; - default: return 0; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::volume(unsigned int percent) -{ - if(percent <= 100) - myVolumePercentage = percent; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::process(short* buffer, unsigned int samples, DivDispatchOscBuffer** oscBuf) -{ - // Make temporary local copy - unsigned char audc0 = myAUDC[0], audc1 = myAUDC[1]; - unsigned char p5_0 = myP5[0], p5_1 = myP5[1]; - unsigned char div_n_cnt0 = myDivNCnt[0], div_n_cnt1 = myDivNCnt[1]; - short v0 = myVolume[0], v1 = myVolume[1]; - - // Take external volume into account - short audv0 = (myAUDV[0] * myVolumePercentage) / 100, - audv1 = (myAUDV[1] * myVolumePercentage) / 100; - - // Loop until the sample buffer is full - while(samples > 0) - { - // Process channel 0 - if (div_n_cnt0 > 1) - { - div_n_cnt0--; - } - else if (div_n_cnt0 == 1) - { - int prev_bit5 = Bit5[p5_0]; - div_n_cnt0 = myDivNMax[0]; - - // The P5 counter has multiple uses, so we increment it here - p5_0++; - if (p5_0 == POLY5_SIZE) - p5_0 = 0; - - // Check clock modifier for clock tick - if ((audc0 & 0x02) == 0 || - ((audc0 & 0x01) == 0 && Div31[p5_0]) || - ((audc0 & 0x01) == 1 && Bit5[p5_0]) || - ((audc0 & 0x0f) == POLY5_DIV3 && Bit5[p5_0] != prev_bit5)) - { - if (audc0 & 0x04) // Pure modified clock selected - { - if ((audc0 & 0x0f) == POLY5_DIV3) // POLY5 -> DIV3 mode - { - if ( Bit5[p5_0] != prev_bit5 ) - { - myDiv3Cnt[0]--; - if ( !myDiv3Cnt[0] ) - { - myDiv3Cnt[0] = 3; - v0 = v0 ? 0 : audv0; - } - } - } - else - { - // If the output was set turn it off, else turn it on - v0 = v0 ? 0 : audv0; - } - } - else if (audc0 & 0x08) // Check for p5/p9 - { - if (audc0 == POLY9) // Check for poly9 - { - // Increase the poly9 counter - myP9[0]++; - if (myP9[0] == POLY9_SIZE) - myP9[0] = 0; - - v0 = Bit9[myP9[0]] ? audv0 : 0; - } - else if ( audc0 & 0x02 ) - { - v0 = (v0 || audc0 & 0x01) ? 0 : audv0; - } - else // Must be poly5 - { - v0 = Bit5[p5_0] ? audv0 : 0; - } - } - else // Poly4 is the only remaining option - { - // Increase the poly4 counter - myP4[0]++; - if (myP4[0] == POLY4_SIZE) - myP4[0] = 0; - - v0 = Bit4[myP4[0]] ? audv0 : 0; - } - } - } - - // Process channel 1 - if (div_n_cnt1 > 1) - { - div_n_cnt1--; - } - else if (div_n_cnt1 == 1) - { - int prev_bit5 = Bit5[p5_1]; - - div_n_cnt1 = myDivNMax[1]; - - // The P5 counter has multiple uses, so we increment it here - p5_1++; - if (p5_1 == POLY5_SIZE) - p5_1 = 0; - - // Check clock modifier for clock tick - if ((audc1 & 0x02) == 0 || - ((audc1 & 0x01) == 0 && Div31[p5_1]) || - ((audc1 & 0x01) == 1 && Bit5[p5_1]) || - ((audc1 & 0x0f) == POLY5_DIV3 && Bit5[p5_1] != prev_bit5)) - { - if (audc1 & 0x04) // Pure modified clock selected - { - if ((audc1 & 0x0f) == POLY5_DIV3) // POLY5 -> DIV3 mode - { - if ( Bit5[p5_1] != prev_bit5 ) - { - myDiv3Cnt[1]--; - if ( ! myDiv3Cnt[1] ) - { - myDiv3Cnt[1] = 3; - v1 = v1 ? 0 : audv1; - } - } - } - else - { - // If the output was set turn it off, else turn it on - v1 = v1 ? 0 : audv1; - } - } - else if (audc1 & 0x08) // Check for p5/p9 - { - if (audc1 == POLY9) // Check for poly9 - { - // Increase the poly9 counter - myP9[1]++; - if (myP9[1] == POLY9_SIZE) - myP9[1] = 0; - - v1 = Bit9[myP9[1]] ? audv1 : 0; - } - else if ( audc1 & 0x02 ) - { - v1 = (v1 || audc1 & 0x01) ? 0 : audv1; - } - else // Must be poly5 - { - v1 = Bit5[p5_1] ? audv1 : 0; - } - } - else // Poly4 is the only remaining option - { - // Increase the poly4 counter - myP4[1]++; - if (myP4[1] == POLY4_SIZE) - myP4[1] = 0; - - v1 = Bit4[myP4[1]] ? audv1 : 0; - } - } - } - - short byte = v0 + v1; - switch(myChannelMode) - { - case Hardware2Mono: // mono sampling with 2 hardware channels - *(buffer++) = byte; - *(buffer++) = byte; - samples--; - break; - - case Hardware2Stereo: // stereo sampling with 2 hardware channels - *(buffer++) = v0; - *(buffer++) = v1; - samples--; - break; - - case Hardware1: // mono/stereo sampling with only 1 hardware channel - *(buffer++) = (v0 + v1) >> 1; - samples--; - break; - } - - if (oscBuf!=NULL) { - oscBuf[0]->data[oscBuf[0]->needle++]=v0; - oscBuf[1]->data[oscBuf[1]->needle++]=v1; - } - } - - // Save for next round - myP5[0] = p5_0; - myP5[1] = p5_1; - myVolume[0] = v0; - myVolume[1] = v1; - myDivNCnt[0] = div_n_cnt0; - myDivNCnt[1] = div_n_cnt1; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::polyInit(unsigned char* poly, int size, int f0, int f1) -{ - int mask = (1 << size) - 1, x = mask; - - for(int i = 0; i < mask; i++) - { - int bit0 = ( ( size - f0 ) ? ( x >> ( size - f0 ) ) : x ) & 0x01; - int bit1 = ( ( size - f1 ) ? ( x >> ( size - f1 ) ) : x ) & 0x01; - poly[i] = x & 1; - // calculate next bit - x = ( x >> 1 ) | ( ( bit0 ^ bit1 ) << ( size - 1) ); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const unsigned char TIASound::Div31[POLY5_SIZE] = { - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; diff --git a/src/engine/platform/sound/tia/TIASnd.h b/src/engine/platform/sound/tia/TIASnd.h deleted file mode 100644 index 78459426f..000000000 --- a/src/engine/platform/sound/tia/TIASnd.h +++ /dev/null @@ -1,186 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id: TIASnd.hxx 3239 2015-12-29 19:22:46Z stephena $ -//============================================================================ - -#ifndef TIASOUND_HXX -#define TIASOUND_HXX - -#include -#include "../../../dispatch.h" - -/** - This class implements a fairly accurate emulation of the TIA sound - hardware. This class uses code/ideas from z26 and MESS. - - Currently, the sound generation routines work at 31400Hz only. - Resampling can be done by passing in a different output frequency. - - @author Bradford W. Mott, Stephen Anthony, z26 and MESS teams - @version $Id: TIASnd.hxx 3239 2015-12-29 19:22:46Z stephena $ -*/ -class TIASound -{ - public: - /** - Create a new TIA Sound object using the specified output frequency - */ - TIASound(int outputFrequency = 31400); - - public: - /** - Reset the sound emulation to its power-on state - */ - void reset(); - - /** - Set the frequency output samples should be generated at - */ - void outputFrequency(int freq); - - /** - Selects the number of audio channels per sample. There are two factors - to consider: hardware capability and desired mixing. - - @param hardware The number of channels supported by the sound system - @param stereo Whether to output the internal sound signals into 1 - or 2 channels - - @return Status of the channel configuration used - */ - std::string channels(unsigned int hardware, bool stereo); - - public: - /** - Sets the specified sound register to the given value - - @param address Register address - @param value Value to store in the register - */ - void set(unsigned short address, unsigned char value); - - /** - Gets the specified sound register's value - - @param address Register address - */ - unsigned char get(unsigned short address) const; - - /** - Create sound samples based on the current sound register settings - in the specified buffer. NOTE: If channels is set to stereo then - the buffer will need to be twice as long as the number of samples. - - @param buffer The location to store generated samples - @param samples The number of samples to generate - */ - void process(short* buffer, unsigned int samples, DivDispatchOscBuffer** oscBuf=NULL); - - /** - Set the volume of the samples created (0-100) - */ - void volume(unsigned int percent); - - private: - void polyInit(unsigned char* poly, int size, int f0, int f1); - - private: - // Definitions for AUDCx (15, 16) - enum AUDCxRegister - { - SET_TO_1 = 0x00, // 0000 - POLY4 = 0x01, // 0001 - DIV31_POLY4 = 0x02, // 0010 - POLY5_POLY4 = 0x03, // 0011 - PURE1 = 0x04, // 0100 - PURE2 = 0x05, // 0101 - DIV31_PURE = 0x06, // 0110 - POLY5_2 = 0x07, // 0111 - POLY9 = 0x08, // 1000 - POLY5 = 0x09, // 1001 - DIV31_POLY5 = 0x0a, // 1010 - POLY5_POLY5 = 0x0b, // 1011 - DIV3_PURE = 0x0c, // 1100 - DIV3_PURE2 = 0x0d, // 1101 - DIV93_PURE = 0x0e, // 1110 - POLY5_DIV3 = 0x0f // 1111 - }; - - enum { - POLY4_SIZE = 0x000f, - POLY5_SIZE = 0x001f, - POLY9_SIZE = 0x01ff, - DIV3_MASK = 0x0c, - AUDV_SHIFT = 10 // shift 2 positions for AUDV, - // then another 8 for 16-bit sound - }; - - enum ChannelMode { - Hardware2Mono, // mono sampling with 2 hardware channels - Hardware2Stereo, // stereo sampling with 2 hardware channels - Hardware1 // mono/stereo sampling with only 1 hardware channel - }; - - private: - // Structures to hold the 6 tia sound control bytes - unsigned char myAUDC[2]; // AUDCx (15, 16) - unsigned char myAUDF[2]; // AUDFx (17, 18) - short myAUDV[2]; // AUDVx (19, 1A) - - short myVolume[2]; // Last output volume for each channel - - unsigned char myP4[2]; // Position pointer for the 4-bit POLY array - unsigned char myP5[2]; // Position pointer for the 5-bit POLY array - unsigned short myP9[2]; // Position pointer for the 9-bit POLY array - - unsigned char myDivNCnt[2]; // Divide by n counter. one for each channel - unsigned char myDivNMax[2]; // Divide by n maximum, one for each channel - unsigned char myDiv3Cnt[2]; // Div 3 counter, used for POLY5_DIV3 mode - - ChannelMode myChannelMode; - int myOutputFrequency; - unsigned int myVolumePercentage; - - /* - Initialize the bit patterns for the polynomials (at runtime). - - The 4bit and 5bit patterns are the identical ones used in the tia chip. - Though the patterns could be packed with 8 bits per byte, using only a - single bit per byte keeps the math simple, which is important for - efficient processing. - */ - unsigned char Bit4[POLY4_SIZE]; - unsigned char Bit5[POLY5_SIZE]; - unsigned char Bit9[POLY9_SIZE]; - - /* - The 'Div by 31' counter is treated as another polynomial because of - the way it operates. It does not have a 50% duty cycle, but instead - has a 13:18 ratio (of course, 13+18 = 31). This could also be - implemented by using counters. - */ - static const unsigned char Div31[POLY5_SIZE]; - - private: - // Following constructors and assignment operators not supported - TIASound(const TIASound&) = delete; - TIASound(TIASound&&) = delete; - TIASound& operator=(const TIASound&) = delete; - TIASound& operator=(TIASound&&) = delete; -}; - -#endif diff --git a/src/engine/platform/sound/tia/TIATables.h b/src/engine/platform/sound/tia/TIATables.h deleted file mode 100644 index 782a24de9..000000000 --- a/src/engine/platform/sound/tia/TIATables.h +++ /dev/null @@ -1,219 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id: TIATables.hxx 3239 2015-12-29 19:22:46Z stephena $ -//============================================================================ - -#ifndef TIA_TABLES_HXX -#define TIA_TABLES_HXX - -enum TIABit { - P0Bit = 0x01, // Bit for Player 0 - M0Bit = 0x02, // Bit for Missle 0 - P1Bit = 0x04, // Bit for Player 1 - M1Bit = 0x08, // Bit for Missle 1 - BLBit = 0x10, // Bit for Ball - PFBit = 0x20, // Bit for Playfield - ScoreBit = 0x40, // Bit for Playfield score mode - PriorityBit = 0x80 // Bit for Playfield priority -}; - -enum TIAColor { - BKColor = 0, // Color index for Background - PFColor = 1, // Color index for Playfield - P0Color = 2, // Color index for Player 0 - P1Color = 3, // Color index for Player 1 - M0Color = 4, // Color index for Missle 0 - M1Color = 5, // Color index for Missle 1 - BLColor = 6, // Color index for Ball - HBLANKColor = 7 // Color index for HMove blank area -}; - -enum CollisionBit -{ - Cx_M0P1 = 1 << 0, // Missle0 - Player1 collision - Cx_M0P0 = 1 << 1, // Missle0 - Player0 collision - Cx_M1P0 = 1 << 2, // Missle1 - Player0 collision - Cx_M1P1 = 1 << 3, // Missle1 - Player1 collision - Cx_P0PF = 1 << 4, // Player0 - Playfield collision - Cx_P0BL = 1 << 5, // Player0 - Ball collision - Cx_P1PF = 1 << 6, // Player1 - Playfield collision - Cx_P1BL = 1 << 7, // Player1 - Ball collision - Cx_M0PF = 1 << 8, // Missle0 - Playfield collision - Cx_M0BL = 1 << 9, // Missle0 - Ball collision - Cx_M1PF = 1 << 10, // Missle1 - Playfield collision - Cx_M1BL = 1 << 11, // Missle1 - Ball collision - Cx_BLPF = 1 << 12, // Ball - Playfield collision - Cx_P0P1 = 1 << 13, // Player0 - Player1 collision - Cx_M0M1 = 1 << 14 // Missle0 - Missle1 collision -}; - -// TIA Write/Read register names -enum TIARegister { - VSYNC = 0x00, // Write: vertical sync set-clear (D1) - VBLANK = 0x01, // Write: vertical blank set-clear (D7-6,D1) - WSYNC = 0x02, // Write: wait for leading edge of hrz. blank (strobe) - RSYNC = 0x03, // Write: reset hrz. sync counter (strobe) - NUSIZ0 = 0x04, // Write: number-size player-missle 0 (D5-0) - NUSIZ1 = 0x05, // Write: number-size player-missle 1 (D5-0) - COLUP0 = 0x06, // Write: color-lum player 0 (D7-1) - COLUP1 = 0x07, // Write: color-lum player 1 (D7-1) - COLUPF = 0x08, // Write: color-lum playfield (D7-1) - COLUBK = 0x09, // Write: color-lum background (D7-1) - CTRLPF = 0x0a, // Write: cntrl playfield ballsize & coll. (D5-4,D2-0) - REFP0 = 0x0b, // Write: reflect player 0 (D3) - REFP1 = 0x0c, // Write: reflect player 1 (D3) - PF0 = 0x0d, // Write: playfield register byte 0 (D7-4) - PF1 = 0x0e, // Write: playfield register byte 1 (D7-0) - PF2 = 0x0f, // Write: playfield register byte 2 (D7-0) - RESP0 = 0x10, // Write: reset player 0 (strobe) - RESP1 = 0x11, // Write: reset player 1 (strobe) - RESM0 = 0x12, // Write: reset missle 0 (strobe) - RESM1 = 0x13, // Write: reset missle 1 (strobe) - RESBL = 0x14, // Write: reset ball (strobe) - AUDC0 = 0x15, // Write: audio control 0 (D3-0) - AUDC1 = 0x16, // Write: audio control 1 (D4-0) - AUDF0 = 0x17, // Write: audio frequency 0 (D4-0) - AUDF1 = 0x18, // Write: audio frequency 1 (D3-0) - AUDV0 = 0x19, // Write: audio volume 0 (D3-0) - AUDV1 = 0x1a, // Write: audio volume 1 (D3-0) - GRP0 = 0x1b, // Write: graphics player 0 (D7-0) - GRP1 = 0x1c, // Write: graphics player 1 (D7-0) - ENAM0 = 0x1d, // Write: graphics (enable) missle 0 (D1) - ENAM1 = 0x1e, // Write: graphics (enable) missle 1 (D1) - ENABL = 0x1f, // Write: graphics (enable) ball (D1) - HMP0 = 0x20, // Write: horizontal motion player 0 (D7-4) - HMP1 = 0x21, // Write: horizontal motion player 1 (D7-4) - HMM0 = 0x22, // Write: horizontal motion missle 0 (D7-4) - HMM1 = 0x23, // Write: horizontal motion missle 1 (D7-4) - HMBL = 0x24, // Write: horizontal motion ball (D7-4) - VDELP0 = 0x25, // Write: vertical delay player 0 (D0) - VDELP1 = 0x26, // Write: vertical delay player 1 (D0) - VDELBL = 0x27, // Write: vertical delay ball (D0) - RESMP0 = 0x28, // Write: reset missle 0 to player 0 (D1) - RESMP1 = 0x29, // Write: reset missle 1 to player 1 (D1) - HMOVE = 0x2a, // Write: apply horizontal motion (strobe) - HMCLR = 0x2b, // Write: clear horizontal motion registers (strobe) - CXCLR = 0x2c, // Write: clear collision latches (strobe) - - CXM0P = 0x00, // Read collision: D7=(M0,P1); D6=(M0,P0) - CXM1P = 0x01, // Read collision: D7=(M1,P0); D6=(M1,P1) - CXP0FB = 0x02, // Read collision: D7=(P0,PF); D6=(P0,BL) - CXP1FB = 0x03, // Read collision: D7=(P1,PF); D6=(P1,BL) - CXM0FB = 0x04, // Read collision: D7=(M0,PF); D6=(M0,BL) - CXM1FB = 0x05, // Read collision: D7=(M1,PF); D6=(M1,BL) - CXBLPF = 0x06, // Read collision: D7=(BL,PF); D6=(unused) - CXPPMM = 0x07, // Read collision: D7=(P0,P1); D6=(M0,M1) - INPT0 = 0x08, // Read pot port: D7 - INPT1 = 0x09, // Read pot port: D7 - INPT2 = 0x0a, // Read pot port: D7 - INPT3 = 0x0b, // Read pot port: D7 - INPT4 = 0x0c, // Read P1 joystick trigger: D7 - INPT5 = 0x0d // Read P2 joystick trigger: D7 -}; - -/** - The TIA class uses some static tables that aren't dependent on the actual - TIA state. For code organization, it's better to place that functionality - here. - - @author Stephen Anthony - @version $Id: TIATables.hxx 3239 2015-12-29 19:22:46Z stephena $ -*/ -class TIATables -{ - public: - /** - Compute all static tables used by the TIA - */ - static void computeAllTables(); - - // Player mask table - // [suppress mode][nusiz][pixel] - static unsigned char PxMask[2][8][320]; - - // Missle mask table (entries are true or false) - // [number][size][pixel] - // There are actually only 4 possible size combinations on a real system - // The fifth size is used for simulating the starfield effect in - // Cosmic Ark and Stay Frosty - static unsigned char MxMask[8][5][320]; - - // Ball mask table (entries are true or false) - // [size][pixel] - static unsigned char BLMask[4][320]; - - // Playfield mask table for reflected and non-reflected playfields - // [reflect, pixel] - static unsigned int PFMask[2][160]; - - // A mask table which can be used when an object is disabled - static unsigned char DisabledMask[640]; - - // Used to set the collision register to the correct value - static unsigned short CollisionMask[64]; - - // Indicates the update delay associated with poking at a TIA address - static const short PokeDelay[64]; - -#if 0 - // Used to convert value written in a motion register into - // its internal representation - static const int CompleteMotion[76][16]; -#endif - - // Indicates if HMOVE blanks should occur for the corresponding cycle - static const bool HMOVEBlankEnableCycles[76]; - - // Used to reflect a players graphics - static unsigned char GRPReflect[256]; - - // Indicates if player is being reset during delay, display or other times - // [nusiz][old pixel][new pixel] - static signed char PxPosResetWhen[8][160][160]; - - private: - // Compute the collision decode table - static void buildCollisionMaskTable(); - - // Compute the player mask table - static void buildPxMaskTable(); - - // Compute the missle mask table - static void buildMxMaskTable(); - - // Compute the ball mask table - static void buildBLMaskTable(); - - // Compute playfield mask table - static void buildPFMaskTable(); - - // Compute the player reflect table - static void buildGRPReflectTable(); - - // Compute the player position reset when table - static void buildPxPosResetWhenTable(); - - private: - // Following constructors and assignment operators not supported - TIATables() = delete; - TIATables(const TIATables&) = delete; - TIATables(TIATables&&) = delete; - TIATables& operator=(const TIATables&) = delete; - TIATables& operator=(TIATables&&) = delete; -}; - -#endif diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 82d032703..54ef306f4 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -22,7 +22,7 @@ #include #include -#define rWrite(a,v) if (!skipRegisterWrites) {tia.set(a,v); regPool[((a)-0x15)&0x0f]=v; if (dumpWrites) {addWrite(a,v);} } +#define rWrite(a,v) if (!skipRegisterWrites) {tia.write(a,v); regPool[((a)-0x15)&0x0f]=v; if (dumpWrites) {addWrite(a,v);} } const char* regCheatSheetTIA[]={ "AUDC0", "15", @@ -39,7 +39,10 @@ const char** DivPlatformTIA::getRegisterSheet() { } void DivPlatformTIA::acquire(short* bufL, short* bufR, size_t start, size_t len) { - tia.process(bufL+start,len,oscBuf); + for (size_t h=start; h& wlist) { void DivPlatformTIA::setFlags(unsigned int flags) { if (flags&1) { - rate=31250; + rate=COLOR_PAL*4.0/5.0; } else { - rate=31468; + rate=COLOR_NTSC; } chipClock=rate; for (int i=0; i<2; i++) { @@ -351,7 +354,6 @@ int DivPlatformTIA::init(DivEngine* p, int channels, int sugRate, unsigned int f isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } - tia.channels(1,false); setFlags(flags); reset(); return 2; diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index 168175367..fe45c18b1 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -22,7 +22,7 @@ #include "../dispatch.h" #include "../macroInt.h" #include -#include "sound/tia/TIASnd.h" +#include "sound/tia/Audio.h" class DivPlatformTIA: public DivDispatch { protected: @@ -42,7 +42,7 @@ class DivPlatformTIA: public DivDispatch { Channel chan[2]; DivDispatchOscBuffer* oscBuf[2]; bool isMuted[2]; - TIASound tia; + TIA::Audio tia; unsigned char regPool[16]; friend void putDispatchChan(void*,int,int); From 917a03eb070b8f195a4fcfa9828a0936c575f8bc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 23:40:21 -0500 Subject: [PATCH 370/515] TIA: fixes fixes fixes --- src/engine/platform/sound/tia/Audio.cpp | 6 ++++++ src/engine/platform/sound/tia/Audio.h | 1 + src/engine/platform/tia.cpp | 24 ++++++++++++++++++++---- src/engine/platform/tia.h | 2 ++ src/gui/sysConf.cpp | 18 ++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/sound/tia/Audio.cpp b/src/engine/platform/sound/tia/Audio.cpp index a90aee5a3..662bd7fd5 100644 --- a/src/engine/platform/sound/tia/Audio.cpp +++ b/src/engine/platform/sound/tia/Audio.cpp @@ -53,6 +53,9 @@ void Audio::reset(bool st) myCurrentSample[0]=0; myCurrentSample[1]=0; + myChannelOut[0]=0; + myChannelOut[1]=0; + myChannel0.reset(); myChannel1.reset(); } @@ -120,6 +123,9 @@ void Audio::addSample(unsigned char sample0, unsigned char sample1) else { myCurrentSample[0] = myMixingTableSum[sample0 + sample1]; } + + myChannelOut[0] = myMixingTableIndividual[sample0]; + myChannelOut[1] = myMixingTableIndividual[sample1]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/engine/platform/sound/tia/Audio.h b/src/engine/platform/sound/tia/Audio.h index ff3888074..4a782bb38 100644 --- a/src/engine/platform/sound/tia/Audio.h +++ b/src/engine/platform/sound/tia/Audio.h @@ -38,6 +38,7 @@ namespace TIA { AudioChannel& channel1(); short myCurrentSample[2]; + short myChannelOut[2]; private: void phase1(); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 54ef306f4..59c534913 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -41,7 +41,19 @@ const char** DivPlatformTIA::getRegisterSheet() { void DivPlatformTIA::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h>1; + } else { + bufL[h]=tia.myCurrentSample[0]; + } + if (++chanOscCounter>=114) { + chanOscCounter=0; + oscBuf[0]->data[oscBuf[0]->needle++]=tia.myChannelOut[0]; + oscBuf[1]->data[oscBuf[1]->needle++]=tia.myChannelOut[1]; + } } } @@ -303,7 +315,7 @@ int DivPlatformTIA::getRegisterPoolSize() { } void DivPlatformTIA::reset() { - tia.reset(false); + tia.reset(mixingType); memset(regPool,0,16); for (int i=0; i<2; i++) { chan[i]=DivPlatformTIA::Channel(); @@ -313,7 +325,7 @@ void DivPlatformTIA::reset() { } bool DivPlatformTIA::isStereo() { - return false; + return (mixingType==2); } bool DivPlatformTIA::keyOffAffectsArp(int ch) { @@ -341,15 +353,19 @@ void DivPlatformTIA::setFlags(unsigned int flags) { rate=COLOR_NTSC; } chipClock=rate; + mixingType=(flags>>1)&3; for (int i=0; i<2; i++) { - oscBuf[i]->rate=rate; + oscBuf[i]->rate=rate/114; } + tia.reset(mixingType); } int DivPlatformTIA::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; dumpWrites=false; skipRegisterWrites=false; + mixingType=0; + chanOscCounter=0; for (int i=0; i<2; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index fe45c18b1..c6ea280d7 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -42,6 +42,8 @@ class DivPlatformTIA: public DivDispatch { Channel chan[2]; DivDispatchOscBuffer* oscBuf[2]; bool isMuted[2]; + unsigned char mixingType; + unsigned char chanOscCounter; TIA::Audio tia; unsigned char regPool[16]; friend void putDispatchChan(void*,int,int); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index a6bbcb921..ba3ded1a6 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -402,6 +402,24 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } break; } + case DIV_SYSTEM_TIA: { + ImGui::Text("Mixing mode:"); + if (ImGui::RadioButton("Mono",(flags&6)==0)) { + copyOfFlags=(flags&(~6)); + } + if (ImGui::RadioButton("Mono (no distortion)",(flags&6)==2)) { + copyOfFlags=(flags&(~6))|2; + } + if (ImGui::RadioButton("Stereo",(flags&6)==4)) { + copyOfFlags=(flags&(~6))|4; + } + + sysPal=flags&1; + if (ImGui::Checkbox("PAL",&sysPal)) { + copyOfFlags=(flags&(~1))|(unsigned int)sysPal; + } + break; + } case DIV_SYSTEM_PCSPKR: { ImGui::Text("Speaker type:"); if (ImGui::RadioButton("Unfiltered",(flags&3)==0)) { From 2e49f9c8a0cd33808a5ec8b0f937b323c8e70253 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 23:42:48 -0500 Subject: [PATCH 371/515] TIA: volume --- src/engine/platform/tia.cpp | 4 ++++ src/engine/platform/tia.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 59c534913..796c94481 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -324,6 +324,10 @@ void DivPlatformTIA::reset() { } } +float DivPlatformTIA::getPostAmp() { + return 0.5f; +} + bool DivPlatformTIA::isStereo() { return (mixingType==2); } diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index c6ea280d7..b838e0682 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -63,6 +63,7 @@ class DivPlatformTIA: public DivDispatch { void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); + float getPostAmp(); bool isStereo(); bool keyOffAffectsArp(int ch); void notifyInsDeletion(void* ins); From 68587dab0dc005bf9173a46f5f17d99b525d763b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 23:44:08 -0500 Subject: [PATCH 372/515] update Nuked-OPN2 core --- extern/Nuked-OPN2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/Nuked-OPN2 b/extern/Nuked-OPN2 index 64704a443..b0e9de0f8 160000 --- a/extern/Nuked-OPN2 +++ b/extern/Nuked-OPN2 @@ -1 +1 @@ -Subproject commit 64704a443f8f6c1906ba26297092ea70fa1d45d7 +Subproject commit b0e9de0f816943ad3820ddfefa0fff276d659250 From 183d78e2a137fd7268ef278db2a495ac1763c13d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 9 Sep 2022 23:47:22 -0500 Subject: [PATCH 373/515] update Nuked-OPM to latest version --- extern/opm/opm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extern/opm/opm.c b/extern/opm/opm.c index 79f6414cb..aafce483d 100644 --- a/extern/opm/opm.c +++ b/extern/opm/opm.c @@ -1,5 +1,5 @@ /* Nuked OPM - * Copyright (C) 2020 Nuke.YKT + * Copyright (C) 2022 Nuke.YKT * * This file is part of Nuked OPM. * @@ -21,7 +21,7 @@ * siliconpr0n.org(digshadow, John McMaster): * YM2151 and other FM chip decaps and die shots. * - * version: 0.9.2 beta + * version: 0.9.3 beta */ #include #include @@ -651,7 +651,7 @@ static inline void OPM_EnvelopePhase4(opm_t *chip) chip->eg_instantattack = chip->eg_ratemax[1] && (kon || !chip->eg_ratemax[1]); eg_off = (chip->eg_level[slot] & 0x3f0) == 0x3f0; - slreach = (chip->eg_level[slot] >> 5) == chip->eg_sl[1]; + slreach = (chip->eg_level[slot] >> 4) == (chip->eg_sl[1] << 1); eg_zero = chip->eg_level[slot] == 0; chip->eg_mute = eg_off && chip->eg_state[slot] != eg_num_attack && !kon; From 023d065fcc05c7b25aeef896907a623f93fce74a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 00:09:38 -0500 Subject: [PATCH 374/515] fix .dmp loading --- src/engine/fileOpsIns.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index c8dbb57fd..7c2071dea 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -171,9 +171,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St mode=reader.readC(); logD("instrument mode is %d",mode); if (mode==0) { - if (version<11) { - ins->type=DIV_INS_STD; - } + if (ins->type==DIV_INS_FM) ins->type=DIV_INS_STD; } else { ins->type=DIV_INS_FM; } From 3c5d71ce4ceb396713a512778f0b20c67ab4dbb6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 00:12:53 -0500 Subject: [PATCH 375/515] fix .dmp loading for Neo Geo presets --- src/engine/fileOpsIns.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 7c2071dea..842f29f76 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -150,6 +150,10 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St ins->type=DIV_INS_FM; logD("instrument type is Arcade"); break; + case 9: // Neo Geo + ins->type=DIV_INS_FM; + logD("instrument type is Neo Geo"); + break; default: logD("instrument type is unknown"); lastError="unknown instrument type!"; @@ -171,7 +175,13 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St mode=reader.readC(); logD("instrument mode is %d",mode); if (mode==0) { - if (ins->type==DIV_INS_FM) ins->type=DIV_INS_STD; + if (ins->type==DIV_INS_FM) { + if (sys==9) { + ins->type=DIV_INS_AY; + } else { + ins->type=DIV_INS_STD; + } + } } else { ins->type=DIV_INS_FM; } From 9ac9cfc9038370895452fbadb3f323323570f1e1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 00:28:21 -0500 Subject: [PATCH 376/515] more .dmp loading fixes this time for OPLL --- src/engine/fileOpsIns.cpp | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 842f29f76..9668c8d95 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -156,7 +156,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St break; default: logD("instrument type is unknown"); - lastError="unknown instrument type!"; + lastError=fmt::sprintf("unknown instrument type %d!",sys); delete ins; return; break; @@ -183,7 +183,14 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } } else { - ins->type=DIV_INS_FM; + if (sys==3 || sys==6) { + ins->type=DIV_INS_OPLL; + } else if (sys==1) { + ins->type=DIV_INS_OPL; + } else { + ins->type=DIV_INS_FM; + } + } } else { ins->type=DIV_INS_FM; @@ -240,12 +247,23 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St ins->fm.op[j].dvb=reader.readC(); ins->fm.op[j].dam=reader.readC(); } else { - ins->fm.op[j].rs=reader.readC(); - ins->fm.op[j].dt=reader.readC(); - ins->fm.op[j].dt2=ins->fm.op[j].dt>>4; - ins->fm.op[j].dt&=15; - ins->fm.op[j].d2r=reader.readC(); - ins->fm.op[j].ssgEnv=reader.readC(); + if (sys==3 || sys==6) { // OPLL/VRC7 + ins->fm.op[j].ksr=reader.readC()?1:0; + ins->fm.op[j].vib=reader.readC(); + if (j==0) { + ins->fm.opllPreset=ins->fm.op[j].vib>>4; + } + ins->fm.op[j].vib=ins->fm.op[j].vib?1:0; + ins->fm.op[j].ksl=reader.readC()?1:0; + ins->fm.op[j].ssgEnv=reader.readC(); + } else { + ins->fm.op[j].rs=reader.readC(); + ins->fm.op[j].dt=reader.readC(); + ins->fm.op[j].dt2=ins->fm.op[j].dt>>4; + ins->fm.op[j].dt&=15; + ins->fm.op[j].d2r=reader.readC(); + ins->fm.op[j].ssgEnv=reader.readC(); + } } } } else { // STD From ac0decd01b2aca0e785c4dc979883a77b9b840b1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 00:31:17 -0500 Subject: [PATCH 377/515] .dmf FDS instrument detection --- src/engine/fileOpsIns.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 9668c8d95..83361130b 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -190,7 +190,6 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } else { ins->type=DIV_INS_FM; } - } } else { ins->type=DIV_INS_FM; @@ -273,6 +272,9 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St if (version>5) { for (int i=0; istd.volMacro.len; i++) { ins->std.volMacro.val[i]=reader.readI(); + if (ins->std.volMacro.val[i]>15 && sys==6) { // FDS + ins->type=DIV_INS_FDS; + } } } else { for (int i=0; istd.volMacro.len; i++) { From 187653a70f13d23b1920e80fe5543a4a85aee60f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 01:39:42 -0500 Subject: [PATCH 378/515] dev113 - loop detection changes --- android/app/build.gradle | 4 +-- android/app/src/main/AndroidManifest.xml | 4 +-- papers/format.md | 4 ++- src/engine/engine.cpp | 1 + src/engine/engine.h | 8 +++-- src/engine/fileOps.cpp | 14 ++++++-- src/engine/playback.cpp | 42 ++++++++++++++++++++---- src/engine/song.h | 6 ++++ src/gui/compatFlags.cpp | 20 +++++++++++ 9 files changed, 87 insertions(+), 16 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index f332e6f58..92a79e4d6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,8 +15,8 @@ android { } minSdkVersion 21 targetSdkVersion 26 - versionCode 112 - versionName "dev112" + versionCode 113 + versionName "dev113" externalNativeBuild { cmake { arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e28b7fd14..b77cf32e1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/papers/format.md b/papers/format.md index def8cba16..8528a7d63 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 113: Furnace dev113 - 112: Furnace dev112 - 111: Furnace dev111 - 110: Furnace dev110 @@ -338,7 +339,8 @@ size | description 1 | broken initial position of porta after arp (>=101) or reserved 1 | SN periods under 8 are treated as 1 (>=108) or reserved 1 | cut/delay effect policy (>=110) or reserved - 5 | reserved + 1 | 0B/0D effect treatment (>=113) or reserved + 4 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 4a8b7f5b2..a184b5b55 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1658,6 +1658,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { speedAB=false; playing=true; skipping=true; + memset(walked,0,8192); for (int i=0; isetSkipRegisterWrites(true); while (playing && curOrder conf; std::deque pendingNotes; + // bitfield + unsigned char walked[8192]; bool isMuted[DIV_MAX_CHANS]; std::mutex isBusy, saveLock; String configPath; @@ -1072,6 +1073,7 @@ class DivEngine { memset(reversePitchTable,0,4096*sizeof(int)); memset(pitchTable,0,4096*sizeof(int)); memset(sysDefs,0,256*sizeof(void*)); + memset(walked,0,8192); for (int i=0; i<256; i++) { sysFileMapFur[i]=DIV_SYSTEM_NULL; diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 66ca9d468..10a4bcce9 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -179,6 +179,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenPortaArp=false; ds.snNoLowPeriods=true; ds.delayBehavior=0; + ds.jumpTreatment=2; // 1.1 compat flags if (ds.version>24) { @@ -1081,6 +1082,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<110) { ds.delayBehavior=1; } + if (ds.version<113) { + ds.jumpTreatment=1; + } ds.isDMF=false; reader.readS(); // reserved @@ -1503,7 +1507,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<5; i++) { + if (ds.version>=113) { + ds.jumpTreatment=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<4; i++) { reader.readC(); } } @@ -3747,7 +3756,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.brokenPortaArp); w->writeC(song.snNoLowPeriods); w->writeC(song.delayBehavior); - for (int i=0; i<5; i++) { + w->writeC(song.jumpTreatment); + for (int i=0; i<4; i++) { w->writeC(0); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 7fb9583d7..898bb2b05 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -31,7 +31,9 @@ void DivEngine::nextOrder() { curRow=0; if (repeatPattern) return; if (++curOrder>=curSubSong->ordersLen) { + logV("end of orders reached"); endOfSong=true; + memset(walked,0,8192); curOrder=0; } } @@ -348,15 +350,31 @@ void DivEngine::processRow(int i, bool afterDelay) { if (effectVal>0) speed2=effectVal; break; case 0x0b: // change order - if (changeOrd==-1) { + if (changeOrd==-1 || song.jumpTreatment==0) { changeOrd=effectVal; - changePos=0; + if (song.jumpTreatment==1 || song.jumpTreatment==2) { + changePos=0; + } } break; case 0x0d: // next order - if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) { - changeOrd=-2; - changePos=effectVal; + if (song.jumpTreatment==2) { + if ((curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) { + changeOrd=-2; + changePos=effectVal; + } + } else if (song.jumpTreatment==1) { + if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) { + changeOrd=-2; + changePos=effectVal; + } + } else { + if (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd) { + if (changeOrd<0) { + changeOrd=-2; + } + changePos=effectVal; + } } break; case 0xed: // delay @@ -911,18 +929,23 @@ void DivEngine::nextRow() { processRow(i,false); } + walked[((curOrder<<5)+(curRow>>3))&8191]|=1<<(curRow&7); + if (changeOrd!=-1) { if (repeatPattern) { curRow=0; changeOrd=-1; } else { curRow=changePos; + changePos=0; if (changeOrd==-2) changeOrd=curOrder+1; - if (changeOrd<=curOrder) endOfSong=true; + // old loop detection routine + //if (changeOrd<=curOrder) endOfSong=true; curOrder=changeOrd; if (curOrder>=curSubSong->ordersLen) { curOrder=0; endOfSong=true; + memset(walked,0,8192); } changeOrd=-1; } @@ -932,6 +955,13 @@ void DivEngine::nextRow() { if (haltOn==DIV_HALT_PATTERN) halted=true; } + // new loop detection routine + if (!endOfSong && walked[((curOrder<<5)+(curRow>>3))&8191]&(1<<(curRow&7))) { + logV("loop reached"); + endOfSong=true; + memset(walked,0,8192); + } + if (song.brokenSpeedSel) { if ((curSubSong->patLen&1) && curOrder&1) { ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1); diff --git a/src/engine/song.h b/src/engine/song.h index ac49832e7..493fc4125 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -468,6 +468,11 @@ struct DivSong { // 1: broken (don't allow value higher than speed) // 2: lax (allow value higher than speed) unsigned char delayBehavior; + // 0B/0D treatment + // 0: normal (0B/0D accepted) + // 1: old Furnace (first one accepted) + // 2: DefleMask (0D takes priority over 0B) + unsigned char jumpTreatment; bool properNoiseLayout; bool waveDutyIsVol; bool resetMacroOnPorta; @@ -571,6 +576,7 @@ struct DivSong { pitchSlideSpeed(4), loopModality(2), delayBehavior(2), + jumpTreatment(0), properNoiseLayout(true), waveDutyIsVol(false), resetMacroOnPorta(false), diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 74d493e7f..63571dcac 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -213,6 +213,26 @@ void FurnaceGUI::drawCompatFlags() { ImGui::SetTooltip("no checks (like FamiTracker)"); } + ImGui::Text("Simultaneous jump (0B+0D) treatment:"); + if (ImGui::RadioButton("Normal",e->song.jumpTreatment==0)) { + e->song.jumpTreatment=0; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("accept 0B+0D to jump to a specific row of an order"); + } + if (ImGui::RadioButton("Old Furnace",e->song.jumpTreatment==1)) { + e->song.jumpTreatment=1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("only accept the first jump effect"); + } + if (ImGui::RadioButton("DefleMask",e->song.jumpTreatment==2)) { + e->song.jumpTreatment=2; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("only accept 0Dxx"); + } + ImGui::Separator(); ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions."); From a99f1bd8a070045170352ad2cbec1f2898e9bd12 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 02:34:47 -0500 Subject: [PATCH 379/515] fix walkSong --- src/engine/engine.cpp | 53 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index a184b5b55..f6fe659ea 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -147,37 +147,68 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) { int nextOrder=-1; int nextRow=0; int effectVal=0; + int lastSuspectedLoopEnd=-1; DivPattern* pat[DIV_MAX_CHANS]; + unsigned char wsWalked[8192]; + memset(wsWalked,0,8192); for (int i=0; iordersLen; i++) { for (int j=0; jord[j][i],false); } + if (i>lastSuspectedLoopEnd) { + lastSuspectedLoopEnd=i; + } for (int j=nextRow; jpatLen; j++) { nextRow=0; + bool changingOrder=false; + bool jumpingOrder=false; + if (wsWalked[((i<<5)+(j>>3))&8191]&(1<<(j&7))) { + loopOrder=i; + loopRow=j; + loopEnd=lastSuspectedLoopEnd; + return; + } for (int k=0; kdata[j][5+(l<<1)]; if (effectVal<0) effectVal=0; if (pat[k]->data[j][4+(l<<1)]==0x0d) { - if (nextOrder==-1 && (iordersLen-1 || !song.ignoreJumpAtEnd)) { - nextOrder=i+1; - nextRow=effectVal; + if (song.jumpTreatment==2) { + if ((iordersLen-1 || !song.ignoreJumpAtEnd)) { + nextOrder=i+1; + nextRow=effectVal; + jumpingOrder=true; + } + } else if (song.jumpTreatment==1) { + if (nextOrder==-1 && (iordersLen-1 || !song.ignoreJumpAtEnd)) { + nextOrder=i+1; + nextRow=effectVal; + jumpingOrder=true; + } + } else { + if ((iordersLen-1 || !song.ignoreJumpAtEnd)) { + if (!changingOrder) { + nextOrder=i+1; + } + jumpingOrder=true; + nextRow=effectVal; + } } } else if (pat[k]->data[j][4+(l<<1)]==0x0b) { - if (nextOrder==-1) { + if (nextOrder==-1 || song.jumpTreatment==0) { nextOrder=effectVal; - nextRow=0; + if (song.jumpTreatment==1 || song.jumpTreatment==2 || !jumpingOrder) { + nextRow=0; + } + changingOrder=true; } } } } + + wsWalked[((i<<5)+(j>>3))&8191]|=1<<(j&7); + if (nextOrder!=-1) { - if (nextOrder<=i) { - loopOrder=nextOrder; - loopRow=nextRow; - loopEnd=i; - return; - } i=nextOrder-1; nextOrder=-1; break; From 99340234b8a3883b9eee985230ce54bcabf47583 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 16:01:22 -0500 Subject: [PATCH 380/515] GUI: wave generator, part 7 prepare for WaveTools (formerly Mangle) --- src/gui/gui.cpp | 6 ++++ src/gui/gui.h | 2 ++ src/gui/waveEdit.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 65e982c73..0b1d008b3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5241,6 +5241,12 @@ FurnaceGUI::FurnaceGUI(): waveGenDuty(0.5f), waveGenPower(1), waveGenInvertPoint(1.0f), + waveGenScaleX(32), + waveGenScaleY(31), + waveGenOffsetX(0), + waveGenOffsetY(0), + waveGenSmooth(1), + waveGenAmplify(1.0f), waveGenFM(false) { // value keys valueKeys[SDLK_0]=0; diff --git a/src/gui/gui.h b/src/gui/gui.h index 180013dfa..79a39a1f9 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1573,6 +1573,8 @@ class FurnaceGUI { float waveGenTL[4]; int waveGenMult[4]; int waveGenFB[4]; + int waveGenScaleX, waveGenScaleY, waveGenOffsetX, waveGenOffsetY, waveGenSmooth; + float waveGenAmplify; bool waveGenFMCon1[4]; bool waveGenFMCon2[3]; bool waveGenFMCon3[2]; diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index c46e2ec0c..de106cb5d 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -503,7 +503,91 @@ void FurnaceGUI::drawWaveEdit() { } ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Mangle")) { + if (ImGui::BeginTabItem("WaveTools")) { + if (ImGui::BeginTable("WGParamItems",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##WGScaleX",&waveGenScaleX,1,16)) { + if (waveGenScaleX<2) waveGenScaleX=2; + if (waveGenScaleX>256) waveGenScaleX=256; + } + ImGui::TableNextColumn(); + ImGui::Button("Scale X"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##WGScaleY",&waveGenScaleY,1,16)) { + if (waveGenScaleY<2) waveGenScaleY=2; + if (waveGenScaleY>256) waveGenScaleY=256; + } + ImGui::TableNextColumn(); + ImGui::Button("Scale Y"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##WGOffsetX",&waveGenOffsetX,1,16)) { + if (waveGenOffsetX<-wave->len+1) waveGenOffsetX=-wave->len+1; + if (waveGenOffsetX>wave->len-1) waveGenOffsetX=wave->len-1; + } + ImGui::TableNextColumn(); + ImGui::Button("Offset X"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##WGOffsetY",&waveGenOffsetY,1,16)) { + if (waveGenOffsetY<-wave->max) waveGenOffsetY=-wave->max; + if (waveGenOffsetY>wave->max) waveGenOffsetY=wave->max; + } + ImGui::TableNextColumn(); + ImGui::Button("Offset Y"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##WGSmooth",&waveGenSmooth,1,4)) { + if (waveGenSmooth>wave->len) waveGenSmooth=wave->len; + if (waveGenSmooth<1) waveGenSmooth=1; + } + ImGui::TableNextColumn(); + ImGui::Button("Smooth"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + float amp=waveGenAmplify*100.0f; + if (ImGui::InputFloat("##WGAmplify",&,1.0f,10.0f)) { + waveGenAmplify=amp/100.0f; + if (waveGenAmplify<0.0f) waveGenAmplify=0.0f; + if (waveGenAmplify>100.0f) waveGenAmplify=100.0f; + } + ImGui::TableNextColumn(); + ImGui::Button("Amplify"); + + ImGui::EndTable(); + } + + ImVec2 buttonSize=ImGui::GetContentRegionAvail(); + buttonSize.y=0.0f; + ImVec2 buttonSizeHalf=buttonSize; + buttonSizeHalf.x-=ImGui::GetStyle().ItemSpacing.x; + buttonSizeHalf.x*=0.5; + + ImGui::Button("Normalize",buttonSize); + ImGui::Button("Invert",buttonSize); + + ImGui::Button("/2",buttonSizeHalf); + ImGui::SameLine(); + ImGui::Button("×2",buttonSizeHalf); + + ImGui::Button("Convert Signed/Unsigned",buttonSize); + ImGui::Button("Randomize",buttonSize); ImGui::EndTabItem(); } ImGui::EndTabBar(); From 8e256d4dd5c26b6b5b20870e95e1f070a0c0cd1e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 16:33:40 -0500 Subject: [PATCH 381/515] allocate ID for MSM5232 --- papers/format.md | 1 + 1 file changed, 1 insertion(+) diff --git a/papers/format.md b/papers/format.md index 8528a7d63..14512fe12 100644 --- a/papers/format.md +++ b/papers/format.md @@ -255,6 +255,7 @@ size | description | - 0xc3: OPN CSM - 10 channels | - 0xc4: PC-98 CSM - 20 channels | - 0xc5: YM2610B CSM - 20 channels + | - 0xc6: MSM5232 - 8 channels | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels | - 0xfd: Dummy System - 8 channels From 7c9384a63f16c4328acde310b4d5dd98241e52d1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 17:01:58 -0500 Subject: [PATCH 382/515] update test suite with new assert_delta --- .gitignore | 1 + test/assert_delta.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ test/furnace-test.sh | 20 ++++++++++++++++-- 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 test/assert_delta.c diff --git a/.gitignore b/.gitignore index 566a3c3fc..25bd6d0e0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ linuxbuild/ test/songs/ test/delta/ test/result/ +test/assert_delta android/.gradle/ android/app/build/ android/app/.cxx/ diff --git a/test/assert_delta.c b/test/assert_delta.c new file mode 100644 index 000000000..6dad6992b --- /dev/null +++ b/test/assert_delta.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#define BUF_SIZE 8192 + +// usage: assert_delta file +// return values: +// - 0: pass (file is silence) +// - 1: fail (noise found) +// - 2: command line error +// - 3: file open error +int main(int argc, char** argv) { + if (argc<2) return 2; + + SF_INFO si; + memset(&si,0,sizeof(SF_INFO)); + SNDFILE* sf=sf_open(argv[1],SFM_READ,&si); + if (sf==NULL) { + fprintf(stderr,"open: %s\n",sf_strerror(NULL)); + return 3; + } + + if (si.channels<1) { + fprintf(stderr,"invalid channel count\n"); + return 3; + } + + float* buf=malloc(BUF_SIZE*si.channels*sizeof(float)); + + sf_count_t totalRead=0; + size_t seekPos=0; + while ((totalRead=sf_readf_float(sf,buf,BUF_SIZE))!=0) { + for (int i=0; i Date: Sat, 10 Sep 2022 15:21:39 -0700 Subject: [PATCH 383/515] Kinda simple demo song --- demos/lunacommdemo.fur | Bin 0 -> 12875 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/lunacommdemo.fur diff --git a/demos/lunacommdemo.fur b/demos/lunacommdemo.fur new file mode 100644 index 0000000000000000000000000000000000000000..43531b8bc141cb1aa260b96f7e0bb9224dade1fc GIT binary patch literal 12875 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 literal 0 HcmV?d00001 From fd98ecee4f549d4ea623883a1e7fd0dc2225d465 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 17:57:14 -0500 Subject: [PATCH 384/515] also on OPZ --- src/engine/platform/tx81z.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 0fe0265e1..1c6470fc4 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -906,6 +906,7 @@ void DivPlatformTX81Z::reset() { pmDepth=0x7f; //rWrite(0x18,0x10); + immWrite(0x18,0x00); // LFO Freq Off immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); //rWrite(0x1b,0x00); From 7b19c8afa273f3f2e8c25065e31d3e23be390bf3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 17:57:28 -0500 Subject: [PATCH 385/515] no verbose FFmpeg output in furnace-test.sh --- test/furnace-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/furnace-test.sh b/test/furnace-test.sh index 0b1568a25..bb0ec375a 100755 --- a/test/furnace-test.sh +++ b/test/furnace-test.sh @@ -29,7 +29,7 @@ if [ -z $lastTest ]; then echo "skipping since this apparently is your first run." else mkdir -p "test/delta/$testDir" || exit 1 - ls "test/result/$testDir/" | parallel --verbose -j4 ffmpeg -i "test/result/$lastTest/{0}" -i "test/result/$testDir/{0}" -filter_complex stereotools=phasel=1:phaser=1,amix=inputs=2:duration=longest -c:a pcm_s16le -y "test/delta/$testDir/{0}" + ls "test/result/$testDir/" | parallel --verbose -j4 ffmpeg -loglevel fatal -i "test/result/$lastTest/{0}" -i "test/result/$testDir/{0}" -filter_complex stereotools=phasel=1:phaser=1,amix=inputs=2:duration=longest -c:a pcm_s16le -y "test/delta/$testDir/{0}" fi echo "--- STEP 3: check deltas" if [ -z $lastTest ]; then From eb2c01097f865fbe02af71551991ef4a97cdc860 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 18:53:27 -0500 Subject: [PATCH 386/515] GUI: add recent file list --- src/engine/config.cpp | 4 +++ src/engine/engine.h | 1 + src/gui/gui.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++ src/gui/gui.h | 4 +++ src/gui/settings.cpp | 16 +++++++++++- 5 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/engine/config.cpp b/src/engine/config.cpp index 862cd4c03..38cb2b042 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -239,6 +239,10 @@ void DivEngine::setConf(String key, double value) { conf[key]=fmt::sprintf("%f",value); } +void DivEngine::setConf(String key, const char* value) { + conf[key]=String(value); +} + void DivEngine::setConf(String key, String value) { conf[key]=value; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 4b78828e8..7c700e005 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -544,6 +544,7 @@ class DivEngine { void setConf(String key, int value); void setConf(String key, float value); void setConf(String key, double value); + void setConf(String key, const char* value); void setConf(String key, String value); // calculate base frequency/period diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0b1d008b3..0d0635ec5 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -536,6 +536,7 @@ void FurnaceGUI::setFileName(String name) { } #endif updateWindowTitle(); + pushRecentFile(curFileName); } void FurnaceGUI::updateWindowTitle() { @@ -1724,6 +1725,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); } + pushRecentFile(path); return 0; } @@ -1801,9 +1803,26 @@ int FurnaceGUI::load(String path) { if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); } + pushRecentFile(path); return 0; } +void FurnaceGUI::pushRecentFile(String path) { + if (path.empty()) return; + if (path==backupPath) return; + for (int i=0; i<(int)recentFile.size(); i++) { + if (recentFile[i]==path) { + recentFile.erase(recentFile.begin()+i); + i--; + } + } + recentFile.push_front(path); + + while (!recentFile.empty() && (int)recentFile.size()>settings.maxRecentFile) { + recentFile.pop_back(); + } +} + void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) { e->saveAudio(path.c_str(),exportLoops+1,mode,exportFadeOut); displayExporting=true; @@ -3045,6 +3064,27 @@ bool FurnaceGUI::loop() { openFileDialog(GUI_FILE_OPEN); } } + if (ImGui::BeginMenu("open recent")) { + for (int i=0; i<(int)recentFile.size(); i++) { + String item=recentFile[i]; + if (ImGui::MenuItem(item.c_str())) { + if (modified) { + nextFile=item; + showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP); + } else { + recentFile.erase(recentFile.begin()+i); + i--; + if (load(item)>0) { + showError(fmt::sprintf("Error while loading file! (%s)",lastError)); + } + } + } + } + if (recentFile.empty()) { + ImGui::Text("nothing here yet"); + } + ImGui::EndMenu(); + } ImGui::Separator(); if (ImGui::MenuItem("save",BIND_FOR(GUI_ACTION_SAVE))) { if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { @@ -4628,6 +4668,13 @@ bool FurnaceGUI::init() { syncSettings(); + for (int i=0; igetConfString(fmt::sprintf("recentFile%d",i),""); + if (!r.empty()) { + recentFile.push_back(r); + } + } + if (settings.dpiScale>=0.5f) { dpiScale=settings.dpiScale; } @@ -4900,6 +4947,16 @@ bool FurnaceGUI::finish() { e->setConf("chanOscUseGrad",chanOscUseGrad); e->setConf("chanOscGrad",chanOscGrad.toString()); + // commit recent files + for (int i=0; i<30; i++) { + String key=fmt::sprintf("recentFile%d",i); + if (i>=settings.maxRecentFile || i>=(int)recentFile.size()) { + e->setConf(key,""); + } else { + e->setConf(key,recentFile[i]); + } + } + for (int i=0; i sysSearchResults; std::vector newSongSearchResults; + std::deque recentFile; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; bool portrait, mobileMenuOpen; @@ -1171,6 +1172,7 @@ class FurnaceGUI { int channelStyle; int channelVolStyle; int channelFeedbackStyle; + int maxRecentFile; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1291,6 +1293,7 @@ class FurnaceGUI { channelStyle(0), channelVolStyle(0), channelFeedbackStyle(1), + maxRecentFile(10), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -1728,6 +1731,7 @@ class FurnaceGUI { void openFileDialog(FurnaceGUIFileDialogs type); int save(String path, int dmfVersion); int load(String path); + void pushRecentFile(String path); void exportAudio(String path, DivAudioExportModes mode); bool parseSysEx(unsigned char* data, size_t len); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 53ce0cdeb..54da8e893 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1130,6 +1130,13 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); + if (ImGui::InputInt("Number of recent files",&settings.maxRecentFile)) { + if (settings.maxRecentFile<0) settings.maxRecentFile=0; + if (settings.maxRecentFile>30) settings.maxRecentFile=30; + } + + ImGui::Separator(); + ImGui::Text("Pattern view labels:"); ImGui::InputTextWithHint("Note off (3-char)","OFF",&settings.noteOffLabel); ImGui::InputTextWithHint("Note release (3-char)","===",&settings.noteRelLabel); @@ -2273,6 +2280,7 @@ void FurnaceGUI::syncSettings() { settings.channelStyle=e->getConfInt("channelStyle",0); settings.channelVolStyle=e->getConfInt("channelVolStyle",0); settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1); + settings.maxRecentFile=e->getConfInt("maxRecentFile",10); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2371,6 +2379,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelStyle,0,5); clampSetting(settings.channelVolStyle,0,3); clampSetting(settings.channelFeedbackStyle,0,3); + clampSetting(settings.maxRecentFile,0,30); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2403,7 +2412,7 @@ void FurnaceGUI::syncSettings() { } void FurnaceGUI::commitSettings() { - bool sampleROMsChanged = settings.yrw801Path!=e->getConfString("yrw801Path","") || + bool sampleROMsChanged=settings.yrw801Path!=e->getConfString("yrw801Path","") || settings.tg100Path!=e->getConfString("tg100Path","") || settings.mu5Path!=e->getConfString("mu5Path",""); @@ -2525,6 +2534,7 @@ void FurnaceGUI::commitSettings() { e->setConf("channelStyle",settings.channelStyle); e->setConf("channelVolStyle",settings.channelVolStyle); e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle); + e->setConf("maxRecentFile",settings.maxRecentFile); // colors for (int i=0; isaveConf(); + while (!recentFile.empty() && (int)recentFile.size()>settings.maxRecentFile) { + recentFile.pop_back(); + } + if (sampleROMsChanged) { if (e->loadSampleROMs()) { showError(e->getLastError()); From a46ef0c0be52cc4bb0fad78b8c02abb48f403f2f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 19:35:50 -0500 Subject: [PATCH 387/515] GUI: wave generator, part 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to-do: - normalize - /2 - ×2 - smooth --- src/gui/waveEdit.cpp | 85 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index de106cb5d..37b8cc808 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -516,7 +516,17 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenScaleX>256) waveGenScaleX=256; } ImGui::TableNextColumn(); - ImGui::Button("Scale X"); + if (ImGui::Button("Scale X")) { + if (waveGenScaleX>0 && wave->len!=waveGenScaleX) e->lockEngine([this,wave]() { + int origData[256]; + memcpy(origData,wave->data,wave->len*sizeof(int)); + for (int i=0; idata[i]=origData[i*wave->len/waveGenScaleX]; + } + wave->len=waveGenScaleX; + MARK_MODIFIED; + }); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -526,7 +536,15 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenScaleY>256) waveGenScaleY=256; } ImGui::TableNextColumn(); - ImGui::Button("Scale Y"); + if (ImGui::Button("Scale Y")) { + if (waveGenScaleY>0 && wave->max!=waveGenScaleY) e->lockEngine([this,wave]() { + for (int i=0; ilen; i++) { + wave->data[i]=(wave->data[i]*(waveGenScaleY+1))/(wave->max+1); + } + wave->max=waveGenScaleY; + MARK_MODIFIED; + }); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -536,7 +554,19 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenOffsetX>wave->len-1) waveGenOffsetX=wave->len-1; } ImGui::TableNextColumn(); - ImGui::Button("Offset X"); + if (ImGui::Button("Offset X")) { + if (waveGenOffsetX!=0 && wave->len>0) e->lockEngine([this,wave]() { + int origData[256]; + memcpy(origData,wave->data,wave->len*sizeof(int)); + int realOff=-waveGenOffsetX; + while (realOff<0) realOff+=wave->len; + + for (int i=0; ilen; i++) { + wave->data[i]=origData[(i+realOff)%wave->len]; + } + MARK_MODIFIED; + }); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -546,7 +576,14 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenOffsetY>wave->max) waveGenOffsetY=wave->max; } ImGui::TableNextColumn(); - ImGui::Button("Offset Y"); + if (ImGui::Button("Offset Y")) { + if (waveGenOffsetY!=0) e->lockEngine([this,wave]() { + for (int i=0; ilen; i++) { + wave->data[i]=CLAMP(wave->data[i]+waveGenOffsetY,0,wave->max); + } + MARK_MODIFIED; + }); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -568,7 +605,14 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenAmplify>100.0f) waveGenAmplify=100.0f; } ImGui::TableNextColumn(); - ImGui::Button("Amplify"); + if (ImGui::Button("Amplify")) { + if (waveGenAmplify!=1.0f) e->lockEngine([this,wave]() { + for (int i=0; ilen; i++) { + wave->data[i]=CLAMP(round((float)(wave->data[i]-((wave->max+1)/2))*waveGenAmplify),(int)(-((wave->max+1)/2)),(int)(wave->max/2))+((wave->max+1)/2); + } + MARK_MODIFIED; + }); + } ImGui::EndTable(); } @@ -580,14 +624,39 @@ void FurnaceGUI::drawWaveEdit() { buttonSizeHalf.x*=0.5; ImGui::Button("Normalize",buttonSize); - ImGui::Button("Invert",buttonSize); + if (ImGui::Button("Invert",buttonSize)) { + e->lockEngine([this,wave]() { + for (int i=0; ilen; i++) { + wave->data[i]=wave->max-wave->data[i]; + } + MARK_MODIFIED; + }); + } ImGui::Button("/2",buttonSizeHalf); ImGui::SameLine(); ImGui::Button("×2",buttonSizeHalf); - ImGui::Button("Convert Signed/Unsigned",buttonSize); - ImGui::Button("Randomize",buttonSize); + if (ImGui::Button("Convert Signed/Unsigned",buttonSize)) { + if (wave->max>0) e->lockEngine([this,wave]() { + for (int i=0; ilen; i++) { + if (wave->data[i]>(wave->max/2)) { + wave->data[i]-=(wave->max+1)/2; + } else { + wave->data[i]+=wave->max/2; + } + } + MARK_MODIFIED; + }); + } + if (ImGui::Button("Randomize",buttonSize)) { + if (wave->max>0) e->lockEngine([this,wave]() { + for (int i=0; ilen; i++) { + wave->data[i]=rand()%wave->max; + } + MARK_MODIFIED; + }); + } ImGui::EndTabItem(); } ImGui::EndTabBar(); From 06fe2daa017757749a3dea6fa025595c4deda8ed Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 19:36:41 -0500 Subject: [PATCH 388/515] update to-do list --- TODO.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index cba0b7c65..859ad68c2 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,7 @@ -# to-do for 0.6pre1.5-0.6pre2 +# to-do for 0.6pre1.5 -- volume commands should work on Game Boy - stereo separation control for AY -- "paste with instrument" \ No newline at end of file +- "paste with instrument" +- FM operator muting +- FM operator swap +- bug fixes From fc4aea3c916ca8cd40fdb66c72d038853b199a68 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 21:21:08 -0500 Subject: [PATCH 389/515] update demo songs (#661) --- demos/FEDMS.fur | Bin 0 -> 75333 bytes demos/hope_for_the_dream.fur | Bin 0 -> 3467 bytes demos/iji_tor.fur | Bin 0 -> 299701 bytes src/gui/about.cpp | 3 ++- 4 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 demos/FEDMS.fur create mode 100644 demos/hope_for_the_dream.fur create mode 100644 demos/iji_tor.fur diff --git a/demos/FEDMS.fur b/demos/FEDMS.fur new file mode 100644 index 0000000000000000000000000000000000000000..4c521dadaa23f90f934abdee9e692d25f2bac28f GIT binary patch literal 75333 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 B?h*h1 literal 0 HcmV?d00001 diff --git a/demos/iji_tor.fur b/demos/iji_tor.fur new file mode 100644 index 0000000000000000000000000000000000000000..84a6ac5b3575319834d026f47838a1e8147d5155 GIT binary patch literal 299701 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�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%0D&UXZQbOXjDYI-E9L9W@bkL>(w!Gk9zuK2op%i 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[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 Z6CU$`gVrO0zV~95pJHBGO~-z`;XhYgN-qEa literal 0 HcmV?d00001 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 39cb1192e..47ae9e983 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -87,8 +87,9 @@ const char* aboutLine[]={ "Miker", "nicco1690", "NikonTeen", - "psdominator", + "psxdominator", "Raijin", + "SnugglyBun", "SuperJet Spade", "TheDuccinator", "theloredev", From 7d89708bf747455fdc0717ebe40247f7c11c254a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 21:25:58 -0500 Subject: [PATCH 390/515] Clang can you stop complaining --- src/gui/waveEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 37b8cc808..2b7e638b0 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -608,7 +608,7 @@ void FurnaceGUI::drawWaveEdit() { if (ImGui::Button("Amplify")) { if (waveGenAmplify!=1.0f) e->lockEngine([this,wave]() { for (int i=0; ilen; i++) { - wave->data[i]=CLAMP(round((float)(wave->data[i]-((wave->max+1)/2))*waveGenAmplify),(int)(-((wave->max+1)/2)),(int)(wave->max/2))+((wave->max+1)/2); + wave->data[i]=CLAMP(round((float)(wave->data[i]-(int)( /* Clang can you stop complaining */ (int)(wave->max+1)/(int)2))*waveGenAmplify),(int)(-((wave->max+1)/2)),(int)(wave->max/2))+(int)((wave->max+1)/2); } MARK_MODIFIED; }); From 60e37714dacbd0f7942b1d4b5aa241742ebd36c6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 21:28:54 -0500 Subject: [PATCH 391/515] Vim mistakes *** for italic --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d2308dd75..7efe2c2a0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ the biggest multi-system chiptune tracker ever made! [downloads](#downloads) | [discussion/help](#quick-references) | [developer info](#developer-info) | [unofficial packages](#unofficial-packages) | [FAQ](#frequently-asked-questions) -*** +--- ## downloads check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux (AppImage). @@ -74,7 +74,7 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a - loads .dmf modules from all versions (beta 1 to 1.1.3) - saves .dmf modules - both modern and legacy - Furnace doubles as a module downgrader - - loads .dmp instruments and .dmw wavetables as well + - loads/saves .dmp instruments and .dmw wavetables as well - clean-room design (guesswork and ABX tests only, no decompilation involved) - bug/quirk implementation for increased playback accuracy through compatibility flags - VGM export @@ -103,7 +103,7 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a - built-in visualizer in pattern view - open-source under GPLv2 or later. -*** +--- # quick references - **discussion**: see the [Discussions](https://github.com/tildearrow/furnace/discussions) section, or (preferably) the [official Discord server](https://discord.gg/EfrwT2wq7z). @@ -119,7 +119,7 @@ some people have provided packages for Unix/Unix-like distributions. here's a li - **Nix**: [package](https://search.nixos.org/packages?channel=unstable&show=furnace&from=0&size=50&sort=relevance&type=packages&query=furnace) thanks to OPNA2608. - **openSUSE**: [a package](https://software.opensuse.org/package/furnace) is available, courtesy of fpesari. -*** +--- # developer info [![Build furnace](https://github.com/tildearrow/furnace/actions/workflows/build.yml/badge.svg)](https://github.com/tildearrow/furnace/actions/workflows/build.yml) @@ -228,7 +228,7 @@ this will play a compatible file and enable the commands view. **note that these commands only actually work in Linux environments. on other command lines, such as Windows' Command Prompt, or MacOS Terminal, it may not work correctly.** -*** +--- # frequently asked questions > woah! 50 sound chips?! I can't believe it! @@ -274,7 +274,7 @@ the DefleMask format has several limitations. save in Furnace song format instea right click on the channel name. -*** +--- # footnotes copyright (C) 2021-2022 tildearrow and contributors. From f0d3ad1c82d9b089101fd731e4704ed209e5ea07 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 21:33:35 -0500 Subject: [PATCH 392/515] GUI: don't care about clipboard data version --- src/gui/editing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 391a39f62..201c9be26 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -431,7 +431,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { int startOff=-1; bool invalidData=false; if (data.size()<2) return; - if (data[0]!=fmt::sprintf("org.tildearrow.furnace - Pattern Data (%d)",DIV_ENGINE_VERSION)) return; + if (data[0].find("org.tildearrow.furnace - Pattern Data")!=0) return; if (sscanf(data[1].c_str(),"%d",&startOff)!=1) return; if (startOff<0) return; From 2a051900a77dcb2f1dd54aeece23b424d47dc5fd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 21:46:10 -0500 Subject: [PATCH 393/515] update Bullet_Hell.fur --- demos/Bullet_Hell.fur | Bin 60233 -> 60291 bytes src/gui/about.cpp | 1 + 2 files changed, 1 insertion(+) diff --git a/demos/Bullet_Hell.fur b/demos/Bullet_Hell.fur index 48c50f674d7d8a4c9cfbb2f632a1d1de602a617e..dfd2a04251e144596f21d8dd6aeaa3d2cc0a297b 100644 GIT binary patch literal 60291 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

      lfopXzJz@$ zNdYH|Mdw5=Eu1J1@9~*)o4udf4k{2?VrFa7pr@?+A%E&2SgaBLV~xqT{M;hS_Zg`} z*3z*?h|@9lj@;pt`DhXMKJw48;-cFTn^!;%<=hz42nMY1kbRb)5GRRR^O>50Q{8*IRdcKb68iq3>ZuMA4w^s@5`=G^sVE=3|D95}s$k%QqrfCrle(V&b|k zSwaR>&0ibQ4B*QG`T4T7EZdRs+t`|{-X!q{Qy2o5-6n0fmC7_=c?(9%0 z&?o>0f_hj`ttwSk(-DIDs1Z|2d;Z-#X?6h{{vq5WrSW8|XD$u&!X@6_>jGQqA2(G= z)2jS>h%Mr=fMkN}$`RE72KQhF!tVmHKhX71QCRB5K8O@&P=y{9J)MN`&q0RDd8Wjj zl%VeZk!-;z;GhBJuby7Q!3+ z^(57c;+k-U78blY>H<|Jd?C4DpQX(T7AIOSynGIvqO1K5Ox2=mLI0vcl8%FDcG;~mx=4cDI; z4ZeAlNT9JeFUMWgqGbQ+}xQvJ!4I`7&^mi1~ zNz%#A`YJ}8_cVu;<3lOJ>&d|t8)2PoQqyKFQ3?s{UJJtju0uT23?2@W9LdqpTq**~ z;?QszJf!lE^?1)xxbjwC;q#I3#kufBS%L)4Lj-XiXq_ec(dDEkpF*2SfmS+a>ZW21 z85VQ5yeEOMMa-jcO(_?CH=Tt|N-bugNM3EgJ{A50H2#}Ynniv2`FhLSKHb^F5Hn)= zNkKO+9rB>USBdYmEtbunC<`0TaM#iS`>K(J$x?l#C2bB`*YD1*8F_?ScRsnOyasI+ z0Q!;=PnA0$>Bwumrb`BK$BpQkT}o>k-&kNDnmPiQ3i5Q6<^op4fFX9k;<|4(NUTfT zQtPFp&d(~O3IM4lge-@^f+b<_tu1Kz#9CS+b4FpClj#y3mf3|rLqzy{?BwU-VWS|FbHz69jaIHtG7RpEql~byt}-%W{~_Wi5Ua1^>3=qDM` zT9I=;w`aW5f*1_tj_RJ29kk?Fnx2#i799?T;tT`SBV>K5U*YEZwD`(ST2ouy*vjp< z7E@x!x`cBpU1?OSY6`xWZ$F=EL(<@D(S0jr(-cLVaz@*zb`!HVHb>bcH3JToV$vlP zkm=tNo)q!M#@ZOSbEb9$0F9k>0_iFiRxMc!jrffyG|aIUI!Fd>{F=mKU;M)fi~!G$ z1OZYU4dKsXtixaWJegs*Y@dNrE&Mi+laKcgv92xh`qHuM*F51s_M zxU7?Uw1xl#JcPe{zxVrQ|>n*q^WJ36mR%oc)N z_<$|jf_7CeEx8Lf#rS1VyVi!uN?u8#dUKGElsUpmXYAsIyWZ4}fxMy!b1|MoR$Z$Y zJ;K=hWlCl<_qjyioLa6JBu`9>eptHI-MG4pG|h`pYeR`#7-4};zYaysY7*EE+3w>% zC2I=N*=1!DO%9RQ#7z@;^u+`nrzTVqoeSFY#py6iLf#U%6>Y+F%>(|+rRkJE(mP7Y?FnpN?d|nP z)WH%4p@%#?t3-6Cpc+SI7QMAf0@B%x-2E9I=0}hEPP;1Z>^CAs>6JZ!@myICDTa7z zhNA5*Awu|jYp?zAPKfLluyi++`R($11c#`*hETHVi_{wBnjoeV4L}_;y zwwkgO!uk97ggo(~9Rx8cYn-|XTY|0{af}}(=*YQeNi?u>GyO#W9ny11FpnWKLzwV( zzIV4l%*H&1nlQ?_L*cT8i3hK|^?1yWpgU8wzQ>EwdhE@7HU70I8+_$d9+bpGTn4pX zr`sL$!^s--g=uq@=TDF1o?5`XZK1qsyJd{?wCa~f>T)d$1*JAhRwMCvsZkM@ImMBN zKE)-)>BJS{aJ;2tm2iaO`fR#YUAuG%z$!Li*!IHu2rx z^@G3I7?$Z1fQnA@v=-oH?>q_CCvo4Bfeylf<;HkbL{C1Jkgd~dq3B^}#l&a)_flph z`NdAw1bTsU9;jCuD_(;-12y0tf=^WYwOqghm)blIP z%U=OS|0&J1&fx7waN~pCfw9CyhrwZf-V|PuU#3G3#YcRb;@X>WLguln_A6Yt=<+}{=T9E*V~r`rTavWk*aLdma$mDvO{ zenMCP8r23WqvXs6AQK~@UntEWnye(Whd~u3nw)jt`)$Q22TknXd&f8(#st}&_<4PV+{Er7-$I{qri?Hkr5QlF67-s5K_QsMJ=7kF61$HNJ%fPMu zaQ3L!lUVo2Nko#w;3QdR0v-fnZ+~8BJ-LR=N2Z(1qzGpUTH8z+>h$5FargqRtE_gk z+s!`$r9_Vu71u}3L^%R~=aHQGGnMjb%{5ib$+T?j7@msO6s}OtCG-RoJYmrlVSKLM zmT&a!^O5yAu$h4C2e+OEjRVbfS_YxFiBGv9)zxjnF_S!yg5t#W;vFvrKeWezYb3?L z%S%xyz$NTrJc=7dlNP5}N7Hw7BE6nFaGd5#%~hJwHN~pSScP$FrxwvIteWxG8LyCe zof>j7Gj3KSyP@uG(d<01nZSpCYw%TKUw&&W?cU8W zU4Ug_yp0~`bn8DH0KRGnB|D&lMnf4FxJ%%wNHz>W_WLE2qg#;SK$-iF11UVXK6#Y^{Z~Vssvm;9<~#6C-u_dWH;!KP?2+e7&2a0ohBc#rKk) zb>^s@i#*s3LEykh5+I};Lu*_h8y?t7{f^cLEW&s`t1?xkSBl%XgGm_^oCdl4S>a?_ z>*z_~K2t`?%I*#0g0KG_sE5_~>5c@xsV$uuTW8jX$x{kBGJ=u6GT)g0yL*xix_y$X zZfE{iAfGs*ktt)?9MO&&| z#%&;h8*Nd%J<(IhqlBTP=U&l*jzGcln9uG$KyVgv$sEc(-Klw#}#}BzWr`T{~0RH+=eEyyx@z%U!K?>c@-R9 z>GnwRIwxw*J8HnT&M1Tcycn;ope)a_4l~`Yc%*-ax(#2rU<5tE?$2iV4sXq38+$@i z_*hh)cO$UvF=dAi)ZxsVil+8zr$Zd*v%~TipZcHI5+#c*hX3`^2j>v#kMT0PO8V&6 zzsU|zN+G*q}$yfyl;N*NKe(NxPKYeU0NMogoQ56~Q|nK%+#3k9PxvuOO4q zBy$rEe$yI0voG?}Ccu#IavVq8cgggdl!J1}ed^N>Z=fnB3gcjO$CwEPBZ!)SIm7d~ z>*1(PHaQFtFtTAkj8oz{!H|f?45@iMWf03bqpfHzf}9^OYC2QSa5(+{e$rjEWBg{NOzjdc4V0&WXDPgR}*JcuM6t-8{D z7PQ5+a?^r#C*ci~Y8WX#82EVIt-d?&z>7E-J|tT`YOlR*4HA92n7_2ADECUk-U42Z zu;hKtl$K2whriZ>YO0x8b)X6DHmQeY%;*eRVD{+eLfXpWhCe*pGP??3>7R7;=Lem$@z@qF8}BjF)QW7H{fAO=$FDLO zfPac&6}gsrQ8^vOlaF=%2A1v_bp-}KRx)rr=DH@fNoU1}r>8O_fyPP!{3=-6A{qsjht~Lc&mOFO0K6Z7)31m4DbqR%2JRuL@}t zRQbj3Uq?_zJA6ZZxHj;dF$4D_T)Z<%)9@*7yAJG+XU|1p;frQ~S4+5_%U>UhND>?9 zoKr;2&}ru80!ohY3g%>~Q^6>}7w7;Jra_)E^*1`(saHD{yBoiCDS<|QQw(_Ks=7Wq zXUy6@F8)tOw`P;1<*y>5c-GPob87DA8ocG||cHH78~A(NDQev3kDHM%juZp>s#C3q$T*h6;4q+`-wo(ZfT z_=l{>^nXY*|5HQuwRZHTrY7f(hwrO)I~?t6C@7b+u2Lqcf*8kWPv}kM9UM5^D9mO~inQ|JwD-{2{Az5pODZ!- z>kXSGf-b(A(Yj1{n&MEE5w6SS=A(}id+)jOh842e{F6`~yjq}!!h2^HO`o8#G4~q~ z9ZSK+S@`)#6KhJrbS)d_MkJiVX; z_i*aiCJ{F$^H^}kaut7(`(CLyd@l?#K@VcX6gt18VfR~<8c9-SN$W{vYmp_glT*;Q z{PE7pwBmOkL*VA%_qDWWe1)P#A_-Y`-tm75&?%t$v8SNw_$z8XK*(L~MPaH7wcN99 zo3WWS2V`MZf=)!Neb70qX1p2iX;J7YoKp-~SaFWm+}g#?o@FVYM@=RJ%5r=>{&mvW3%i?u>3Y|)!%-aQ$#)+qfm4!1lqiWMHtnoEy<(`F|LOUVyS zT){^wlMlurI_~ipGtplb&VLESUrl44Kk0q>oZ`4`>c%DFuO&9DDgtLWg_Bft9@>~! zHnEg)>Bhpz*gSn8f9t7(I&-XM6Z$J zLxgnWF@49Th;CHvyx(UZj3 zBp6;aoN}jAK8dMI3;nL%N+06gh@{G zY+JK50G}H*Y6x5%a32FHU2VotsWxgmR$h4Q_L!o6(tUo*r>!?p|j|* zl>1jYWC3w(yAg9>xAEVv`3%>0zzkm=!52xMn&ioYt={Fp_hLCtFsZhKH2Y2d$ZgV{ zU5r!#vvS#lx#_|Lx74EbxZ_g`6Rgv>nTyq#$Ix?DZL+zBm)dHVC7h7zgrr;L(cx6`hY%vDL}Y00CY zC(M5wslQ9e7MCZ|{uwQ2lxN1iKGxTok;o=xM~%;YzJ!^T#ui z6h=wjlFqK#Z0f9>e~6yNlY&F;v3MfJJFy3DXc-S$%>ou^j$7TDL>K{B5+PuQp2dI~ z0=C7n6r!>d%N}$~Jd;F6X%B36vLYntIk93gQoe7S7jMMltYUsU^o+Ak=Yr#Y+-H1%N(iPagq}^eCfT^ZpKI` z*}2Gz-UMHYjGnxVV|N?fg-j#!_X;O?BUJ1Vzwg+JayBf_22eu+b6vbiWpTfI0iK;v1#o<-$y{kl{z zLMIVJ>AW{76v4@$SBO~SY+l2a4gkX+d8F0Jym5|QzFmIock0mlnx}k9b&b6Gk>cwCIeNFb z=m9)fho2I2DxN7Q_0`W`HX3zH<%a?U8O5o6zagN7JGn6>)MjiM6&_UOhD-O=t2v=g8`BP?}t^MThx`e|g0fn*c3iOy;A z02sK3*4V?;lk}&5*=YDGGzmECnrxuFkg1-GEbAU3V+aR}H*s>Xl(0!qdSb#V_e!;y zWi9DM!CRnRTKl3zL$$78#vmxRMh3E z2D_XJ3@}nyMzr&aplCn;pR-u0R*Z3*pRKl&9o^vBTai6Y;oM@9+;lPcFscC z7T5ve%xL+N$dn@#d{Uk(j$fE*rTv_yknqNCj6&BgUS0vGMm1jgtnKhe`XG;Q><24< za-38sqAEy#vq*61lSbiM3!4mN_k@fuz|H-{vH0uNW_lTFZAtB_454hR`wb6mm?%=7 zh8F=*@%wyN;ZO20M8j}+S1`E-<4%P2CW7R_%Lu(N>wlOFKWbx0denDl;c?IfjZ-!5 z;f4fsO1G8J0nd^mEe?TC!Z#?rh9xj)!cM7dn}t6Z;uOwfTwKCMEj67!g>56p)=jV-F9bGLkEY) zILN-dz>(E-Q3s!B1$%T(1q@Bduje$hEhGZ7o|ysY!v+E(1QiR28Qixhz}>x^q^pUN zz4$S?G27KOqpT;tdg)x>%HfwI(ovhWyllq6Vfy7z1hcTXU2)kw(phnn3@2f8^0kyr zbZhZ5JS8z~vyW1;Xf75ztySeQeGwGtHg*ic$*u8v5SeTg4Msg z0A%^dKg*J{dT$jkA6=-6I3^C!aE0MdkRu9+^eiCM?Q)hvnlc7*CkqL{SKIo8o#t)_ z++Wzlv*7!166tCP;<9am6sAJDb%z|uMscVhHe;TP_yWd!mW?*XIRk`1ii)fy0B5ZJ zQW2TXfW zOP5K?o)Jbz0uG_)N@(*#ylQUkwyILcMLz7ew1ti4==qTvS60nPWb?lWmQ3nQwl3OK zBn{0WSJbHaL1msfVH=)#k4n24NMHHe)Zu3m!r)0t`}%f-Ydtka&a& z$h!!yh;Z)0Dr(9Vay)1Y3S}j-4!Q$1G&FxlZ2b3-Hj>Y-0Ri5JQ7RzIgniG!7VSMu z9hn<$<;1Axr)HdxPV3N>+cq)q_(zxLJG~x5InY==+`$`k>jp`=L1`BX@6VODUy2n) zSxW1;?@?@nXhz|rsv|X6a`(N+o9%9AGKgylF=d@q9-fr~cC+nB02F;gD|%aQ1!ERnQd zoTejKLqbQvNqJ=ZBBH|+vEfKv3vUqmKZF7A2+j$8cX0GJpD!ff96oV~b6wDNJ#BrA zi=!5-795y3FYujoCw@N}@3F9028)G|slnGhwo0oW33@gU?`d5e!5~zxa9az83_0Sg zasBY0P`#r}j<8SV^2{fGHz7NY^Hl}o-a{$=Y-!{phy#Bocv5>#i}Vk5s4hx4hYiT* zJ_~AJ@<*KEs{r#}&7h!E!%{XdecOibw0ccN!`d|lcx8`G(tD%r3ZZbO74sf-BJwIZ7b73E_W7V62cDeGQd8L@m z)8Ce!zJT?-;gCmJ|MA0Yeibp8cZ1@)@U7?B<3*B>ur1U%wd4$pEkH4M>Hxpn+Gxr^ ze{rQfHPa{(E~j109PQLdNjNY6l;NH!>Y@0vmXD4~n4uqikqbB?4lwg=+&F+vCW~RV zfyJ(>ibtTlI7GSs-u23$%z!0lN*om?0vSw`M;2$5EE+R4`fYK6ikGu=2A*MJEde3b z;S7=IRiZRcW6}LjJkzGjQaeX~>5pHPiBJ`5U9_JjLT4PU5G~N(roWyK1?%cF9yZ?5 zu)8(X$~fdC8oHyVl-14uaM59XVvb7r?8PzPD`QQ<34C9@4R zRlr^yzFy7?S0d1a>;qeEt}A?~alK_YaUN1-2G@-l1i`s#CO50z+51BfR8{6&7oP zONye#-4oB*2NfpP(HJg>(S*=b|B2%Bc7;{MnO>hGKh=b!^_bC5*^ZJ738hn*Km`zI zQiR$vWEu?c#{dZ0^{E`D7uiF5Nd)=M#`A_O=^B0F6i^wA*N&UM)i+e~GtVq9LM@w= z8{zAB+iYJ_CxF|FWeTi||GU-M3t#%*2mG-)}H+Y16a=wPQ zi^RSSPZ=laAS0L|YgO@xjl4Fxs&q!x&ih);_NgLdji@4M(S5Z-bk=?AEv{|7YW3_e zei1CM`E)=U2d$D#7wFAY*&&xbHN2mt7vNi&JBOZt@THn7wt9VO?2((SNj zFwHbIcYDi&Z4#lxKH%&_P>cWSiccJKIYC)=gOV9VIwRJQQjJeCMmx`JH^!liT{rJ) z%8_=}z{*H;4tbS`LPR@{H!TM3#t;o&%=j(gF{+Zbr(mN_t(%-<1YFzqV;o3-wz74b z`$88s^T0>|Iy@S#nAOD$7GPjOnB_yYLlnS|JfZv_06Rd$zvv6gi{Hf0dI5(wFo4`c zhqe?JLv=U^<;X#p=MblN#GX6M-Na>7)W55roZs9v@zW=J+^?hh`T8FBN_uU*k={b@ zsQ1zb>tpnV`ba%OAEXbqChAH|X}2S$iZsy_L3?;MG_Ch>49*gATCGxOjOB5~$Kfq2 z>9r0w2o2v||5{j$@Z@r-av6(PzIb{Xo#uVw00+r6a+vHPTX7tgk@;jM8Apbb5!mOe zNp5Kaxo`hSj1~p?=maL^lNtb`bH)*YUF1r#tK3+ATClbE7HJRZj<`HgS|&}GCP*Ws z9@1zj2P&6}#-Y+|r!Lm>+5k34OVl=KzuJC1^3N-*KG)UHuoXgm8^ts6mr;dXpOABs z1N6Zwy+S%mH_0Tsd14o@!DE<=xSKP5{;|Yo^N*j_2&c_ZJwxB)D6(RdgZ@Y_k-9p2 zOL>rDubNeZ+D_e|WUy3JN);Pht7Ld|wMT_(7Z~Q1C!h; zEPp-2t$vKZ9@tJ|MvfMX_?~EIx7N@ARaPR&24N73{kz}p9Y)y|KFl`rwl002&&jXs z^U3vbpHCgz3V2uBzR8J*)M@)Bw}`#A-){QwdsJ^ks&Lg!dKNv89;g@6OX-#MIv7>0 z^v?PSy@P&I@2(fIX0gUbg}b~nMZ z8q?)ISA)3fsAjgbQm?4fRacqFbwW4SxDno=-r}&-GS%hzYRfz^P#b!ZDkL{4CB+&y zysOW4@pj0Ui!f)m{_V<)_p6*MkQIML+@hE@HFaTk1nQBEsPG3sA7~G4(tnkw;#byi z5=b=B$aC_5T*c=RGKt)_#ZD80Dx$=0el~d)86zDcz3|-uq#T?eF5XiE^7y-Z9v~;k z3uywmZLCU?Qnw&W??WfKkqu)j{?z^duB$sC_Rc}n-OXpC(z=~m2lA5^kQ0g`^O(U8 zioi|M01_lKc)Dba>c{KrC3t9(O8m$xR17bO5j9*Sd5UcYD#R6to)?|0*2d^YIO3l- z_S5h68(lwH@7am*?jk1gJK`Ka7h`gt3R}o^P+=3)LuXVRHhXN8oah-cjmDA%KBanEzUZ z*YCfvRWp5W&6gEcU#ls4U)5R#ak8q|CW6HrJxnZ)+vkyywt(Gq8`Lr-LkXX8LA}+@ z$}rVmF)A6e=OwFY4?~1lA$~)peiie213!d1iAL9Oy#}kuWtfk5+!Xy{JMZNMGpa(q zr>vBl$-}bEAW1Mrnob%fH|6<6Cd3U3=4(;gnnBI<-O>NIJ$LVOan>if_~~!Mx#{tu zx&BZTu@ZfA+%u0$)RpEp^`kL#KWeoaroxUJoORPucuISt-kwAU(Y~m^+t4Po9<5Hx zqxx29L7Ln4D}rv+o+hB$*MP%m)Le(rg|4N$;c%WZxtw9CX%)?tx0LFfwzF8Rube1S zu;$QkUS)Ej6@DqEPDCenrRwCRWI$$pAw8DvNN1&oh~d%F3F9-#!9|P8%Tf|A7_G+M z(ogvJm5A^YrNP(&q>WOjaj6vTP+5=H*0C@xGoPugj6Uw#PTFNWCYhzSQa`D)3+)$8XqPl*`@KOs+wTqL{8xMD|G2uenr}eNj7Qf-^)0-7f(N-s%D_y-pS6eu zD_|b_|26Jo(|>8xL2SoZxyc`)M@@72XL+dpfMZAoY@Ej zNw6eHAlZ9^ySpY3N^vOeP~6>J3KT8H-QA_QLvbm-cjj)~i2TlODNf(^eZT+b`9J&I zkUmW|cW2J|$elB1+id5 zIg;uwF1<*{WXRw2=?;1MHZbrtq?fH7yAP6T>Wt5^C)~$F&SBAY$r;}gIZ1)P5;rM3 zI>vN#_2c`&myf02*h8;vxDHp~LY#$@a5N6VzStGpVRPcdI#`unp;(c=%SQS;2fog= z*R;_TVR{oZtH@Jzzq+sHipUBPWh2uXEowBpa^K+N#=ZtmaI>o+0<`Pq?xZ>fn3vf0 zA#5`rG@l`5ec$}T9BocDJKLTZ1ikZ$AD-=w`H#!;W7ekqPMk%BgS3*ojbLcFb`(~6OOj}2e<{-_$eo`&5 zGy|TxQTnC3;}p0+ku#Xj#rj#iir6V8WkAScpAr;X=bhHQkVZ$UCxxeo&e$XXWaoI;wCkL4~Jg znDkuH)paGa79Wa>cx!%$H{@N7eff+mj|v}A3#q>=yVMp1Zg|z?Q8dS|aVEw1Je-E( za2T;scUu?1D7y3NSl-rQFDG&H3kV>OR0@FkB<~dWB}BJyiNK3&I%%i``oE)m;tRDj z)ieE;#{n1MT+->|AOc!LeNtEz>GxE~1tsA&YXmu12~gac$63r3ll(j{u;%2O#*TJ^Cc6hspb{hEc1TzR`YW6K3kq#`~M_QCfM?16~({_ zx_sp#@?5V)*|@>(SMU_L@@B+zL-OWPUzmc_ImB7*l%=NaVMns9hSx4DEF+17Z)x>O z`E(U8wYD-^>!0|@a~OU8EI6H_eFGe0d7*JyaZyHQC6!%_ zqPBD+k9$oXwEXH+g%BzqUxhF6CY~omJ4HJ4DRzOUc+N4mWx8xD{}5p^R%H9C!~1#{ zvyUB~br)}d-dlIqf3(!oqf=aXAa}@-O2Xz7>HfO4%Nx$Z)Qm<35)`ePov2$k?GtBARr z()3G&OhrjY*CVC)_ciZ-Cu251kUUImu$}0)CJfBnK*5p?)FHa-A5sN0i2mOr; zaDR>(ro+k&WxBdsX%fCvSy%RSqmhwoBPT@a5lb5KGFihsmF_u5vOb3_?!>MmD#U^1uL5AcG%SHZyzlp=ayy#&c^nD_UM{sE$)kD?cbj zl%9$fR!a#COvTrvzXQO+3W5(QG;li}lV2+<+{q(X)p~x^%Y3=5C@Dq{2WTEX6nD*k=a*{lS3(gwo$a7 z(rf8ynf-V;t~M(Ce!v?gQ(2_$Q%9)1)TU~bvRpY9+{{og-c2r$t4J&DCMNiHPyJf* zJ6qkzCeqg@_3z}w)Oj$86vkwJ4@VmxVM30zri)5dHAUH^TnydmR~5RWCH0AIXH+6Z z{56_~Pucjdo)3*kSA9=+TwdV}^dy0RgoXn5Qa2yoE(jL9y7RphwS-hiX4ssuTNxzh(-|U5(ylWL~X{wOJ4)5Xx z+un?`a0>RpHrN8IiG^=MB-|q>_$YgwP-Y4$?2u&z1mk3%U4=|xd2;;0cEC1vk8Nf1 z*e=5JUs$H$55p6WmkB?b?ZiTJPVGLSb;>85yz9_4Un{NoiTheU%LAt|z*t{+!HPk4 z@CF}pbQf7p*lXb6WM}P0GDWMU4WZxa{ZSX?ukYdcP>s@nt~nH4PBKMIwY+eei0;rE zpFkgq+}u1CnrD9&wl(j1(z{#W3i-(+tRmZ%a!e~EZ)wE^qj$>v54_@q&%ENdn0(Sl zOnz1#CQP(Q4?S7mt{=8r#3$fRK8(-gKa;B(&4-Y$D#YjWoH(Bkak^otK$tvNzLdWZ zQfJCtGOOjZ)ZR8G+-<_I@$&q(u_BM~@2fbdht&dVxVk#j*YBbA1P;&c^mRNb*xfjS zq9h0R@p34*rI4fdN<54X*b424-QDP`wXfK;LShv<$vyCVqFoKN({6_K9G}Tg1$i3dz%hhF_;hFLwS8Z%NWe3`9~?1aY_MA(_I)rIodZ!_a1KiH$vKeeP8_pWAsjRf2C+nNBU0bKck-msC zUo`9VN-;ZXp!sR}v{0?2?Fn~Nt?m0K+#itba}DYz@{+sE&d&T}3PgEwBJNB@=eyg)ltep=rEnl`_cGM~MpV$%FkHn_h;Yf>y5+lEXLA z@Y+x&DYsTr*b(X%qj75RjtBewBOd&CKgQoz8+ynzQCbEO-saMO(0ke=KMZbs7wMo^ z^ogALbV$by&Zg+Tlqs5MM4Czcq7G{?#oQEfsW-{-SoGD>C#@=}-(bo)16_A$d;(y8 zN>zD5?;syhzV48RzOfH3P%okv*DL5X^+x*ldV77e-az-VWYs4`uhvJseU?98QBa2z z`yo6})oD%Knp|qKr%BExE1L9+9NhR~rCQm6FXkNQB4QEDYU}QhPH}93R}{;4z>2^J z$sctA4f?VtkmTfUnIpdwSCUQa0*fGIt^vu`y)cN7+v`j|m#j|=PxvNQ&VOszo3Os7 zO{Or@EK&pu!tN9?W=l5Ah0}&btdHTeA2Q5j;oGID@E zR1Qn;Nh9$RtMZrF%9!7{E!W`cuOs_>pV52QfDOHOeV-IDHbRuSV(O`^4;vABCFdnO zT`tomXqjeJb0#0~|A%fv8$art@P;tkPA{yd$ZD1#eN1`^-Xlc6%scZ3#NeDKGnu?d z=CkaV<>+U!>yCOu-B(|&ztG1;7j~{@JcNOyu&;9;;{ZOz=*eGtSIBwUD=#l=4CGG6 z5Z=i+glEeVRoD>zL~#%AtZq@esz0irMyffLd&=yP?pbE1C+K$4C*iC|5>zI&eH6U# z4d`$W;)vH{NL|&3dY*d{_G!iCRjmy%twK8N%kIq^| zNVzT}tvW`;lgqrGu*I_qjn^(xV>59GHYAmo1YL{|y~^QtPEc>z} z#n&=5j;`wRoIu?uSI5P>|BkPSWk=&3+>RSbRZJq>9fX4@qUxomi8y(SK3Af!RzhY9 z_ji@BVU#Pi={4QD7NkqLA@LP9E7(Cjqij)IsT0)3sy8X`)utTkwLDAlJHzROf?}mC zOqkzGY?e1g`}7Oe=Lc8}AHa7w05-uEPrpQ8V%AV{%6-TU%>F;g*Sqo$sgb@CvN$39 z5E1|>79XcT<63kxF6LMG8GexO;am6`zKk#6)A@Klod3wXzdu8#%DerRg}EnJxgYt@ zU}FPpkhgBWZTQrXJ7Wc^ro z){V7dfvi8{hOVqrrcMa>!o13SixB>TZ4b}m_j`DJKHJ0d^*y;?TQ96i=+K#1dVrWJ zUklHS=imp~Fc)5eI@lDpLP^iA2`=K8G;31&i`1lZhFO&VrSLwK$CISen!r@(<#{0? zM(Zx!N$u33ck52NdJ?_kBg&J#a*i;@*YjwMb6`2eeIKlaRWO2-N)Tp3Ae4g}Z@Y?x zvMojGbjqhi|6xDamuKUQCM7` z@ebQ=kVjwir!PlpuroQ_DYCuZM89RHa0&IfD=)xH1ma$QkXBW+ATj5b1(x zg*@KQ5^v;E^8Huo^^~-DJgHDO(vzv8g^sfA+qK|K^L2-Gbq2X9h3^D~-}e}uw8=Sv z7liEGM0&D6_QmexvLorcwiM4bxDyW`)@*7zt2{DoHgyd>nYBI~@mL(cP@9(c(4#dR zXUid!Tv!A&g(}bz(pg97#$K?q?kD4lX>&vw($OPH)%^NSiT&w-|GWNy|D+c7SJKOx zTqz&wLbgnNZnzaVK}9uLjaRRzr@~8x+gIBYIi`F$)k)o}lrHGu6@&*p*2XmyWr@=l z5f^uTcL!f%n7{6T{cSzUx1U!2RgY4Ebk=CSsBUjb)gfl0Q&^U3g>n~dquviM5k4@y za(L-*-|!o1y1Gy~r0&UgpRhaukKh$tVC!fy0@o6kZ6v?bf(PV#s_Zo_SGJi7n;zw? z2km%y!&uLo&>t31+>eCmP=xXzJ9EZR`(c*Tj`5I-Z6_X%f-+FdRwtMba+0>;fDp?{ z!ddnV_Ol6DybE6}vc+!%n*}}De%6CcX4P3&=ElYw_Ikcf>S%tbjWG-J5%U>B>c5_F z|2JJUvyro^NjcD86r~YtYZrjm8R8RI4f!#Zor13J`Qu!KB4da{!YDpIRQJsgQ^jub zTy`|$b@Z|66|$ulnXg1Camrz3qViZ7Ze(2d019EVBAUE+49G>lu&`C-iB}N&h>{f;`$crK#5-q$ONKz0%mmxXR7z9!{K*F@ zS{Bj@U#^EQB|mtboIQw@qJd1XI|_{mxmr?wY^50g0YcpF$NZ|T6T>u5v4;@quR2uc zul5`K{AtoL;`6%{C86?wD5f73`;%e}_<}eqV#GB=C8!m<__`OGP{6uj^ z4ihL3k_z~;OMC@Vf!$?GIZw9G2kDjUtMcd2oj=9_{5F4J+#Z~&^i(z#{L$Ohdrg6i z@Ws`$G`Smbvhjlm)>y4|M4hf^gT#uX=>4qTSdKejJxGBPnSu0fOX&{QQO2(MthPi@mL-U~@}6j- zKN97WtFwmWQetQ}9@(BepTT|QVl#igTu1F6R)U50J0* zDe^_)9)pQr#$QQKkLKSICb#8f`2b#&l(&U@c~uQ|2=ArrQzO)D}W|5(1+B_Sgjy=!G?N0$4gL<-GOZ68#%V)=L1VCZNmJO zs$nxt#{(}zKlshXHM$I`pR4BDT9P@>KdMG~L7A9aXj)&2m{5IR`dHWcH_8zWjD@`gsEGJsh#y2`XkFor`6mahw%WOj)Qql zY`|x@wTfLpd{R@Mr^s4Kj%%KLBiG0pdQZJ+bVcXKya^uR<@qSylXoUB)s|P_`3Pe< z#-q&qU7oQtm)lcH!x&=g^2FNVwpwU^ehU401jSpjp;eMm@1cL67J*M;KjGk76r{H@ zaVuQHS?+`4Zpo|`vmNJc-~uVJSvZf-a?HDGj`r9B8%tkm>gD~r#oc(5Hwh&@9qnxUH%gp5CtRE@; zT>J_mfAd*I_owSOANPcKc4j*&13*Sy(8aZ%1fvGzPgSS3`d_?GJS@70Y*y1waGmd-`>AL9Ma* zH}gR9iYv^U%zMno$u0hM{_4l|P!;}lJ=A}ycK!1#-2{>GMUBO$C*-b_ljSSNT%G?(i2%mhge<3U#TnTv?HCx!dd5&K6InXSf1RVkhFoNu=zCQjB!_ zs0vfH?umj>+)w&iWyTbDab4yS{p3?IF1obS>YUDDHI#hH0j0e%Rf$k)C@QJJoQhXi zR+CfCjCcdFR6auUidt{2+yC^0dlOwcX_n@M;pZ&q{2W`taq?m1aXZ$4mAJ}fU33;X zNp2Q7^ae6Z=6Co5jH5Vci4zFpmXlr>gUK$@(bq*=Qa?J4>$%VN=6`qs^Z7IIF}5x{ z%WZqy|2(1RmVETpp39Z=+IpnkLhnG?IzS((Pts>oUi_l()0gWRbd9!Duq=t~?H1@& zj!*G^%#Y^@4ewR?cK4HmG6xhLe0M;lLE&BNHt~$|syn3E6t%T7P+1W2z-K+o!U(tq zT?lJ?K__Sp4WS)muyK%wHHSJb$1KspMGQ`~c+O`hSUnJ|5n*c?7|tfL=N{z~>S{e@ zH&N2g+UK_@++z;lNT?pq{;U?GSxm$mx4729NJW2lyL%$!wRGzV(-nuF$J zTh}S_Ze1tpqjept|Jrc2?!gAb6Cp~i=z9&973=P;mFgQn9a#8lL)v|~S z6!RbV5Bzq=x?QAv&yk-$DE##+BH(RDI0LOnyA35Ja|SDswrq*Ved-lDt^^mU?Kju> zOM&^yY|}i2o9>xf<=PFyu?w_-3Qzz7X;hY{UDOtf8QNxYfj^O7{`yLk^(kZ(5ki_m zrFgg{k}S)d2jW}S60KEO)$tao!OG4XEIUXosbVR8-r@gpCF<`_)R z=%w_^dX!$BVyUx!Opmf8SSC1jGiG8_V;s+E3^tzQRgE{Wn6Z{imKclv+HzN)Z@-Ce z=CzGQeQSo?53j7g41cI5hW8KOQM^^%9ZljRJ2Y7o`9tI1s^wNp>VcpgZ##>p(wkgI zr1TJPlC!a5qzGbR2S~#4OK%Khg0ItPeUdCC#;3Gmi&;bH4C9EQ zuY(188MXYS3eWT@1{y46<6)1XCM0A!!RSU`{ctCJ$La2FyZ;iGu9cJV+C;*s?`$gcuU=*=#3XW3vqWoh zPr0KvI^V)5ID+BCN}UK#n_z4D-rAo$H!KIQ^i5)koI#lOinM%pnJykgUw7GtwP7nF zTKA#mB_?~~`NXgUA3!;Dpx=8Ac61-vVH)d`>Mf2*d#TCt_F;I1<-+4Mjv9^Q1Gr_Y z6g&!hVH>O?g|?1RVy; za5*4$n_C@jfjN8@-si=5O`rOOcB+MyCF)Jn1%>6^4KsN|r;?T;(ov3}_nJzX^5K0Y zT}9+;F`LxRIm;EN{QM65fyek_e3EmNX|1x-6rpwtywBg_aP+|_8ifX!$UHICbyrM1 zkzX3gDOV$H@wJY|Ut`U$RpU_vDW=`G*)d(f<1VISfxyo9IewSiR2MQn!_ zJ_NGn?jM+mC5^x1Z@E?wZ*EhzD20{VN}y?&(y36mZ%J2E>{QKJb|Eymo-q)rvtfj1 zO`$#Ee?zDRm7p{fg~AX70l**!m`O`tXJ$iw=Jd9))=&(j96)hI^R%3GY64|h2;~(q zgI98abEdIji%qVk#IX8d1w+^RZ?#X8L0VyLHffok&4OE7iI>1z1nUdQbit*nan(I#} z4)T#kFGxz_-=6#Qp>sl4a*M-=^SjC$`XCwgR+6T0|2!>nhFnFlB}ti#)V+1b*bLV*ygeS}`S}FikQe9Q^DqQn!_KHL zv%HXj@!Q?cf7K2=BN}iQOyK z$l0WUqA6RN%3owI%SOky*dHF!-&<)r3)HHv2NN=N!M51UcH%-6Eb|W0{7GS1*W@z^ zmF@8);na2*MQGIA>A2fHz8^Z}Rg_aY<_+_V-VDU-t0Fv ziuEMVSc7#j%rKNr-DiHPZK24!XTD*6{a#mR`OMjM`Ak=Tswcm`&)`3uR7rkAbe3ij zu7}E3am73`$wLg_UD3>+;xb=LNISKR(n`Hxs;2DDIWUoYtrLD2qk0 z2nNx3TB~(jFcBQ_GP%+1aGS-jDQ|;BZRt<5oL>x-#l^(bb1aCEK9yX0CXMz}Qi#uC zB>DDL>^?klIS?I8QE*d>5{{&@tgEYa=~^y=h@l3HS+Re(Rm7su1@A!$nD81aii_;; zko($5JU)-q*!WLQb2$8s+QG75U^j@N9b(HvnF!TffC@Syh};Sh$4 ziH&C1>Hz!G9Q0r>;E;n+-$Em3N2+Roc$_{KHnL;H{A=JKtfsH)U_3m8Ix)lNL8^GG#L@4RQ*pqtps(Xu1>nICNsp$DS?VUd9=%lD5>`(>&kY)jXYE|LNS} ze_vty`Ch$`D~m4C>$&ii_k~H%6rO3PNrR2Wow$Rp@%#)n^Y>L+hwSk!iUHgMhoL?8 zLTTM|i)VZq6s}jWu~&I4hMgcC8nc5CVCOC`kjb#`PBCZd9JDs%pPo!t8&+hNOuO391BHBnzpdKL?#NKtw%HI$} zE}_4E1@GbkWPBLj{n1$VI{(XXz$=_3`pi#w45zPjC^< z+d5Kw{R68iITWSP0q?fx&pmMn1`~(3%~Q*?-PEu^lvfh8#O{O(17J1`BLwIP9c{Zg zz6TQoLm*^l8(ICdz1l)Cj(o_kG!7fT(Qhc2a&eeQ)7r^=qHX*LkB6l2%HtMz2|65N zry(Wd524Ctq-ffcPi_0vZis(>HpPdP{V_CdQ{*3{aNg+sqy%=&C?F8Ab@_3w<@L7d`d6V(43Mr;x{tdlIq@Ka{|lg`nt~uB()wy z`N?D_;@aQi(KCbGe;xiC%|#q0(_OvBCwK?1;#oXS*|q(B<>r+4&n?>#zjh*L)tZ#a zPcYc9BhgXbmsMgCT$^D*=!dt-V_Ds38oXq4VM6*U(NcD!5$!K#$j#z%+5(!#EQDzd z@Fke|Em)IvYLQ6gm}#YAuY?gxn8Q|^d~>fN1s=ofGdx6X(N7zst<$2kEn=b8@a+gz zhIv6gKu{qI_<;vxgZ-=&oHG=Molf~JleK!ntksahE&?taLg6$^X0hxAd(2+5nal&` z7+he!V*z~>MNYE0m6lbj{0$xSd3ITKP;Ox)cV3F{G?cVmqFp%NW+prgWl5`D#8D7?NI;`1mn7&CTbD&M|G|; z&onQ`XspQxc`k#q#6Le_4e}bC;$k2eaF|E4`0vT{Hxqtxh=`VJMV+^eVG5`eFXbp| zYQNiuUgF(8bU$=MZ;F5?l=pQjJmet2s$eTx2z8W-^0=-BXP9wgq10Fb@f#+zr&0_*bDtp30l%Gr|O)E`5 znLtTLrUPSuhLr>$xk9ryxdsh$D>Z6{(6~&-@kkIJI1C#mcQTU z^)&`4L)ReUfm@^s9$St&_2#djA-OUyZpV*c4!#+(@(T{P^;9`QR+n?h+fC9}NWYAq zXg1TWt0w5qEnlF>dh$s#u|LkkrZ5xlWGvF>$naz*)(m&TRqltavp9s*D7&Dcq4Ai= zSCO8PWgGobW;iPIhlB1n2N0UPOS`A>lOqVV?>VA42 zy^tQRm(?5TrS(~QEj?CemXMedE+>qaakbZKKF$A}5~r33pAyc(cZbI*V~d95FO-jm z=TaxB8`TEtK(!*}Evjzn&x(^e%=AF%p8vTqfU<9*ZOw58>kWC`8pKG7jc4(Jo*rH zrR*m{*D-7?>&q(AzafThYKZ>%Vs$$r9L3f$4`-4`R@sEl3&ZG8H%7kaAuHiYtU#gGPlWK2u zpITCxq51{oHHP!k0?_2+0V#P7N&4!b!FjR>%LG)WHimLR?G^WsW=^wg&uW@>04ew@qD5gZvMGD8(~LWUqx%Lb+Ya6`X^^J{k6toWvC&ZYF*4&`=}UC>G12#E&CwztvLAlzYUu*c)!cu`{e7 zT<(WKs9-kIW`kj5+8nV;j<)SMKSi4CnLJAVa}FUwC2~XILob=$<~f07@BxkUdFI4^N?D{i$!!`JuPE-{ezmrw{TFfn8)<7Uw~Iv- zIxc!UW6@KVmlf2gEdzkou|EMVaz>mysgGT0an9t(Q6V z+?G(sCj1VR=I4ovGKl$o_+k35R!;MytLsxTr=S@QU<^(~C*vTTnRBLToHA5tqyAtj zrM3*dz!O+V>KkpNbS6w`B)$`!KJo)UzxM-wbvlXr+jDn5?R0WXUYF-&qO{Xpb+k;@ zGc!l>g}8%H=kxhGKI@A!D(k;Hqq4~RGb)|A6Zzj5%)>`xUE?6=65tygY%F1{$S?XY zQ_Ut;!7H+CWR=E2kxL`z*FRjccA@4z9?5Mes;sA7tkddf2SroOE9I1-CljO-T%inP zC#3fS4({LpZ*41>PuU}Oi_K>`8*4DLUUrMbb;^t!S_$n3&0ec2N@_u|ecduy9#)?6 zh>^Y*><)`&%h?~SCdhn_Fo9Hm?5jxygq!^1gKjsx=RSDE58CNSTL( z&Ky<@)`J(hcXu2LIl-B|PQIaSlc%-WGK;7Y-^JsKwcZg|(a&rq4LO27L4FpIaz|?* z$CTtpH1oESbs-yl!DHIV`;#z*mDdAs$$={1ZvL5ARTPb8S``&1PHt0lJBMfuXIA@NBnHg3y`DGWBAg;T-ve7= zEv$frFqK}zh;0`_Fk1*c>|7~xI*KCcm7p5y3e^a2`a(LJ48>V}xb6}VeUN7L=h#U1 zY|xhtfLK@>vNMauoeV5wR*%C*9xGQC@p2+O<&hnNL+!v(kv zCv9uTd%^k?rX{-t6CKjzRMA8{)Cveq^Z6ghCH2> z{OTArP3@)b3m>X3s`wysLghXxR|hGcg`<6fA%s0hWTJ%BwN8WfFM31Irl?@eD4x&ad!5<81!O_%mg;&q*sAf^RtEH8P%EXZG zd``h1hN_7@#B5oIP=Ac=l-7S+IrbB2cC+j*_vl;Xu=sNxeMy;bQyK&g)_! zj7sYx_vt^%6?brF`Kt$_>*KrG_$1 ziB!rfC6#2;OVe@F;jq-OoB_AkbC|`h8R85tQ+jCkL`fOq;041C(X1QW!hT^b*fG|? zaEx8HTP0>|Wwg8I9NKfUr{=EtXaQOQEnF*4&OSnGNjkg>Mc+Ddf=7hCxR;i}>ai*i zLFhk({=#jx)WaNKTH7faX-_CKc2I`=-<~#5oo4e#V)Nw`D|7TQ_SJYQROYdyCjGc8 zw<9Kv!)@rvmylyT=5SemK;F#S!MnNMP3B6kkFgMkDfkAxjTQL*yd9O&N=C>a-%&Wh zI2VKRY*pr%(v`=ino9qW3tlcc1{Xe_B@h-Phci%{yi63-gBs*yN|L@QNST!lvcN^A z!Vv>0BKt}*jy`c^ZHm@F8}tvl0et94)!5eWw$CSh$#=c)Oa5tvRe>)mto}OjZ-ZPZ zFUou5Devp+^huecjHPg7wt8X1)M;vKwW9hubh6(8oJ;YS%z{!*iRJnhF-1=jClii) zZlH)a^2MY=PU3H*&M#tbynt~~1f2}+6GwhAlFLbfU!r@z|BY^mHEcVH+LLo`OUk<;dD=B{Zrn5X?z{!%fg^9m z!%1J4;QqWcH}S$eyKxaOk++-LPU)c5RyC!$T1DBUEGsfI>lrXmmZcFd4xtEqYcM4b z5nJRs%R^^hT+0mD7cRp}7zsO|8>y3=nY$^be8}5nv#rGeaZ{YuOQvXnN!1Mfpbv1| z3+eQ3pKG9{Fc%gRvLAqoY#&^9oU4}?4aH_Hi`Y-^6|YsIO#M#&VyDAw_6(-b-#biN z=_IM-^H2}BU`p;bN|n5CF%4EhdD08N=00jF7k0zcAgs12X8|YUNOsiyNbGs@Ic>h# zU%P0wyxVVYJt@}O$I80j-rC3Nhfg|r@6tAq0(wIFMAa}vS zq?9jWJzfH@Vm;5o34XGp?km^I#x&1^zBrTP8|0N(VZ{O z<{#E1e5E=*+@dxNKcZr|NiC(G4_)E6loapW)ONZihbGTwc`5cTkczuNDsB%xAts9T ztd%%SB+5A=kGy5O_h`{b-V`vR%Bs1+xg$vdI~>A(gFojiA; zKYH;6ggr;`H2q!cso86A8RgFm%A$`?&HnQYolBS8)uSp&Av}YMUbqMVyO-h-{H>YQ0u{ zOmjkfy(3tBW*=>Ww!l2lywu#wJeOWe&Fjp&%tvge%Kv%(YQ{&WWtaWtY1tpv_C7x? zyUKsrlk_hIYVDsio7~lWy}l*NajLN@pBi{u-KM-&o2rx4iOPA!kbk?OcYJYqT3#2~ z4nqBKI6zi$B8*vpb!Fe>|(@6Orq%m&Do8Z)}+d}6D z7cyR@pSJp?-&fHj@UN4*g&Tgu;CIg**PICAF7|y7wPVnVU|hJGo75gESTc;nitP$ubwLEQ1ejK^u}YO<}^OhWJa9_MT5hG ziqy_>7vJzwe6rCksHb|*lwaMfTvqlfiHpa#>Dn_ zf5B>y>)XwO-~@|hi^^U5j*FD9N+_tlzTdhW*KZb%LSVZ-q6QspFV_Cvm?D%el5}#)z(hlPR&E^)#?Z*VIY*sM|cjT2aem9 z!qY4ZTG=o!-e-^CdpFP60O2Jq+EC(wh98|c_)kt#{c`vGUng?>`VQa!>K^=YXPm<1 z)9UE$^ay=`Wvkvja~;pX3@-R%?oAFY$ao3kc~AH7xDvXP<$+vFk$6l`)E7nvI&U-% z$I)Jsc-L&dhj|z4U2{lO&c=D80vfk&Qn>craI-2x5`3m%7Vb!@#hdcC8eU}8ag*ao z{V92ZO630Ak|Wt9hKoeeLQc_7IjqFIFrL(NJ*+|~U~OBJ6D^P*?=UBPo@xDTr$u#f zo-%P?%52tw^gsxyp@Qi0MLqYG_x0Qxh~1aKJi-WTPx>A(26Dm*XvEq<3)i2cUlSsZ zP8jHUo!wyViJv<{d+;VK+Mlm==*g^CSvquJt>Ku#%+9%ti7u$w3uzvp<hgcW7nhO|6;8LNQyE08&7$ zzf?fge{^28^;}0+Qf->(pvQ_eNvVcG6vruqudlHTpUkfsBZJ$LI-5)SETo7-)_pLS zdl=dn>fj}CCO;|R1}Um5u!@ZV?~Iuum;BQQ1QVxLBNbd%Y#`>?Aj^vWiEllx(H(zB zqh21f5CZz3fpGHAlR;m>L%0SHNZF-Pro=+3Q)^2b;^3!RJ>f|1_V0GDeR}G&la!*W zOcNXBK^brHbFR*5#`si>;=_1`ac=My^}1=gy3O=fxfjHFG(K}J9kZEqMQL)Jt!bP- zRBoLh#U4%LHb*VfBU4pntCDG2qck!7VKNkn&AP?CP=d2&7Ui`+wCSW6tgCSs z$PeWeziJ>)X>H>>c?^aa!laIrMYD)mXTU@l1%pVBccC2l9_m0#NMXYukky8gE_W?O zX#`%%2*;t|Lm5*IwzDO;&yYXc!ysW?#V*4TRt$Esd+Y$a$$GID?3`f)>*5v~d(!+? z+heY+C6dPe?^R7z(TuK5q@DZAp&}`^rh8?q2mL9>>SHn>J_jRl#<;h2#TZ$Gu>VKO z$+6^am(ukIMPYN&&$*&EIX}XRkbr*VRg*D?my*AhI=~dHRyR#mx(0^QSWj{Zi*841 z;St4jx>n#bP1W@aP4(ZOx$ub4Iy*V#AIUX#iVkr`;{>$uetd`Rl+qb|4t?L6x97dF z5dYcE!E!D72dBfl91iEcye6-}2og2?2XM~3Pxf_>_R{&hT5zKcJrJQdkaUN7zf# zx%~Z%gJ2O`%U-%xh{>t>ir40$S^=%5Hd_nSmW%w_&BXnlbJ<2#2F$DoxPm8nZZFtO znkLK**$kh-Y0|DMaS+XGf706> zv6ZcZbPX&=j9VTbKr2jORdBY;oalujCvoi-!qf#6+2<%%3X{uhYH8+l0!zVa%uC*= z3H@$mdIxX%*OA;$ReWOa=+c>6SVO!Go1g%0VgBgvJl-;ua>0|BEQE69(=J@zn?aZD0@6Oz5 z^#079asS{f%RkT2Zu&{(=yKx!^&*2DyN5nUK(ae?K*ZIg0oP(EvDzsxgNtE!VwAWg zdkc5DOa#aU;&+)tu8x`Sdfsb6@J)(^AT?e&X3C-R{HKgV@H<=#sW6jufdT0qMQ)i> zgp&)%MSuU#HTKVUEUE zoARs;MbR?)`BVQmsy@}?x8xBSs2`Ds^j3O6T!cqHqnl5?kP_h~)$-w6)pcsLVy}4S z$?F^)eVBf>u8+YBkGmpY)JRKu>5w7rpJU92_oV#&5 ziZcs7p=&xaaxlrLyST(Oq~ComzLy4BhVHSfoFMbb#d-mGA*BF$*`1h=KgR4l0aNiM zrsD$AA;-amH*((*H%F#M8=c$oq2SE>5l5`SO*j!B(pY!lOYwqFdZ9ApCOfMU$^!MW z;$1v@-5iZ)MLdu6ig*%nyYkGiKFZy|!?2CHq~*|#ks`dEIgc^J0Or9;u*&SUp*=Hu z{=h0b_TXUXF;C&aL=;sLBtZGne>=#{U`V z%vU&*zVpT7p7Y@mVeV~;so#jZ>*d~U`ptB)@PsTkAeirik{APPARGR{&cZ3T5wS^H zTe()7EHkvLaVhTCAv@&36{NN=k!HUDCqFuMYXSM2pUJ`Og|=)Wc)9)_eNmeuCfUyO zd_gKNg|6DdmskBpBuc`CdY4&?%y^HhqkTd3k*`0j0}oUK=oOXQD~A5(1gTK5QfqxEre zRq7ttiC%=2#dr^1i+@Kf`7^26HpU>VlI2j)Io~*FWemjt<82J^Z4%N`&8M_g512YA zJ#&|U0sM%=K#J*8bnmN3mCgDl$AC;E?H41GWG{I&#_U>%-+>~02}a`;dVRa1`>#$E z)~?)zune)VA2FvFq_Q5VdqrMd==GdB<84+850b~Szz*=lm4s`J?3YtS4Hktd{uI&+ zf7VzIC(Uq()Ix3Y1{GtsK|+X!QbD<`G*jLvjZBA>y@5k0$1O0J+-y4-2u-0kc+h+| zB28W1Ejng^HeNI)&pCsT_arH0Pq9;*M1P@`C6{wnoX;Hj@6aW8ya{O{r0KBfv}wL+ zVpwL_ZGS&F#@4VW^j|LGVxU# zbjQKo_X^c3^wR4xc%TQI1}8QP%Gp;Z6_ZAq{xQAR)qin1&&RvwzJB6ICEJ=}%a6KI zSohUhJ16|Pul6SK`pd6$PN=BY(j)Zd`Vaaby}f=xZ>0ZhnX3Pmu)}kKm%>ZtdadLs z+CThcsXGk{M7?U9+N4Tj$0j8!-%xw2+e2FwH2LPhrd)?bjcn0pl8Q4iUGXxGo7(8Y@4N6jD(NV@)I=b9} z(d;2qBA)CHt)K@fle$nTqbcR@ri|{;oc#b5$s=|E6O4d@unexiHGVpO^MbpKEnol~ zX4&8nyTq=rWwz6xmKz=$PNrs>vk76&ulZ^QEuR+jMNi`~pDFRjEvAQni40t1G2Hd#>{BCu>|f5kso7jV!90^rLne zcphB&Q9|z+nk(RoArl+9{2bkZJex+G3gr1e@P044PLNlctk0AzzNJSbZ;cc9TWrJ& z5mV@aCf%@4tIBV*Tdc2T@Kfs?%BA@zjg^+u)F*G{@>TW7ELz0GgVK$pPB9|T@C&I zz?%8n2Q82%=u|047ol5Kpboi911zjXn&8Tf)D~nNsSV>G3N@e;bU{7n33f0ALP#6f zU^ggclhT&A!lN@C_27T){=6BF!+vflR`ERQT3#k~CHVxQsDBNy+Uw|Qx))q%bLT;c zUHKg`5M%8C9;hy_Z_98sSRIA6 zVyI{+`ib5-Q>o_V?1MM;#rl%3Mv)>cRVURIv(-b5RI92Z)GEf_M!i)J?NVC9WidP9 zxi++{{(!tpe^mZM|4x$h5dk&b8nF}XA`M~JvHsqsS5VP6(j?5W_AG|3cOB#3TmGnP zDz}jwWgAH+y$PP?UX>oF_1tO&RMK6}zX-ic1eAp!RP_)NM#9r2Ws9h$xW$J!Iza?! z3pa@cc)$YSrgk>w6OUq91ajo-cYJebChMr@q zXl3^g!AoUH?^|naaOMls_TlGS3O8UA+(#NYh`%3!Xm|vJ$pM&T*FDDC^gfgz{uJM@%{Mb;>*U;l z`Ct3#=k8)MORPZ#OA>>`6Lp!mpBU#H!FJKTtPnCoTNX%5ux=KO)m7>Raa7#I`g&PB z6n5%0;cbi&4w;9rz7J#zSr7InlEx7>iFRa@oysPx5vPz`%BshNq@Gk;8b4UwW?kt? z{JO#HDr?AswYOOjw{Zbfww34k*LCg7=CRY%o1LLga$S|1kE&jco}r^*6#e9|Ebchp zDW-D|aTY7rC#+l_c|GxlzroKkCw95L59WmrTZoZL@O?aF)2O${;b41xG2P_y2^D;$ zp7KatODU>QHTow#gv_@db#z?L^|+R(1@)l@dc;!Z`z*fZ`z)5oi~ETVoX90Iz+pvf zd2Y*_$A5HOi^S~(i-;YpAdg8mlCFtyev*92P?LW!G&M(H#hgwHKie~M@fWjUs$c}R z!ZW%T|GY!gL3L+g8alKyl<<_LZnBjY`C z`YlEMf0(*sz=tJjbTY4}<`Z5Sf59hMjptw=J%$uFkJd!BUG1{2cx$P!^vJ)w>v(i5 z$I#oIBn4=Fi+1ROW+7ut;q8zya`(J4b$##<>-c4)+YWJ?9d6K#V5GHaDpKEmR+skl zC>wGHDa}J3Ds7fVNCS0ubhCWCp+BwT=oY_MIgeUUfL}&J`f@KSZ?3hFjdQr#^qCf8 zw%)=V@f735di9Rgc^VE|u=4k#U1>`sgI3gTYc)tJg%L^nKU<1x3t-@9&s zN1+I2NeNL!{Zn{mZ>QJb4MyV$s?ed-imikfbhZ7&*dTF9+~>`aLF&G8+CA&WTB7LY}*q;=pYMSp%3tL7$Dm|yLj z{MFpSbz%cn%ozOD$#_t_N;gGx4K@KYb`tBvy5Uc4#u}NgVwPe$tdri%ol$1bvS~`r z)$b?t9^Fqpn4Sh|>qFywm;ENX)?yvlJkO^(EtdGe#-k&TM~;Zhin!6prhNIJ4<0+y z-=g}ARO%_wN+qR9uK8n&F}~j^W0c`YpO^@CXP^T)2_cwU9q`c_nm{9{g`{Jej247? zFC*iYhFWANdF7Z8Z=>|&T4lWwr3_YvDN~fm$h9{xR}B27QX_pU8Alpmg>C?Ypt<>~ zc}uJ&BY=>uP}8=v@tmUPE%58dBDI^c>oZrsz&v=bROeTf>f)hdn>5S07rvit7=T=} z2-Xl^*qo7%cM^9L2hoUo#kRG#pl1lsLGTQgBK<6bi6j)rv`Hz670M2VNNS`qxVR@2jDD z;Cb&aZipyx13C10aya>jsyl`y(dx{F`Jt;inYmo7Qb&kwVijunM&$M57#q&&Qt_wi zsAk2LaJo~b)`(hZ+fd(p!$QYM>rnxSqzzr~xsCLtN$Ios0MU_;=2OKQUOsab zIDjQh#^bA@@wu*Oo930w9Qc(2CJwiZHMYvl~zW_90yG>`l9I)tNN(hH!;q(U~De@ zX6o=$tdw!_rJN?x{cwer!HQak_C~)w6pDjm`ego6%t!UVh?U@xIR;JlSTcAc@rrj< zZ}QD4A;g<4roX${2K*^IN^_)C-JXIC=qM)9F8B_LP(SKnp4E^5KzBl3njhxDSf|km zuazpopo~IFsc*hk*oQaeCwX1oU+m^Au8G4SS`TK@Y>1{3)l(l-#u#v?`%oELlCi14 zCkTJ^6dmvw4FAuoyz5}3PDQs+RDCB(#;&t*D{wxvzU(Nc$VKD{dRZP`{!qmJnuYYX zvLuCs^z&#CH%hB^le3WD}(D(Gz+G%z9U8=l~d>nZz@>rA- z-a&s}rqZI|EL{nyx#XoQE7kL>ti1zAkgvzvzl-Ukg!3TfAS(8ZA9_9|VWkOH zv*frU1>NL4p^v14y4sRPO3@i~*L0(Gr*+|>i*Muxje zFGIRvkKwxEu6d?T%-5MZUr4+`E)t)fL*hrw(@gX5J&M0Lpy*OIXsn>Lc|Gb@s0N!z zd6JO2L(z!iiU*IwJhA<{x=+um@iM5a1^8SM%AY3AcfN@^Uyt5Hhkp~i=wz%mt2G~! zW0YaS6)8T_yuU5?Zh@otBw_)-h$?p^&e3r{T?LPjOjgt3bQJAQN7GWYGv?Q1=uN^? z8}OT=7k_SMg)=$K^a=ShotG7#c%+)dFQoNEw?B!xutC&KJCy44PuA6y4AL+uLdpnU zq1%oxwfzdMgfwzbd#C7g`ElqLd68cimoxM^R>`gOJ-kOQ^Kwlr{$A>>J1Tiet)yVd zO|p~T=vL}(>pF$b*1arr6zlwJ5~0~eu4SH6ZX*j=WvwI8nl+?3=|QHELS!>3t64&7 z*bGwB4egZahHS%L!*h(l4~AGnhQS^qFu!@KQ)Q*55{Zgl1y#77aw=t&rVqJC!r?Y4 zgKA!jw9)iV@m7}b^2%n6(6P#_f9W^)Ppg~v|3f`5XRhZ>zgykB#=M%rUY#Z`t4~Fq zgdR@o*>Xy?j6KlmSm*p7blv4>xwt+Vh9BD}hWjDrr*@61LA60(O z*Si=$pMhB)b$%}XOpW?lyoecOH=0?|ZtO4Wk94iUM<&grMc8$kUwfM7D_BwbUCNfK z%4Z}Wxwlk6S`eC%Zvj}dRqzte!eW?0e1K$h$0~hLBwMCJXL29fU_1SD@Z@1CiTujs=ijO(M4-ON41W<$Hxoyk)6~Q(cblaBNdc`e4lCkwS7E# zhn$p!6eC;74`o$1PhM0kzqTGkr#0X%Y7dOKgZS>R|3pLd81X$Y_Wr~ysBP?T-JKCy zf;njOuvXq@q@_|dxrZDtHI=7G-K6TF1@hg8RMV_#%<>TDo{2A%C=suW$DwzO&wh! zhKwd1Q~%)4L;>SV8;Ncso^%4n-XWy)%P@(&f@T)ARUg4J%fTTs6OJOc-=NDtS8%BA zTByC05IRVAE?}bTVshGfU6Q?0Grp{YGknx&U;=qe_K<^Q9XUq2lU;-oRg>ammo&}* ze51i%`DDmK{r}Z0%YW`C`_H>q{z>152nw{mQ#pB~c<#p0Zxu)Dz z9xC0JlKd-Z%Oy)lg(py7&f{x6{9$!-Nj%d-QE%Re529MkXxm=wJv3quXci4;$EjeP z7RcK!XpG!Pnud{7OeXSHDIP0mjBanp7?0<~AuC0RFm-D|owh~C>d(EAf}(gY-WIjf zB|8(0#0#r+Dmb8@GQvlEECpLSli1O0tA^@cJ_UKWDe`bt9*!*B8FQ-}Um^DK#EeZ4 zj4mt?NvjU+hn3{9bC;wn<&IF4Pw0?Rld5U~GOt`<`}k z@z=KSxDcAGUs}zx$sbWtlM_+hqYpP2RI0eFgck9fMwhT^bRTU(e>2}f`qC$}C`Ne- z^rkZ*kVV6RJQ@B~JqN>YEZs%;_mBc~Ev4(aySfKDEZe%3K>;2OGS>1}N?WAhl1c%5 zmO=vge)iK=RJeD_UZn(|!QYGeRxh9xIRgz~3KH!g=#SO;OQ(r&sEkLxDx{Ji_>)8s zAI*#8{K_m|7i;qvWgY*d9Lsn`bi@xz!Yk4S29hIWoYSp@g32OZLOG9Qvrt*~i?t=W zR{_>Xb?C{PqZ(A>3&m)@CEn;*mG*%N)QN`U@zBwsG?tcUVTG^gHiw=oxCNfmgQ(sL zv?I@&J&<9InSRe}S(Tlf}pE-)L#*i#{*{k99NJ z3OT$nYew(+$hv#F@S+cxA8m;*G#1V~@v^(mZnvpJ!o#S^J7(ZmFtE3qU zC_Xurzt-2vKjJ5AOI|C982$D5H6>IeD%ylFr#(Qyna)5`IgA8!4yGcnc7*k0D4Cyj zLD7oqN&%jwWGL`W%znQf>gSy^{@#yM5h=72p8MZLe>G6Gwg|yW+MdO;OeP9?#|i_fl=iLUsxLD7|o>VeBFH@Yl%Jua%-d*$HEc!P&@A*Z6#12!BGH zI?ehVtq2=w2>MD>&1^*L(5kd7m1zJiLi1zAEJ*KQ&71%w;FhL!$_J&laN=X}6`PoM zF@L|p?}T}xn`xGPuuw!1wSeUdIvQf>0(yh)Lf1Clx3s)dS5H2sJ1bT9FXduIjZW|4 z%X7W3M#U}7TYR0%Fb?129IX8J`3`OrANanE>o68tp*O38m7ZeFkA^6E* zN0M5CNA%}CDFTs8f{~0}#BeoC97sIl{E;@Nwb@Nth@~PEf20;{BmN$O8Qwv2JLwFs ztUlpgF&|6ecjmq$H33zAm)In3i*4!>m00#<6=`2qpV_i2tOAYJf^!K=PG+Oi9>Q+Z z0G3X_tmyvLRFScC80~MGL`M(PE3lL0g>3gnep}ooppGqYFBwuqx~+8tJ^%45!`nLLP zxscukiR_vGKo*$1O`T#qWZ9Hm0xeS3a$1mmg45L3=|OxpFQ~rdgU~gU!)$Jc^{S)V zP(5K$m?eXb8PPvzSr#>Qi8uA$GGxSRV8?-|ujWeMAi?jgNZh z#&q-uL_sh~Npa^(L`A*{b!#tX_{7@#tC~2KKz8CzGA6( zBcJ?gF6BPtg%8LV1@R2k6#Ff%L3eTzIv~GKM?M*fyxt8$@K2s(0F1H7!1KzL&B)W+ zl$-z4nxxIBYTK|zU*J{5dhtvxWSvA?K{{j(OwziDqh9aUR{!8f2@3n5pN*L$!?BH(Sqsqy1SVYsPx9X!D*O z)6|797L;@6NW=c_8}w!B!V$U~dAvKlME`(C)Y>*UCM;&2Ra}9L&`4>G6esPLK1$7{ zo2cI|k~XNTTX!g8xdlIg0d+J^xuAT?wc5iE$)O{X!x^5*|5W!|52IP67duAX3-^|* z%e%wzO;h@}EDh?C6i~a{!)?7D#}Tc&~(|PSxom zSWF2WNj;I3RcHfy2uZ8O4~lkp<|g5D4fnzG^H8mAeUVm$Rpx0Vt7&cMM{OLg#2(}Q zg{fEXJu!p#OLEb8(MPZX9nM(V6bYp^ZBH#}HzfXd@WAPALJ2-kR6=zgj_#}V;eqW$yLb+x)6i%^fxGi~Yh`-LEb-ez4x9ox(heI_RHB?)q)= z3HgA$P%bO)ms54O0HF6$gz!!S6HljD4z`i_pPv&u7XG?4zlyK#MS5q4=LeDVIHV!rYq9b zFn9X%c6=pojpu!WMNOJcs?h{6?X+}82Wv&sARfKyTO_jkSUvAz%x=XxcAQKkH2s{i zLk!>s^_8_19YL#}xXQ#?cG-DT`(A5S7)>F0}@d$3Jyl7RW%ps$)|G0!!!OVBYpjXh z;uRl;=eWPIJTk>hNTDO>G4tLwQ^)?D&RIU=5BHY z+GMFbL~ScdTe#D0#D;E%%kaX~n5Q`Q6HKoq(e(MN87@4j}akHLW}8=g4X0U5Y}yx zD;B&gPkjicr^rDNn%;22#@={c@!`=(@xzekf1ao8|LhKosdK{QubmSP{7dJANVTlG zTrH&r8PBL2;+8s$(WcXF+Jo$YcDQz;Td{z*`Vjf1{*_cuzpO|JZK^htSg<92H{{*Y zExC)_Np3D9l}N!-kAg0=2YW|CXyt5oRD#)jBEIk8NH{<4GDt%Ao=51>yVp_Mi>;YW zuwGq28aqrMVkDY6o$SojabzGJk2S0fx|A-c62;Pg=eMwKK1ISaO{2U1-R_iD7*p@W zJmDRiXjhT_1qIm~^pKNT88+Uvl>aW-PZ}h@m+nY@@_L=Eyv{GLOAXqIu7EgL40~ZE za_}g0q%~)N=fOnoK5;B#b2r zWx)$v(9vBcWzY>=Ai<7~C{8W71|3~}be=<%A?P++E06ha%B7?m&iBa+bc4Ro1u8=g zkf9!Yz<8=a(#b)GA#s(IUOZSig_JQ5AIp(1mSe1}R3`H3dYs{+Q;e*>O&?kE>d|FwYXTFVM!mtI%Ktl^eK}2d%6WZ?{ALU z_=o(7*vTu159pHrse|QgjKC%0inxlgcVC^WcD6XcWZF?XomI;-FtDcnzSKkCQl6rJ zFRv~+x?Vu^h{%+v_y``^v-+jb7g9O5BWi!)&(EOW*nmv+H&-#N4-N5i?LZ1YtS+&x zLr;@Hx)XiW3-spKP$%}mLR5)yq%V}r8i$|B4V`jfZjTvO^t<_ngD_5qqoTJ#&L74H zB>v{?NB6*d>WV6uhel&$j)qd?ZAxi=Ofslfn?XbL;qn~)Jh`dfQa&wL4*r<;8hyp)P#64~({$H&J$pV+VXcpv z?t$6#0$RW%qNF_Hzp1;7rR>Yom7W(upXusL>!iZc0?AkBFIDj^gWfk561B0#!vpuZ zhQbl}gS3aanqU}fwM?8qS6C2ZT95JEQt7R9LzUd3EL2W$qcSnWKpK%cPzf`l2~_;r ziOe)v-qhVMk1R{p!aYt#6AI*C7AaH+HjGLG!>EngLajrv0&E7D4(pKn6S}8zD1u504Vf zku3UR{QcM;_SbXe|5o@RNDdc~B6_Rm#ojoB!$ekt&SthOFYCY(pcnJCSzs)venJgC ziX^s0EE6#plj-U>;hdUHj5M3hWjZ#Gd9qP#7b@;2P4nc+;-cCZqwTmjC0?j`)azNm zy3kJO<|0^6e1@~OEQt3f5N#RP#)70XAfwvRue@B9}(KICQD_Bjs<}FctXWrWMH2aiC4p}BuC^fyo z)yR;@%aOezT13pPL_^#PT*|&C&MD)Ryyz8O(J|`q_ZsFMG@Z;n>c4bw_^fYtlv}8* z?)-zI7kT;EbQQIEA?(5`dJI;9si)X{BqLL|pdm=y?V%&oM`~#S&ZHDLXZJ;#IDxNq z3f21PH~oHWxT@6Q$;w%bt&v7c+w$}TDMpv!dAf;p`XqXVm9W6nO9hGNS;i~HS^c2w zi8DH^h7;rkG=RaTYh7do^s&gqh_^&?S;Ob6=dF{W4|$5*vjQeTUHqCdWGOtgki`tt z<_k&&>UE4_RIKqQhhY3QTC(dVGFGzlRfH(jFWdsw)&^KV*2|&*6!9J@1!6pS^7gaOgFZ` zB;vqcWY@twnapkYRKb;^sUai~rh$Onc$Uw@6*vP&k;k^f20UBeu2bs>tspw5Q)viP zgTIh2JV<_MXTLCJ6~10_g2s6z`2$({0+HY(VbGT}AZ?ucC%rNB;r7ZDr8crc=bSwY z(|_2B`+XO2H>$A>o;3%OV9QrnMt*8~b_j?N&JkXlI1B@dmGbhnTv^@GD?SNaKM z37>+@y#c-7?w@p<&)rEa3Ms@iZ(%R*CiaVK7Om08Hlfzkj|Nar%Fw%*#lPq_vlk3sT z@59fqFQ+@y6XbTuv;tdw#?L3jI4!2{AQshq9$jnd#Ypp7JVN(USDZ2mqrKc3=DfFrRi3MHp)-PYT7kxE2{o`q`+7_6GqJO zZ_h)eZ|>UuxO?tNt~EZtx?1^V2Kbho8Q}Nv_^HBOHHc87m-=UBDm{bzw1LfH``7}u zh|OdZ*=RP%oH?eej`ee{ItJr|uy*VQEvCInD|*xmv64SYouy#e#s8_xc{+>Mc6Nq+ z^gLvmI>opSE$%7r5A7ql1^0Ka3tMRzW==(DiJq_#8BR*3uT?Jc1 znzYm$Bp0%)@B>&MguzFNHRSolB&jLN608@o_~%!AmeMPslT#JU$GuPlI$#c$BL(3^ zW)QN&MO6N$SO=cv%0APIr9M1CkwpzYBJPF*q0Uf-t^-Do!)@3BH%Tm6o}QoA5R^CK zp1Gb7DHjS&ps{g z6+fI@Rx_J^0v}eCK4SG~PmiV{E2U`ZsB}ShBDAU3@8mq)k$IiVqAah6Y+nN3Rqp+E zGk(}_mz%{*)jt&7orH>8Ph1v$YA@p{>we4#k?b$(&a~_-)v-h94PRR~F}@btk?lue zz3BRr89jg30#pB4(|RaCHqWPaQZ3b?Mq71hS~k>Xvzfhi2dk`|$1GiDF^hcrLo?;6 zatr-Y`Gb5#UMLlm!waRuA@(TyuJBTQkrTr(`X%%F<@y-?1M#O$6SGyVTFK%Q9=8ds zoLl(-XZ=Fyn%qPqpOE>Mw~z+%D~D6pYg%YZk@}=4=}qD^LrG0dF;c}oKBlW-q*B}P)G*Po>+3z1 z$6xQUFpNKUWvG&27|4n8E@8IQcG8NJgl!~&+#`21eTY6|xYC$cRXQr|l=>K-rm0W= zWt!@@({X;jbMpH$nVaKG9qWc+wKjFETV?K_aMY|17e%1DO}H5^iyleCG^1G}ZLX!P zvMXgp0`@na6=@l1taM-UEfFJiDZiz0$*8lD9isFR&l-0Mo2ji!UuCF@tyqHZ_8PwP zdtX;^*>Zc#oJbD5mnhD6q}?QLa1azY2XSx*$>j!IfK$lZdteLl&jRGL30O%NLuoP@ zs#+wY@>%oC=u|GFU&-y6{r+*5)RAAzlKMP>yB_+_2(c4mW|=xlEKj~hDzSK%%Kq2o zdD3aQwDeJm@m@%8vbwO7Ua+_-4htLc1nKAj9@E_O;l6aGh|0NZFcFXJIgET?wT`Nb z$!mLrm8TQgZ!Cm)YR9k(Zg&H&%8#TS(p33OF|MtPUUxeB$@a7w9SN18Qu;#vUaZ8r zatq)4%UtKs8*5Ai{3d_1A&DPg7_a@}cAz7C;Bq-jzq zd8PDRnlG)>J<=U6cpGlgrFh)C!fL2ORzX&FB0nvr@w1uTpfULaA|VRK0)?eek_>|o zJNKB&N(bH-YtxFKc3%D2cS+YsS3RVshbK&h zc*o(SBC2g+ct_I6NAiZ;C-0E1>|mM3NL+1wjI}Ux-WXabL@8rl+t@&9sWiiks-zs{ zHIzX~3!G1plcWu#khbuF)Pjj*IWanoPt+<4cqlsL{>WhS{(np|`#bsss(Ui8FP`yc z>Py}-C7Lv#5j2wyqqpdItQ%)Q&Pe8=YCO6+AK{7I{j1)RtG=!QyoR~T(S?Pm&&3LL zuIdvz)UJSb3ANG=XJ^@VwwA4Ci&+Fa#{6j_>t)?GW|Jz%XF1$tZRvXC#;Tg)+W>HG?Ru@6Z7#;o75tr za_S;-g|(s8ye@_6r*CKB@o z%;_=2iKbaT7Ps*I=iyDbH-4h;@7u0K#ZZxpmWdDCF|L-wRyqW^FPQ#;XS_3J$#2O2 zp46ZDf-c{we1Y%~W9TW^(YfFR{YiT22W6MItBevl-Z_4kqj~O%c>>mcjD-cL4YNq+ zv^b@nu)v=hhL0NmhdZOT=1}#GpG=l5u9i~EsI}Gc=#5txqt&R4e5?RlrCp}=&2uDZ zy}o{>lTinw_D0)AzmKZccz@YQ)ajl1$I?m6w9=sp9zi|2rQCC(K0q?M{X4J=k~S6UHj11H@fNz)c)+Pqh< zDtUQB+w`_9DZcnPI39@>!cFxS3T>@j5( zAFt4yj%eSn?kbaM?6_@CnE`91C;u5%C7L$ppSPE)|>wlvU5t|P@tDY{VI zQ?Cb5mc0RM8jGIa6}*T~>MNy{$WnTk`@=T+MQ@hBuRq3OcKtXbwfT3uc-DR0#d8N^ z>Y*s99u^@;W8;!bkWS2Tl^dg-3b2st%4&^;UCp?0djh*Hz|VUfv)s8o>T&6>5S)Wz6wbQdpk zt!?^z|8h0fg!!0_+stc)>stM$PDG+Shg@>itQv2zy4~hlwV)Uff5DN{S5Ta7N3Zgd z*|1?gPo*%)Q_hw?NO95yX}`2cnk^NUW=OWWPLiG9Q0+#fzgW@ktKcfOi5$dIKhF}NyE44({% zKkV=Qd8eIg_{`6DC}+`c$Hx@2e*^1C477y_HqqSF+@kquKUxo~X*jJ&15qWC!JqDeM&M3vrw~3zgrb)9z}Oz2tCzUx%E~34 zPweIa>R!Ghr3+!SG(AT9&|P%0d7a?rKCz#tVAMkntw9qo=M1D1-E4hJwGjr4?0xvj zmZ85`iLdt(pQ#u*DH$=C3q$Az8j1D3D{WoSUplS(OX9lPl24Fl9u0((BFULbfOw%a z!Tk0|H~eKiis=qlKde2?_-)aOZ%Qdec3}0tP+dGN%Wmp#Cugzi)IJ0zH|s{hmRqwEo;RZvt}%t4rUoJoNch}5#y_7 ziACxS@gSog@`eqo!7kE8ECQ*iG~pH#oRgR}?Znp5EOeKBePvV}&DUoVf_n%sxCD0y z?(QzZ-GT)OI%x3V?(XjH?gWCn4(<$Y!_M>U{@>kw&z}9z=TvufUHR3O57m8dtJCgq zDY;=vp`i7mZ5ys^-RR%HcBO`b(S?8g6WyK}Yl`O#xOCeJ#_9EE&yXVjGBUL!B}{xT zjo4~T+`OC?KDu#vx)oY)fAk7!CSO=cE8%K1;!Pf_OEq4V@H*G6{OkIhvOeD$0ONr%6L4O2m!Q`x_laFUFYG7q z_Gml@{UzbIoQo?hT{WrQD0b&VIEr7E((e{o)1vZy*MeMpIobwVSy1&?q$y4?NqaFL zGT93%iF%*-mwJZz<^26!f?OnAlEvgco~-3d!vpfJ<~pRaENc#QQGf|9?c3>B_<2ge`Nef>D!N$o)q$H))a;_RKMfoaC$= z@9cli$V&_6&0$O>E~HQwo&VZAAI}`6CVeFm%j{y%K}?I}L9U;8`$cOI;+rMMx6 z9-c-{P%ehS_MMdN^^J{eX6}quS^l%SyvlW0_$cfM(r!Nnv?fwB)j`#bng>^L`7^P4 zZf42Qq7}Pdfr70Nz71LHrm*2-(t&1ssEjtzp(@LK;?oVj_s7B`Cd-h5#s^=%K}Hop z&(B0~mv3_+eg;b;Ziak9FNG7I32CK2E+ zDXnl9lU)p3;c{E~4EdX26+td;1ljd0wD9Fl*3Kj&u!J?;HPvM+LR|F7+LU~D^+NktL~%q^1TZrk}9Hh?N07^Ar{gWl0oJhcV-5oErS!! zW5$N3SQPi}CAlmOcDLaVhX%)uY7u?~^iQ~CLp~s18XpjM>S&kfsxkgP@NH?d9X2bU z@lgCER0w#zQc9Z6`qNJv@N`>NA!;nqVALJB1W7iAL{Ai#Jw{X!G`WCM+{P3gHZW3~H ziSB~3iMfZn2Y6*a2F}GDB2Ck`O%M_CkC-?F_}xEOhqqB#o+QC5{;X8=vZML5%P%Gl zW;p0byG`T%gBD4YnpaD{JgLUc3qRE&mF=Hcoc)B4gkOel4Zz3O0r28K0fGsJ2rLMa z@Hqjlcu{~!ydQX3fDOEeVD^B>5BrM!WIUO{>HEj*wkvxO(CZ)jXVitqqs;htt!f_C z5_(>Wd@W1IcN#X-`&J4bp;aLZ4Yg`nff_HdDgEKU)A_fl7kz{@rv>)~PdEnjT>KAH z9R^BSZ6xe#U!B|T=qh&}X$q3fzN|C1L|f}q)n4{_?=7|+gXKr%taDBh-gpm}HQYma zYTm88iP6j5@`3~T?EfHx+95M<)g(hZMi7MS!{Eby66zm6C&keFoFi6<8>}bABYr+K zr!^qNnNZ!DRXAu`byc%}FLS*?FR+2Ko*rU5K1N-_e=*=`HrW9qCLb z+iWqBBij^(FPWs-8rfQ7O)BPTu8N~-N#NumDf){)^&XdbyfN8-wvn!BVn@q7_`)ggDgIm{t^fK#rns9KH9ixjLVpa%&v>4`7)NXh zTl2F~>S7wts+ERF@xE7qG!0fJ5t=w*NTw6*hvmI{>L0Kou0G+&S=lc|Z~z&;<&(7* z-FbToERXYR4h->YiU(<4;_?UbXa$8}$?5bS=PD1PWThA&DoYu|cqETYBcK}-r=n}$ zwVPhh<37Mi>`YB~%PTkn0tf!$xHyn8M^+rzXh(LDL)3%%m7{dX4bAvYL$CYa>IbV! z0yJKg%qCj%1ejz0PLGD%`Mobu*q&SMh+l~OWF1~+b&N&5MR#bWU((|dr$l@Zrs41h zKE4E*-(R{SRg4s2rQe1vGhuE`p{h!6Ka-UY2h`f_&+dsff1+~t?YmNwFuik$udwe6 zv0AjUJMsRoiTSO%rbVjxr1CS4_0^`(+nmDrSNivp*I2o@q_J%OuD3)(ViXDbT-l(P2svFr%Kw?>(TA@|uN zQZH6KEsjOCzg1$!T#OwzSWuS6+ND$Peq4cGv->uy3`}S`PCVto=@Z@*^ zR+z0{`*od9C`hL%^|?&fB!YWKf((YE|scqJ9s;%O%Od zV-+U+fOYJzHk?XGm1`7_h3D^Ev-^~delq9sE`z1Am9P0MaEB%f-+_)zA zv#`Wm-uY=>bw7`hNch}1r#Ervw?y6NZp4(|E^}IX(HO0G0Fs8}=H_4Ysl;%O5a_=K zgLCsjfkf^~*B>h`+R?ms?`xRoya095ruow=;eVvYbcEqeb|s>U|E8Bw2ohZ-M35R z2J0mJksH}&vZ0#KdF5aw7fV=<)Kn)w3EBr{OJ@j+xJsu?@mu8~hib5aFt&me?0p{J z)r4UUaS*GjW;!`J~s5{uJUq9?CWS3D`d%tYY_)!EEKC{IhML4+R8*c zS>3(pYWhmFoPD0_)G-){GTvvm4P(kvs{34~wr$LPY=hTs?QLwh+bsd&v%G?LgtZr# ztCCie=6ek@Fs1w1dNyR&Yu(*$%~1mfv;~1I{6mWoly*vL_AMdVkJx*2W9BZkKc2?g z6cf4F(IO|Rfbwl*^S9NYI&^~=wcQ}Gd2X4|ovM^%%rRwitx4)fAnp}&`~j6cHtzJS9Vlqdv_mc~x`<<8MoOAa>d=;7$#fb%Q9`N#3;Y*p@)oNd zoNn^YddDYXOG+qJLHWaNXJAS&4^B7|G0yCgD}$UL&Y=#;EZnI;f{EH`@qi+x{B6IN zO(1qo{bSe=nhOHk6~853s_!Sc;`LM_`d(sFJqCXztGK0-1xZ1nC~Z%}Gdi?FyO7k9 zHq41k4x{%K81&IC%twCDyFPUuwos*sFi*ggreYwtD$J>2VJ(y6W{m z{T0$S<|JHhrLA-2E+3Gsi^)j!DoQ-`v;wrF!Yk-~6PM0R?8R^jjZG;E0C z0waTSq&ii*S{Y680}`frWsGYY-ve{~D5)x*ozy>U8EgZ9Nqj-TMtZUO zYI?N;?(;U%eYHg@516}9WrYrH$ChF6iiTX(nR<*142TR@3EmpvPVBO3eq1ygDVmSY0eLs$r&OJF2~ z3Wi8=WISuQQdCwl5EBjCWM0a$N1Y46awThtDa?(Il_!gAn+TUPI<3S=P@_ShH(X@1 zwiK5w@D?8(Ii8>UTP~|4RnWjJoT6WB_pSU(5@tF+=Vt$g{X-<9DpKMHSV*YE2ar33IGXDbsr96hgmsh-2iT$ni410sx zu6M56&jM)aGG72&T9iJy;Fu|8uglk=?Sr@KC!aBX%GXuCSdkIYfY{Nqc@7hCTl;4O zi(mMsC<031H3AqtH%)j$`Xh*s1IoF$l|Hr9*BPyzHPEtQfdHk@ax1usSJY*Lh0x3a z!0J?#awzs+cdAGnk~v6TlLx}6b)q%y*A=Ry+ni=?xuzHe2~Q(v#nFX!8?LL4-b3NLRI!I)j|)fPL+;+tk5i7`B{~cOX!)(3GWwh>};T zoEH4oO}Z>vMxbqkPS0F=jWK49?;4LMaZ9PoUpE}qOJHcdYsvCXv-WN+k3%JdYg)A? zgt)nhjT6h*gsWK?{1T{=*1LHHxAVSPlM?got{l+7 z5BdFqPSU>uZfr8&b&Wj4N~9}k>%79(_enfajAh>~$bZM1ui&Lh46PPhdVLPEbOmO{xrVPrDGfL zO6gwH^*R=9cDg@gXX=uomL%M=8}NX%jvVA2=M)iTppSmtWBh4bkEj7_PvJ3i6CZr3 zP=U5N-uLJ!Z)~cC-83)ww96&i=BkcY${DOJ)4{72uBn-=^*tM|z8mg^+M;4I?BK^Y zvE5osnMH0@qV%+lZ?{x;Eb6VywOtsV(RFC5)J>Bf-gn;$%hL)L)KARTad^@j28|)&Iv6TB%Ai zQgH^_YRUDChf&3_Li5itW~<0)B`-ZNWOj!z%_HAQ|JXOPv=Y9E==@dv$+WZB8IKBG zeuZHk_aexv;Oqkll8SCmy-Mi`CZz2^%;op+-HMA&@Pe9~l|A;$fUgBkZNP<}wJlmT z(?Z?s3zg0NY1YaQ(2FC0nKw(fRkh*mR9)zK3g_HI!`T-ibfeyxxnXEuK=Sv?O-h9r zFCVb23zU{@e!$T*$66|RP8|Cr)8AhkT8k`R)}o+}8JZWmG*FGr34xCepPaBNid?{U zY0s)4;@>lgd{}%z8Np*x|2?aw9B+0-GDs7vr{s#3_$7l;b#atnwOPh6vz8vzjw0~o ztGBi!wAH-MjU#)4O)-Pa@~XSRL__|M#XL~zG~XHhnLq)|-H#d9XO0<`=lZ+Bro%P= zFS7}0Rg3yC`f7U7Z5C}fFMAbZpemTE^D#8d3LUA`wAaep8s`Cn_&+fV($59MXYd7T zu%>f{xjv<3YXx(Gr}n2@DFz*zIahcQZ}WxbXD8=Ei;IjIZrJm_66-7NQ!X}<91ka? zQh|r{jm)|i6+Txx2pue zSQ1#OU$Ecjz9A8lv+QxZB9*iF<-v(@O28)Z;dWK%7vWmvdU09g8FI*Ybhn zhRCV0%b?AI#Ijp|2bW@csQ~nJFsYyB&T3=c_QTZf=nl)ACM>_a*_HGaTQwtEZS@1W z?nOph+G&@_^UbL=gyY%2IzW3;Gwb34418gkn-3pYf0?&#PtT0S+Vz;U0)GM)X6(BQ zXK7D8%(-Hx4^^2e)x*t@C*ds^TvQL1MDMvINXl~LM3wdh*Z0q4RunsbL#nsq^T-6p ztl$q7B94W#bkqBWxN&Kbsys`3!!}$SFEorOv%(*DlabzDX9SYSY0-J0vfK z$8U1P=+|4td+0={swP-nl~2-Osi@YduTgfiN`*I-jg#lQ_Sr-guFBN3VhQlMI%x=o zPFt-6`%UXT^*;0MLH4Fx()RUKwuC2Bkij1ouQ{UO=BCThcT?I^vr!q}rd4c9*nf92 zH=1lp17~Du;mGTBvaqdF#Z%B8L{tZJOA@l|8t~ssV@_4&r zx$td`=&5l-&k(uQh)f;1o(%W&?~oPzZRkq;BmEKqOMVw}6)_!eXq7USGnSNl8UTf3 zA>mL=3Z96-$Z%x%TD%s?Vr59MO%7-}4!?r$UG2KC&X5O*AM zsiP0}!`T<*>bpqd7`|^BTlPWP{^q<&!Q9_JUO%P-+jrK(BiG$2h)0o^5J4LrO(bPY z`nCkm5q3rwb&E?#O#nJDx;FKZ=|0L4GCqDG6aRW}WJ1v|%X@PtZPYv7lMjg}+aq*R z)HJ%$>$vLy3h`aWs|7MFBpK>wsTKi5I%8(TF$r#I_Eog2*_JYv2JoKQ4twq7M(0)< zUiSrU8y8vXLVfjBPlYBG`rV6m;agr^&Pe-i1Y}>Bf>sVFQ-mUn1C}t3JWG#`0>*q? zu;y@lMPWvB}< zs|o5#*(1hs!wx+^=YpA5tAJK4SxO<(CgBU($?FPz=K zR$qS0WyK-qw{NfK+S-k&-mo0|wwLGAGaoq5Po>JLmK)4rSC;`+Sndn)Tbg#p28;S0 z$)($wYc4r;x>W$T5Q6N~H^jzk<2|`sN0)9-ptutxS3P+u;9(i1_L^y~^16qbx|V0g zZDwC>IZR`HuQgyrGq_4d@o}O-Pa-ass`dyFIj7hb>4dq z^T;$b-;)n}0wpOQE-=sAH^CoV@U(=`eFSs=s4kLRd{^>M-PMip9m4kn)?a8(u;o8X8Fy^^Tu3R zVf9v9r{Yd zF&azF!#P&BrtpJC*PPKj#nkTXNO?8GXlmZ@n`dh$3<-UsnN#83Ddmwvqh_4ug3w@F z9eg2sDZ2a8^_>)0vrSMn%gGzGa;O9Ea=%z5pzLB(g;j+ySf#F3rJ6>|n5f9Id6JL9 z(B%m>2h891PdsPGz!V*R?el@2jaxT_JQg{ES1>qJGy-&JWj#{nk-SxGV0?IBUT%V} z6|ZT4Pv+Cs37+2H@*mD&T|d%Y+1^T?!QbM%Qa5gidzW&3-=**kJh%?kdtd!*I6-a8 zbuqsA&bzaR;2PVDVSFpVwwC95u5d-*Si7XuRg|M0eLtnuTCD`P?Z|RIv^c3R7D&%p}NL(0^uN%cFX10N%fS*hQQ-a#t0{^2fI6vV^ZwJ@-&}t4-hIk2bN#SGrFl}`&Y_WAG9|>z zb$q@=>E*812GFKAfDE-R^YFNIeHCa7aBA)tWfeIMYy0wpwq0)G!=Ek~d;>V_jC=Li zX~E(!XBt6`0qe@?ab@YWruAY5AAc>92!l4h!i6 zT%RMpIprKj1g+$8P9RKmGk5MDoKh~jmBgN-jW6xq_Q>ZA;%iB{%G@@aDMO>Pfln4P zUUYlLQVksotdp#yt;Q})h@7PMwRQ4D@3EhJ6AUsvi&u9T2BUK?8CrV!MKib^cLqYS zs1^Tfz|Y;%O!nD?)+6Ur%zvLW*fFjLd>mmlU=$zZZ48Ee~E`Dy5|fOjkL$H zMGK0=J%*3wU*c~1_$$)%n#A_5uZYB!Fuk+J5uDxAp)6$leaOxB7Vc5WNbw1Af>sEA zf9VAtI(-CBFl@nW%b#&0_G0pn1QuTT!OFB5pInU;5&2k#_l1^DgA|08xH&zILENwK zx-e89Qu*DFQ8OR`A@M#RoW`d7csSpBp){U)hiaFR35tU;uEKXVf|XmYBJo8F9b}jM zcqmVM2-Dw;>Tx+=jX+R>k)RtAYXsONc%@FiS>H>C8K_u~JpYZ`zXBd6)vEp@mhr!0 z5$g6BgO)zM{|i~d;(i93z)U0m_1d#zf&m+Ht%q%eVss_lJyzl<; z#z7oOY;@FMf5(iu{_^`+2-U6`^UfZK_4CC)BPYkYWNq$wA&Y;X?m}UouDwqF^8Q61 zzSI_+lBxEACHXC;^TmH^hZp~V(+b^VbSwArxL(GoIS#Spj|MiZ6%|*#oiIy+zTi&%@6%l}pnoE6)ny6Pra2WMplY|M;qjd`Zy&M#=V+quNE!9(&pOA4RER zsS$uGVl;EA4>_g>|A{w=k!r7E{|oeLXDH@KtW{TQ+&Hd3Mos2g61pX7UT4-CF$<$jUN8sLqvu!>~Xd{)7wvh^T8@ul9_4ZfNyuwF!It<|w zzhaQUKu;(4203pfD~5U^N$NmD{;%dVsJqVnlbZ3A|lm%n1Z0TG1OTO zbxZ*C;Uj1qdi=U~0Cvnr>nn!FHz>I)hXhE#umPvp zQ?18tZ$3!|L~KouFj~kIr2dxB*NK|z0K%6;kqt5i{YLp60m`V^sl}aq=*uVB@#9f^ z>m3@+rWHz#24%!-Pe&)-V8wuJX?CWSjKydsqJ3WM@CiU6v->pzq3NN+BCnXf=RYV= zz!-1H|AY{J$vSP(tztm9eI3&qL9o7aUlWkxnu}D=2WS#AiWMbKT>W;5beX*cl6Wdj z*)(*#3ZmX{JcbYF$4>X93p0G#)R?~7<9lq40~>*~Kv1(WpAb@iQ|FB0=%RU3A9_(! z$v7sdcc8C(s3RX25=70F2H{&HB=(h(B2D~r)uKJP?+_LH)QpJ1su(Fkum7wRyHzs( zFOt}Ur4Ux+Xb~Jk))8>DlGuo~9!y@4HaR22hn4YYVD$B9GrRMWqGoKUa%5+GKeqUE zQIpem$bxyteB1p6o*){*+PBNS9UASu++_q}-X6el9yPK5-h8}&@gE}E0l5F;V={#Q zY6mm{bpB2b0$q{dcYE`?Ys0-q5fueB0#3PUn8aWIcYgfWUg@I%nocE9?~0aAvQ& zzCsdcN}Dohxe53u`;BX6UHb}+g8m`6tzf!Dh~(7s2;TauBr$?D0p->T^@PU*QE<%L z$0X{MTQP`JDKve*4`256XBN^7^Rre70 z-*=PmB3iu0yy+>v<-RzP0Y`j4jQ>kM_XXrB@Q7~lcD2`=O9CbtgQ_0?W_0&2h*0ix N5YtCrb8Rn|{{f|H`MUrB literal 60233 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

      @Jkl=4Ns}LO9Yo9Q>HcR&Vv2yWz%NN& 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 Date: Sat, 10 Sep 2022 22:12:03 -0500 Subject: [PATCH 394/515] GUI: wave generator, part 9 it's complete! --- src/gui/waveEdit.cpp | 74 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 2b7e638b0..69594f5dc 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -593,7 +593,23 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenSmooth<1) waveGenSmooth=1; } ImGui::TableNextColumn(); - ImGui::Button("Smooth"); + if (ImGui::Button("Smooth")) { + if (waveGenSmooth>0) e->lockEngine([this,wave]() { + int origData[256]; + memcpy(origData,wave->data,wave->len*sizeof(int)); + for (int i=0; ilen; i++) { + int dataSum=0; + for (int j=i; jlen; + dataSum+=origData[pos%wave->len]; + } + dataSum/=waveGenSmooth+1; + wave->data[i]=dataSum; + } + MARK_MODIFIED; + }); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -623,7 +639,39 @@ void FurnaceGUI::drawWaveEdit() { buttonSizeHalf.x-=ImGui::GetStyle().ItemSpacing.x; buttonSizeHalf.x*=0.5; - ImGui::Button("Normalize",buttonSize); + if (ImGui::Button("Normalize",buttonSize)) { + e->lockEngine([this,wave]() { + // find lowest point + int lowest=wave->max; + for (int i=0; ilen; i++) { + if (wave->data[i]data[i]; + } + + // find highest point + int highest=0; + for (int i=0; ilen; i++) { + if (wave->data[i]>highest) highest=wave->data[i]; + } + + // abort if lowest and highest points are equal + if (lowest==highest) return; + + // abort if lowest and highest points already span the entire height + if (lowest==wave->max && highest==0) return; + + // apply offset + for (int i=0; ilen; i++) { + wave->data[i]-=lowest; + } + highest-=lowest; + + // scale + for (int i=0; ilen; i++) { + wave->data[i]=(wave->data[i]*wave->max)/highest; + } + MARK_MODIFIED; + }); + } if (ImGui::Button("Invert",buttonSize)) { e->lockEngine([this,wave]() { for (int i=0; ilen; i++) { @@ -633,9 +681,25 @@ void FurnaceGUI::drawWaveEdit() { }); } - ImGui::Button("/2",buttonSizeHalf); + if (ImGui::Button("Half",buttonSizeHalf)) { + int origData[256]; + memcpy(origData,wave->data,wave->len*sizeof(int)); + + for (int i=0; ilen; i++) { + wave->data[i]=origData[i>>1]; + } + MARK_MODIFIED; + } ImGui::SameLine(); - ImGui::Button("×2",buttonSizeHalf); + if (ImGui::Button("Double",buttonSizeHalf)) { + int origData[256]; + memcpy(origData,wave->data,wave->len*sizeof(int)); + + for (int i=0; ilen; i++) { + wave->data[i]=origData[(i*2)%wave->len]; + } + MARK_MODIFIED; + } if (ImGui::Button("Convert Signed/Unsigned",buttonSize)) { if (wave->max>0) e->lockEngine([this,wave]() { @@ -643,7 +707,7 @@ void FurnaceGUI::drawWaveEdit() { if (wave->data[i]>(wave->max/2)) { wave->data[i]-=(wave->max+1)/2; } else { - wave->data[i]+=wave->max/2; + wave->data[i]+=(wave->max+1)/2; } } MARK_MODIFIED; From 09233b6de01faf39748192be53f8dbecff629214 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 22:35:21 -0500 Subject: [PATCH 395/515] GUI: add signed waveform view mode --- src/gui/gui.cpp | 13 ++++++++----- src/gui/gui.h | 4 ++-- src/gui/waveEdit.cpp | 32 ++++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0d0635ec5..66b562b6d 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -228,7 +228,7 @@ void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macr } } -void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMax, bool hex) { +void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMin, int macroMax, bool hex) { int buf=0; bool negaBuf=false; bool hasVal=false; @@ -264,9 +264,9 @@ void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int ma case ' ': if (hasVal) { hasVal=false; - negaBuf=false; macro[macroLen]=negaBuf?-buf:buf; - if (macro[macroLen]<0) macro[macroLen]=0; + negaBuf=false; + if (macro[macroLen]macroMax) macro[macroLen]=macroMax; macroLen++; buf=0; @@ -277,9 +277,9 @@ void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int ma } if (hasVal && macroLen<256) { hasVal=false; - negaBuf=false; macro[macroLen]=negaBuf?-buf:buf; - if (macro[macroLen]<0) macro[macroLen]=0; + negaBuf=false; + if (macro[macroLen]macroMax) macro[macroLen]=macroMax; macroLen++; buf=0; @@ -4621,6 +4621,7 @@ bool FurnaceGUI::init() { tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); + waveSigned=e->getConfBool("waveSigned",false); waveGenVisible=e->getConfBool("waveGenVisible",false); waveEditStyle=e->getConfInt("waveEditStyle",0); lockLayout=e->getConfBool("lockLayout",false); @@ -4906,6 +4907,7 @@ bool FurnaceGUI::finish() { e->setConf("tempoView",tempoView); e->setConf("waveHex",waveHex); + e->setConf("waveSigned",waveSigned); e->setConf("waveGenVisible",waveGenVisible); e->setConf("waveEditStyle",waveEditStyle); e->setConf("lockLayout",lockLayout); @@ -5112,6 +5114,7 @@ FurnaceGUI::FurnaceGUI(): firstFrame(true), tempoView(true), waveHex(false), + waveSigned(false), waveGenVisible(false), lockLayout(false), editOptsVisible(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 0f52115d6..2fb566d5c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1327,7 +1327,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, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble; + bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, waveSigned, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble; FurnaceGUIWindows curWindow, nextWindow, curWindowLast; float peak[2]; float patChanX[DIV_MAX_CHANS+1]; @@ -1741,7 +1741,7 @@ class FurnaceGUI { void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false, bool bit30=false); void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel, bool bit30=false); - void decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMax, bool hex=false); + void decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMin, int macroMax, bool hex=false); String encodeKeyMap(std::map& map); void decodeKeyMap(std::map& map, String source); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 69594f5dc..006ee4304 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -255,6 +255,9 @@ void FurnaceGUI::drawWaveEdit() { for (int i=0; ilen; i++) { if (wave->data[i]>wave->max) wave->data[i]=wave->max; wavePreview[i]=wave->data[i]; + if (waveSigned && !waveHex) { + wavePreview[i]-=(int)((wave->max+1)/2); + } } if (wave->len>0) wavePreview[wave->len]=wave->data[wave->len-1]; @@ -269,9 +272,9 @@ void FurnaceGUI::drawWaveEdit() { ImVec2 contentRegion=ImGui::GetContentRegionAvail(); // wavetable graph size determined here contentRegion.y-=ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().WindowPadding.y; if (waveEditStyle) { - PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,0,wave->max,contentRegion); + PlotNoLerp("##Waveform",wavePreview,wave->len+1,0,NULL,(waveSigned && !waveHex)?(-(int)((wave->max+1)/2)):0,(waveSigned && !waveHex)?((int)(wave->max/2)):wave->max,contentRegion); } else { - PlotCustom("##Waveform",wavePreview,wave->len,0,NULL,0,wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true); + PlotCustom("##Waveform",wavePreview,wave->len,0,NULL,(waveSigned && !waveHex)?(-(int)((wave->max+1)/2)):0,(waveSigned && !waveHex)?((int)(wave->max/2)):wave->max,contentRegion,sizeof(float),ImVec4(1.0f,1.0f,1.0f,1.0f),0,NULL,NULL,true); } if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { waveDragStart=ImGui::GetItemRectMin(); @@ -737,12 +740,33 @@ void FurnaceGUI::drawWaveEdit() { waveHex=true; } ImGui::SameLine(); + if (!waveHex) if (ImGui::Button(waveSigned?"±##WaveSign":"+##WaveSign",ImVec2(ImGui::GetFrameHeight(),ImGui::GetFrameHeight()))) { + waveSigned=!waveSigned; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Signed/Unsigned"); + } + ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); // wavetable text input size found here if (ImGui::InputText("##MMLWave",&mmlStringW)) { - decodeMMLStrW(mmlStringW,wave->data,wave->len,wave->max,waveHex); + int actualData[256]; + decodeMMLStrW(mmlStringW,actualData,wave->len,(waveSigned && !waveHex)?(-((wave->max+1)/2)):0,(waveSigned && !waveHex)?(wave->max/2):wave->max,waveHex); + if (waveSigned && !waveHex) { + for (int i=0; ilen; i++) { + actualData[i]+=(wave->max+1)/2; + } + } + memcpy(wave->data,actualData,wave->len*sizeof(int)); } if (!ImGui::IsItemActive()) { - encodeMMLStr(mmlStringW,wave->data,wave->len,-1,-1,waveHex); + int actualData[256]; + memcpy(actualData,wave->data,256*sizeof(int)); + if (waveSigned && !waveHex) { + for (int i=0; ilen; i++) { + actualData[i]-=(wave->max+1)/2; + } + } + encodeMMLStr(mmlStringW,actualData,wave->len,-1,-1,waveHex); } } } From 2952baaa5409f3e2d3f9c0d32d9eaef64a062d5b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 22:40:25 -0500 Subject: [PATCH 396/515] update 6-sample --- papers/doc/6-sample/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/papers/doc/6-sample/README.md b/papers/doc/6-sample/README.md index 59613da27..4fbb6c914 100644 --- a/papers/doc/6-sample/README.md +++ b/papers/doc/6-sample/README.md @@ -64,7 +64,3 @@ In there, you can modify certain data pertaining to your sample, such as the: - and many more. The changes you make will be applied as soon as you've committed them to your sample, but they can be undoed and redoed, just like text. - -# tips - -if you have a sample you wanna use that is about 44100 or anything over 32000Hz, downsample the sample to 32000Hz so that the pitch of the sample in Furnace stays like the original audio file, From 2f0e97f6d95a24ca718174cd826f69c769655941 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 23:20:22 -0500 Subject: [PATCH 397/515] GUI: FM operator swapping --- src/gui/gui.cpp | 1 + src/gui/gui.h | 2 +- src/gui/insEdit.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 66b562b6d..329c3e8e0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5217,6 +5217,7 @@ FurnaceGUI::FurnaceGUI(): chanToMove(-1), sysToMove(-1), sysToDelete(-1), + opToMove(-1), transposeAmount(0), randomizeMin(0), randomizeMax(255), diff --git a/src/gui/gui.h b/src/gui/gui.h index 2fb566d5c..f91c4beec 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1471,7 +1471,7 @@ class FurnaceGUI { int renderTimeBegin, renderTimeEnd, renderTimeDelta; int eventTimeBegin, eventTimeEnd, eventTimeDelta; - int chanToMove, sysToMove, sysToDelete; + int chanToMove, sysToMove, sysToDelete, opToMove; ImVec2 patWindowPos, patWindowSize; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ec9ba32ba..c2c7a2600 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1557,6 +1557,35 @@ void FurnaceGUI::drawMacros(std::vector& macros) { #define CENTER_TEXT_20(text) \ ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(20.0f*dpiScale-ImGui::CalcTextSize(text).x)); +#define OP_DRAG_POINT \ + if (ImGui::Button(ICON_FA_ARROWS)) { \ + } \ + if (ImGui::BeginDragDropSource()) { \ + opToMove=i; \ + ImGui::SetDragDropPayload("FUR_OP",NULL,0,ImGuiCond_Once); \ + ImGui::Button(ICON_FA_ARROWS "##SysDrag"); \ + ImGui::EndDragDropSource(); \ + } else if (ImGui::IsItemHovered()) { \ + ImGui::SetTooltip("(drag to swap operators)"); \ + } \ + if (ImGui::BeginDragDropTarget()) { \ + const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_OP"); \ + if (dragItem!=NULL) { \ + if (dragItem->IsDataType("FUR_OP")) { \ + if (opToMove!=i && opToMove>=0) { \ + e->lockEngine([this,ins,i]() { \ + DivInstrumentFM::Operator origOp=ins->fm.op[orderedOps[opToMove]]; \ + ins->fm.op[orderedOps[opToMove]]=ins->fm.op[orderedOps[i]]; \ + ins->fm.op[orderedOps[i]]=origOp; \ + }); \ + PARAMETER; \ + } \ + opToMove=-1; \ + } \ + } \ + ImGui::EndDragDropTarget(); \ + } + void FurnaceGUI::drawInsEdit() { if (nextWindow==GUI_WINDOW_INS_EDIT) { insEditOpen=true; @@ -2073,6 +2102,9 @@ void FurnaceGUI::drawInsEdit() { } else { ImGui::Text("OP%d",i+1); } + + // drag point + OP_DRAG_POINT; int maxTl=127; if (ins->type==DIV_INS_OPLL) { @@ -2356,7 +2388,10 @@ void FurnaceGUI::drawInsEdit() { } else { snprintf(tempID,1024,"Operator %d",i+1); } - CENTER_TEXT(tempID); + float nextCursorPosX=ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(tempID).x); + OP_DRAG_POINT; + ImGui::SameLine(); + ImGui::SetCursorPosX(nextCursorPosX); ImGui::TextUnformatted(tempID); float sliderHeight=200.0f*dpiScale; @@ -2789,6 +2824,8 @@ void FurnaceGUI::drawInsEdit() { } ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + OP_DRAG_POINT; + ImGui::SameLine(); if (ins->type==DIV_INS_OPL_DRUMS) { ImGui::Text("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { From 29f1be3b3605afa599cf099115a3a8f6d9e0bfac Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 23:32:04 -0500 Subject: [PATCH 398/515] fix audio backend not changing on switchMaster --- src/engine/engine.cpp | 11 ++++++++--- src/engine/engine.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index f6fe659ea..91764034e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3453,7 +3453,8 @@ void DivEngine::setConsoleMode(bool enable) { } bool DivEngine::switchMaster() { - deinitAudioBackend(); + logI("switching output..."); + deinitAudioBackend(true); quitDispatch(); initDispatch(); if (initAudioBackend()) { @@ -3599,6 +3600,7 @@ void DivEngine::quitDispatch() { bool DivEngine::initAudioBackend() { // load values + logI("initializing audio."); if (audioEngine==DIV_AUDIO_NULL) { if (getConfString("audioEngine","SDL")=="JACK") { audioEngine=DIV_AUDIO_JACK; @@ -3704,8 +3706,9 @@ bool DivEngine::initAudioBackend() { return true; } -bool DivEngine::deinitAudioBackend() { +bool DivEngine::deinitAudioBackend(bool dueToSwitchMaster) { if (output!=NULL) { + logI("closing audio output."); output->quit(); if (output->midiIn) { if (output->midiIn->isDeviceOpen()) { @@ -3722,7 +3725,9 @@ bool DivEngine::deinitAudioBackend() { output->quitMidi(); delete output; output=NULL; - //audioEngine=DIV_AUDIO_NULL; + if (dueToSwitchMaster) { + audioEngine=DIV_AUDIO_NULL; + } } return true; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 7c700e005..869587a24 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -452,7 +452,7 @@ class DivEngine { int loadSampleROM(String path, ssize_t expectedSize, unsigned char*& ret); bool initAudioBackend(); - bool deinitAudioBackend(); + bool deinitAudioBackend(bool dueToSwitchMaster=false); void registerSystems(); void initSongWithDesc(const int* description); From 03e226e52b1854ffb939b2da1b5b7dc312920693 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 10 Sep 2022 23:33:05 -0500 Subject: [PATCH 399/515] seamless switchMaster --- src/engine/engine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 91764034e..bb03eda18 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3455,8 +3455,6 @@ void DivEngine::setConsoleMode(bool enable) { bool DivEngine::switchMaster() { logI("switching output..."); deinitAudioBackend(true); - quitDispatch(); - initDispatch(); if (initAudioBackend()) { for (int i=0; i Date: Sat, 10 Sep 2022 23:50:53 -0500 Subject: [PATCH 400/515] GUI: fix toggles losing their colors on hover --- src/gui/editControls.cpp | 92 ++++++++++++++++++++-------------------- src/gui/gui.cpp | 29 +++++++++++++ src/gui/gui.h | 5 ++- src/gui/insEdit.cpp | 32 +++++++------- src/gui/sampleEdit.cpp | 16 +++---- 5 files changed, 102 insertions(+), 72 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 9d6c0d008..1d0e2a250 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -59,12 +59,12 @@ void FurnaceGUI::drawMobileControls() { if (!portrait) ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(e->isPlaying())); + pushToggleColors(e->isPlaying()); if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_PLAY "##Play",buttonSize)) { play(); } - ImGui::PopStyleColor(); + popToggleColors(); if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_STOP "##Stop",buttonSize)) { stop(); @@ -76,27 +76,27 @@ void FurnaceGUI::drawMobileControls() { } bool repeatPattern=e->getRepeatPattern(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(repeatPattern)); + pushToggleColors(repeatPattern); if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern",buttonSize)) { e->setRepeatPattern(!repeatPattern); } - ImGui::PopStyleColor(); + popToggleColors(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(edit)); + pushToggleColors(edit); if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_CIRCLE "##Edit",buttonSize)) { edit=!edit; } - ImGui::PopStyleColor(); + popToggleColors(); bool metro=e->getMetronome(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(metro)); + pushToggleColors(metro); if (portrait) ImGui::SameLine(); if (ImGui::Button(ICON_FA_BELL_O "##Metronome",buttonSize)) { e->setMetronome(!metro); } - ImGui::PopStyleColor(); + popToggleColors(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -306,11 +306,11 @@ void FurnaceGUI::drawEditControls() { ImGui::EndTable(); } - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(e->isPlaying())); + pushToggleColors(e->isPlaying()); if (ImGui::Button(ICON_FA_PLAY "##Play")) { play(); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); if (ImGui::Button(ICON_FA_STOP "##Stop")) { stop(); @@ -340,12 +340,12 @@ void FurnaceGUI::drawEditControls() { } ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + pushToggleColors(noteInputPoly); if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } - ImGui::PopStyleColor(); + popToggleColors(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -356,11 +356,11 @@ void FurnaceGUI::drawEditControls() { stop(); } ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(e->isPlaying())); + pushToggleColors(e->isPlaying()); if (ImGui::Button(ICON_FA_PLAY "##Play")) { play(); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROW_DOWN "##StepOne")) { e->stepOne(cursor.y); @@ -369,26 +369,26 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); bool repeatPattern=e->getRepeatPattern(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(repeatPattern)); + pushToggleColors(repeatPattern); if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern")) { e->setRepeatPattern(!repeatPattern); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(edit)); + pushToggleColors(edit); if (ImGui::Button(ICON_FA_CIRCLE "##Edit")) { edit=!edit; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); bool metro=e->getMetronome(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(metro)); + pushToggleColors(metro); if (ImGui::Button(ICON_FA_BELL_O "##Metronome")) { e->setMetronome(!metro); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); ImGui::Text("Octave"); @@ -425,12 +425,12 @@ void FurnaceGUI::drawEditControls() { unimportant(ImGui::Checkbox("Pattern",&followPattern)); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + pushToggleColors(noteInputPoly); if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } - ImGui::PopStyleColor(); + popToggleColors(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -438,11 +438,11 @@ void FurnaceGUI::drawEditControls() { case 2: // compact vertical if (ImGui::Begin("Play/Edit Controls",&editControlsOpen,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { ImVec2 buttonSize=ImVec2(ImGui::GetContentRegionAvail().x,0.0f); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(e->isPlaying())); + pushToggleColors(e->isPlaying()); if (ImGui::Button(ICON_FA_PLAY "##Play",buttonSize)) { play(); } - ImGui::PopStyleColor(); + popToggleColors(); if (ImGui::Button(ICON_FA_STOP "##Stop",buttonSize)) { stop(); } @@ -452,24 +452,24 @@ void FurnaceGUI::drawEditControls() { } bool repeatPattern=e->getRepeatPattern(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(repeatPattern)); + pushToggleColors(repeatPattern); if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern",buttonSize)) { e->setRepeatPattern(!repeatPattern); } - ImGui::PopStyleColor(); + popToggleColors(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(edit)); + pushToggleColors(edit); if (ImGui::Button(ICON_FA_CIRCLE "##Edit",buttonSize)) { edit=!edit; } - ImGui::PopStyleColor(); + popToggleColors(); bool metro=e->getMetronome(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(metro)); + pushToggleColors(metro); if (ImGui::Button(ICON_FA_BELL_O "##Metronome",buttonSize)) { e->setMetronome(!metro); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::Text("Oct."); float avail=ImGui::GetContentRegionAvail().x; @@ -496,23 +496,23 @@ void FurnaceGUI::drawEditControls() { } ImGui::Text("Foll."); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(followOrders)); + pushToggleColors(followOrders); if (ImGui::Button("Ord##FollowOrders",buttonSize)) { handleUnimportant followOrders=!followOrders; } - ImGui::PopStyleColor(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(followPattern)); + popToggleColors(); + pushToggleColors(followPattern); if (ImGui::Button("Pat##FollowPattern",buttonSize)) { handleUnimportant followPattern=!followPattern; } - ImGui::PopStyleColor(); + popToggleColors(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + pushToggleColors(noteInputPoly); if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } - ImGui::PopStyleColor(); + popToggleColors(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -520,11 +520,11 @@ void FurnaceGUI::drawEditControls() { case 3: // split if (ImGui::Begin("Play Controls",&editControlsOpen,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|globalWinFlags)) { if (e->isPlaying()) { - ImGui::PushStyleColor(ImGuiCol_Button,uiColors[GUI_COLOR_TOGGLE_ON]); + pushToggleColors(true); if (ImGui::Button(ICON_FA_STOP "##Stop")) { stop(); } - ImGui::PopStyleColor(); + popToggleColors(); } else { if (ImGui::Button(ICON_FA_PLAY "##Play")) { play(oldRow); @@ -547,35 +547,35 @@ void FurnaceGUI::drawEditControls() { } ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(edit)); + pushToggleColors(edit); if (ImGui::Button(ICON_FA_CIRCLE "##Edit")) { edit=!edit; } - ImGui::PopStyleColor(); + popToggleColors(); bool metro=e->getMetronome(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(metro)); + pushToggleColors(metro); if (ImGui::Button(ICON_FA_BELL_O "##Metronome")) { e->setMetronome(!metro); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); bool repeatPattern=e->getRepeatPattern(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(repeatPattern)); + pushToggleColors(repeatPattern); if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern")) { e->setRepeatPattern(!repeatPattern); } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + pushToggleColors(noteInputPoly); if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } - ImGui::PopStyleColor(); + popToggleColors(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 329c3e8e0..4785ee818 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2408,6 +2408,35 @@ void FurnaceGUI::toggleMobileUI(bool enable, bool force) { } } +void FurnaceGUI::pushToggleColors(bool status) { + ImVec4 toggleColor=status?uiColors[GUI_COLOR_TOGGLE_ON]:uiColors[GUI_COLOR_TOGGLE_OFF]; + ImGui::PushStyleColor(ImGuiCol_Button,toggleColor); + if (settings.guiColorsBase) { + toggleColor.x*=0.8f; + toggleColor.y*=0.8f; + toggleColor.z*=0.8f; + } else { + toggleColor.x=CLAMP(toggleColor.x*1.3f,0.0f,1.0f); + toggleColor.y=CLAMP(toggleColor.y*1.3f,0.0f,1.0f); + toggleColor.z=CLAMP(toggleColor.z*1.3f,0.0f,1.0f); + } + ImGui::PushStyleColor(ImGuiCol_ButtonHovered,toggleColor); + if (settings.guiColorsBase) { + toggleColor.x*=0.8f; + toggleColor.y*=0.8f; + toggleColor.z*=0.8f; + } else { + toggleColor.x=CLAMP(toggleColor.x*1.5f,0.0f,1.0f); + toggleColor.y=CLAMP(toggleColor.y*1.5f,0.0f,1.0f); + toggleColor.z=CLAMP(toggleColor.z*1.5f,0.0f,1.0f); + } + ImGui::PushStyleColor(ImGuiCol_ButtonActive,toggleColor); +} + +void FurnaceGUI::popToggleColors() { + ImGui::PopStyleColor(3); +} + int _processEvent(void* instance, SDL_Event* event) { return ((FurnaceGUI*)instance)->processEvent(event); } diff --git a/src/gui/gui.h b/src/gui/gui.h index f91c4beec..b71fe368d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -47,8 +47,6 @@ #define MARK_MODIFIED modified=true; #define WAKE_UP drawHalt=16; -#define TOGGLE_COLOR(x) ((x)?uiColors[GUI_COLOR_TOGGLE_ON]:uiColors[GUI_COLOR_TOGGLE_OFF]) - #define BIND_FOR(x) getKeyName(actionKeys[x],true).c_str() // TODO: @@ -1616,6 +1614,9 @@ class FurnaceGUI { void toggleMobileUI(bool enable, bool force=false); + void pushToggleColors(bool status); + void popToggleColors(); + void drawMobileControls(); void drawEditControls(); void drawSongInfo(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index c2c7a2600..563e05794 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3400,29 +3400,29 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) { ImGui::Text("Waveform"); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.triOn)); + pushToggleColors(ins->c64.triOn); if (ImGui::Button("tri")) { PARAMETER ins->c64.triOn=!ins->c64.triOn; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.sawOn)); + pushToggleColors(ins->c64.sawOn); if (ImGui::Button("saw")) { PARAMETER ins->c64.sawOn=!ins->c64.sawOn; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.pulseOn)); + pushToggleColors(ins->c64.pulseOn); if (ImGui::Button("pulse")) { PARAMETER ins->c64.pulseOn=!ins->c64.pulseOn; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.noiseOn)); + pushToggleColors(ins->c64.noiseOn); if (ImGui::Button("noise")) { PARAMETER ins->c64.noiseOn=!ins->c64.noiseOn; } - ImGui::PopStyleColor(); + popToggleColors(); ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); @@ -3484,29 +3484,29 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Filter Mode"); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.lp)); + pushToggleColors(ins->c64.lp); if (ImGui::Button("low")) { PARAMETER ins->c64.lp=!ins->c64.lp; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.bp)); + pushToggleColors(ins->c64.bp); if (ImGui::Button("band")) { PARAMETER ins->c64.bp=!ins->c64.bp; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.hp)); + pushToggleColors(ins->c64.hp); if (ImGui::Button("high")) { PARAMETER ins->c64.hp=!ins->c64.hp; } - ImGui::PopStyleColor(); + popToggleColors(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(ins->c64.ch3off)); + pushToggleColors(ins->c64.ch3off); if (ImGui::Button("ch3off")) { PARAMETER ins->c64.ch3off=!ins->c64.ch3off; } - ImGui::PopStyleColor(); + popToggleColors(); P(ImGui::Checkbox("Volume Macro is Cutoff Macro",&ins->c64.volIsCutoff)); P(ImGui::Checkbox("Absolute Cutoff Macro",&ins->c64.filterIsAbs)); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 76f654c16..51411c430 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -152,20 +152,20 @@ void FurnaceGUI::drawSampleEdit() { ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); + pushToggleColors(!sampleDragMode); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { sampleDragMode=false; } - ImGui::PopStyleColor(); + popToggleColors(); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Edit mode: Select"); } ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(sampleDragMode)); + pushToggleColors(sampleDragMode); if (ImGui::Button(ICON_FA_PENCIL "##SDraw")) { sampleDragMode=true; } - ImGui::PopStyleColor(); + popToggleColors(); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Edit mode: Draw"); } @@ -687,20 +687,20 @@ void FurnaceGUI::drawSampleEdit() { ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); + pushToggleColors(!sampleDragMode); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { sampleDragMode=false; } - ImGui::PopStyleColor(); + popToggleColors(); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Edit mode: Select"); } ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(sampleDragMode)); + pushToggleColors(sampleDragMode); if (ImGui::Button(ICON_FA_PENCIL "##SDraw")) { sampleDragMode=true; } - ImGui::PopStyleColor(); + popToggleColors(); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Edit mode: Draw"); } From d4867c505039461cb98606eb813643cf78c27e62 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 11 Sep 2022 05:14:15 -0500 Subject: [PATCH 401/515] GUI: consistency in credits --- src/gui/about.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index fae8019c5..b763ab97c 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -104,7 +104,7 @@ const char* aboutLine[]={ "fd", "GENATARi", "host12prog", - "lunathir", + "Lunathir", "plane", "TheEssem", "", From 7b1713758bca595ddc86acda8b087bf844d1379a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 12 Sep 2022 00:37:25 -0500 Subject: [PATCH 402/515] dev114 - operator muting for OPN/OPM --- papers/format.md | 4 ++- src/engine/engine.h | 4 +-- src/engine/instrument.cpp | 12 ++++++-- src/engine/platform/arcade.cpp | 7 ++++- src/engine/platform/arcade.h | 5 ++-- src/engine/platform/genesis.cpp | 7 ++++- src/engine/platform/genesis.h | 3 +- src/engine/platform/ym2203.cpp | 7 ++++- src/engine/platform/ym2203.h | 3 +- src/engine/platform/ym2608.cpp | 7 ++++- src/engine/platform/ym2608.h | 3 +- src/engine/platform/ym2610.cpp | 7 ++++- src/engine/platform/ym2610.h | 5 ++-- src/engine/platform/ym2610b.cpp | 7 ++++- src/engine/platform/ym2610b.h | 5 ++-- src/gui/insEdit.cpp | 52 ++++++++++++++++++++++++++------- 16 files changed, 108 insertions(+), 30 deletions(-) diff --git a/papers/format.md b/papers/format.md index 14512fe12..da06488fa 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 114: Furnace dev114 - 113: Furnace dev113 - 112: Furnace dev112 - 111: Furnace dev111 @@ -497,7 +498,8 @@ size | description 1 | vib 1 | ws 1 | ksr - 12 | reserved + 1 | operator enabled (>=114) or reserved + 11 | reserved --- | **Game Boy instrument data** 1 | volume 1 | direction diff --git a/src/engine/engine.h b/src/engine/engine.h index 869587a24..3047a8af7 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev113" -#define DIV_ENGINE_VERSION 113 +#define DIV_VERSION "dev114" +#define DIV_ENGINE_VERSION 114 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 19cb1ba55..22cdddf4b 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -71,8 +71,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(op.ws); w->writeC(op.ksr); + w->writeC(op.enable); + // reserved - for (int k=0; k<12; k++) { + for (int k=0; k<11; k++) { w->writeC(0); } } @@ -716,8 +718,14 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { op.ws=reader.readC(); op.ksr=reader.readC(); + if (version>=114) { + op.enable=reader.readC(); + } else { + reader.readC(); + } + // reserved - for (int k=0; k<12; k++) reader.readC(); + for (int k=0; k<11; k++) reader.readC(); } // GB diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 90de2387a..7d44fe8a8 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -348,7 +348,7 @@ void DivPlatformArcade::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x08,0x78|i); + immWrite(0x08,(chan[i].opMask<<3)|i); chan[i].keyOn=false; } } @@ -370,6 +370,11 @@ int DivPlatformArcade::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } chan[c.chan].macroInit(ins); diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 93aa490d0..683394e3b 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -45,7 +45,7 @@ class DivPlatformArcade: public DivPlatformOPM { signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; int vol, outVol; - unsigned char chVolL, chVolR; + unsigned char chVolL, chVolR, opMask; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -71,7 +71,8 @@ class DivPlatformArcade: public DivPlatformOPM { vol(0), outVol(0), chVolL(127), - chVolR(127) {} + chVolR(127), + opMask(15) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index f499865ef..5b4b535bf 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -480,7 +480,7 @@ void DivPlatformGenesis::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - if (i<6) immWrite(0x28,0xf0|konOffs[i]); + if (i<6) immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -591,6 +591,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } chan[c.chan].macroInit(ins); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 5e61fe678..34a4d4f23 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -47,7 +47,7 @@ class DivPlatformGenesis: public DivPlatformOPN { int ins; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset; int vol, outVol; - unsigned char pan; + unsigned char pan, opMask; bool dacMode; int dacPeriod; @@ -85,6 +85,7 @@ class DivPlatformGenesis: public DivPlatformOPN { vol(0), outVol(0), pan(3), + opMask(15), dacMode(false), dacPeriod(0), dacRate(0), diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 178ef05b8..46696b8ac 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -386,7 +386,7 @@ void DivPlatformYM2203::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -409,6 +409,11 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 0395c9d0f..921c1d94b 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -43,7 +43,7 @@ class DivPlatformYM2203: public DivPlatformOPN { DivInstrumentFM state; unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + unsigned char psgMode, autoEnvNum, autoEnvDen, opMask; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; @@ -66,6 +66,7 @@ class DivPlatformYM2203: public DivPlatformOPN { psgMode(1), autoEnvNum(0), autoEnvDen(0), + opMask(15), active(false), insChanged(true), freqChanged(false), diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 244e4a16e..801bab329 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -582,7 +582,7 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -683,6 +683,11 @@ int DivPlatformYM2608::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 7a471b8bf..1689436ee 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -48,7 +48,7 @@ class DivPlatformYM2608: public DivPlatformOPN { DivInstrumentFM state; unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + unsigned char psgMode, autoEnvNum, autoEnvDen, opMask; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; @@ -72,6 +72,7 @@ class DivPlatformYM2608: public DivPlatformOPN { psgMode(1), autoEnvNum(0), autoEnvDen(0), + opMask(15), active(false), insChanged(true), freqChanged(false), diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 064b49f2d..63a6d72e3 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -619,7 +619,7 @@ void DivPlatformYM2610::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -727,6 +727,11 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 5e22ed2a0..0e363329a 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -76,7 +76,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; int sample; - unsigned char pan; + unsigned char pan, opMask; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -107,7 +107,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { vol(0), outVol(15), sample(-1), - pan(3) {} + pan(3), + opMask(15) {} }; Channel chan[14]; DivDispatchOscBuffer* oscBuf[14]; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 8d283374d..f01f39b42 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -601,7 +601,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -709,6 +709,11 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 703f8dd4a..87500e9b0 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -43,7 +43,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; int sample; - unsigned char pan; + unsigned char pan, opMask; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -74,7 +74,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { vol(0), outVol(15), sample(-1), - pan(3) {} + pan(3), + opMask(15) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 563e05794..3ffc86a8a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1737,6 +1737,7 @@ void FurnaceGUI::drawInsEdit() { int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; + bool opsAreMutable=(ins->type==DIV_INS_FM); if (ImGui::BeginTabItem("FM")) { if (ImGui::BeginTable("fmDetails",3,ImGuiTableFlags_SizingStretchSame)) { @@ -2091,16 +2092,27 @@ void FurnaceGUI::drawInsEdit() { if (i==0) sliderHeight=(ImGui::GetContentRegionAvail().y/opCount)-ImGui::GetStyle().ItemSpacing.y; ImGui::PushID(fmt::sprintf("op%d",i).c_str()); + String opNameLabel; if (ins->type==DIV_INS_OPL_DRUMS) { - ImGui::Text("%s",oplDrumNames[i]); + opNameLabel=fmt::sprintf("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { - ImGui::Text("Kick"); + opNameLabel="Kick"; } else { - ImGui::Text("Env"); + opNameLabel="Env"; } } else { - ImGui::Text("OP%d",i+1); + opNameLabel=fmt::sprintf("OP%d",i+1); + } + if (opsAreMutable) { + pushToggleColors(op.enable); + if (ImGui::Button(opNameLabel.c_str())) { + op.enable=!op.enable; + PARAMETER; + } + popToggleColors(); + } else { + ImGui::TextUnformatted(opNameLabel.c_str()); } // drag point @@ -2388,11 +2400,20 @@ void FurnaceGUI::drawInsEdit() { } else { snprintf(tempID,1024,"Operator %d",i+1); } - float nextCursorPosX=ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(tempID).x); + float nextCursorPosX=ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(tempID).x-(opsAreMutable?(ImGui::GetStyle().FramePadding.x*2.0f):0.0f)); OP_DRAG_POINT; ImGui::SameLine(); ImGui::SetCursorPosX(nextCursorPosX); - ImGui::TextUnformatted(tempID); + if (opsAreMutable) { + pushToggleColors(op.enable); + if (ImGui::Button(tempID)) { + op.enable=!op.enable; + PARAMETER; + } + popToggleColors(); + } else { + ImGui::TextUnformatted(tempID); + } float sliderHeight=200.0f*dpiScale; float waveWidth=140.0*dpiScale; @@ -2824,18 +2845,29 @@ void FurnaceGUI::drawInsEdit() { } ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + String opNameLabel; OP_DRAG_POINT; ImGui::SameLine(); if (ins->type==DIV_INS_OPL_DRUMS) { - ImGui::Text("%s",oplDrumNames[i]); + opNameLabel=fmt::sprintf("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { - ImGui::Text("Envelope 2 (kick only)"); + opNameLabel="Envelope 2 (kick only)"; } else { - ImGui::Text("Envelope"); + opNameLabel="Envelope"; } } else { - ImGui::Text("OP%d",i+1); + opNameLabel=fmt::sprintf("OP%d",i+1); + } + if (opsAreMutable) { + pushToggleColors(op.enable); + if (ImGui::Button(opNameLabel.c_str())) { + op.enable=!op.enable; + PARAMETER; + } + popToggleColors(); + } else { + ImGui::TextUnformatted(opNameLabel.c_str()); } ImGui::SameLine(); From d64e20e85958d12451b94a01173e01786a07fea0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 12 Sep 2022 00:51:09 -0500 Subject: [PATCH 403/515] implement operator muting for ExtCh mode --- src/engine/platform/genesisext.cpp | 9 ++++++--- src/engine/platform/genesisext.h | 3 ++- src/engine/platform/ym2203ext.cpp | 9 ++++++--- src/engine/platform/ym2203ext.h | 4 ++-- src/engine/platform/ym2608ext.cpp | 9 ++++++--- src/engine/platform/ym2608ext.h | 4 ++-- src/engine/platform/ym2610bext.cpp | 9 ++++++--- src/engine/platform/ym2610bext.h | 4 ++-- src/engine/platform/ym2610ext.cpp | 9 ++++++--- src/engine/platform/ym2610ext.h | 4 ++-- 10 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index dfd7d514c..3f03e622a 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -69,6 +69,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { rWrite(baseAddr+0x70,op.d2r&31); rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+0x90,op.ssgEnv&15); + opChan[ch].mask=op.enable; } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); @@ -412,7 +413,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) { bool writeSomething=false; unsigned char writeMask=2; for (int i=0; i<4; i++) { - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn || opChan[i].keyOff) { writeSomething=true; writeMask&=~(1<<(4+i)); @@ -459,10 +460,12 @@ void DivPlatformGenesisExt::tick(bool sysTick) { immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsL[i],opChan[i].freq&0xff); } - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn) { writeNoteOn=true; - writeMask|=1<<(4+i); + if (opChan[i].mask) { + writeMask|=1<<(4+i); + } opChan[i].keyOn=false; } } diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 07e0d5cc3..d4dd93e77 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -27,7 +27,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; unsigned char pan; OpChannel(): @@ -46,6 +46,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { keyOff(false), portaPause(false), inPorta(false), + mask(true), vol(0), pan(3) {} }; diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 3ff24eb74..c7080d431 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -59,6 +59,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x70,op.d2r&31); rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+0x90,op.ssgEnv&15); + opChan[ch].mask=op.enable; } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); @@ -358,7 +359,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) { bool writeSomething=false; unsigned char writeMask=2; for (int i=0; i<4; i++) { - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn || opChan[i].keyOff) { writeSomething=true; writeMask&=~(1<<(4+i)); @@ -395,10 +396,12 @@ void DivPlatformYM2203Ext::tick(bool sysTick) { immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsL[i],opChan[i].freq&0xff); } - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn) { writeNoteOn=true; - writeMask|=1<<(4+i); + if (opChan[i].mask) { + writeMask|=1<<(4+i); + } opChan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index 1a398d1a6..d25ca45d5 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -27,12 +27,12 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; unsigned char pan; // UGLY OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} + inPorta(false), mask(true), vol(0), pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 63503ccc3..c6d7e03b6 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -59,6 +59,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x70,op.d2r&31); rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+0x90,op.ssgEnv&15); + opChan[ch].mask=op.enable; } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); @@ -358,7 +359,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) { bool writeSomething=false; unsigned char writeMask=2; for (int i=0; i<4; i++) { - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn || opChan[i].keyOff) { writeSomething=true; writeMask&=~(1<<(4+i)); @@ -395,10 +396,12 @@ void DivPlatformYM2608Ext::tick(bool sysTick) { immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsL[i],opChan[i].freq&0xff); } - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn) { writeNoteOn=true; - writeMask|=1<<(4+i); + if (opChan[i].mask) { + writeMask|=1<<(4+i); + } opChan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2608ext.h b/src/engine/platform/ym2608ext.h index bc3d4f991..21c8a35c4 100644 --- a/src/engine/platform/ym2608ext.h +++ b/src/engine/platform/ym2608ext.h @@ -27,12 +27,12 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; unsigned char pan; // UGLY OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} + inPorta(false), mask(true), vol(0), pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 7c8247ff8..f55e6561c 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -59,6 +59,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { rWrite(baseAddr+0x70,op.d2r&31); rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+0x90,op.ssgEnv&15); + opChan[ch].mask=op.enable; } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); @@ -358,7 +359,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { bool writeSomething=false; unsigned char writeMask=2; for (int i=0; i<4; i++) { - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn || opChan[i].keyOff) { writeSomething=true; writeMask&=~(1<<(4+i)); @@ -395,10 +396,12 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsL[i],opChan[i].freq&0xff); } - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn) { writeNoteOn=true; - writeMask|=1<<(4+i); + if (opChan[i].mask) { + writeMask|=1<<(4+i); + } opChan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index 732678fe5..e60f97133 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -27,12 +27,12 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; unsigned char pan; // UGLY OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} + inPorta(false), mask(true), vol(0), pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index b2bd06a8c..6cee242f4 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -59,6 +59,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x70,op.d2r&31); rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+0x90,op.ssgEnv&15); + opChan[ch].mask=op.enable; } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[1]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); @@ -358,7 +359,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { bool writeSomething=false; unsigned char writeMask=2; for (int i=0; i<4; i++) { - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn || opChan[i].keyOff) { writeSomething=true; writeMask&=~(1<<(4+i)); @@ -395,10 +396,12 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsL[i],opChan[i].freq&0xff); } - writeMask|=opChan[i].active<<(4+i); + writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); if (opChan[i].keyOn) { writeNoteOn=true; - writeMask|=1<<(4+i); + if (opChan[i].mask) { + writeMask|=1<<(4+i); + } opChan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 119d63569..07d855c0d 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -27,12 +27,12 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; unsigned char pan; // UGLY OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} + inPorta(false), mask(true), vol(0), pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; From 6e1f54b77736d1040f7001c3b46f1b174c52e99a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 12 Sep 2022 01:50:27 -0500 Subject: [PATCH 404/515] YM2612: implement OpMask will be done for OPM and the rest of the OPN chips later --- src/engine/platform/genesis.cpp | 7 ++++++- src/engine/platform/genesis.h | 3 ++- src/gui/insEdit.cpp | 7 +++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 5b4b535bf..515f0c0ae 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -347,6 +347,10 @@ void DivPlatformGenesis::tick(bool sysTick) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } + if (chan[i].std.ex4.had && chan[i].active) { + chan[i].opMask=chan[i].std.ex4.val&15; + chan[i].opMaskChanged=true; + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -479,8 +483,9 @@ void DivPlatformGenesis::tick(bool sysTick) { } chan[i].freqChanged=false; } - if (chan[i].keyOn) { + if (chan[i].keyOn || chan[i].opMaskChanged) { if (i<6) immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; chan[i].keyOn=false; } } diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 34a4d4f23..8588b21d4 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -45,7 +45,7 @@ class DivPlatformGenesis: public DivPlatformOPN { unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, note; int ins; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset, opMaskChanged; int vol, outVol; unsigned char pan, opMask; @@ -82,6 +82,7 @@ class DivPlatformGenesis: public DivPlatformOPN { furnaceDac(false), inPorta(false), hardReset(false), + opMaskChanged(false), vol(0), outVol(0), pan(3), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 3ffc86a8a..1c49bf99e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3101,7 +3101,14 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); + } + if (ins->type==DIV_INS_FM) { macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,fmOperatorBits)); + } else if (ins->type==DIV_INS_OPZ) { + macroList.push_back(FurnaceGUIMacroDesc("AM Depth 2",&ins->std.ex5Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("PM Depth 2",&ins->std.ex6Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("LFO2 Speed",&ins->std.ex7Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("LFO2 Shape",&ins->std.ex8Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } drawMacros(macroList); ImGui::EndTabItem(); From a08ae8cce7e0b8d41a79db90de61cb46020ef184 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 12 Sep 2022 02:26:00 -0500 Subject: [PATCH 405/515] implement OpMask for the rest of FM chips whether supported --- src/engine/platform/arcade.cpp | 7 ++++++- src/engine/platform/arcade.h | 3 ++- src/engine/platform/ym2203.cpp | 7 ++++++- src/engine/platform/ym2203.h | 3 ++- src/engine/platform/ym2608.cpp | 7 ++++++- src/engine/platform/ym2608.h | 3 ++- src/engine/platform/ym2610.cpp | 7 ++++++- src/engine/platform/ym2610.h | 3 ++- src/engine/platform/ym2610b.cpp | 7 ++++++- src/engine/platform/ym2610b.h | 3 ++- 10 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 7d44fe8a8..6e925c9a0 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -255,6 +255,10 @@ void DivPlatformArcade::tick(bool sysTick) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } + if (chan[i].std.ex4.had && chan[i].active) { + chan[i].opMask=chan[i].std.ex4.val&15; + chan[i].opMaskChanged=true; + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -347,8 +351,9 @@ void DivPlatformArcade::tick(bool sysTick) { immWrite(i+0x30,chan[i].freq<<2); chan[i].freqChanged=false; } - if (chan[i].keyOn) { + if (chan[i].keyOn || chan[i].opMaskChanged) { immWrite(0x08,(chan[i].opMask<<3)|i); + chan[i].opMaskChanged=false; chan[i].keyOn=false; } } diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 683394e3b..2a9c2b40c 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -43,7 +43,7 @@ class DivPlatformArcade: public DivPlatformOPM { int freq, baseFreq, pitch, pitch2, note; int ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset, opMaskChanged; int vol, outVol; unsigned char chVolL, chVolR, opMask; void macroInit(DivInstrument* which) { @@ -68,6 +68,7 @@ class DivPlatformArcade: public DivPlatformOPM { portaPause(false), furnacePCM(false), hardReset(false), + opMaskChanged(false), vol(0), outVol(0), chVolL(127), diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 46696b8ac..1c3488006 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -273,6 +273,10 @@ void DivPlatformYM2203::tick(bool sysTick) { chan[i].state.fb=chan[i].std.fb.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); } + if (chan[i].std.ex4.had && chan[i].active) { + chan[i].opMask=chan[i].std.ex4.val&15; + chan[i].opMaskChanged=true; + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -385,8 +389,9 @@ void DivPlatformYM2203::tick(bool sysTick) { immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); chan[i].freqChanged=false; } - if (chan[i].keyOn) { + if (chan[i].keyOn || chan[i].opMaskChanged) { immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; chan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 921c1d94b..756603651 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -45,7 +45,7 @@ class DivPlatformYM2203: public DivPlatformOPN { int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; unsigned char psgMode, autoEnvNum, autoEnvDen, opMask; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset, opMaskChanged; int vol, outVol; int sample; DivMacroInt std; @@ -76,6 +76,7 @@ class DivPlatformYM2203: public DivPlatformOPN { inPorta(false), furnacePCM(false), hardReset(false), + opMaskChanged(false), vol(0), outVol(15), sample(-1) {} diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 801bab329..ec90c1c6b 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -441,6 +441,10 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } + if (chan[i].std.ex4.had && chan[i].active) { + chan[i].opMask=chan[i].std.ex4.val&15; + chan[i].opMaskChanged=true; + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -581,8 +585,9 @@ void DivPlatformYM2608::tick(bool sysTick) { immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); chan[i].freqChanged=false; } - if (chan[i].keyOn) { + if (chan[i].keyOn || chan[i].opMaskChanged) { immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; chan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 1689436ee..ed850bf85 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -50,7 +50,7 @@ class DivPlatformYM2608: public DivPlatformOPN { int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; unsigned char psgMode, autoEnvNum, autoEnvDen, opMask; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset, opMaskChanged; int vol, outVol; int sample; unsigned char pan; @@ -82,6 +82,7 @@ class DivPlatformYM2608: public DivPlatformOPN { inPorta(false), furnacePCM(false), hardReset(false), + opMaskChanged(false), vol(0), outVol(15), sample(-1), diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 63a6d72e3..6a8509d55 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -482,6 +482,10 @@ void DivPlatformYM2610::tick(bool sysTick) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } + if (chan[i].std.ex4.had && chan[i].active) { + chan[i].opMask=chan[i].std.ex4.val&15; + chan[i].opMaskChanged=true; + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -618,8 +622,9 @@ void DivPlatformYM2610::tick(bool sysTick) { immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); chan[i].freqChanged=false; } - if (chan[i].keyOn) { + if (chan[i].keyOn || chan[i].opMaskChanged) { immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; chan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 0e363329a..4f1a16642 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -73,7 +73,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; unsigned char psgMode, autoEnvNum, autoEnvDen; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset, opMaskChanged; int vol, outVol; int sample; unsigned char pan, opMask; @@ -104,6 +104,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { inPorta(false), furnacePCM(false), hardReset(false), + opMaskChanged(false), vol(0), outVol(15), sample(-1), diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index f01f39b42..31cd7b3ff 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -465,6 +465,10 @@ void DivPlatformYM2610B::tick(bool sysTick) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } + if (chan[i].std.ex4.had && chan[i].active) { + chan[i].opMask=chan[i].std.ex4.val&15; + chan[i].opMaskChanged=true; + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -600,8 +604,9 @@ void DivPlatformYM2610B::tick(bool sysTick) { immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); chan[i].freqChanged=false; } - if (chan[i].keyOn) { + if (chan[i].keyOn || chan[i].opMaskChanged) { immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; chan[i].keyOn=false; } } diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 87500e9b0..1d5fc1f31 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -40,7 +40,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; unsigned char psgMode, autoEnvNum, autoEnvDen; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset, opMaskChanged; int vol, outVol; int sample; unsigned char pan, opMask; @@ -71,6 +71,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { inPorta(false), furnacePCM(false), hardReset(false), + opMaskChanged(false), vol(0), outVol(15), sample(-1), From d19c6fc236ffe0e789a990e8dbbced41a4e26289 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 13 Sep 2022 03:29:28 -0500 Subject: [PATCH 406/515] GUI: add operator copy --- src/gui/insEdit.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1c49bf99e..a4b99d141 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1564,20 +1564,32 @@ void FurnaceGUI::drawMacros(std::vector& macros) { opToMove=i; \ ImGui::SetDragDropPayload("FUR_OP",NULL,0,ImGuiCond_Once); \ ImGui::Button(ICON_FA_ARROWS "##SysDrag"); \ + ImGui::SameLine(); \ + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ + ImGui::Text("(copying)"); \ + } else { \ + ImGui::Text("(swapping)"); \ + } \ ImGui::EndDragDropSource(); \ } else if (ImGui::IsItemHovered()) { \ - ImGui::SetTooltip("(drag to swap operators)"); \ + ImGui::SetTooltip("- drag to swap operator\n- shift-drag to copy operator"); \ } \ if (ImGui::BeginDragDropTarget()) { \ const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_OP"); \ if (dragItem!=NULL) { \ if (dragItem->IsDataType("FUR_OP")) { \ if (opToMove!=i && opToMove>=0) { \ - e->lockEngine([this,ins,i]() { \ - DivInstrumentFM::Operator origOp=ins->fm.op[orderedOps[opToMove]]; \ - ins->fm.op[orderedOps[opToMove]]=ins->fm.op[orderedOps[i]]; \ - ins->fm.op[orderedOps[i]]=origOp; \ - }); \ + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ + e->lockEngine([this,ins,i]() { \ + ins->fm.op[orderedOps[i]]=ins->fm.op[orderedOps[opToMove]]; \ + }); \ + } else { \ + e->lockEngine([this,ins,i]() { \ + DivInstrumentFM::Operator origOp=ins->fm.op[orderedOps[opToMove]]; \ + ins->fm.op[orderedOps[opToMove]]=ins->fm.op[orderedOps[i]]; \ + ins->fm.op[orderedOps[i]]=origOp; \ + }); \ + } \ PARAMETER; \ } \ opToMove=-1; \ From 146255b08e03250486d165dab911cf24f61fd8f7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 13 Sep 2022 03:29:36 -0500 Subject: [PATCH 407/515] OPZ: SysEx fixes and notes --- src/engine/platform/sound/ymfm/ymfm_opz.cpp | 4 ++++ src/gui/sysEx.cpp | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/sound/ymfm/ymfm_opz.cpp b/src/engine/platform/sound/ymfm/ymfm_opz.cpp index 94123bf62..37c6a5fce 100644 --- a/src/engine/platform/sound/ymfm/ymfm_opz.cpp +++ b/src/engine/platform/sound/ymfm/ymfm_opz.cpp @@ -292,6 +292,10 @@ bool opz_registers::write(uint16_t index, uint8_t data, uint32_t &channel, uint3 // note from tildearrow: // - are you kidding? I have to write to this "load preset" register before keying on? + // another note from tildearrow: + // - see https://github.com/110-kenichi/ymfm/blob/main/src/ymfm_opz.cpp + // - is 0x08 the actual key on register just like OPM? + // - if so then what's bit 5? if ((index & 0xf8) == 0x20 /*&& bitfield(index, 0, 3) == bitfield(m_regdata[0x08], 0, 3)*/) { channel = bitfield(index, 0, 3); diff --git a/src/gui/sysEx.cpp b/src/gui/sysEx.cpp index 5b2b66576..f8849b562 100644 --- a/src/gui/sysEx.cpp +++ b/src/gui/sysEx.cpp @@ -1,6 +1,17 @@ #include "gui.h" #include "../ta-log.h" +// table taken from https://nornand.hatenablog.com/entry/2020/11/21/201911 +// Yamaha why didn't you just use 0-127 as it should be? +const unsigned char tlTable[100]={ + 127, 122, 118, 114, 110, 107, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 85, 84, 82, 81, + // desde aquí la tabla consiste de valores que bajan de 1 en 1 + 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, + 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, + 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +}; + bool FurnaceGUI::parseSysEx(unsigned char* data, size_t len) { SafeReader reader(data,len); @@ -137,7 +148,7 @@ bool FurnaceGUI::parseSysEx(unsigned char* data, size_t len) { op.sl=15-reader.readC(); reader.readC(); // LS - ignore op.am=(reader.readC()&0x40)?1:0; - op.tl=3+((99-reader.readC())*124)/99; + op.tl=tlTable[reader.readC()%100]; unsigned char freq=reader.readC(); logV("OP%d freq: %d",i,freq); op.mult=freq>>2; From 216acd5ec5a8130f9d9f04dea5623db3a7720a81 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 09:21:16 +0000 Subject: [PATCH 408/515] fix n163 doc 256 bytes, not 128. https://www.nesdev.org/wiki/Namco_163_audio also some better wording --- papers/doc/7-systems/n163.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 3c2f389f9..78aca3ae6 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,6 +1,6 @@ # Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) -This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 128 byte of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consumes 8 bytes for each channel. You must avoid conflict with channel register area and waveform for avoid broken channel playback. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 bytes of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. It outputs only a single channel at clock; so its sound quality gets more crunchy as more channels are activated. From f60e650a91070cdd7914150e7d1888c6bc1707d5 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:18:08 +0000 Subject: [PATCH 409/515] correct doc no brainwashing --- papers/doc/7-systems/n163.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 78aca3ae6..fb9502deb 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,8 +1,8 @@ # Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) -This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 bytes of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 64 bytes can dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. -It outputs only a single channel at clock; so its sound quality gets more crunchy as more channels are activated. +Namco 163 does not internally mix its channels. Instead, each channel is output one at a time, when multiple channels are used it will cycle between them; so its sound quality gets more crunchy as more channels are activated. Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. From 6a735ee3487068f4fface2ee4b38611f867472a2 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:25:37 +0000 Subject: [PATCH 410/515] no noise for MMC5 --- papers/doc/7-systems/mmc5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/mmc5.md b/papers/doc/7-systems/mmc5.md index faf305c60..5949dbb94 100644 --- a/papers/doc/7-systems/mmc5.md +++ b/papers/doc/7-systems/mmc5.md @@ -9,4 +9,4 @@ additionally, it offers an 8-bit DAC which can be used to play samples. only one # effects - `12xx`: set duty cycle or noise mode of channel. - - may be 0-3 for the pulse channels and 0-1 for the noise channel. + - may be 0-3 for the pulse channels From 70ca9033c76bef4d8624f09d11b1cb1f13209782 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:58:43 +0000 Subject: [PATCH 411/515] Add Generic PCM DAC document --- papers/doc/7-systems/dac.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 papers/doc/7-systems/dac.md diff --git a/papers/doc/7-systems/dac.md b/papers/doc/7-systems/dac.md new file mode 100644 index 000000000..856db2cd0 --- /dev/null +++ b/papers/doc/7-systems/dac.md @@ -0,0 +1,7 @@ +# Generic PCM DAC + +Realtek HD Audio's predecessor. It's just a 1/8/16-bit sample channel, with freely selectable rate and mono/stereo settings. With it, you can emulate PCM DACs found in Williams arcade boards, Sound Blasters, MSX TurboR, Atari STE, NEC PC-9801-86 etc. + +# effects + +none yet. From c99ac948389b92a8414a02c0986541aa9421a25c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 14 Sep 2022 00:19:24 -0500 Subject: [PATCH 412/515] YM2612: fix clicks when muting with CSM on --- src/engine/platform/genesisext.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 3f03e622a..d22f71acb 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -25,6 +25,7 @@ #define CHIP_DIVIDER fmDivBase #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) +#define IS_EXTCH_MUTED (isOpMuted[0] && isOpMuted[1] && isOpMuted[2] && isOpMuted[3]) int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.chan<2) { @@ -73,7 +74,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); + rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -124,7 +125,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { opChan[i].pan=opChan[ch].pan; } } - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); + rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -398,6 +399,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { rWrite(baseAddr+0x40,op.tl); immWrite(baseAddr+0x40,op.tl); } + + rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-2].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); } static int opChanOffsL[4]={ @@ -547,7 +550,11 @@ void DivPlatformGenesisExt::forceIns() { rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); - rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + if (i==2) { + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + } else { + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + } if (chan[i].active) { chan[i].keyOn=true; chan[i].freqChanged=true; From 480243b652d1dea8be853561a9c8b47321240095 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 14 Sep 2022 00:51:45 -0500 Subject: [PATCH 413/515] what? --- src/engine/platform/genesisext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index d22f71acb..a2df33c41 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -551,7 +551,7 @@ void DivPlatformGenesisExt::forceIns() { } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (i==2) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } else { rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } From 359fda701677d83f1d9c58a96da5e3ca2c34825b Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Wed, 14 Sep 2022 11:04:28 +0000 Subject: [PATCH 414/515] addressing feedback --- papers/doc/7-systems/mmc5.md | 2 +- papers/doc/7-systems/n163.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/papers/doc/7-systems/mmc5.md b/papers/doc/7-systems/mmc5.md index 5949dbb94..d483bd57c 100644 --- a/papers/doc/7-systems/mmc5.md +++ b/papers/doc/7-systems/mmc5.md @@ -9,4 +9,4 @@ additionally, it offers an 8-bit DAC which can be used to play samples. only one # effects - `12xx`: set duty cycle or noise mode of channel. - - may be 0-3 for the pulse channels + - may be 0-3 for the pulse channels. diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index fb9502deb..90f432289 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,8 +1,8 @@ # Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) -This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 64 bytes can dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 128 nibbles (64 bytes) can be dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. -Namco 163 does not internally mix its channels. Instead, each channel is output one at a time, when multiple channels are used it will cycle between them; so its sound quality gets more crunchy as more channels are activated. +Namco 163 does not internally mix its channels. Because of that, only one channel can be output at the time, when multiple channels are used it will cycle between them, similarily to OPLL. Therefore, its sound quality gets more crunchy as more channels are activated. Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. From aa38292ca4e91aeedcefdc32701389c99deac521 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 16 Sep 2022 00:04:43 -0500 Subject: [PATCH 415/515] GUI: fix OPLL/OPL op swapping --- src/gui/insEdit.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index a4b99d141..df92dd523 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1579,15 +1579,17 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (dragItem!=NULL) { \ if (dragItem->IsDataType("FUR_OP")) { \ if (opToMove!=i && opToMove>=0) { \ + int destOp=(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i; \ + int sourceOp=(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[opToMove]:opToMove; \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ - e->lockEngine([this,ins,i]() { \ - ins->fm.op[orderedOps[i]]=ins->fm.op[orderedOps[opToMove]]; \ + e->lockEngine([ins,destOp,sourceOp]() { \ + ins->fm.op[destOp]=ins->fm.op[sourceOp]; \ }); \ } else { \ - e->lockEngine([this,ins,i]() { \ - DivInstrumentFM::Operator origOp=ins->fm.op[orderedOps[opToMove]]; \ - ins->fm.op[orderedOps[opToMove]]=ins->fm.op[orderedOps[i]]; \ - ins->fm.op[orderedOps[i]]=origOp; \ + e->lockEngine([ins,destOp,sourceOp]() { \ + DivInstrumentFM::Operator origOp=ins->fm.op[sourceOp]; \ + ins->fm.op[sourceOp]=ins->fm.op[destOp]; \ + ins->fm.op[destOp]=origOp; \ }); \ } \ PARAMETER; \ From 587e066d4300578cc7701bb959399f18670143b2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 16 Sep 2022 00:18:14 -0500 Subject: [PATCH 416/515] GUI: randomize in macros under the right click --- src/gui/gui.cpp | 2 ++ src/gui/gui.h | 1 + src/gui/insEdit.cpp | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4785ee818..5153e1f6a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5216,6 +5216,8 @@ FurnaceGUI::FurnaceGUI(): macroOffY(0), macroScaleX(100.0f), macroScaleY(100.0f), + macroRandMin(0), + macroRandMax(0), macroLoopDragStart(0,0), macroLoopDragAreaSize(0,0), macroLoopDragTarget(NULL), diff --git a/src/gui/gui.h b/src/gui/gui.h index b71fe368d..1c8ee713f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1446,6 +1446,7 @@ class FurnaceGUI { FurnaceGUIMacroDesc lastMacroDesc; int macroOffX, macroOffY; float macroScaleX, macroScaleY; + int macroRandMin, macroRandMax; ImVec2 macroLoopDragStart; ImVec2 macroLoopDragAreaSize; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index df92dd523..b5347cbee 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4556,6 +4556,28 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndMenu(); } + if (ImGui::BeginMenu("randomize...")) { + if (macroRandMinlastMacroDesc.max) macroRandMin=lastMacroDesc.max; + if (macroRandMaxlastMacroDesc.max) macroRandMax=lastMacroDesc.max; + ImGui::InputInt("Min",¯oRandMin,1,10); + ImGui::InputInt("Max",¯oRandMax,1,10); + if (ImGui::Button("randomize")) { + for (int i=0; ilen; i++) { + int val=0; + if (macroRandMax<=macroRandMin) { + val=macroRandMin; + } else { + val=macroRandMin+(rand()%(macroRandMax-macroRandMin+1)); + } + lastMacroDesc.macro->val[i]=val; + } + + ImGui::CloseCurrentPopup(); + } + ImGui::EndMenu(); + } ImGui::EndPopup(); } From 6b0aee8cf7cb6f6ea89fd02c42939b80f1fc02f4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 16 Sep 2022 02:00:42 -0500 Subject: [PATCH 417/515] OPL: "fix" stereo in OPL1/2 --- src/engine/platform/opl.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index eb49637e3..2dd6d1dcf 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -249,7 +249,9 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_ if (os[1]>32767) os[1]=32767; bufL[h]=os[0]; - bufR[h]=os[1]; + if (oplType==3 || oplType==759) { + bufR[h]=os[1]; + } } } @@ -1520,7 +1522,7 @@ void DivPlatformOPL::reset() { } bool DivPlatformOPL::isStereo() { - return true; + return (oplType==3 || oplType==759); } bool DivPlatformOPL::keyOffAffectsArp(int ch) { From 3e311d94a208108b0c07aa8d3406b73b8593e2ac Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 16 Sep 2022 02:04:01 -0500 Subject: [PATCH 418/515] GUI: fix FM wave gen mult 16 --- src/gui/waveEdit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 006ee4304..87f5ad38f 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -32,7 +32,7 @@ const char* waveGenBaseShapes[4]={ "Pulse" }; -const float multFactors[16]={ +const float multFactors[17]={ M_PI, 2*M_PI, 4*M_PI, @@ -49,6 +49,7 @@ const float multFactors[16]={ 26*M_PI, 28*M_PI, 30*M_PI, + 32*M_PI, }; void FurnaceGUI::doGenerateWave() { From b461ffe41141f4b90ee4f40899bc87350783cf56 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 16 Sep 2022 23:48:06 +0900 Subject: [PATCH 419/515] Update vgsound_emu library --- CMakeLists.txt | 37 +- src/engine/platform/bubsyswsg.cpp | 12 +- src/engine/platform/bubsyswsg.h | 4 +- src/engine/platform/msm6295.cpp | 14 +- src/engine/platform/msm6295.h | 4 +- src/engine/platform/n163.cpp | 2 +- src/engine/platform/n163.h | 2 +- src/engine/platform/scc.cpp | 2 +- src/engine/platform/scc.h | 2 +- src/engine/platform/sound/k005289/k005289.cpp | 46 -- src/engine/platform/sound/k005289/k005289.hpp | 68 -- src/engine/platform/sound/n163/n163.cpp | 167 ----- src/engine/platform/sound/n163/n163.hpp | 90 --- src/engine/platform/sound/oki/msm6295.cpp | 215 ------ src/engine/platform/sound/oki/msm6295.hpp | 95 --- src/engine/platform/sound/oki/util.hpp | 159 ----- src/engine/platform/sound/oki/vox.hpp | 116 ---- src/engine/platform/sound/scc/scc.cpp | 617 ------------------ src/engine/platform/sound/scc/scc.hpp | 139 ---- src/engine/platform/sound/vrcvi/vrcvi.cpp | 324 --------- src/engine/platform/sound/vrcvi/vrcvi.hpp | 242 ------- src/engine/platform/sound/x1_010/x1_010.cpp | 225 ------- src/engine/platform/sound/x1_010/x1_010.hpp | 134 ---- src/engine/platform/vrc6.cpp | 7 +- src/engine/platform/vrc6.h | 7 +- src/engine/platform/x1_010.cpp | 28 +- src/engine/platform/x1_010.h | 23 +- src/main.cpp | 2 +- 28 files changed, 78 insertions(+), 2705 deletions(-) delete mode 100644 src/engine/platform/sound/k005289/k005289.cpp delete mode 100644 src/engine/platform/sound/k005289/k005289.hpp delete mode 100644 src/engine/platform/sound/n163/n163.cpp delete mode 100644 src/engine/platform/sound/n163/n163.hpp delete mode 100644 src/engine/platform/sound/oki/msm6295.cpp delete mode 100644 src/engine/platform/sound/oki/msm6295.hpp delete mode 100644 src/engine/platform/sound/oki/util.hpp delete mode 100644 src/engine/platform/sound/oki/vox.hpp delete mode 100644 src/engine/platform/sound/scc/scc.cpp delete mode 100644 src/engine/platform/sound/scc/scc.hpp delete mode 100644 src/engine/platform/sound/vrcvi/vrcvi.cpp delete mode 100644 src/engine/platform/sound/vrcvi/vrcvi.hpp delete mode 100644 src/engine/platform/sound/x1_010/x1_010.cpp delete mode 100644 src/engine/platform/sound/x1_010/x1_010.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ff7db42e6..39d3321cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ else() endif() list(APPEND DEPENDENCIES_INCLUDE_DIRS "extern/SAASound/include") +list(APPEND DEPENDENCIES_INCLUDE_DIRS "extern/vgsound_emu-modified") find_package(Threads REQUIRED) list(APPEND DEPENDENCIES_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) @@ -319,6 +320,31 @@ extern/SAASound/src/SAANoise.cpp extern/SAASound/src/SAASndC.cpp extern/SAASound/src/SAASound.cpp +extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp +extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp +extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp +extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp +extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp +extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp + +extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp + extern/adpcm/bs_codec.c extern/adpcm/oki_codec.c extern/adpcm/yma_codec.c @@ -398,28 +424,17 @@ src/engine/platform/sound/lynx/Mikey.cpp src/engine/platform/sound/qsound.c -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 - src/engine/platform/sound/vic20sound.c -src/engine/platform/sound/vrcvi/vrcvi.cpp - -src/engine/platform/sound/scc/scc.cpp - src/engine/platform/sound/ymz280b.cpp src/engine/platform/sound/rf5c68.cpp src/engine/platform/sound/oki/okim6258.cpp -src/engine/platform/sound/oki/msm6295.cpp src/engine/platform/oplAInterface.cpp src/engine/platform/ym2608Interface.cpp diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 89503cceb..89d609cec 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -44,7 +44,7 @@ void DivPlatformBubSysWSG::acquire(short* bufL, short* bufR, size_t start, size_ for (size_t h=start; htick(); + k005289.tick(); // Wavetable part for (int i=0; i<2; i++) { @@ -52,7 +52,7 @@ void DivPlatformBubSysWSG::acquire(short* bufL, short* bufR, size_t start, size_ oscBuf[i]->data[oscBuf[i]->needle++]=0; continue; } else { - chanOut=chan[i].waveROM[k005289->addr(i)]*(regPool[2+i]&0xf); + chanOut=chan[i].waveROM[k005289.addr(i)]*(regPool[2+i]&0xf); out+=chanOut; if (writeOscBuf==0) { oscBuf[i]->data[oscBuf[i]->needle++]=chanOut<<7; @@ -122,9 +122,9 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>4095) chan[i].freq=4095; - k005289->load(i,chan[i].freq); + k005289.load(i,chan[i].freq); rWrite(i,chan[i].freq); - k005289->update(i); + k005289.update(i); if (chan[i].keyOn) { // ??? } @@ -295,7 +295,7 @@ void DivPlatformBubSysWSG::reset() { if (dumpWrites) { addWrite(0xffffffff,0); } - k005289->reset(); + k005289.reset(); } bool DivPlatformBubSysWSG::isStereo() { @@ -347,7 +347,6 @@ int DivPlatformBubSysWSG::init(DivEngine* p, int channels, int sugRate, unsigned oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); - k005289=new k005289_core(); reset(); return 2; } @@ -356,7 +355,6 @@ void DivPlatformBubSysWSG::quit() { for (int i=0; i<2; i++) { delete oscBuf[i]; } - delete k005289; } DivPlatformBubSysWSG::~DivPlatformBubSysWSG() { diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index cfc41dc12..f14b94a77 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -24,7 +24,7 @@ #include #include "../macroInt.h" #include "../waveSynth.h" -#include "sound/k005289/k005289.hpp" +#include "vgsound_emu/src/k005289/k005289.hpp" class DivPlatformBubSysWSG: public DivDispatch { struct Channel { @@ -60,7 +60,7 @@ class DivPlatformBubSysWSG: public DivDispatch { bool isMuted[2]; unsigned char writeOscBuf; - k005289_core* k005289; + k005289_core k005289; unsigned short regPool[4]; void updateWave(int ch); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 0a76a2c9b..4d32f4319 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -79,7 +79,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t updateOsc=0; // TODO: per-channel osc for (int i=0; i<4; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=msm.m_voice[i].m_muted?0:(msm.m_voice[i].m_out<<6); + oscBuf[i]->data[oscBuf[i]->needle++]=msm.voice_out(i)<<6; } } } @@ -113,7 +113,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - rWriteDelay(0,(8<getSample(12*sampleBank+c.value%12); chan[c.chan].sample=12*sampleBank+c.value%12; - rWriteDelay(0,(8<rate=rate/22; } diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index 0953bd33e..33f5c85fb 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -22,7 +22,7 @@ #include "../dispatch.h" #include "../macroInt.h" #include -#include "sound/oki/msm6295.hpp" +#include "vgsound_emu/src/msm6295/msm6295.hpp" class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { protected: @@ -57,7 +57,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { unsigned short addr; unsigned char val; unsigned short delay; - QueuedWrite(unsigned short a, unsigned char v, unsigned short d=32): + QueuedWrite(unsigned short a, unsigned char v, unsigned short d=96): addr(a), val(v), delay(d) {} diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index bc985b42b..1597d0fa2 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -117,7 +117,7 @@ void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len bufL[i]=bufR[i]=out; if (n163.voice_cycle()==0x78) for (int i=0; i<8; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=n163.chan_out(i)<<7; + oscBuf[i]->data[oscBuf[i]->needle++]=n163.voice_out(i)<<7; } // command queue diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index c77510f56..d4a9ee357 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -24,7 +24,7 @@ #include #include "../macroInt.h" #include "../waveSynth.h" -#include "sound/n163/n163.hpp" +#include "vgsound_emu/src/n163/n163.hpp" class DivPlatformN163: public DivDispatch { struct Channel { diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index d8859cffd..725c53da9 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -89,7 +89,7 @@ void DivPlatformSCC::acquire(short* bufL, short* bufR, size_t start, size_t len) bufL[h]=bufR[h]=out; for (int i=0; i<5; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=scc->chan_out(i)<<7; + oscBuf[i]->data[oscBuf[i]->needle++]=scc->voice_out(i)<<7; } } } diff --git a/src/engine/platform/scc.h b/src/engine/platform/scc.h index f9fa31725..b6117d4a1 100644 --- a/src/engine/platform/scc.h +++ b/src/engine/platform/scc.h @@ -24,7 +24,7 @@ #include #include "../macroInt.h" #include "../waveSynth.h" -#include "sound/scc/scc.hpp" +#include "vgsound_emu/src/scc/scc.hpp" class DivPlatformSCC: public DivDispatch { struct Channel { diff --git a/src/engine/platform/sound/k005289/k005289.cpp b/src/engine/platform/sound/k005289/k005289.cpp deleted file mode 100644 index c9bdf83ae..000000000 --- a/src/engine/platform/sound/k005289/k005289.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Konami K005289 emulation core - - This chip is used at infamous Konami Bubble System, for part of Wavetable sound generator. - But seriously, It is just to 2 internal 12 bit timer and address generators, rather than sound generator. - - Everything except for internal counter and address are done by external logic, the chip is only has external address, frequency registers and its update pins. - - Frequency calculation: Input clock / (4096 - Pitch input) -*/ - -#include "k005289.hpp" - -void k005289_core::tick() -{ - for (auto & elem : m_voice) - elem.tick(); -} - -void k005289_core::reset() -{ - for (auto & elem : m_voice) - elem.reset(); -} - -void k005289_core::voice_t::tick() -{ - if (bitfield(++counter, 0, 12) == 0) - { - addr = bitfield(addr + 1, 0, 5); - counter = freq; - } -} - -void k005289_core::voice_t::reset() -{ - addr = 0; - pitch = 0; - freq = 0; - counter = 0; -} diff --git a/src/engine/platform/sound/k005289/k005289.hpp b/src/engine/platform/sound/k005289/k005289.hpp deleted file mode 100644 index 575a98b87..000000000 --- a/src/engine/platform/sound/k005289/k005289.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Konami K005289 emulation core - - See k005289.cpp for more info. -*/ - -#include -#include - -#ifndef _VGSOUND_EMU_K005289_HPP -#define _VGSOUND_EMU_K005289_HPP - -#pragma once - -namespace k005289 -{ - typedef unsigned char u8; - typedef unsigned short u16; - typedef signed short s16; - - // get bitfield, bitfield(input, position, len) - template T bitfield(T in, u8 pos, u8 len = 1) - { - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); - } -} - -using namespace k005289; -class k005289_core -{ -public: - // accessors, getters, setters - u8 addr(int voice) { return m_voice[voice & 1].addr; } // 1QA...E/2QA...E pin - void load(int voice, u16 addr) { m_voice[voice & 1].load(addr); } // LD1/2 pin, A0...11 pin - void update(int voice) { m_voice[voice & 1].update(); } // TG1/2 pin - - // internal state - void reset(); - void tick(); - -private: - // k005289 voice structs - struct voice_t - { - // internal state - void reset(); - void tick(); - - // accessors, getters, setters - void load(u16 addr) { pitch = addr; } // Load pitch data (address pin) - void update() { freq = pitch; } // Replace current frequency to lastest loaded pitch - - // registers - u8 addr = 0; // external address pin - u16 pitch = 0; // pitch - u16 freq = 0; // current frequency - s16 counter = 0; // frequency counter - }; - - voice_t m_voice[2]; -}; - -#endif diff --git a/src/engine/platform/sound/n163/n163.cpp b/src/engine/platform/sound/n163/n163.cpp deleted file mode 100644 index 3fd30bc44..000000000 --- a/src/engine/platform/sound/n163/n163.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900, tildearrow - Namco 163 Sound emulation core - - This chip is one of NES mapper with sound expansion, This one is by Namco. - - It has 1 to 8 wavetable channels, All channel registers and waveforms are stored to internal RAM. - 4 bit Waveforms are freely allocatable, and its length is variables; its can be stores many short waveforms or few long waveforms in RAM. - - But waveforms are needs to squash, reallocate to avoid conflict with channel register area, each channel register size is 8 bytes per channels. - - Sound output is time division multiplexed, it's can be captured only single channels output at once. in reason, More activated channels are less sound quality. - - Sound register layout - - Address Bit Description - 7654 3210 - - 78-7f Channel 0 - 78 xxxx xxxx Channel 0 Pitch input bit 0-7 - 79 xxxx xxxx Channel 0 Accumulator bit 0-7* - 7a xxxx xxxx Channel 0 Pitch input bit 8-15 - 7b xxxx xxxx Channel 0 Accumulator bit 8-15* - 7c xxxx xx-- Channel 0 Waveform length, 256 - (x * 4) - ---- --xx Channel 0 Pitch input bit 16-17 - 7d xxxx xxxx Channel 0 Accumulator bit 16-23* - 7e xxxx xxxx Channel 0 Waveform base offset - xxxx xxx- RAM byte (0 to 127) - ---- ---x RAM nibble - ---- ---0 Low nibble - ---- ---1 High nibble - 7f ---- xxxx Channel 0 Volume - - 7f Number of active channels - 7f -xxx ---- Number of active channels - -000 ---- Channel 0 activated - -001 ---- Channel 1 activated - -010 ---- Channel 2 activated - ... - -110 ---- Channel 6 activated - -111 ---- Channel 7 activated - - 70-77 Channel 1 (Optional if activated) - 68-6f Channel 2 (Optional if activated) - ... - 48-4f Channel 6 (Optional if activated) - 40-47 Channel 7 (Optional if activated) - - Rest of RAM area are for 4 bit Waveform and/or scratchpad. - Each waveform byte has 2 nibbles packed, fetches LSB first, MSB next. - ---- xxxx 4 bit waveform, LSB - xxxx ---- Same as above, MSB - - Waveform address: Waveform base offset + Bit 16 to 23 of Accumulator, 1 LSB of result is nibble select, 7 MSB of result is Byte address in RAM. - - Frequency formula: - Frequency: Pitch input * ((Input clock * 15 * Number of activated voices) / 65536) - - There's to way for reduce N163 noises: reduce channel limit and demultiplex - - Channel limit is runtime changeable and it makes some usable effects. - - Demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered) - This core is support both, You can choose output behavior - -*/ - -#include "n163.hpp" -#include - -void n163_core::tick() -{ - if (m_multiplex) - m_out = 0; - // 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank 0x8000-0x9fff select.) - if (m_disable) - { - if (!m_multiplex) - m_out = 0; - return; - } - - // tick per each clock - const u32 freq = m_ram[m_voice_cycle + 0] | (u32(m_ram[m_voice_cycle + 2]) << 8) | (bitfield(m_ram[m_voice_cycle + 4], 0, 2) << 16); // 18 bit frequency - u32 accum = m_ram[m_voice_cycle + 1] | (u32(m_ram[m_voice_cycle + 3]) << 8) | ( u32(m_ram[m_voice_cycle + 5]) << 16); // 24 bit accumulator - const u16 length = 256 - (m_ram[m_voice_cycle + 4] & 0xfc); - const u8 addr = m_ram[m_voice_cycle + 6] + bitfield(accum, 16, 8); - const s16 wave = (bitfield(m_ram[bitfield(addr, 1, 7)], bitfield(addr, 0) << 2, 4) - 8); - const s16 volume = bitfield(m_ram[m_voice_cycle + 7], 0, 4); - - // accumulate address - accum = bitfield(accum + freq, 0, 24); - if (bitfield(accum, 16, 8) >= length) - accum = bitfield(accum, 0, 18); - - // writeback to register - m_ram[m_voice_cycle + 1] = bitfield(accum, 0, 8); - m_ram[m_voice_cycle + 3] = bitfield(accum, 8, 8); - m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8); - - const u8 prev_voice_cycle = m_voice_cycle; - - // update voice cycle - bool flush = m_multiplex ? true : false; - m_voice_cycle -= 0x8; - if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3))) - { - if (!m_multiplex) - flush = true; - m_voice_cycle = 0x78; - } - - // output 4 bit waveform and volume, multiplexed - const u8 chan_index = ((0x78-prev_voice_cycle)>>3)&7; - m_ch_out[chan_index]=wave * volume; - m_acc += m_ch_out[chan_index]; - if (flush) - { - m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1)); - m_acc = 0; - } -} - -void n163_core::reset() -{ - // reset this chip - m_disable = false; - m_multiplex = true; - memset(m_ram,0,sizeof(m_ram)); - m_voice_cycle = 0x78; - m_addr_latch.reset(); - m_out = 0; - m_acc = 0; - memset(m_ch_out,0,sizeof(m_ch_out)); -} - -// accessor -void n163_core::addr_w(u8 data) -{ - // 0xf800-0xffff Sound address, increment - m_addr_latch.addr = bitfield(data, 0, 7); - m_addr_latch.incr = bitfield(data, 7); -} - -void n163_core::data_w(u8 data, bool cpu_access) -{ - // 0x4800-0x4fff Sound data write - m_ram[m_addr_latch.addr] = data; - - // address latch increment - if (cpu_access && m_addr_latch.incr) - m_addr_latch.addr = bitfield(m_addr_latch.addr + 1, 0, 7); -} - -u8 n163_core::data_r(bool cpu_access) -{ - // 0x4800-0x4fff Sound data read - const u8 ret = m_ram[m_addr_latch.addr]; - - // address latch increment - if (cpu_access && m_addr_latch.incr) - m_addr_latch.addr = bitfield(m_addr_latch.addr + 1, 0, 7); - - return ret; -} diff --git a/src/engine/platform/sound/n163/n163.hpp b/src/engine/platform/sound/n163/n163.hpp deleted file mode 100644 index 317a33b45..000000000 --- a/src/engine/platform/sound/n163/n163.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900, tildearrow - Namco 163 Sound emulation core -*/ - -#include -#include - -#ifndef _VGSOUND_EMU_N163_HPP -#define _VGSOUND_EMU_N163_HPP - -#pragma once - -namespace n163 -{ - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; - typedef signed short s16; - - // get bitfield, bitfield(input, position, len) - template T bitfield(T in, u8 pos, u8 len = 1) - { - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); - } -}; - -using namespace n163; -class n163_core -{ -public: - // accessors, getters, setters - void addr_w(u8 data); - void data_w(u8 data, bool cpu_access = false); - u8 data_r(bool cpu_access = false); - - void set_disable(bool disable) { m_disable = disable; } - - // internal state - void reset(); - void tick(); - - // sound output pin - s16 out() { return m_out; } - - // get channel output - s16 chan_out(u8 ch) { return m_ch_out[ch]; } - - // get voice cycle - u8 voice_cycle() { return m_voice_cycle; } - - // register pool - u8 reg(u8 addr) { return m_ram[addr & 0x7f]; } - void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; } - -private: - // Address latch - struct addr_latch_t - { - addr_latch_t() - : addr(0) - , incr(0) - { } - - void reset() - { - addr = 0; - incr = 0; - } - - u8 addr : 7; - u8 incr : 1; - }; - - bool m_disable = false; - u8 m_ram[0x80] = {0}; // internal 128 byte RAM - u8 m_voice_cycle = 0x78; // Voice cycle for processing - addr_latch_t m_addr_latch; // address latch - s16 m_out = 0; // output - s16 m_ch_out[8] = {0}; // per channel output - // demultiplex related - bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate! - s16 m_acc = 0; // accumulated output -}; - -#endif diff --git a/src/engine/platform/sound/oki/msm6295.cpp b/src/engine/platform/sound/oki/msm6295.cpp deleted file mode 100644 index e7f39d27e..000000000 --- a/src/engine/platform/sound/oki/msm6295.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: tildearrow - OKI MSM6295 emulation core - - It is 4 channel ADPCM playback chip from OKI semiconductor. - It was becomes de facto standard for ADPCM playback in arcade machine, due to cost performance. - - The chip itself is pretty barebone: there is no "register" in chip. - It can't control volume and pitch in currently playing channels, only stopable them. - And volume is must be determined at playback start command. - - Command format: - - Playback command (2 byte): - - Byte Bit Description - 76543210 - 0 1xxxxxxx Phrase select (Header stored in ROM) - 1 x000---- Play channel 4 - 0x00---- Play channel 3 - 00x0---- Play channel 2 - 000x---- Play channel 1 - ----xxxx Volume - ----0000 0.0dB - ----0001 -3.2dB - ----0010 -6.0dB - ----0011 -9.2dB - ----0100 -12.0dB - ----0101 -14.5dB - ----0110 -18.0dB - ----0111 -20.5dB - ----1000 -24.0dB - - Suspend command (1 byte): - - Byte Bit Description - 76543210 - 0 0x------ Suspend channel 4 - 0-x----- Suspend channel 3 - 0--x---- Suspend channel 2 - 0---x--- Suspend channel 1 - - Frequency calculation: - if (SS) then - Frequency = Input clock / 165 - else then - Frequency = Input clock / 132 - -*/ - -#include "msm6295.hpp" - -#define CORE_DIVIDER 3 - -#define CHANNEL_DELAY (15/CORE_DIVIDER) -#define MASTER_DELAY (33/CORE_DIVIDER) - -void msm6295_core::tick() -{ - // command handler - if (m_command_pending) - { - if (bitfield(m_command, 7)) // play voice - { - if ((++m_clock) >= ((CHANNEL_DELAY * (m_ss ? 5 : 4)))) - { - m_clock = 0; - if (bitfield(m_next_command, 4, 4) != 0) - { - for (int i = 0; i < 4; i++) - { - if (bitfield(m_next_command, 4 + i)) - { - if (!m_voice[i].m_busy) - { - m_voice[i].m_command = m_command; - m_voice[i].m_volume = (bitfield(m_next_command, 0, 4) < 9) ? m_volume_table[std::min(8, bitfield(m_next_command, 0, 4))] : 0; - } - break; // voices aren't be playable simultaneously at once - } - } - } - m_command = 0; - m_command_pending = false; - } - } - else if (bitfield(m_next_command, 7)) // select phrase - { - if ((++m_clock) >= ((CHANNEL_DELAY * (m_ss ? 5 : 4)))) - { - m_clock = 0; - m_command = m_next_command; - m_command_pending = false; - } - } - else - { - if (bitfield(m_next_command, 3, 4) != 0) // suspend voices - { - for (int i = 0; i < 4; i++) - { - if (bitfield(m_next_command, 3 + i)) - { - if (m_voice[i].m_busy) - m_voice[i].m_command = m_next_command; - } - } - m_next_command &= ~0x78; - } - m_command_pending = false; - } - } - m_out = 0; - for (int i = 0; i < 4; i++) - { - m_voice[i].tick(); - if (!m_voice[i].m_muted) m_out += m_voice[i].m_out; - } -} - -void msm6295_core::reset() -{ - for (auto & elem : m_voice) - elem.reset(); - - m_command = 0; - m_next_command = 0; - m_command_pending = false; - m_clock = 0; - m_out = 0; -} - -void msm6295_core::voice_t::tick() -{ - if (!m_busy) - { - if (bitfield(m_command, 7)) - { - // get phrase header (stored in data memory) - const u32 phrase = bitfield(m_command, 0, 7) << 3; - // Start address - m_addr = (bitfield(m_host.m_intf.read_byte(phrase | 0), 0, 2) << 16) - | (m_host.m_intf.read_byte(phrase | 1) << 8) - | (m_host.m_intf.read_byte(phrase | 2) << 0); - // End address - m_end = (bitfield(m_host.m_intf.read_byte(phrase | 3), 0, 2) << 16) - | (m_host.m_intf.read_byte(phrase | 4) << 8) - | (m_host.m_intf.read_byte(phrase | 5) << 0); - m_nibble = 4; // MSB first, LSB second - m_command = 0; - m_busy = true; - vox_decoder_t::reset(); - } - m_out = 0; - } - else - { - // playback - if ((++m_clock) >= ((MASTER_DELAY * (m_host.m_ss ? 5 : 4)))) - { - m_clock = 0; - bool is_end = (m_command != 0); - m_curr.decode(bitfield(m_host.m_intf.read_byte(m_addr), m_nibble, 4)); - if (m_nibble <= 0) - { - m_nibble = 4; - if (++m_addr > m_end) - is_end = true; - } - else - m_nibble -= 4; - if (is_end) - { - m_command = 0; - m_busy = false; - } - m_out = (out() * m_volume) >> 7; // scale out to 12 bit output - } - } -} - -void msm6295_core::voice_t::reset() -{ - vox_decoder_t::reset(); - m_clock = 0; - m_busy = false; - m_command = 0; - m_addr = 0; - m_nibble = 0; - m_end = 0; - m_volume = 0; - m_out = 0; -} - -// accessors -u8 msm6295_core::busy_r() -{ - return (m_voice[0].m_busy ? 0x01 : 0x00) - | (m_voice[1].m_busy ? 0x02 : 0x00) - | (m_voice[2].m_busy ? 0x04 : 0x00) - | (m_voice[3].m_busy ? 0x08 : 0x00); -} - -void msm6295_core::command_w(u8 data) -{ - if (!m_command_pending) - { - m_next_command = data; - m_command_pending = true; - } -} diff --git a/src/engine/platform/sound/oki/msm6295.hpp b/src/engine/platform/sound/oki/msm6295.hpp deleted file mode 100644 index ca8b81d41..000000000 --- a/src/engine/platform/sound/oki/msm6295.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: tildearrow - OKI MSM6295 emulation core - - See msm6295.cpp for more info. -*/ - -#include "util.hpp" -#include "vox.hpp" -#include -#include - -#ifndef _VGSOUND_EMU_MSM6295_HPP -#define _VGSOUND_EMU_MSM6295_HPP - -#pragma once - -class msm6295_core : public vox_core -{ - friend class vgsound_emu_mem_intf; // common memory interface -public: - // constructor - msm6295_core(vgsound_emu_mem_intf &intf) - : m_voice{{*this,*this},{*this,*this},{*this,*this},{*this,*this}} - , m_intf(intf) - { - } - // accessors, getters, setters - u8 busy_r(); - void command_w(u8 data); - void ss_w(bool ss) { m_ss = ss; } // SS pin - - // internal state - void reset(); - void tick(); - - s32 out() { return m_out; } // built in 12 bit DAC - -private: - // Internal volume table, 9 step - const s32 m_volume_table[9] = { - 32/* 0.0dB */, - 22/* -3.2dB */, - 16/* -6.0dB */, - 11/* -9.2dB */, - 8/* -12.0dB */, - 6/* -14.5dB */, - 4/* -18.0dB */, - 3/* -20.5dB */, - 2/* -24.0dB */ }; // scale out to 5 bit for optimization - -public: - // msm6295 voice structs - struct voice_t : vox_decoder_t - { - // constructor - voice_t(vox_core &vox, msm6295_core &host) - : vox_decoder_t(vox) - , m_host(host) - {}; - - // internal state - virtual void reset() override; - void tick(); - - // accessors, getters, setters - // registers - msm6295_core &m_host; - u16 m_clock = 0; // clock counter - bool m_busy = false; // busy status - bool m_muted = false; // muted - u8 m_command = 0; // current command - u32 m_addr = 0; // current address - s8 m_nibble = 0; // current nibble - u32 m_end = 0; // end address - s32 m_volume = 0; // volume - s32 m_out = 0; // output - }; - voice_t m_voice[4]; -private: - vgsound_emu_mem_intf &m_intf; // common memory interface - - bool m_ss = false; // SS pin controls divider, input clock / 33 * (SS ? 5 : 4) - u8 m_command = 0; // Command byte - u8 m_next_command = 0; // Next command - bool m_command_pending = false; // command pending flag - u16 m_clock = 0; // clock counter - s32 m_out = 0; // 12 bit output -}; - -#endif diff --git a/src/engine/platform/sound/oki/util.hpp b/src/engine/platform/sound/oki/util.hpp deleted file mode 100644 index b9c50d7bf..000000000 --- a/src/engine/platform/sound/oki/util.hpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: tildearrow - Various core utilities for vgsound_emu -*/ - -#include -#include -#include - -#ifndef _VGSOUND_EMU_CORE_UTIL_HPP -#define _VGSOUND_EMU_CORE_UTIL_HPP - -#pragma once - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; -typedef signed long long s64; -typedef float f32; -typedef double f64; - -const f64 PI = 3.1415926535897932384626433832795; - -// get bitfield, bitfield(input, position, len) -template T bitfield(T in, u8 pos, u8 len = 1) -{ - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); -} - -// get sign extended value, sign_ext(input, len) -template T sign_ext(T in, u8 len) -{ - len = std::max(0, (8 * sizeof(T)) - len); - return T(T(in) << len) >> len; -} - -// convert attenuation decibel value to gain -inline f32 dB_to_gain(f32 attenuation) -{ - return powf(10.0f, attenuation / 20.0f); -} - -class vgsound_emu_mem_intf -{ -public: - virtual u8 read_byte(u32 address) { return 0; } - virtual u16 read_word(u32 address) { return 0; } - virtual u32 read_dword(u32 address) { return 0; } - virtual u64 read_qword(u32 address) { return 0; } - virtual void write_byte(u32 address, u8 data) { } - virtual void write_word(u32 address, u16 data) { } - virtual void write_dword(u32 address, u32 data) { } - virtual void write_qword(u32 address, u64 data) { } -}; - -template -struct clock_pulse_t -{ - void reset(T init = InitWidth) - { - m_edge.reset(); - m_width = m_width_latch = m_counter = init; - m_cycle = 0; - } - - bool tick(T width = 0) - { - bool carry = ((--m_counter) <= 0); - if (carry) - { - if (!width) - m_width = m_width_latch; - else - m_width = width; // reset width - m_counter = m_width; - m_cycle = 0; - } - else - m_cycle++; - - m_edge.tick(carry); - return carry; - } - - void set_width(T width) { m_width = width; } - void set_width_latch(T width) { m_width_latch = width; } - - // Accessors - bool current_edge() { return m_edge.m_current; } - bool rising_edge() { return m_edge.m_rising; } - bool falling_edge() { return m_edge.m_rising; } - T cycle() { return m_cycle; } - - struct edge_t - { - edge_t() - : m_current(InitEdge ^ 1) - , m_previous(InitEdge) - , m_rising(0) - , m_falling(0) - , m_changed(0) - { - set(InitEdge); - } - - void tick(bool toggle) - { - u8 current = m_current; - if (toggle) - current ^= 1; - set(current); - } - - void set(u8 edge) - { - edge &= 1; - m_rising = m_falling = m_changed = 0; - if (m_current != edge) - { - m_changed = 1; - if (m_current && (!edge)) - m_falling = 1; - else if ((!m_current) && edge) - m_rising = 1; - m_current = edge; - } - m_previous = m_current; - } - - void reset() - { - m_previous = InitEdge; - m_current = InitEdge ^ 1; - set(InitEdge); - } - - u8 m_current : 1; // current edge - u8 m_previous : 1; // previous edge - u8 m_rising : 1; // rising edge - u8 m_falling : 1; // falling edge - u8 m_changed : 1; // changed flag - }; - - edge_t m_edge; - T m_width = InitWidth; // clock pulse width - T m_width_latch = InitWidth; // clock pulse width latch - T m_counter = InitWidth; // clock counter - T m_cycle = 0; // clock cycle -}; - -#endif diff --git a/src/engine/platform/sound/oki/vox.hpp b/src/engine/platform/sound/oki/vox.hpp deleted file mode 100644 index 23fbfd78e..000000000 --- a/src/engine/platform/sound/oki/vox.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: tildearrow - Dialogic ADPCM core -*/ - -#include "util.hpp" -#include -#include - -#ifndef _VGSOUND_EMU_CORE_VOX_HPP -#define _VGSOUND_EMU_CORE_VOX_HPP - -#pragma once - -#define MODIFIED_CLAMP(x,xMin,xMax) (std::min(std::max((x),(xMin)),(xMax))) - -class vox_core -{ -protected: - struct vox_decoder_t - { - vox_decoder_t(vox_core &vox) - : m_curr(vox) - , m_loop(vox) - { }; - - virtual void reset() - { - m_curr.reset(); - m_loop.reset(); - m_loop_saved = false; - } - - void save() - { - if (!m_loop_saved) - { - m_loop.copy(m_curr); - m_loop_saved = true; - } - } - - void restore() - { - if (m_loop_saved) - m_curr.copy(m_loop); - } - - s32 out() { return m_curr.m_step; } - - struct decoder_state_t - { - decoder_state_t(vox_core &vox) - : m_vox(vox) - { }; - - void reset() - { - m_index = 0; - m_step = 16; - } - - void copy(decoder_state_t src) - { - m_index = src.m_index; - m_step = src.m_step; - } - - void decode(u8 nibble) - { - const u8 delta = bitfield(nibble, 0, 3); - s16 ss = m_vox.m_step_table[m_index]; // ss(n) - - // d(n) = (ss(n) * B2) + ((ss(n) / 2) * B1) + ((ss(n) / 4) * B0) + (ss(n) / 8) - s16 d = ss >> 3; - if (bitfield(delta, 2)) - d += ss; - if (bitfield(delta, 1)) - d += (ss >> 1); - if (bitfield(delta, 0)) - d += (ss >> 2); - - // if (B3 = 1) then d(n) = d(n) * (-1) X(n) = X(n-1) * d(n) - if (bitfield(nibble, 3)) - m_step = std::max(m_step - d, -2048); - else - m_step = std::min(m_step + d, 2047); - - // adjust step index - m_index = MODIFIED_CLAMP(m_index + m_vox.m_index_table[delta], 0, 48); - } - - vox_core &m_vox; - s8 m_index = 0; - s32 m_step = 16; - }; - - decoder_state_t m_curr; - decoder_state_t m_loop; - bool m_loop_saved = false; - }; - - s8 m_index_table[8] = {-1, -1, -1, -1, 2, 4, 6, 8}; - s32 m_step_table[49] = { - 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, - 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, - 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 - }; -}; - -#endif diff --git a/src/engine/platform/sound/scc/scc.cpp b/src/engine/platform/sound/scc/scc.cpp deleted file mode 100644 index e2ebcf200..000000000 --- a/src/engine/platform/sound/scc/scc.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst - Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw - Konami SCC emulation core - - Konami SCC means "Sound Creative Chip", it's actually MSX MegaROM/RAM Mapper with 5 channel Wavetable sound generator. - - It was first appeared at 1987, F-1 Spirit and Nemesis 2/Gradius 2 for MSX. then several MSX cartridges used that until 1990, Metal Gear 2: Solid Snake. - Even after MSX is discontinued, it was still used at some low-end arcade and amusement hardwares. - and some Third-party MSX utilities still support this due to its market shares. - - There's 2 SCC types: - - K051649 (or simply known as SCC) - This chip is used for MSX MegaROM Mapper, some arcade machines. - Channel 4 and 5 must be share waveform, other channels has its own waveforms. - - K052539 (also known as SCC+) - This chip is used for MSX MegaRAM Mapper (Konami Sound Cartridges for Snatcher/SD Snatcher). - All channels can be has its own waveforms, and also has backward compatibility mode with K051649. - - Based on: - https://www.msx.org/wiki/MegaROM_Mappers - https://www.msx.org/wiki/Konami_051649 - https://www.msx.org/wiki/Konami_052539 - http://bifi.msxnet.org/msxnet/tech/scc - http://bifi.msxnet.org/msxnet/tech/soundcartridge - - K051649 Register Layout - - -------------------------------------------------------------------- - - 4000-bfff MegaROM Mapper - - -------------------------------------------------------------------- - - Address Bit R/W Description - 7654 3210 - - 4000-5fff xxxx xxxx R Bank page 0 - c000-dfff mirror of 4000-5fff - - 6000-7fff xxxx xxxx R Bank page 1 - e000-ffff mirror of 6000-7fff - - 8000-9fff xxxx xxxx R Bank page 2 - 0000-1fff mirror of 8000-9fff - - a000-bfff xxxx xxxx R Bank page 3 - 2000-3fff mirror of a000-bfff - - -------------------------------------------------------------------- - - 5000-57ff, 7000-77ff, 9000-97ff, b000-b7ff Bank select - - -------------------------------------------------------------------- - - Address Bit R/W Description - 7654 3210 - - 5000 --xx xxxx W Bank select, Page 0 - 5001-57ff Mirror of 5000 - - 7000 --xx xxxx W Bank select, Page 1 - 7001-77ff Mirror of 7000 - - 9000 --xx xxxx W Bank select, Page 2 - --11 1111 W SCC Enable - 9001-97ff Mirror of 9000 - - b000 --xx xxxx W Bank select, Page 3 - b001-b7ff Mirror of b000 - - -------------------------------------------------------------------- - - 9800-9fff SCC register - - -------------------------------------------------------------------- - - 9800-987f Waveform - - Address Bit R/W Description - 7654 3210 - - 9800-981f xxxx xxxx R/W Channel 0 Waveform (32 byte, 8 bit signed) - 9820-983f xxxx xxxx R/W Channel 1 "" - 9840-985f xxxx xxxx R/W Channel 2 "" - 9860-987f xxxx xxxx R/W Channel 3/4 "" - - 9880-9889 Pitch - - 9880 xxxx xxxx W Channel 0 Pitch LSB - 9881 ---- xxxx W Channel 0 Pitch MSB - 9882 xxxx xxxx W Channel 1 Pitch LSB - 9883 ---- xxxx W Channel 1 Pitch MSB - 9884 xxxx xxxx W Channel 2 Pitch LSB - 9885 ---- xxxx W Channel 2 Pitch MSB - 9886 xxxx xxxx W Channel 3 Pitch LSB - 9887 ---- xxxx W Channel 3 Pitch MSB - 9888 xxxx xxxx W Channel 4 Pitch LSB - 9889 ---- xxxx W Channel 4 Pitch MSB - - 9888-988e Volume - - 988a ---- xxxx W Channel 0 Volume - 988b ---- xxxx W Channel 1 Volume - 988c ---- xxxx W Channel 2 Volume - 988d ---- xxxx W Channel 3 Volume - 988e ---- xxxx W Channel 4 Volume - - 988f ---x ---- W Channel 4 Output enable/disable flag - ---- x--- W Channel 3 Output enable/disable flag - ---- -x-- W Channel 2 Output enable/disable flag - ---- --x- W Channel 1 Output enable/disable flag - ---- ---x W Channel 0 Output enable/disable flag - - 9890-989f Mirror of 9880-988f - - 98a0-98bf xxxx xxxx R Channel 4 Waveform - - 98e0 x--- ---- W Waveform rotate flag for channel 4 - -x-- ---- W Waveform rotate flag for all channels - --x- ---- W Reset waveform position after pitch writes - ---- --x- W 8 bit frequency - ---- --0x W 4 bit frequency - - 98e1-98ff Mirror of 98e0 - - 9900-9fff Mirror of 9800-98ff - - -------------------------------------------------------------------- - - K052539 Register Layout - - -------------------------------------------------------------------- - - 4000-bfff MegaRAM Mapper - - -------------------------------------------------------------------- - - Address Bit R/W Description - 7654 3210 - - 4000-5fff xxxx xxxx R/W Bank page 0 - c000-dfff xxxx xxxx R/W "" - - 6000-7fff xxxx xxxx R/W Bank page 1 - e000-ffff xxxx xxxx R/W "" - - 8000-9fff xxxx xxxx R/W Bank page 2 - 0000-1fff xxxx xxxx R/W "" - - a000-bfff xxxx xxxx R/W Bank page 3 - 2000-3fff xxxx xxxx R/W "" - - -------------------------------------------------------------------- - - 5000-57ff, 7000-77ff, 9000-97ff, b000-b7ff Bank select - - -------------------------------------------------------------------- - - Address Bit R/W Description - 7654 3210 - - 5000 xxxx xxxx W Bank select, Page 0 - 5001-57ff Mirror of 5000 - - 7000 xxxx xxxx W Bank select, Page 1 - 7001-77ff Mirror of 7000 - - 9000 xxxx xxxx W Bank select, Page 2 - --11 1111 W SCC Enable (SCC Compatible mode) - 9001-97ff Mirror of 9000 - - b000 xxxx xxxx W Bank select, Page 3 - 1--- ---- W SCC+ Enable (SCC+ mode) - b001-b7ff Mirror of b000 - - -------------------------------------------------------------------- - - bffe-bfff Mapper configuration - - -------------------------------------------------------------------- - - Address Bit R/W Description - 7654 3210 - - bffe --x- ---- W SCC operation mode - --0- ---- W SCC Compatible mode - --1- ---- W SCC+ mode - ---x ---- W RAM write/Bank select toggle for all Bank pages - ---0 ---- W Bank select enable - ---1 ---- W RAM write enable - ---0 -x-- W RAM write/Bank select toggle for Bank page 2 - ---0 --x- W RAM write/Bank select toggle for Bank page 1 - ---0 ---x W RAM write/Bank select toggle for Bank page 0 - bfff Mirror of bffe - - -------------------------------------------------------------------- - - 9800-9fff SCC Compatible mode register - - -------------------------------------------------------------------- - - 9800-987f Waveform - - Address Bit R/W Description - 7654 3210 - - 9800-981f xxxx xxxx R/W Channel 0 Waveform (32 byte, 8 bit signed) - 9820-983f xxxx xxxx R/W Channel 1 "" - 9840-985f xxxx xxxx R/W Channel 2 "" - 9860-987f xxxx xxxx R/W Channel 3/4 "" - - 9880-9889 Pitch - - 9880 xxxx xxxx W Channel 0 Pitch LSB - 9881 ---- xxxx W Channel 0 Pitch MSB - 9882 xxxx xxxx W Channel 1 Pitch LSB - 9883 ---- xxxx W Channel 1 Pitch MSB - 9884 xxxx xxxx W Channel 2 Pitch LSB - 9885 ---- xxxx W Channel 2 Pitch MSB - 9886 xxxx xxxx W Channel 3 Pitch LSB - 9887 ---- xxxx W Channel 3 Pitch MSB - 9888 xxxx xxxx W Channel 4 Pitch LSB - 9889 ---- xxxx W Channel 4 Pitch MSB - - 9888-988e Volume - - 988a ---- xxxx W Channel 0 Volume - 988b ---- xxxx W Channel 1 Volume - 988c ---- xxxx W Channel 2 Volume - 988d ---- xxxx W Channel 3 Volume - 988e ---- xxxx W Channel 4 Volume - - 988f ---x ---- W Channel 4 Output enable/disable flag - ---- x--- W Channel 3 Output enable/disable flag - ---- -x-- W Channel 2 Output enable/disable flag - ---- --x- W Channel 1 Output enable/disable flag - ---- ---x W Channel 0 Output enable/disable flag - - 9890-989f Mirror of 9880-988f - - 98a0-98bf xxxx xxxx R Channel 4 Waveform - - 98c0 -x-- ---- W Waveform rotate flag for all channels - --x- ---- W Reset waveform position after pitch writes - ---- --x- W 8 bit frequency - ---- --0x W 4 bit frequency - - 98c1-98df Mirror of 98c0 - - 9900-9fff Mirror of 9800-98ff - - -------------------------------------------------------------------- - - b800-bfff SCC+ mode register - - -------------------------------------------------------------------- - - b800-b89f Waveform - - Address Bit R/W Description - 7654 3210 - - b800-b81f xxxx xxxx R/W Channel 0 Waveform (32 byte, 8 bit signed) - b820-b83f xxxx xxxx R/W Channel 1 "" - b840-b85f xxxx xxxx R/W Channel 2 "" - b860-b87f xxxx xxxx R/W Channel 3 "" - b880-b89f xxxx xxxx R/W Channel 3 "" - - b8a0-b8a9 Pitch - - b8a0 xxxx xxxx W Channel 0 Pitch LSB - b8a1 ---- xxxx W Channel 0 Pitch MSB - b8a2 xxxx xxxx W Channel 1 Pitch LSB - b8a3 ---- xxxx W Channel 1 Pitch MSB - b8a4 xxxx xxxx W Channel 2 Pitch LSB - b8a5 ---- xxxx W Channel 2 Pitch MSB - b8a6 xxxx xxxx W Channel 3 Pitch LSB - b8a7 ---- xxxx W Channel 3 Pitch MSB - b8a8 xxxx xxxx W Channel 4 Pitch LSB - b8a9 ---- xxxx W Channel 4 Pitch MSB - - b8a8-b8ae Volume - - b8aa ---- xxxx W Channel 0 Volume - b8ab ---- xxxx W Channel 1 Volume - b8ac ---- xxxx W Channel 2 Volume - b8ad ---- xxxx W Channel 3 Volume - b8ae ---- xxxx W Channel 4 Volume - - b8af ---x ---- W Channel 4 Output enable/disable flag - ---- x--- W Channel 3 Output enable/disable flag - ---- -x-- W Channel 2 Output enable/disable flag - ---- --x- W Channel 1 Output enable/disable flag - ---- ---x W Channel 0 Output enable/disable flag - - b8b0-b8bf Mirror of b8a0-b8af - - b8c0 -x-- ---- W Waveform rotate flag for all channels - --x- ---- W Reset waveform position after pitch writes - ---- --x- W 8 bit frequency - ---- --0x W 4 bit frequency - - b8c1-b8df Mirror of b8c0 - - b900-bfff Mirror of b800-b8ff - - -------------------------------------------------------------------- - - SCC Frequency calculation: - if 8 bit frequency then - Frequency = Input clock / ((bit 0 to 7 of Pitch input) + 1) - else if 4 bit frequency then - Frequency = Input clock / ((bit 8 to 11 of Pitch input) + 1) - else - Frequency = Input clock / (Pitch input + 1) - -*/ - -#include "scc.hpp" -#include - -// shared SCC features -void scc_core::tick() -{ - m_out = 0; - for (auto & elem : m_voice) - { - elem.tick(); - m_out += elem.out; - } -} - -void scc_core::voice_t::tick() -{ - if (pitch >= 9) // or voice is halted - { - // update counter - Post decrement - u16 temp = counter; - if (m_host.m_test.freq_4bit) // 4 bit frequency mode - { - counter = (counter & ~0x0ff) | (bitfield(bitfield(counter, 0, 8) - 1, 0, 8) << 0); - counter = (counter & ~0xf00) | (bitfield(bitfield(counter, 8, 4) - 1, 0, 4) << 8); - } - else - counter = bitfield(counter - 1, 0, 12); - - // handle counter carry - bool carry = m_host.m_test.freq_8bit ? (bitfield(temp, 0, 8) == 0) : - (m_host.m_test.freq_4bit ? (bitfield(temp, 8, 4) == 0) : - (bitfield(temp, 0, 12) == 0)); - if (carry) - { - addr = bitfield(addr + 1, 0, 5); - counter = pitch; - } - } - // get output - if (enable) - out = (wave[addr] * volume) >> 4; // scale to 11 bit digital output - else - out = 0; -} - -void scc_core::reset() -{ - for (auto & elem : m_voice) - elem.reset(); - - m_test.reset(); - m_out = 0; - memset(m_reg,0,sizeof(m_reg)); -} - -void scc_core::voice_t::reset() -{ - memset(wave,0,sizeof(wave)); - enable = false; - pitch = 0; - volume = 0; - addr = 0; - counter = 0; - out = 0; -} - -// SCC accessors -u8 scc_core::wave_r(bool is_sccplus, u8 address) -{ - u8 ret = 0xff; - const u8 voice = bitfield(address, 5, 3); - if (voice > 4) - return ret; - - u8 wave_addr = bitfield(address, 0, 5); - - if (m_test.rotate) // rotate flag - wave_addr = bitfield(wave_addr + m_voice[voice].addr, 0, 5); - - if (!is_sccplus) - { - if (voice == 3) // rotate voice 3~4 flag - { - if (m_test.rotate4 || m_test.rotate) // rotate flag - wave_addr = bitfield(bitfield(address, 0, 5) + m_voice[3 + m_test.rotate].addr, 0, 5); - } - } - ret = m_voice[voice].wave[wave_addr]; - - return ret; -} - -void scc_core::wave_w(bool is_sccplus, u8 address, u8 data) -{ - if (m_test.rotate) // write protected - return; - - const u8 voice = bitfield(address, 5, 3); - if (voice > 4) - return; - - const u8 wave_addr = bitfield(address, 0, 5); - - if (!is_sccplus) - { - if (((voice >= 3) && m_test.rotate4) || (voice >= 4)) // Ignore if write protected, or voice 4 - return; - if (voice >= 3) // voice 3, 4 shares waveform - { - m_voice[3].wave[wave_addr] = data; - m_voice[4].wave[wave_addr] = data; - } - else - m_voice[voice].wave[wave_addr] = data; - } - else - m_voice[voice].wave[wave_addr] = data; -} - -void scc_core::freq_vol_enable_w(u8 address, u8 data) -{ - const u8 voice_freq = bitfield(address, 1, 3); - const u8 voice_reg = bitfield(address, 0, 4); - // *0-*f Pitch, Volume, Enable - switch (voice_reg) - { - case 0x0: // 0x*0 Voice 0 Pitch LSB - case 0x2: // 0x*2 Voice 1 Pitch LSB - case 0x4: // 0x*4 Voice 2 Pitch LSB - case 0x6: // 0x*6 Voice 3 Pitch LSB - case 0x8: // 0x*8 Voice 4 Pitch LSB - if (m_test.resetpos) // Reset address - m_voice[voice_freq].addr = 0; - m_voice[voice_freq].pitch = (m_voice[voice_freq].pitch & ~0x0ff) | data; - m_voice[voice_freq].counter = m_voice[voice_freq].pitch; - break; - case 0x1: // 0x*1 Voice 0 Pitch MSB - case 0x3: // 0x*3 Voice 1 Pitch MSB - case 0x5: // 0x*5 Voice 2 Pitch MSB - case 0x7: // 0x*7 Voice 3 Pitch MSB - case 0x9: // 0x*9 Voice 4 Pitch MSB - if (m_test.resetpos) // Reset address - m_voice[voice_freq].addr = 0; - m_voice[voice_freq].pitch = (m_voice[voice_freq].pitch & ~0xf00) | (u16(bitfield(data, 0, 4)) << 8); - m_voice[voice_freq].counter = m_voice[voice_freq].pitch; - break; - case 0xa: // 0x*a Voice 0 Volume - case 0xb: // 0x*b Voice 1 Volume - case 0xc: // 0x*c Voice 2 Volume - case 0xd: // 0x*d Voice 3 Volume - case 0xe: // 0x*e Voice 4 Volume - m_voice[voice_reg - 0xa].volume = bitfield(data, 0, 4); - break; - case 0xf: // 0x*f Enable/Disable flag - m_voice[0].enable = bitfield(data, 0); - m_voice[1].enable = bitfield(data, 1); - m_voice[2].enable = bitfield(data, 2); - m_voice[3].enable = bitfield(data, 3); - m_voice[4].enable = bitfield(data, 4); - break; - } -} - -void k051649_scc_core::scc_w(bool is_sccplus, u8 address, u8 data) -{ - const u8 voice = bitfield(address, 5, 3); - switch (voice) - { - case 0b000: // 0x00-0x1f Voice 0 Waveform - case 0b001: // 0x20-0x3f Voice 1 Waveform - case 0b010: // 0x40-0x5f Voice 2 Waveform - case 0b011: // 0x60-0x7f Voice 3/4 Waveform - wave_w(false, address, data); - break; - case 0b100: // 0x80-0x9f Pitch, Volume, Enable - freq_vol_enable_w(address, data); - break; - case 0b111: // 0xe0-0xff Test register - m_test.freq_4bit = bitfield(data, 0); - m_test.freq_8bit = bitfield(data, 1); - m_test.resetpos = bitfield(data, 5); - m_test.rotate = bitfield(data, 6); - m_test.rotate4 = bitfield(data, 7); - break; - } - m_reg[address] = data; -} - -void k052539_scc_core::scc_w(bool is_sccplus, u8 address, u8 data) -{ - const u8 voice = bitfield(address, 5, 3); - if (is_sccplus) - { - switch (voice) - { - case 0b000: // 0x00-0x1f Voice 0 Waveform - case 0b001: // 0x20-0x3f Voice 1 Waveform - case 0b010: // 0x40-0x5f Voice 2 Waveform - case 0b011: // 0x60-0x7f Voice 3 Waveform - case 0b100: // 0x80-0x9f Voice 4 Waveform - wave_w(true, address, data); - break; - case 0b101: // 0xa0-0xbf Pitch, Volume, Enable - freq_vol_enable_w(address, data); - break; - case 0b110: // 0xc0-0xdf Test register - m_test.freq_4bit = bitfield(data, 0); - m_test.freq_8bit = bitfield(data, 1); - m_test.resetpos = bitfield(data, 5); - m_test.rotate = bitfield(data, 6); - break; - default: - break; - } - } - else - { - switch (voice) - { - case 0b000: // 0x00-0x1f Voice 0 Waveform - case 0b001: // 0x20-0x3f Voice 1 Waveform - case 0b010: // 0x40-0x5f Voice 2 Waveform - case 0b011: // 0x60-0x7f Voice 3/4 Waveform - wave_w(false, address, data); - break; - case 0b100: // 0x80-0x9f Pitch, Volume, Enable - freq_vol_enable_w(address, data); - break; - case 0b110: // 0xc0-0xdf Test register - m_test.freq_4bit = bitfield(data, 0); - m_test.freq_8bit = bitfield(data, 1); - m_test.resetpos = bitfield(data, 5); - m_test.rotate = bitfield(data, 6); - break; - default: - break; - } - } - m_reg[address] = data; -} - -u8 k051649_scc_core::scc_r(bool is_sccplus, u8 address) -{ - const u8 voice = bitfield(address, 5, 3); - const u8 wave = bitfield(address, 0, 5); - u8 ret = 0xff; - switch (voice) - { - case 0b000: // 0x00-0x1f Voice 0 Waveform - case 0b001: // 0x20-0x3f Voice 1 Waveform - case 0b010: // 0x40-0x5f Voice 2 Waveform - case 0b011: // 0x60-0x7f Voice 3 Waveform - case 0b101: // 0xa0-0xbf Voice 4 Waveform - ret = wave_r(false, (std::min(4, voice) << 5) | wave); - break; - } - return ret; -} - -u8 k052539_scc_core::scc_r(bool is_sccplus, u8 address) -{ - const u8 voice = bitfield(address, 5, 3); - const u8 wave = bitfield(address, 0, 5); - u8 ret = 0xff; - if (is_sccplus) - { - switch (voice) - { - case 0b000: // 0x00-0x1f Voice 0 Waveform - case 0b001: // 0x20-0x3f Voice 1 Waveform - case 0b010: // 0x40-0x5f Voice 2 Waveform - case 0b011: // 0x60-0x7f Voice 3 Waveform - case 0b100: // 0x80-0x9f Voice 4 Waveform - ret = wave_r(true, address); - break; - } - } - else - { - switch (voice) - { - case 0b000: // 0x00-0x1f Voice 0 Waveform - case 0b001: // 0x20-0x3f Voice 1 Waveform - case 0b010: // 0x40-0x5f Voice 2 Waveform - case 0b011: // 0x60-0x7f Voice 3 Waveform - case 0b101: // 0xa0-0xbf Voice 4 Waveform - ret = wave_r(false, (std::min(4, voice) << 5) | wave); - break; - } - } - return ret; -} diff --git a/src/engine/platform/sound/scc/scc.hpp b/src/engine/platform/sound/scc/scc.hpp deleted file mode 100644 index 24a365ccf..000000000 --- a/src/engine/platform/sound/scc/scc.hpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst - Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw - Konami SCC emulation core - - See scc.cpp for more info. -*/ - -#include -#include - -#ifndef _VGSOUND_EMU_SCC_HPP -#define _VGSOUND_EMU_SCC_HPP - -#pragma once - -namespace scc -{ - typedef unsigned char u8; - typedef signed char s8; - typedef unsigned short u16; - typedef signed short s16; - typedef unsigned int u32; - typedef signed int s32; - - // get bitfield, bitfield(input, position, len) - template T bitfield(T in, u8 pos, u8 len = 1) - { - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); - } -} - -using namespace scc; -// shared for SCCs -class scc_core -{ -public: - // constructor - scc_core() - : m_voice{*this,*this,*this,*this,*this} - {}; - virtual ~scc_core(){}; - - // accessors - virtual u8 scc_r(bool is_sccplus, u8 address) = 0; - virtual void scc_w(bool is_sccplus, u8 address, u8 data) = 0; - - // internal state - virtual void reset(); - void tick(); - - // getters - s32 out() { return m_out; } // output to DA0...DA10 pin - s32 chan_out(u8 ch) { return m_voice[ch].out; } - u8 reg(u8 address) { return m_reg[address]; } - -protected: - // voice structs - struct voice_t - { - // constructor - voice_t(scc_core &host) : m_host(host) {}; - - // internal state - void reset(); - void tick(); - - // registers - scc_core &m_host; - s8 wave[32] = {0}; // internal waveform - bool enable = false; // output enable flag - u16 pitch = 0; // pitch - u8 volume = 0; // volume - u8 addr = 0; // waveform pointer - u16 counter = 0; // frequency counter - s32 out = 0; // current output - }; - voice_t m_voice[5]; // 5 voices - - // accessor - u8 wave_r(bool is_sccplus, u8 address); - void wave_w(bool is_sccplus, u8 address, u8 data); - void freq_vol_enable_w(u8 address, u8 data); - - struct test_t - { - // constructor - test_t() - : freq_4bit(0) - , freq_8bit(0) - , resetpos(0) - , rotate(0) - , rotate4(0) - { }; - - void reset() - { - freq_4bit = 0; - freq_8bit = 0; - resetpos = 0; - rotate = 0; - rotate4 = 0; - } - - u8 freq_4bit : 1; // 4 bit frequency - u8 freq_8bit : 1; // 8 bit frequency - u8 resetpos : 1; // reset counter after pitch writes - u8 rotate : 1; // rotate and write protect waveform for all channels - u8 rotate4 : 1; // same as above but for channel 4 only - }; - - test_t m_test; // test register - s32 m_out = 0; // output to DA0...10 - - u8 m_reg[256] = {0}; // register pool -}; - -// SCC core -class k051649_scc_core : public scc_core -{ -public: - // accessors - virtual u8 scc_r(bool is_sccplus, u8 address) override; - virtual void scc_w(bool is_sccplus, u8 address, u8 data) override; -}; - -class k052539_scc_core : public k051649_scc_core -{ -public: - // accessors - virtual u8 scc_r(bool is_sccplus, u8 address) override; - virtual void scc_w(bool is_sccplus, u8 address, u8 data) override; -}; - -#endif diff --git a/src/engine/platform/sound/vrcvi/vrcvi.cpp b/src/engine/platform/sound/vrcvi/vrcvi.cpp deleted file mode 100644 index a811c2f44..000000000 --- a/src/engine/platform/sound/vrcvi/vrcvi.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900, tildearrow - Konami VRC VI sound emulation core - - It's one of NES mapper with built-in sound chip, and also one of 2 Konami VRCs with this feature. (rest one has OPLL derivatives.) - - It's also DACless like other sound chip and mapper-with-sound manufactured by konami, - the Chips 6 bit digital sound output is needs converted to analog sound output when you it want to make some sounds, or send to sound mixer. - - Its are used for Akumajou Densetsu (Japan release of Castlevania III), Madara, Esper Dream 2. - - The chip is installed in 351951 PCB and 351949A PCB. - - 351951 PCB is used exclusivly for Akumajou Densetsu, Small board has VRC VI, PRG and CHR ROM. - - It's configuration also calls VRC6a, iNES mapper 024. - - 351949A PCB is for Last 2 titles with VRC VI, Bigger board has VRC VI, PRG and CHR ROM, and Battery Backed 8K x 8 bit SRAM. - - Additionally, It's PRG A0 and A1 bit to VRC VI input is swapped, compare to above. - - It's configuration also calls VRC6b, iNES mapper 026. - - The chip itself has 053328, 053329, 053330 Revision, but Its difference between revision is unknown. - - Like other mappers for NES, It has internal timer - Its timer can be sync with scanline like other Konami mapper in this era. - - Register layout (Sound and Timer only; 351951 PCB case, 351949A swaps xxx1 and xxx2): - - Address Bits Description - 7654 3210 - - 9000-9002 Pulse 1 - - 9000 x--- ---- Pulse 1 Duty ignore - -xxx ---- Pulse 1 Duty cycle - ---- xxxx Pulse 1 Volume - 9001 xxxx xxxx Pulse 1 Pitch bit 0-7 - 9002 x--- ---- Pulse 1 Enable - ---- xxxx Pulse 1 Pitch bit 8-11 - - 9003 Sound control - - 9003 ---- -x-- 4 bit Frequency mode - ---- -0x- 8 bit Frequency mode - ---- ---x Halt - - a000-a002 Pulse 2 - - a000 x--- ---- Pulse 2 Duty ignore - -xxx ---- Pulse 2 Duty cycle - ---- xxxx Pulse 2 Volume - a001 xxxx xxxx Pulse 2 Pitch bit 0-7 - a002 x--- ---- Pulse 2 Enable - ---- xxxx Pulse 2 Pitch bit 8-11 - - b000-b002 Sawtooth - - b000 --xx xxxx Sawtooth Accumulate Rate - b001 xxxx xxxx Sawtooth Pitch bit 0-7 - b002 x--- ---- Sawtooth Enable - ---- xxxx Sawtooth Pitch bit 8-11 - - f000-f002 IRQ Timer - - f000 xxxx xxxx IRQ Timer latch - f001 ---- -0-- Sync with scanline - ---- --x- Enable timer - ---- ---x Enable timer after IRQ Acknowledge - f002 ---- ---- IRQ Acknowledge - - Frequency calculations: - - if 4 bit Frequency Mode then - Frequency: Input clock / (bit 8 to 11 of Pitch + 1) - end else if 8 bit Frequency Mode then - Frequency: Input clock / (bit 4 to 11 of Pitch + 1) - end else then - Frequency: Input clock / (Pitch + 1) - end -*/ - -#include "vrcvi.hpp" -#include - -void vrcvi_core::tick() -{ - m_out = 0; - if (!m_control.m_halt) // Halt flag - { - // tick per each clock - int elemIndex=0; - for (auto & elem : m_pulse) - { - if (elem.tick()) { - m_out += elem.m_control.m_volume; // add 4 bit pulse output - m_ch_out[elemIndex]=elem.m_control.m_volume; - } else { - m_ch_out[elemIndex]=0; - } - elemIndex++; - } - if (m_sawtooth.tick()) { - m_out += bitfield(m_sawtooth.m_accum, 3, 5); // add 5 bit sawtooth output - m_ch_out[2]=bitfield(m_sawtooth.m_accum, 3, 5); - } else { - m_ch_out[2]=0; - } - } - if (m_timer.tick()) - m_timer.counter_tick(); -} - -void vrcvi_core::reset() -{ - for (auto & elem : m_pulse) - elem.reset(); - - m_sawtooth.reset(); - m_timer.reset(); - m_control.reset(); - m_out = 0; - memset(m_ch_out,0,sizeof(m_ch_out)); -} - -bool vrcvi_core::alu_t::tick() -{ - if (m_divider.m_enable) - { - const u16 temp = m_counter; - // post decrement - if (bitfield(m_host.m_control.m_shift, 1)) - { - m_counter = (m_counter & 0x0ff) | (bitfield(bitfield(m_counter, 8, 4) - 1, 0, 4) << 8); - m_counter = (m_counter & 0xf00) | (bitfield(bitfield(m_counter, 0, 8) - 1, 0, 8) << 0); - } - else if (bitfield(m_host.m_control.m_shift, 0)) - { - m_counter = (m_counter & 0x00f) | (bitfield(bitfield(m_counter, 4, 8) - 1, 0, 8) << 4); - m_counter = (m_counter & 0xff0) | (bitfield(bitfield(m_counter, 0, 4) - 1, 0, 4) << 0); - } - else - m_counter = bitfield(bitfield(m_counter, 0, 12) - 1, 0, 12); - - // carry handling - bool carry = bitfield(m_host.m_control.m_shift, 1) ? (bitfield(temp, 8, 4) == 0) : - (bitfield(m_host.m_control.m_shift, 0) ? (bitfield(temp, 4, 8) == 0) : - (bitfield(temp, 0, 12) == 0)); - if (carry) - m_counter = m_divider.m_divider; - - return carry; - } - return false; -} - -bool vrcvi_core::pulse_t::tick() -{ - if (!m_divider.m_enable) - return false; - - if (vrcvi_core::alu_t::tick()) - m_cycle = bitfield(m_cycle + 1, 0, 4); - - return m_control.m_mode ? true : ((m_cycle > m_control.m_duty) ? true : false); -} - -bool vrcvi_core::sawtooth_t::tick() -{ - if (!m_divider.m_enable) - return false; - - if (vrcvi_core::alu_t::tick()) - { - if (bitfield(m_cycle++, 0)) // Even step only - m_accum += m_rate; - if (m_cycle >= 14) // Reset accumulator at every 14 cycles - { - m_accum = 0; - m_cycle = 0; - } - } - return (m_accum == 0) ? false : true; -} - -void vrcvi_core::alu_t::reset() -{ - m_divider.reset(); - m_counter = 0; - m_cycle = 0; -} - -void vrcvi_core::pulse_t::reset() -{ - vrcvi_core::alu_t::reset(); - m_control.reset(); -} - -void vrcvi_core::sawtooth_t::reset() -{ - vrcvi_core::alu_t::reset(); - m_rate = 0; - m_accum = 0; -} - -bool vrcvi_core::timer_t::tick() -{ - if (m_timer_control.m_enable) - { - if (!m_timer_control.m_sync) // scanline sync mode - { - m_prescaler -= 3; - if (m_prescaler <= 0) - { - m_prescaler += 341; - return true; - } - } - } - return (m_timer_control.m_enable && m_timer_control.m_sync) ? true : false; -} - -void vrcvi_core::timer_t::counter_tick() -{ - if (bitfield(++m_counter, 0, 8) == 0) - { - m_counter = m_counter_latch; - irq_set(); - } -} - -void vrcvi_core::timer_t::reset() -{ - m_timer_control.reset(); - m_prescaler = 341; - m_counter = m_counter_latch = 0; - irq_clear(); -} - -// Accessors - -void vrcvi_core::alu_t::divider_t::write(bool msb, u8 data) -{ - if (msb) - { - m_divider = (m_divider & ~0xf00) | (bitfield(data, 0, 4) << 8); - m_enable = bitfield(data, 7); - } - else - m_divider = (m_divider & ~0x0ff) | data; -} - - -void vrcvi_core::pulse_w(u8 voice, u8 address, u8 data) -{ - pulse_t &v = m_pulse[voice]; - switch (address) - { - case 0x00: // Control - 0x9000 (Pulse 1), 0xa000 (Pulse 2) - v.m_control.m_mode = bitfield(data, 7); - v.m_control.m_duty = bitfield(data, 4, 3); - v.m_control.m_volume = bitfield(data, 0, 4); - break; - case 0x01: // Pitch LSB - 0x9001/0x9002 (Pulse 1), 0xa001/0xa002 (Pulse 2) - v.m_divider.write(false, data); - break; - case 0x02: // Pitch MSB, Enable/Disable - 0x9002/0x9001 (Pulse 1), 0xa002/0xa001 (Pulse 2) - v.m_divider.write(true, data); - if (!v.m_divider.m_enable) // Reset duty cycle - v.m_cycle = 0; - break; - } -} - -void vrcvi_core::saw_w(u8 address, u8 data) -{ - switch (address) - { - case 0x00: // Sawtooth Accumulate - 0xb000 - m_sawtooth.m_rate = bitfield(data, 0, 6); - break; - case 0x01: // Pitch LSB - 0xb001/0xb002 (Sawtooth) - m_sawtooth.m_divider.write(false, data); - break; - case 0x02: // Pitch MSB, Enable/Disable - 0xb002/0xb001 (Sawtooth) - m_sawtooth.m_divider.write(true, data); - if (!m_sawtooth.m_divider.m_enable) // Reset accumulator - m_sawtooth.m_accum = 0; - break; - } -} - -void vrcvi_core::timer_w(u8 address, u8 data) -{ - switch (address) - { - case 0x00: // Timer latch - 0xf000 - m_timer.m_counter_latch = data; - break; - case 0x01: // Timer control - 0xf001/0xf002 - m_timer.m_timer_control.m_sync = bitfield(data, 2); - m_timer.m_timer_control.m_enable = bitfield(data, 1); - m_timer.m_timer_control.m_enable_ack = bitfield(data, 0); - if (m_timer.m_timer_control.m_enable) - { - m_timer.m_counter = m_timer.m_counter_latch; - m_timer.m_prescaler = 341; - } - m_timer.irq_clear(); - break; - case 0x02: // IRQ Acknowledge - 0xf002/0xf001 - m_timer.irq_clear(); - m_timer.m_timer_control.m_enable = m_timer.m_timer_control.m_enable_ack; - break; - } -} - -void vrcvi_core::control_w(u8 data) -{ - // Global control - 0x9003 - m_control.m_halt = bitfield(data, 0); - m_control.m_shift = bitfield(data, 1, 2); -} diff --git a/src/engine/platform/sound/vrcvi/vrcvi.hpp b/src/engine/platform/sound/vrcvi/vrcvi.hpp deleted file mode 100644 index 4a80f7577..000000000 --- a/src/engine/platform/sound/vrcvi/vrcvi.hpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900, tildearrow - Konami VRC VI sound emulation core - - See vrcvi.cpp to more infos. -*/ - -#include -#include - -#ifndef _VGSOUND_EMU_VRCVI_HPP -#define _VGSOUND_EMU_VRCVI_HPP - -#pragma once - -namespace vrcvi -{ - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; - typedef signed char s8; - typedef signed short s16; - - // get bitfield, bitfield(input, position, len) - template T bitfield(T in, u8 pos, u8 len = 1) - { - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); - } -}; - -class vrcvi_intf -{ -public: - virtual void irq_w(bool irq) { } -}; - -using namespace vrcvi; -class vrcvi_core -{ -public: - friend class vrcvi_intf; - // constructor - vrcvi_core(vrcvi_intf &intf) - : m_pulse{*this,*this} - , m_sawtooth(*this) - , m_timer(*this) - , m_intf(intf) - { - } - // accessors, getters, setters - void pulse_w(u8 voice, u8 address, u8 data); - void saw_w(u8 address, u8 data); - void timer_w(u8 address, u8 data); - void control_w(u8 data); - - // internal state - void reset(); - void tick(); - - // 6 bit output - s8 out() { return m_out; } - // channel output - s16 chan_out(u8 ch) { return m_ch_out[ch]; } -private: - // Common ALU for sound channels - struct alu_t - { - alu_t(vrcvi_core &host) - : m_host(host) - { }; - - - virtual void reset(); - virtual bool tick(); - - struct divider_t - { - divider_t() - : m_divider(0) - , m_enable(0) - { }; - - void reset() - { - m_divider = 0; - m_enable = 0; - } - - void write(bool msb, u8 data); - - u16 m_divider : 12; // divider (pitch) - u16 m_enable : 1; // channel enable flag - }; - - vrcvi_core &m_host; - divider_t m_divider; - u16 m_counter = 0; // clock counter - u8 m_cycle = 0; // clock cycle - }; - - // 2 Pulse channels - struct pulse_t : alu_t - { - pulse_t(vrcvi_core &host) - : alu_t(host) - { }; - - virtual void reset() override; - virtual bool tick() override; - - // Control bits - struct pulse_control_t - { - pulse_control_t() - : m_mode(0) - , m_duty(0) - , m_volume(0) - { }; - - void reset() - { - m_mode = 0; - m_duty = 0; - m_volume = 0; - } - - u8 m_mode : 1; // duty toggle flag - u8 m_duty : 3; // 3 bit duty cycle - u8 m_volume : 4; // 4 bit volume - }; - - pulse_control_t m_control; - }; - - // 1 Sawtooth channel - struct sawtooth_t : alu_t - { - sawtooth_t(vrcvi_core &host) - : alu_t(host) - { }; - - virtual void reset() override; - virtual bool tick() override; - - u8 m_rate = 0; // sawtooth accumulate rate - u8 m_accum = 0; // sawtooth accumulator, high 5 bit is accumulated to output - }; - - // Internal timer - struct timer_t - { - timer_t(vrcvi_core &host) - : m_host(host) - { }; - - void reset(); - bool tick(); - void counter_tick(); - - // IRQ update - void update() { m_host.m_intf.irq_w(m_timer_control.m_irq_trigger); } - void irq_set() - { - if (!m_timer_control.m_irq_trigger) - { - m_timer_control.m_irq_trigger = 1; - update(); - } - } - void irq_clear() - { - if (m_timer_control.m_irq_trigger) - { - m_timer_control.m_irq_trigger = 0; - update(); - } - } - - // Control bits - struct timer_control_t - { - timer_control_t() - : m_irq_trigger(0) - , m_enable_ack(0) - , m_enable(0) - , m_sync(0) - { }; - - void reset() - { - m_irq_trigger = 0; - m_enable_ack = 0; - m_enable = 0; - m_sync = 0; - } - - u8 m_irq_trigger : 1; - u8 m_enable_ack : 1; - u8 m_enable : 1; - u8 m_sync : 1; - }; - - vrcvi_core &m_host; // host core - timer_control_t m_timer_control; // timer control bits - s16 m_prescaler = 341; // prescaler - u8 m_counter = 0; // clock counter - u8 m_counter_latch = 0; // clock counter latch - }; - - struct global_control_t - { - global_control_t() - : m_halt(0) - , m_shift(0) - { }; - - void reset() - { - m_halt = 0; - m_shift = 0; - } - - u8 m_halt : 1; // halt sound - u8 m_shift : 2; // 4/8 bit right shift - }; - - pulse_t m_pulse[2]; // 2 pulse channels - sawtooth_t m_sawtooth; // sawtooth channel - timer_t m_timer; // internal timer - global_control_t m_control; // control - - vrcvi_intf &m_intf; - - s8 m_out = 0; // 6 bit output - s8 m_ch_out[3] = {0}; // per-channel output -}; - -#endif diff --git a/src/engine/platform/sound/x1_010/x1_010.cpp b/src/engine/platform/sound/x1_010/x1_010.cpp deleted file mode 100644 index 6b0041bad..000000000 --- a/src/engine/platform/sound/x1_010/x1_010.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900, tildearrow - Seta/Allumer X1-010 Emulation core - - the chip has 16 voices, all voices can be switchable to Wavetable or PCM sample playback mode. - It has also 2 output channels, but no known hardware using this feature for stereo sound. - - Wavetable needs to paired with envelope, it's always enabled and similar as AY PSG's one - but its shape is stored at RAM. - - PCM volume is stored by each register. - - Both volume is 4bit per output. - - Everything except PCM sample is stored at paired 8 bit RAM. - - RAM layout (common case: Address bit 12 is swapped when RAM is shared with CPU) - - ----------------------------- - 0000...007f Voice Registers - - 0000...0007 Voice 0 Register - - Address Bits Description - 7654 3210 - 0 x--- ---- Frequency divider* - ---- -x-- Envelope one-shot mode - ---- --x- Sound format - ---- --0- PCM - ---- --1- Wavetable - ---- ---x Keyon/off - PCM case: - 1 xxxx xxxx Volume (Each nibble is for each output) - - 2 xxxx xxxx Frequency* - - 4 xxxx xxxx Start address / 4096 - - 5 xxxx xxxx 0x100 - (End address / 4096) - Wavetable case: - 1 ---x xxxx Wavetable data select - - 2 xxxx xxxx Frequency LSB* - 3 xxxx xxxx "" MSB - - 4 xxxx xxxx Envelope period (.10 fixed point, Low 8 bit) - - 5 ---x xxxx Envelope shape select (!= 0 : Reserved for Voice registers) - - 0008...000f Voice 1 Register - ... - 0078...007f Voice 15 Register - ----------------------------- - 0080...0fff Envelope shape data (Same as volume; Each nibble is for each output) - - 0080...00ff Envelope shape data 1 - 0100...017f Envelope shape data 2 - ... - 0f80...0fff Envelope shape data 31 - ----------------------------- - 1000...1fff Wavetable data - - 1000...107f Wavetable data 0 - 1080...10ff Wavetable data 1 - ... - 1f80...1fff Wavetable data 31 - ----------------------------- - - * Frequency is 4.4 fixed point for PCM, - 6.10 for Wavetable. - Frequency divider is higher precision or just right shift? - needs verification. -*/ - -#include "x1_010.hpp" - -void x1_010_core::tick() -{ - // reset output - m_out[0] = m_out[1] = 0; - for (int i = 0; i < 16; i++) - { - voice_t &v = m_voice[i]; - v.tick(); - m_out[0] += v.data * v.vol_out[0]; - m_out[1] += v.data * v.vol_out[1]; - } -} - -void x1_010_core::voice_t::tick() -{ - data = vol_out[0] = vol_out[1] = 0; - if (flag.keyon) - { - if (flag.wavetable) // Wavetable - { - // envelope, each nibble is for each output - u8 vol = m_host.m_envelope[(bitfield(end_envshape, 0, 5) << 7) | bitfield(env_acc, 10, 7)]; - vol_out[0] = bitfield(vol, 4, 4); - vol_out[1] = bitfield(vol, 0, 4); - env_acc += start_envfreq; - if (flag.env_oneshot && bitfield(env_acc, 17)) - flag.keyon = false; - else - env_acc = bitfield(env_acc, 0, 17); - // get wavetable data - data = m_host.m_wave[(bitfield(vol_wave, 0, 5) << 7) | bitfield(acc, 10, 7)]; - acc = bitfield(acc + (freq >> flag.div), 0, 17); - } - else // PCM sample - { - // volume register, each nibble is for each output - vol_out[0] = bitfield(vol_wave, 4, 4); - vol_out[1] = bitfield(vol_wave, 0, 4); - // get PCM sample - data = m_host.m_intf.read_byte(bitfield(acc, 4, 20)); - acc += bitfield(freq, 0, 8) >> flag.div; - if ((acc >> 16) > (0xff ^ end_envshape)) - flag.keyon = false; - } - } -} - -u8 x1_010_core::ram_r(u16 offset) -{ - if (offset & 0x1000) // wavetable data - return m_wave[offset & 0xfff]; - else if (offset & 0xf80) // envelope shape data - return m_envelope[offset & 0xfff]; - else // channel register - return m_voice[bitfield(offset, 3, 4)].reg_r(offset & 0x7); -} - -void x1_010_core::ram_w(u16 offset, u8 data) -{ - if (offset & 0x1000) // wavetable data - m_wave[offset & 0xfff] = data; - else if (offset & 0xf80) // envelope shape data - m_envelope[offset & 0xfff] = data; - else // channel register - m_voice[bitfield(offset, 3, 4)].reg_w(offset & 0x7, data); -} - -u8 x1_010_core::voice_t::reg_r(u8 offset) -{ - switch (offset & 0x7) - { - case 0x00: return (flag.div << 7) - | (flag.env_oneshot << 2) - | (flag.wavetable << 1) - | (flag.keyon << 0); - case 0x01: return vol_wave; - case 0x02: return bitfield(freq, 0, 8); - case 0x03: return bitfield(freq, 8, 8); - case 0x04: return start_envfreq; - case 0x05: return end_envshape; - default: break; - } - return 0; -} - -void x1_010_core::voice_t::reg_w(u8 offset, u8 data) -{ - switch (offset & 0x7) - { - case 0x00: - { - const bool prev_keyon = flag.keyon; - flag.div = bitfield(data, 7); - flag.env_oneshot = bitfield(data, 2); - flag.wavetable = bitfield(data, 1); - flag.keyon = bitfield(data, 0); - if (!prev_keyon && flag.keyon) // Key on - { - acc = flag.wavetable ? 0 : (u32(start_envfreq) << 16); - env_acc = 0; - } - break; - } - case 0x01: - vol_wave = data; - break; - case 0x02: - freq = (freq & 0xff00) | data; - break; - case 0x03: - freq = (freq & 0x00ff) | (u16(data) << 8); - break; - case 0x04: - start_envfreq = data; - break; - case 0x05: - end_envshape = data; - break; - default: - break; - } -} - -void x1_010_core::voice_t::reset() -{ - flag.reset(); - vol_wave = 0; - freq = 0; - start_envfreq = 0; - end_envshape = 0; - acc = 0; - env_acc = 0; - data = 0; - vol_out[0] = vol_out[1] = 0; -} - -void x1_010_core::reset() -{ - for (auto & elem : m_voice) - elem.reset(); - - std::fill_n(&m_envelope[0], 0x1000, 0); - std::fill_n(&m_wave[0], 0x1000, 0); - m_out[0] = m_out[1] = 0; -} diff --git a/src/engine/platform/sound/x1_010/x1_010.hpp b/src/engine/platform/sound/x1_010/x1_010.hpp deleted file mode 100644 index b533b66d8..000000000 --- a/src/engine/platform/sound/x1_010/x1_010.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - License: BSD-3-Clause - see https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900, tildearrow - Seta/Allumer X1-010 Emulation core - - See x1_010.cpp for more info. -*/ - -#include -#include - -#ifndef _VGSOUND_EMU_X1_010_HPP -#define _VGSOUND_EMU_X1_010_HPP - -#pragma once - -namespace x1_010 -{ - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; - typedef signed char s8; - typedef signed int s32; - - template T bitfield(T in, u8 pos, u8 len = 1) - { - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); - } -} - -using namespace x1_010; -class x1_010_mem_intf -{ -public: - virtual u8 read_byte(u32 address) { return 0; } -}; - -using namespace x1_010; -class x1_010_core -{ - friend class x1_010_mem_intf; -public: - // constructor - x1_010_core(x1_010_mem_intf &intf) - : m_voice{*this,*this,*this,*this, - *this,*this,*this,*this, - *this,*this,*this,*this, - *this,*this,*this,*this} - , m_intf(intf) - { - m_envelope = std::make_unique(0x1000); - m_wave = std::make_unique(0x1000); - - std::fill_n(&m_envelope[0], 0x1000, 0); - std::fill_n(&m_wave[0], 0x1000, 0); - } - - // register accessor - u8 ram_r(u16 offset); - void ram_w(u16 offset, u8 data); - - // getters - s32 output(u8 channel) { return m_out[channel & 1]; } - s32 chan_out(u8 channel) { return (m_voice[channel].data * (m_voice[channel].vol_out[0]+m_voice[channel].vol_out[1]))<<2; } - - // internal state - void reset(); - void tick(); - -private: - // 16 voices in chip - struct voice_t - { - // constructor - voice_t(x1_010_core &host) : m_host(host) {} - - // internal state - void reset(); - void tick(); - - // register accessor - u8 reg_r(u8 offset); - void reg_w(u8 offset, u8 data); - - // registers - x1_010_core &m_host; - struct flag_t - { - u8 div : 1; - u8 env_oneshot : 1; - u8 wavetable : 1; - u8 keyon : 1; - void reset() - { - div = 0; - env_oneshot = 0; - wavetable = 0; - keyon = 0; - } - flag_t() - : div(0) - , env_oneshot(0) - , wavetable(0) - , keyon(0) - { } - }; - flag_t flag; - u8 vol_wave = 0; - u16 freq = 0; - u8 start_envfreq = 0; - u8 end_envshape = 0; - - // internal registers - u32 acc = 0; - u32 env_acc = 0; - s8 data = 0; - u8 vol_out[2] = {0}; - }; - voice_t m_voice[16]; - - // RAM - std::unique_ptr m_envelope = nullptr; - std::unique_ptr m_wave = nullptr; - - // output data - s32 m_out[2] = {0}; - - x1_010_mem_intf &m_intf; -}; - -#endif diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 2500ce190..449ee1597 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -86,9 +86,10 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len // Oscilloscope buffer part if (++writeOscBuf>=32) { writeOscBuf=0; - for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.chan_out(i)<<10; + for (int i=0; i<2; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.pulse_out(i)<<10; } + oscBuf[2]->data[oscBuf[2]->needle++]=vrc6.sawtooth_out()<<10; } // Command part @@ -195,7 +196,7 @@ void DivPlatformVRC6::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].keyOff) { chWrite(i,2,0); - } else { + } else if (chan[i].active) { chWrite(i,1,chan[i].freq&0xff); chWrite(i,2,0x80|((chan[i].freq>>8)&0xf)); } diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index 608baa100..81c81016f 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -23,10 +23,10 @@ #include #include "../dispatch.h" #include "../macroInt.h" -#include "sound/vrcvi/vrcvi.hpp" +#include "vgsound_emu/src/vrcvi/vrcvi.hpp" -class DivPlatformVRC6: public DivDispatch { +class DivPlatformVRC6: public DivDispatch, public vrcvi_intf { struct Channel { int freq, baseFreq, pitch, pitch2, note; int dacPeriod, dacRate, dacOut; @@ -75,7 +75,6 @@ class DivPlatformVRC6: public DivDispatch { std::queue writes; unsigned char sampleBank; unsigned char writeOscBuf; - vrcvi_intf intf; vrcvi_core vrc6; unsigned char regPool[13]; @@ -101,7 +100,7 @@ class DivPlatformVRC6: public DivDispatch { const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); - DivPlatformVRC6() : vrc6(intf) {}; + DivPlatformVRC6() : vrc6(*this) {}; ~DivPlatformVRC6(); }; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 0f989ac9d..87c7a91c4 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -23,9 +23,9 @@ #include //#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) if (!skipRegisterWrites) { x1_010->ram_w(a,v); if (dumpWrites) { addWrite(a,v); } } +#define rWrite(a,v) if (!skipRegisterWrites) { x1_010.ram_w(a,v); if (dumpWrites) { addWrite(a,v); } } -#define chRead(c,a) x1_010->ram_r((c<<3)|(a&7)) +#define chRead(c,a) x1_010.ram_r((c<<3)|(a&7)) #define chWrite(c,a,v) rWrite((c<<3)|(a&7),v) #define waveWrite(c,a,v) rWrite(0x1000|(chan[c].waveBank<<11)|(c<<7)|(a&0x7f),(v-128)&0xff) #define envFill(c,a) rWrite(0x800|(c<<7)|(a&0x7f),(chan[c].lvol<<4)|chan[c].rvol) @@ -207,10 +207,10 @@ const char** DivPlatformX1_010::getRegisterSheet() { void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; htick(); + x1_010.tick(); - signed int tempL=x1_010->output(0); - signed int tempR=x1_010->output(1); + signed int tempL=x1_010.output(0); + signed int tempR=x1_010.output(1); if (tempL<-32768) tempL=-32768; if (tempL>32767) tempL=32767; @@ -222,11 +222,18 @@ void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t l bufR[h]=stereo?tempR:bufL[h]; for (int i=0; i<16; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=x1_010->chan_out(i); + oscBuf[i]->data[oscBuf[i]->needle++]=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))>>1; } } } +u8 DivPlatformX1_010::read_byte(u32 address) { + if ((sampleMem!=NULL) && (addressram_r(i); + regPool[i]=x1_010.ram_r(i); } return regPool; } @@ -829,7 +836,7 @@ void DivPlatformX1_010::reset() { chan[i].ws.setEngine(parent); chan[i].ws.init(NULL,128,255,false); } - x1_010->reset(); + x1_010.reset(); sampleBank=0; // set per-channel initial panning for (int i=0; i<16; i++) { @@ -942,9 +949,7 @@ int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned in setFlags(flags); sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; - intf.memory=sampleMem; - x1_010=new x1_010_core(intf); - x1_010->reset(); + x1_010.reset(); reset(); return 16; } @@ -953,7 +958,6 @@ void DivPlatformX1_010::quit() { for (int i=0; i<16; i++) { delete oscBuf[i]; } - delete x1_010; delete[] sampleMem; } diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 178a89383..84d1040ef 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -24,20 +24,9 @@ #include "../engine.h" #include "../macroInt.h" #include "../waveSynth.h" -#include "sound/x1_010/x1_010.hpp" +#include "vgsound_emu/src/x1_010/x1_010.hpp" -class DivX1_010Interface: public x1_010_mem_intf { - public: - unsigned char* memory; - int sampleBank; - virtual u8 read_byte(u32 address) override { - if (memory==NULL) return 0; - return memory[address & 0xfffff]; - } - DivX1_010Interface(): memory(NULL), sampleBank(0) {} -}; - -class DivPlatformX1_010: public DivDispatch { +class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf { struct Channel { struct Envelope { struct EnvFlag { @@ -118,14 +107,14 @@ class DivPlatformX1_010: public DivDispatch { unsigned char* sampleMem; size_t sampleMemLen; unsigned char sampleBank; - DivX1_010Interface intf; - x1_010_core* x1_010; + x1_010_core x1_010; unsigned char regPool[0x2000]; double NoteX1_010(int ch, int note); void updateWave(int ch); void updateEnvelope(int ch); friend void putDispatchChan(void*,int,int); public: + u8 read_byte(u32 address); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); @@ -151,6 +140,10 @@ class DivPlatformX1_010: public DivDispatch { const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformX1_010(): + DivDispatch(), + vgsound_emu_mem_intf(), + x1_010(*this) {} ~DivPlatformX1_010(); }; diff --git a/src/main.cpp b/src/main.cpp index a18560926..885a4c49e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -183,7 +183,7 @@ TAParamResult pVersion(String) { printf("- reSID by Dag Lem (GPLv2)\n"); printf("- reSIDfp by Dag Lem, Antti Lankila and Leandro Nini (GPLv2)\n"); printf("- Stella by Stella Team (GPLv2)\n"); - printf("- vgsound_emu (first version) by cam900 (BSD 3-clause)\n"); + printf("- vgsound_emu (second version) by cam900 (zlib)\n"); return TA_PARAM_QUIT; } From bf2ec8f1c4138f079277954501a8c3f7b694cc17 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 00:05:54 +0900 Subject: [PATCH 420/515] Temporary workaround for accidently removed libs --- extern/vgsound_emu-modified | 1 + vgsound_emu-modified/.clang-format | 154 ++++ vgsound_emu-modified/.gitignore | 18 + vgsound_emu-modified/CHANGELOG.md | 17 + vgsound_emu-modified/CMakeLists.txt | 161 ++++ vgsound_emu-modified/LICENSE | 19 + vgsound_emu-modified/MODIFIED.md | 7 + vgsound_emu-modified/README.md | 131 +++ .../vgsound_emu/src/core/util.hpp | 263 ++++++ .../vgsound_emu/src/core/vox/vox.cpp | 75 ++ .../vgsound_emu/src/core/vox/vox.hpp | 115 +++ .../vgsound_emu/src/es550x/README.md | 88 ++ .../vgsound_emu/src/es550x/es5504.cpp | 456 +++++++++ .../vgsound_emu/src/es550x/es5504.hpp | 117 +++ .../vgsound_emu/src/es550x/es5505.cpp | 652 +++++++++++++ .../vgsound_emu/src/es550x/es5505.hpp | 304 ++++++ .../vgsound_emu/src/es550x/es5506.cpp | 870 ++++++++++++++++++ .../vgsound_emu/src/es550x/es5506.hpp | 385 ++++++++ .../vgsound_emu/src/es550x/es550x.cpp | 34 + .../vgsound_emu/src/es550x/es550x.hpp | 610 ++++++++++++ .../vgsound_emu/src/es550x/es550x_alu.cpp | 131 +++ .../vgsound_emu/src/es550x/es550x_filter.cpp | 72 ++ .../vgsound_emu/src/k005289/README.md | 23 + .../vgsound_emu/src/k005289/k005289.cpp | 42 + .../vgsound_emu/src/k005289/k005289.hpp | 83 ++ .../vgsound_emu/src/k007232/README.md | 75 ++ .../vgsound_emu/src/k007232/k007232.cpp | 169 ++++ .../vgsound_emu/src/k007232/k007232.hpp | 115 +++ .../vgsound_emu/src/k053260/README.md | 109 +++ .../vgsound_emu/src/k053260/k053260.cpp | 290 ++++++ .../vgsound_emu/src/k053260/k053260.hpp | 262 ++++++ .../vgsound_emu/src/msm6295/README.md | 67 ++ .../vgsound_emu/src/msm6295/msm6295.cpp | 179 ++++ .../vgsound_emu/src/msm6295/msm6295.hpp | 142 +++ .../vgsound_emu/src/n163/README.md | 88 ++ .../vgsound_emu/src/n163/n163.cpp | 120 +++ .../vgsound_emu/src/n163/n163.hpp | 109 +++ .../vgsound_emu/src/scc/README.md | 314 +++++++ .../vgsound_emu/src/scc/scc.cpp | 461 ++++++++++ .../vgsound_emu/src/scc/scc.hpp | 320 +++++++ .../vgsound_emu/src/template/template.cpp | 33 + .../vgsound_emu/src/template/template.hpp | 88 ++ .../vgsound_emu/src/vrcvi/README.md | 97 ++ .../vgsound_emu/src/vrcvi/vrcvi.cpp | 260 ++++++ .../vgsound_emu/src/vrcvi/vrcvi.hpp | 407 ++++++++ .../vgsound_emu/src/x1_010/README.md | 97 ++ .../vgsound_emu/src/x1_010/x1_010.cpp | 163 ++++ .../vgsound_emu/src/x1_010/x1_010.hpp | 179 ++++ 48 files changed, 8972 insertions(+) create mode 160000 extern/vgsound_emu-modified create mode 100644 vgsound_emu-modified/.clang-format create mode 100644 vgsound_emu-modified/.gitignore create mode 100644 vgsound_emu-modified/CHANGELOG.md create mode 100644 vgsound_emu-modified/CMakeLists.txt create mode 100644 vgsound_emu-modified/LICENSE create mode 100644 vgsound_emu-modified/MODIFIED.md create mode 100644 vgsound_emu-modified/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/core/util.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/k005289/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/k007232/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/k053260/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/msm6295/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/n163/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/scc/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/template/template.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/template/template.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/x1_010/README.md create mode 100644 vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp create mode 100644 vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp diff --git a/extern/vgsound_emu-modified b/extern/vgsound_emu-modified new file mode 160000 index 000000000..7b988a671 --- /dev/null +++ b/extern/vgsound_emu-modified @@ -0,0 +1 @@ +Subproject commit 7b988a6714ebf61e8a5fad5c9ccbda2b85853fe1 diff --git a/vgsound_emu-modified/.clang-format b/vgsound_emu-modified/.clang-format new file mode 100644 index 000000000..edce098df --- /dev/null +++ b/vgsound_emu-modified/.clang-format @@ -0,0 +1,154 @@ +# +# License: Zlib +# see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details +# +# Copyright holder(s): cam900 +# Clang Format setting for vgsound_emu +# +--- +BasedOnStyle: Microsoft +UseCRLF: true +IndentWidth: 4 +ColumnLimit: 0 +--- +Language: Proto +DisableFormat: true +--- +Language: TableGen +DisableFormat: true +--- +Language: TextProto +DisableFormat: true +--- +Language: Cpp +TabWidth: 4 +UseTab: Always +AccessModifierOffset: 4 +ColumnLimit: 100 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignEscapedNewlines: Right +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Inline +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both +BreakBeforeBraces: Allman +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakStringLiterals: false +CompactNamespaces: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +EmptyLineAfterAccessModifier: Leave +EmptyLineBeforeAccessModifier: Always +FixNamespaceComments: true +IncludeBlocks: Regroup +IndentAccessModifiers: true +IndentCaseBlocks: true +IndentCaseLabels: true +IndentGotoLabels: true +IndentPPDirectives: AfterHash +IndentRequiresClause: true +IndentRequires: true +IndentWrappedFunctionNames: false +InsertBraces: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PPIndentWidth: 1 +PackConstructorInitializers: Never +PointerAlignment: Right +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: Microsoft +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RequiresClausePosition: OwnLine +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 0 +SortIncludes: CaseSensitive +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: After +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: false + AfterFunctionDeclarationName: false + AfterFunctionDefinitionName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: [] diff --git a/vgsound_emu-modified/.gitignore b/vgsound_emu-modified/.gitignore new file mode 100644 index 000000000..6a46037be --- /dev/null +++ b/vgsound_emu-modified/.gitignore @@ -0,0 +1,18 @@ +.vs/* +.vscode/* +node_modules/* +package.json +package-lock.json + +build/* +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps diff --git a/vgsound_emu-modified/CHANGELOG.md b/vgsound_emu-modified/CHANGELOG.md new file mode 100644 index 000000000..bf1e66771 --- /dev/null +++ b/vgsound_emu-modified/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelogs + +## Important changes + +### V 2.1.0 (2022-09-08) + +Move source folder into vgsound_emu folder +CMake support +Move each readmes into README.md each folders + +## Details + +See [here](https://gitlab.com/cam900/vgsound_emu/-/commits/main). + +### Previous changelogs + +See [here](https://github.com/cam900/vgsound_emu/commits/main). diff --git a/vgsound_emu-modified/CMakeLists.txt b/vgsound_emu-modified/CMakeLists.txt new file mode 100644 index 000000000..17e14291c --- /dev/null +++ b/vgsound_emu-modified/CMakeLists.txt @@ -0,0 +1,161 @@ +# +# License: Zlib +# see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details +# +# Copyright holder(s): cam900 +# CMake for vgsound_emu +# + +cmake_minimum_required(VERSION 3.0) +project(vgsound_emu + VERSION 2.1.0 + LANGUAGES CXX) + +option(VGSOUND_EMU_ES5504 "Use ES5504 core" ON) +option(VGSOUND_EMU_ES5505 "Use ES5505 core" ON) +option(VGSOUND_EMU_ES5506 "Use ES5506 core" ON) +option(VGSOUND_EMU_K005289 "Use K005289 core" ON) +option(VGSOUND_EMU_K007232 "Use K007232 core" ON) +option(VGSOUND_EMU_K053260 "Use K053260 core" ON) +option(VGSOUND_EMU_MSM6295 "Use MSM6295 core" ON) +option(VGSOUND_EMU_NAMCO_163 "Use Namco 163 core" ON) +option(VGSOUND_EMU_SCC "Use SCC core" ON) +option(VGSOUND_EMU_VRCVI "Use VRC VI core" ON) +option(VGSOUND_EMU_X1_010 "Use X1-010 core" ON) + +message(STATUS "Host: ${CMAKE_HOST_SYSTEM_NAME}, ${CMAKE_HOST_SYSTEM_PROCESSOR}") +message(STATUS "Target: ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID}") +message(STATUS "CMake version: ${CMAKE_VERSION}") +message(STATUS "Generator: ${CMAKE_GENERATOR}") +message(STATUS "Extra generator: ${CMAKE_EXTRA_GENERATOR}") +message(STATUS "Make program: ${CMAKE_MAKE_PROGRAM}") + +set(CORE_SOURCE "") +set(EMU_SOURCE "") + +# Core functions +list(APPEND CORE_SOURCE + vgsound_emu/src/core/util.hpp +) + +# Dialogic ADPCM +if(VGSOUND_EMU_MSM6295) + list(APPEND CORE_SOURCE + vgsound_emu/src/core/vox/vox.cpp + vgsound_emu/src/core/vox/vox.hpp + ) + message(STATUS "Using Dialogic ADPCM core") +endif() + +# ES5504, ES5505, ES5506 +if(VGSOUND_EMU_ES5504 OR VGSOUND_EMU_ES5505 OR VGSOUND_EMU_ES5506) + list(APPEND EMU_SOURCE + vgsound_emu/src/es550x/es550x.hpp + + vgsound_emu/src/es550x/es550x.cpp + vgsound_emu/src/es550x/es550x_alu.cpp + vgsound_emu/src/es550x/es550x_filter.cpp + ) + + if(VGSOUND_EMU_ES5504) + list(APPEND EMU_SOURCE + vgsound_emu/src/es550x/es5504.hpp + vgsound_emu/src/es550x/es5504.cpp + ) + message(STATUS "Using ES5504 core") + endif() + + if(VGSOUND_EMU_ES5505) + list(APPEND EMU_SOURCE + vgsound_emu/src/es550x/es5505.hpp + vgsound_emu/src/es550x/es5505.cpp + ) + message(STATUS "Using ES5505 core") + endif() + + if(VGSOUND_EMU_ES5506) + list(APPEND EMU_SOURCE + vgsound_emu/src/es550x/es5506.hpp + vgsound_emu/src/es550x/es5506.cpp + ) + message(STATUS "Using ES5506 core") + endif() +endif() + +# K005289 +if(VGSOUND_EMU_K005289) + list(APPEND EMU_SOURCE + vgsound_emu/src/k005289/k005289.hpp + vgsound_emu/src/k005289/k005289.cpp + ) + message(STATUS "Using K005289 core") +endif() + +# K007232 +if(VGSOUND_EMU_K007232) + list(APPEND EMU_SOURCE + vgsound_emu/src/k007232/k007232.hpp + vgsound_emu/src/k007232/k007232.cpp + ) + message(STATUS "Using K007232 core") +endif() + +# K053260 +if(VGSOUND_EMU_K053260) + list(APPEND EMU_SOURCE + vgsound_emu/src/k053260/k053260.hpp + vgsound_emu/src/k053260/k053260.cpp + ) + message(STATUS "Using K053260 core") +endif() + +# MSM6295 +if(VGSOUND_EMU_MSM6295) + list(APPEND EMU_SOURCE + vgsound_emu/src/msm6295/msm6295.hpp + vgsound_emu/src/msm6295/msm6295.cpp + ) + message(STATUS "Using MSM6295 core") +endif() + +# Namco 163 +if(VGSOUND_EMU_NAMCO_163) + list(APPEND EMU_SOURCE + vgsound_emu/src/n163/n163.hpp + vgsound_emu/src/n163/n163.cpp + ) + message(STATUS "Using Namco 163 core") +endif() + +# SCC +if(VGSOUND_EMU_SCC) + list(APPEND EMU_SOURCE + vgsound_emu/src/scc/scc.hpp + vgsound_emu/src/scc/scc.cpp + ) + message(STATUS "Using SCC core") +endif() + +# VRC VI +if(VGSOUND_EMU_VRCVI) + list(APPEND EMU_SOURCE + vgsound_emu/src/vrcvi/vrcvi.hpp + vgsound_emu/src/vrcvi/vrcvi.cpp + ) + message(STATUS "Using VRC VI core") +endif() + +# X1-010 +if(VGSOUND_EMU_X1_010) + list(APPEND EMU_SOURCE + vgsound_emu/src/x1_010/x1_010.hpp + vgsound_emu/src/x1_010/x1_010.cpp + ) + message(STATUS "Using X1-010 core") +endif() + +add_library(vgsound_emu STATIC ${CORE_SOURCE} ${EMU_SOURCE}) +target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +# target_compile_options(vgsound_emu PRIVATE -Wall -Werror) \ No newline at end of file diff --git a/vgsound_emu-modified/LICENSE b/vgsound_emu-modified/LICENSE new file mode 100644 index 000000000..928144684 --- /dev/null +++ b/vgsound_emu-modified/LICENSE @@ -0,0 +1,19 @@ +zlib License + +(C) 2022-present cam900 and contributors + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/vgsound_emu-modified/MODIFIED.md b/vgsound_emu-modified/MODIFIED.md new file mode 100644 index 000000000..432d014f9 --- /dev/null +++ b/vgsound_emu-modified/MODIFIED.md @@ -0,0 +1,7 @@ +# modification disclaimer + +this is a modified version of vgsound_emu emulation core library tailored for Furnace. + +it should not and shall NOT be mistaken for the original, authentic or actual version and revision of the library. + +you can get original software from [here](https://gitlab.com/cam900/vgsound_emu/). diff --git a/vgsound_emu-modified/README.md b/vgsound_emu-modified/README.md new file mode 100644 index 000000000..b24e2888b --- /dev/null +++ b/vgsound_emu-modified/README.md @@ -0,0 +1,131 @@ +# vgsound_emu V2 (modified) + +This is a library of video game sound chip emulation cores. useful for emulators, chiptune trackers, or players. + +This is a modified version of vgsound_emu, tailored for Furnace. + +## Important + +License is now changed to zlib license in vgsound_emu V2, now you must notify your all modifications. + +but [vgsound_emu V1 (pre-V2)](https://gitlab.com/cam900/vgsound_emu/-/tree/V1) is still exists, and it's still distributed under [BSD-3-Clause license](https://spdx.org/licenses/BSD-3-Clause.html).([details](https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE)) + +## V2 revision changes + +formatting codes with clang-format, Encapsulation for Maintenance, Fix GCC 12, Change license to zlib license for notify modifications in derived works from this cores. + +## Changelog + +See [here](https://gitlab.com/cam900/vgsound_emu/-/blob/main/CHANGELOG.md). + +## License + +This software is distributed under [zlib License](https://spdx.org/licenses/Zlib.html), unlike [vgsound_emu V1](https://gitlab.com/cam900/vgsound_emu/-/tree/V1)([standard BSD-3-Clause license](https://spdx.org/licenses/BSD-3-Clause.html)([details](https://gitlab.com/cam900/vgsound_emu/-/blob/V1/LICENSE))). +You must notify your modifications at all files you have modified! + +See [here](https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE) for details. + +## Folders + +- vgsound_emu: base folder + - src: source codes for emulation cores + - core: core files used in most of emulation cores + - vox: Dialogic ADPCM core + - es550x: Ensoniq ES5504, ES5505, ES5506 PCM sound chip families, 25/32 voices with 16/4 stereo/6 stereo output channels + - k005289: Konami K005289, 2 timers + - k007232: Konami K007232, 2 PCM channels + - k053260: Konami K053260, 4 PCM or ADPCM channels with CPU to CPU communication feature + - msm6295: OKI MSM6295, 4 ADPCM channels + - n163: Namco 163, NES Mapper with up to 8 Wavetable channels + - scc: Konami SCC, MSX Mappers with 5 Wavetable channels + - vrcvi: Konami VRC VI, NES Mapper with 2 Pulse channels and 1 Sawtooth channel + - x1_010: Seta/Allumer X1-010, 16 Wavetable/PCM channels + - template: Template for sound emulation core + +## Build instruction + +### dependencies + +- CMake +- git (for source repository management) +- MSVC or GCC or Clang (for compile) + +### Clone repository + +type the following on a terminal/console/shell/whatever: + +``` +git clone https://gitlab.com/cam900/vgsound_emu.git +cd vgsound_emu +``` + +### Compile + +#### MSVC + +type the following on a developer tools command prompt: + +``` +mkdir build +cd build +cmake .. +msbuild ALL_BUILD.vcxproj +``` + +#### MinGW, GCC, Clang with MakeFile + +type the following on a terminal/console/shell/whatever: + +``` +mkdir build +cd build +cmake .. +make +``` + +### CMake options + +To add an CMake option from the command line: ```cmake -D= ..``` +You can add multiple option with CMake. + +#### Available options + +| Options | Available Value | Default | Descriptions | +| :-: | :-: | :-: | :-: | +| VGSOUND_EMU_ES5504 | ON/OFF | ON | Use ES5504 core | +| VGSOUND_EMU_ES5505 | ON/OFF | ON | Use ES5505 core | +| VGSOUND_EMU_ES5506 | ON/OFF | ON | Use ES5506 core | +| VGSOUND_EMU_K005289 | ON/OFF | ON | Use K005289 core | +| VGSOUND_EMU_K007232 | ON/OFF | ON | Use K007232 core | +| VGSOUND_EMU_K053260 | ON/OFF | ON | Use K053260 core | +| VGSOUND_EMU_MSM6295 | ON/OFF | ON | Use MSM6295 core | +| VGSOUND_EMU_NAMCO_163 | ON/OFF | ON | Use Namco 163 core | +| VGSOUND_EMU_SCC | ON/OFF | ON | Use SCC core | +| VGSOUND_EMU_VRCVI | ON/OFF | ON | Use VRC VI core | +| VGSOUND_EMU_X1_010 | ON/OFF | ON | Use X1-010 core | + +### Link at another project + +Copy this repository as submodule first, type the following on a terminal/console/shell/whatever: + +``` +git submodule add https://gitlab.com/cam900/vgsound_emu.git +``` + +Then, Add following options at your CMakeLists.txt file. + +example: + +``` +add_subdirectory( [EXCLUDE_FROM_ALL]) +... +target_include_directories( SYSTEM PRIVATE ) +target_link_libraries( PRIVATE vgsound_emu) +``` + +## Contributors + +- [cam900](https://gitlab.com/cam900) +- [Natt Akuma](https://github.com/akumanatt) +- [James Alan Nguyen](https://github.com/djtuBIG-MaliceX) +- [Laurens Holst](https://github.com/Grauw) diff --git a/vgsound_emu-modified/vgsound_emu/src/core/util.hpp b/vgsound_emu-modified/vgsound_emu/src/core/util.hpp new file mode 100644 index 000000000..a6a9d6a29 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/core/util.hpp @@ -0,0 +1,263 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Various core utilities for vgsound_emu +*/ + +#ifndef _VGSOUND_EMU_SRC_CORE_UTIL_HPP +#define _VGSOUND_EMU_SRC_CORE_UTIL_HPP + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace vgsound_emu +{ + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + typedef unsigned long long u64; + typedef signed char s8; + typedef signed short s16; + typedef signed int s32; + typedef signed long long s64; + typedef float f32; + typedef double f64; + + class vgsound_emu_core + { + public: + // constructors + vgsound_emu_core(std::string tag) + : m_tag(tag) + { + } + + // getters + std::string tag() { return m_tag; } + + protected: + const f64 PI = 3.1415926535897932384626433832795; + + // std::clamp is only for C++17 or later; I use my own code + template + T clamp(T in, T min, T max) + { +#if defined(_HAS_CXX17) && _HAS_CXX17 + // just use std::clamp if C++17 or above + return std::clamp(in, min, max); +#else + // otherwise, use my own implementation of std::clamp + return std::min(std::max(in, min), max); +#endif + } + + // get bitfield, bitfield(input, position, len) + template + T bitfield(T in, u8 pos, u8 len = 1) + { + return (in >> pos) & (len ? (T(1 << len) - 1) : 1); + } + + // get sign extended value, sign_ext(input, len) + template + T sign_ext(T in, u8 len) + { + len = std::max(0, (8 * sizeof(T)) - len); + return T(T(in) << len) >> len; + } + + // convert attenuation decibel value to gain + inline f32 dB_to_gain(f32 attenuation) { return std::pow(10.0f, attenuation / 20.0f); } + + private: + std::string m_tag = ""; // core tags + }; + + class vgsound_emu_mem_intf : public vgsound_emu_core + { + public: + // constructor + vgsound_emu_mem_intf() + : vgsound_emu_core("mem_intf") + { + } + + virtual u8 read_byte(u32 address) { return 0; } + + virtual u16 read_word(u32 address) { return 0; } + + virtual u32 read_dword(u32 address) { return 0; } + + virtual u64 read_qword(u32 address) { return 0; } + + virtual void write_byte(u32 address, u8 data) {} + + virtual void write_word(u32 address, u16 data) {} + + virtual void write_dword(u32 address, u32 data) {} + + virtual void write_qword(u32 address, u64 data) {} + }; + + template + class clock_pulse_t : public vgsound_emu_core + { + private: + const T m_init_width = 1; + + class edge_t : public vgsound_emu_core + { + private: + const u8 m_init_edge = 1; + + public: + edge_t(u8 init_edge = 0) + : vgsound_emu_core("clock_pulse_edge") + , m_init_edge(init_edge) + , m_current(init_edge ^ 1) + , m_previous(init_edge) + , m_rising(0) + , m_falling(0) + , m_changed(0) + { + set(init_edge); + } + + // internal states + void reset() + { + m_previous = m_init_edge; + m_current = m_init_edge ^ 1; + set(m_init_edge); + } + + void tick(bool toggle) + { + u8 current = m_current; + if (toggle) + { + current ^= 1; + } + set(current); + } + + void set(u8 edge) + { + edge &= 1; + m_rising = m_falling = m_changed = 0; + if (m_current != edge) + { + m_changed = 1; + if (m_current && (!edge)) + { + m_falling = 1; + } + else if ((!m_current) && edge) + { + m_rising = 1; + } + m_current = edge; + } + m_previous = m_current; + } + + // getters + inline bool current() { return m_current; } + + inline bool rising() { return m_rising; } + + inline bool falling() { return m_falling; } + + inline bool changed() { return m_changed; } + + private: + u8 m_current : 1; // current edge + u8 m_previous : 1; // previous edge + u8 m_rising : 1; // rising edge + u8 m_falling : 1; // falling edge + u8 m_changed : 1; // changed flag + }; + + public: + clock_pulse_t(T init_width, u8 init_edge = 0) + : vgsound_emu_core("clock_pulse") + , m_init_width(init_width) + , m_edge(edge_t(init_edge & 1)) + , m_width(init_width) + , m_width_latch(init_width) + , m_counter(init_width) + , m_cycle(0) + { + } + + void reset(T init) + { + m_edge.reset(); + m_width = m_width_latch = m_counter = init; + m_cycle = 0; + } + + inline void reset() { reset(m_init_width); } + + bool tick(T width = 0) + { + bool carry = ((--m_counter) <= 0); + if (carry) + { + if (!width) + { + m_width = m_width_latch; + } + else + { + m_width = width; // reset width + } + m_counter = m_width; + m_cycle = 0; + } + else + { + m_cycle++; + } + + m_edge.tick(carry); + return carry; + } + + inline void set_width(T width) { m_width = width; } + + inline void set_width_latch(T width) { m_width_latch = width; } + + // Accessors + inline bool current_edge() { return m_edge.current(); } + + inline bool rising_edge() { return m_edge.rising(); } + + inline bool falling_edge() { return m_edge.falling(); } + + // getters + edge_t &edge() { return m_edge; } + + inline T cycle() { return m_cycle; } + + private: + edge_t m_edge; + T m_width = 1; // clock pulse width + T m_width_latch = 1; // clock pulse width latch + T m_counter = 1; // clock counter + T m_cycle = 0; // clock cycle + }; +}; // namespace vgsound_emu + +using namespace vgsound_emu; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp b/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp new file mode 100644 index 000000000..ef06c1511 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp @@ -0,0 +1,75 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Dialogic ADPCM core +*/ + +#include "vox.hpp" + +// reset decoder +void vox_core::vox_decoder_t::decoder_state_t::reset() +{ + m_index = 0; + m_step = 16; +} + +// copy from source +void vox_core::vox_decoder_t::decoder_state_t::copy(decoder_state_t src) +{ + m_index = src.index(); + m_step = src.step(); +} + +// decode single nibble +void vox_core::vox_decoder_t::decoder_state_t::decode(u8 nibble) +{ + const u8 delta = bitfield(nibble, 0, 3); + const s16 ss = m_vox.m_step_table[m_index]; // ss(n) + + // d(n) = (ss(n) * B2) + ((ss(n) / 2) * B1) + ((ss(n) / 4) * B0) + // + (ss(n) / 8) + s16 d = ss >> 3; + if (bitfield(delta, 2)) + { + d += ss; + } + if (bitfield(delta, 1)) + { + d += (ss >> 1); + } + if (bitfield(delta, 0)) + { + d += (ss >> 2); + } + + // if (B3 = 1) then d(n) = d(n) * (-1) X(n) = X(n-1) * d(n) + if (bitfield(nibble, 3)) + { + m_step -= d; + } + else + { + m_step += d; + } + + if (m_wraparound) // wraparound (MSM5205) + { + if (m_step < -2048) + { + m_step &= 0x7ff; + } + else if (m_step > 2047) + { + m_step |= ~0x7ff; + } + } + else + { + m_step = clamp(m_step, -2048, 2047); + } + + // adjust step index + m_index = clamp(m_index + m_vox.m_index_table[delta], 0, 48); +} diff --git a/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp b/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp new file mode 100644 index 000000000..f3ae6d4c1 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp @@ -0,0 +1,115 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Dialogic ADPCM core +*/ + +#ifndef _VGSOUND_EMU_SRC_CORE_VOX_VOX_HPP +#define _VGSOUND_EMU_SRC_CORE_VOX_VOX_HPP + +#pragma once + +#include "../util.hpp" + +class vox_core : public vgsound_emu_core +{ + protected: + class vox_decoder_t : public vgsound_emu_core + { + private: + class decoder_state_t : public vgsound_emu_core + { + public: + decoder_state_t(vox_core &vox, bool wraparound) + : vgsound_emu_core("vox_decoder_state") + , m_wraparound(wraparound) + , m_vox(vox) + , m_index(0) + , m_step(16) + { + } + + // internal states + void reset(); + void decode(u8 nibble); + + // getters + s8 index() { return m_index; } + + s32 step() { return m_step; } + + decoder_state_t &operator=(decoder_state_t src) + { + copy(src); + return *this; + } + + private: + const bool m_wraparound = false; // wraparound or clamp? + + void copy(decoder_state_t src); + + vox_core &m_vox; + s8 m_index = 0; + s32 m_step = 16; + }; + + public: + vox_decoder_t(vox_core &vox, bool wraparound) + : vgsound_emu_core("vox_decoder") + , m_curr(vox, wraparound) + , m_loop(vox, wraparound) + , m_loop_saved(false) + { + } + + virtual void reset() + { + m_curr.reset(); + m_loop.reset(); + m_loop_saved = false; + } + + void save() + { + if (!m_loop_saved) + { + m_loop = m_curr; + m_loop_saved = true; + } + } + + void restore() + { + if (m_loop_saved) + { + m_curr = m_loop; + } + } + + void decode(u8 nibble) { m_curr.decode(nibble); } + + s32 step() { return m_curr.step(); } + + private: + decoder_state_t m_curr; + decoder_state_t m_loop; + bool m_loop_saved = false; + }; + + const s8 m_index_table[8] = {-1, -1, -1, -1, 2, 4, 6, 8}; + const s32 m_step_table[49] = { + 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, + 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, + 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552}; + + public: + vox_core(std::string tag) + : vgsound_emu_core(tag) + { + } +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/README.md b/vgsound_emu-modified/vgsound_emu/src/es550x/README.md new file mode 100644 index 000000000..6f410e7d4 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/README.md @@ -0,0 +1,88 @@ +# Ensoniq ES5504 DOCII, ES5505 OTIS, ES5506 OTTO + +## Summary + +- 32 voice of PCMs + - per-voice features: + - 4 pole, 4 mode filter (2 filter coefficient, 12 bit per them) + - max 16 output, 12 bit volume (ES5504) + - max 4 stereo output channels, 8 bit logarithmic volume per left/right output (ES5505) + - max 6 stereo output channels, 12 bit logarithmic volume per left/right output (ES5506) + - Hardware envelope for volume and filter (ES5506) + - 16 bit linear PCM + - 8 bit compressed PCM (ES5506) + - total accessible memory: 1 MWord (2MByte) per bank (ES5504, ES5505) or 2 MWord (4MByte) per bank (ES5506) + - CA flag is also usable for bank + - 1 bit BS flag for bank - 2 bank total (ES5505) + - 2 bit BS flag for bank - 4 bank total (ES5506) + +## Source code + +- es550x.hpp: Base header + - es550x.cpp: Emulation core for common shared features + - es550x_alu.cpp: Emulation core for shared ALU function + - es550x_filter.cpp: Emulation core for shared filter function + - es5504.hpp: ES5504 header + - es5504.cpp: Emulation core for ES5504 specific features + - es5505.hpp: ES5505 header + - es5505.cpp: Emulation core for ES5505 specific features + - es5506.hpp: ES5506 header + - es5506.cpp: Emulation core for ES5506 specific features + +## Description + +After ES5503 DOC's appeared, Ensoniq announces ES5504 DOC II, ES5505 OTIS, ES5506 OTTO. + +These are not just PCM chip; but with built-in 4 pole filters and variable voice limits. + +It can be trades higher sample rate and finer frequency and Tons of voices, or vice-versa. + +These are mainly used with their synthesizers, musical stuffs. It's also mainly paired with ES5510 ESP/ES5511 ESP2 for post processing. ES5506 can be paired with itself, It's called Dual chip configuration and Both chips are can be shares same memory spaces. + +ES5505 was also mainly used on Taito's early- to late-90s arcade hardware for their PCM sample based sound system, paired with ES5510 ESP for post processing. It's configuration is borrowed from Ensoniq's 32 Voice synths powered by these chips. It's difference is external logic to adds per-voice bankswitching looks like what Konami doing on K007232. + +Atari Panther was will be use ES5505, but finally canceled. + +Ensoniq's ISA Sound Card for PC, Soundscape used ES5506, "Elite" model has optional daughterboard with ES5510 for digital effects. + +## Related chips + +- ES5530 "OPUS" variant is 2-in-one chip with built-in ES5506 and Sequoia. + +- ES5540 "OTTOFX" variant is ES5506 and ES5510 merged in single package. + +- ES5548 "OTTO48" variant is used at late-90s ensoniq synths and musical instruments, 2 ES5506s are merged in single package, or with 48 voices in chip? + +## Chip difference + +### ES5504 to ES5505 + +- Total voice amount is expanded to 32, rather than 25. + +- ADC and DAC is completely redesigned. + +- it's has now voice-independent 10 bit and Sony/Burr-Brown format DAC. + +- Output channel and Volume is changed to 16 mono to 4 stereo, 12 bit Analog to 8 bit Stereo digital, also Floating point-ish format and independent per left and right output. + +- Channel 3 is can be Input/Output. + +- Channel output is can be accessible at host for test purpose. + +- Max sample memory is expanded to 2MWords (1MWords * 2 Banks) + +### ES5505 to ES5506 + +- Frequency is more finer now: 11 bit fraction rather than 9 bit. + +- Output channel and Volume is changed to 4 stereo to 6 stereo, 8 bit to 16 bit, but only 12 bit is used for calculation; 4 LSB is used for envelope ramping. + +- Transwave flag is added - its helpful for transwave process, with interrupt per voices. Hardware envelope is added - K1, K2, Volume value is can be modified in run-time. also K1, K2 is expanded to 16 bit for finer envelope ramping. + +- Filter calculation resolution is expanded to 18 bit. + +- All channels are output, Serial output is now partially programmable. + +- Max sample memory is expanded to 8MWords (2MWords * 4 Banks) + +- Register format between these chips are incompatible. diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp new file mode 100644 index 000000000..586f15f30 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp @@ -0,0 +1,456 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core +*/ + +#include "es5504.hpp" + +// Internal functions +void es5504_core::tick() +{ + m_voice_update = false; + m_voice_end = false; + // /CAS, E + if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock + { + // /CAS + if (m_cas.tick()) + { + // /CAS high, E low: get sample address + if (m_cas.falling_edge()) + { + // /CAS low, E low: fetch sample + if (!m_e.current_edge()) + { + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + } + // E + if (m_clkin.falling_edge()) // falling edge triggers E clock + { + if (m_e.tick()) + { + m_intf.e_pin(m_e.current_edge()); + if (m_e.rising_edge()) // Host access + { + m_host_intf.update_strobe(); + voice_tick(); + } + if (m_e.falling_edge()) // Voice memory + { + m_host_intf.clear_host_access(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + if (m_e.current_edge()) // Host interface + { + if (m_host_intf.host_access()) + { + if (m_host_intf.rw() && (m_e.cycle() == 2)) // Read + { + m_hd = read(m_ha); + m_host_intf.clear_host_access(); + } + else if ((!m_host_intf.rw()) && (m_e.cycle() == 2)) + { // Write + write(m_ha, m_hd); + } + } + } + else if (!m_e.current_edge()) + { + if (m_e.cycle() == 2) + { + // reset host access state + m_hd = 0; + m_host_intf.clear_strobe(); + } + } + } + } +} + +// less cycle accurate, but less CPU heavy routine +void es5504_core::tick_perf() +{ + m_voice_update = false; + m_voice_end = false; + // update + // falling edge + m_e.edge().set(false); + m_intf.e_pin(false); + m_host_intf.clear_host_access(); + m_host_intf.clear_strobe(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.edge().set(true); + m_intf.e_pin(true); + m_host_intf.update_strobe(); + // falling edge + m_e.edge().set(false); + m_intf.e_pin(false); + m_host_intf.clear_host_access(); + m_host_intf.clear_strobe(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.edge().set(true); + m_intf.e_pin(true); + m_host_intf.update_strobe(); +} + +void es5504_core::voice_tick() +{ + // Voice updates every 2 E clock cycle (= 1 CHSTRB cycle or 4 BCLK clock cycle) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) + { + // Update voice + m_voice[m_voice_cycle].tick(m_voice_cycle); + + // Refresh output (Multiplexed analog output) + m_out[m_voice[m_voice_cycle].cr().ca()] = m_voice[m_voice_cycle].out(); + + if ((++m_voice_cycle) > std::min(24, m_active)) // ~ 25 voices + { + m_voice_end = true; + m_voice_cycle = 0; + } + + m_voice_fetch = 0; + } +} + +void es5504_core::voice_t::fetch(u8 voice, u8 cycle) +{ + m_alu.set_sample( + cycle, + m_host.m_intf.read_sample(voice, + bitfield(m_cr.ca(), 0, 3), + bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer))); +} + +void es5504_core::voice_t::tick(u8 voice) +{ + m_out = 0; + + // Filter execute + m_filter.tick(m_alu.interpolation()); + + if (m_alu.busy()) + { + // Send to output + m_out = ((sign_ext(m_filter.o4_1(), 16) >> 3) * m_volume) >> + 12; // Analog multiplied in real chip, 13/12 bit ladder DAC + + // ALU execute + if (m_alu.tick()) + { + m_alu.loop_exec(); + } + + // ADC check + adc_exec(); + } + + // Update IRQ + m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); +} + +// ADC; Correct? +void es5504_core::voice_t::adc_exec() +{ + if (m_cr.adc()) + { + m_host.m_adc = m_host.m_intf.adc_r() & ~0x7; + } +} + +void es5504_core::reset() +{ + es550x_shared_core::reset(); + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_adc = 0; + std::fill(m_out.begin(), m_out.end(), 0); +} + +void es5504_core::voice_t::reset() +{ + es550x_shared_core::es550x_voice_t::reset(); + m_volume = 0; + m_out = 0; +} + +// Accessors +u16 es5504_core::host_r(u8 address) +{ + if (!m_host_intf.host_access()) + { + m_ha = address; + if (m_e.rising_edge()) + { // update directly + m_hd = read(m_ha, true); + } + else + { + m_host_intf.set_strobe(true); + } + } + return m_hd; +} + +void es5504_core::host_w(u8 address, u16 data) +{ + if (!m_host_intf.host_access()) + { + m_ha = address; + m_hd = data; + if (m_e.rising_edge()) + { // update directly + write(m_ha, m_hd, true); + } + else + { + m_host_intf.set_strobe(false); + } + } +} + +u16 es5504_core::read(u8 address, bool cpu_access) { return regs_r(m_page, address, cpu_access); } + +void es5504_core::write(u8 address, u16 data, bool cpu_access) +{ + regs_w(m_page, address, data, cpu_access); +} + +u16 es5504_core::regs_r(u8 page, u8 address, bool cpu_access) +{ + u16 ret = 0xffff; + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 12) // Global registers + { + switch (address) + { + case 12: // A/D (A to D Convert/Test) + ret = (ret & ~0xfffb) | (m_adc & 0xfffb); + break; + case 13: // ACT (Number of voices) + ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); + break; + case 14: // IRQV (Interrupting voice vector) + ret = (ret & ~0x9f) | m_irqv.get(); + if (cpu_access) + { + m_irqv.clear(); + if (bool(bitfield(ret, 7)) != m_irqv.irqb()) + { + m_voice[m_irqv.voice()].alu().irq_update(m_intf, m_irqv); + } + } + break; + case 15: // PAGE (Page select register) + ret = (ret & ~0x3f) | bitfield(m_page, 0, 6); + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + if (voice < 25) + { + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 56 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + ret = v.filter().o4_1(); + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + ret = v.filter().o3_2(); + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + ret = v.filter().o3_1(); + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + ret = v.filter().o2_2(); + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + ret = v.filter().o2_1(); + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + ret = v.filter().o1_1(); + break; + } + } + else // Page 0 - 24 + { + switch (address) + { + case 0: // CR (Control Register) + ret = (ret & ~0xff) | (v.alu().stop() ? 0x01 : 0x00) | + (v.cr().adc() ? 0x04 : 0x00) | (v.alu().lpe() ? 0x08 : 0x00) | + (v.alu().ble() ? 0x10 : 0x00) | (v.alu().irqe() ? 0x20 : 0x00) | + (v.alu().dir() ? 0x40 : 0x00) | (v.alu().irq() ? 0x80 : 0x00); + break; + case 1: // FC (Frequency Control) + ret = (ret & ~0xfffe) | (v.alu().fc() << 1); + break; + case 2: // STRT-H (Loop Start Register High) + ret = (ret & ~0x1fff) | bitfield(v.alu().start(), 16, 13); + break; + case 3: // STRT-L (Loop Start Register Low) + ret = (ret & ~0xffe0) | (v.alu().start() & 0xffe0); + break; + case 4: // END-H (Loop End Register High) + ret = (ret & ~0x1fff) | bitfield(v.alu().end(), 16, 13); + break; + case 5: // END-L (Loop End Register Low) + ret = (ret & ~0xffe0) | (v.alu().end() & 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + ret = (ret & ~0xfff0) | (v.filter().k2() & 0xfff0); + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + ret = (ret & ~0xfff0) | (v.filter().k1() & 0xfff0); + break; + case 8: // Volume + ret = (ret & ~0xfff0) | ((v.volume() << 4) & 0xfff0); + break; + case 9: // CA (Filter Config, Channel Assign) + ret = (ret & ~0x3f) | bitfield(v.cr().ca(), 0, 4) | + (bitfield(v.filter().lp(), 0, 2) << 4); + break; + case 10: // ACCH (Accumulator High) + ret = (ret & ~0x1fff) | bitfield(v.alu().accum(), 16, 13); + break; + case 11: // ACCL (Accumulator Low) + ret = bitfield(v.alu().accum(), 0, 16); + break; + } + } + } + } + + return ret; +} + +void es5504_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) +{ + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 12) // Global registers + { + switch (address) + { + case 12: // A/D (A to D Convert/Test) + if (bitfield(m_adc, 0)) // Writam_ble ADC + { + m_adc = (m_adc & 7) | (data & ~7); + m_intf.adc_w(m_adc & ~7); + } + m_adc = (m_adc & ~3) | (data & 3); + break; + case 13: // ACT (Number of voices) + m_active = std::min(24, bitfield(data, 0, 5)); + break; + case 14: // IRQV (Interrupting voice vector) + // Read only + break; + case 15: // PAGE (Page select register) + m_page = bitfield(data, 0, 6); + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + if (voice < 25) + { + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 56 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + v.filter().set_o4_1(sign_ext(data, 16)); + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + v.filter().set_o3_2(sign_ext(data, 16)); + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + v.filter().set_o3_1(sign_ext(data, 16)); + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + v.filter().set_o2_2(sign_ext(data, 16)); + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + v.filter().set_o2_1(sign_ext(data, 16)); + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + v.filter().set_o1_1(sign_ext(data, 16)); + break; + } + } + else // Page 0 - 24 + { + switch (address) + { + case 0: // CR (Control Register) + v.alu().set_stop(bitfield(data, 0, 2)); + v.cr().set_adc(bitfield(data, 2)); + v.alu().set_lpe(bitfield(data, 3)); + v.alu().set_ble(bitfield(data, 4)); + v.alu().set_irqe(bitfield(data, 5)); + v.alu().set_dir(bitfield(data, 6)); + v.alu().set_irq(bitfield(data, 7)); + break; + case 1: // FC (Frequency Control) + v.alu().set_fc(bitfield(data, 1, 15)); + break; + case 2: // STRT-H (Loop Start Register High) + v.alu().set_start(bitfield(data, 0, 13) << 16, 0x1fff0000); + break; + case 3: // STRT-L (Loop Start Register Low) + v.alu().set_start(data & 0xffe0, 0xffe0); + break; + case 4: // END-H (Loop End Register High) + v.alu().set_end(bitfield(data, 0, 13) << 16, 0x1fff0000); + break; + case 5: // END-L (Loop End Register Low) + v.alu().set_end(data & 0xffe0, 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + v.filter().set_k2(data & 0xfff0); + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + v.filter().set_k1(data & 0xfff0); + break; + case 8: // Volume + v.set_volume(bitfield(data, 4, 12)); + break; + case 9: // CA (Filter Config, Channel Assign) + v.cr().set_ca(bitfield(data, 0, 4)); + v.filter().set_lp(bitfield(data, 4, 2)); + break; + case 10: // ACCH (Accumulator High) + v.alu().set_accum(bitfield(data, 0, 13) << 16, 0x1fff0000); + break; + case 11: // ACCL (Accumulator Low) + v.alu().set_accum(data, 0xffff); + break; + } + } + } + } +} diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp new file mode 100644 index 000000000..d37ef36da --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp @@ -0,0 +1,117 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_ES5504_HPP +#define _VGSOUND_EMU_SRC_ES5504_HPP + +#pragma once + +#include "es550x.hpp" + +// ES5504 specific +class es5504_core : public es550x_shared_core +{ + private: + // es5504 voice classes + class voice_t : public es550x_voice_t + { + public: + // constructor + voice_t(es5504_core &host) + : es550x_voice_t("es5504_voice", 20, 9, false) + , m_host(host) + , m_volume(0) + , m_out(0) + { + } + + // internal state + virtual void reset() override; + virtual void fetch(u8 voice, u8 cycle) override; + virtual void tick(u8 voice) override; + + // setters + inline void set_volume(u16 volume) { m_volume = volume; } + + // getters + inline u16 volume() { return m_volume; } + + inline s32 out() { return m_out; } + + private: + void adc_exec(); + + // registers + es5504_core &m_host; + u16 m_volume = 0; // 12 bit Volume + s32 m_out = 0; // channel outputs + }; + + public: + // constructor + es5504_core(es550x_intf &intf) + : es550x_shared_core("es5504", 25, intf) + , m_voice{*this, *this, *this, *this, *this, *this, *this, *this, *this, + *this, *this, *this, *this, *this, *this, *this, *this, *this, + *this, *this, *this, *this, *this, *this, *this} + , m_adc(0) + , m_out{0} + { + } + + // host interface + u16 host_r(u8 address); + void host_w(u8 address, u16 data); + + // internal state + virtual void reset() override; + virtual void tick() override; + + // less cycle accurate, but also less cpu heavy update routine + void tick_perf(); + + // 16 analog output channels + inline s32 out(u8 ch) { return m_out[ch & 0xf]; } + + //----------------------------------------------------------------- + // + // for preview/debug purpose only, not for serious emulators + // + //----------------------------------------------------------------- + + // bypass chips host interface for debug purpose only + u16 read(u8 address, bool cpu_access = false); + void write(u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address, bool cpu_access = false); + void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address) + { + u8 prev = m_page; + m_page = page; + u16 ret = read(address, false); + m_page = prev; + return ret; + } + + // per-voice outputs + inline s32 voice_out(u8 voice) { return (voice < 25) ? m_voice[voice].out() : 0; } + + protected: + virtual inline u8 max_voices() override { return 25; } + + virtual void voice_tick() override; + + private: + std::array m_voice; // 25 voices + u16 m_adc = 0; // ADC register + std::array m_out = {0}; // 16 channel outputs +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp new file mode 100644 index 000000000..07a7b7046 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp @@ -0,0 +1,652 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5505 emulation core +*/ + +#include "es5505.hpp" + +// Internal functions +void es5505_core::tick() +{ + m_voice_update = false; + m_voice_end = false; + // CLKIN + if (m_clkin.tick()) + { + // SERBCLK + if (m_clkin.edge().changed()) // BCLK is freely running clock + { + if (m_bclk.tick()) + { + m_intf.bclk(m_bclk.current_edge()); + // Serial output + if (m_bclk.falling_edge()) + { + // SERLRCLK + if (m_lrclk.tick()) + { + m_intf.lrclk(m_lrclk.current_edge()); + } + } + // SERWCLK + if (m_lrclk.edge().changed()) + { + m_wclk = 0; + } + if (m_bclk.falling_edge()) + { + if (m_wclk == ((m_sermode.sony_bb()) ? 1 : 0)) + { + if (m_lrclk.current_edge()) + { + for (int i = 0; i < 4; i++) + { + // copy output + m_output[i] = m_output_temp[i]; + m_output_latch[i] = m_ch[i]; + m_output_temp[i].reset(); + // clamp to 16 bit (upper 5 bits are overflow + // guard bits) + m_output_latch[i].clamp16(); + // set signed + if (m_output_latch[i].left() < 0) + { + m_output_temp[i].set_left(-1); + } + if (m_output_latch[i].right() < 0) + { + m_output_temp[i].set_right(-1); + } + } + } + m_wclk_lr = m_lrclk.current_edge(); + m_output_bit = 16; + } + s8 output_bit = --m_output_bit; + if (m_output_bit >= 0) + { + for (int i = 0; i < 4; i++) + { + if (m_wclk_lr) + { // Right output + m_output_temp[i].serial_in( + m_wclk_lr, + bitfield(m_output_latch[i].right(), output_bit)); + } + else + { // Left output + m_output_temp[i].serial_in( + m_wclk_lr, + bitfield(m_output_latch[i].left(), output_bit)); + } + } + } + m_wclk++; + } + } + } + // /CAS, E + if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock + { + // /CAS + if (m_cas.tick()) + { + // /CAS high, E low: get sample address + if (m_cas.falling_edge()) + { + // /CAS low, E low: fetch sample + if (!m_e.current_edge()) + { + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + } + // E + if (m_e.tick()) + { + m_intf.e_pin(m_e.current_edge()); + if (m_e.rising_edge()) // Host access + { + m_host_intf.update_strobe(); + voice_tick(); + } + else if (m_e.falling_edge()) // Voice memory + { + m_host_intf.clear_host_access(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + if (m_e.current_edge()) // Host interface + { + if (m_host_intf.host_access()) + { + if (m_host_intf.rw() && (m_e.cycle() == 2)) // Read + { + m_hd = read(m_ha); + m_host_intf.clear_host_access(); + } + else if ((!m_host_intf.rw()) && (m_e.cycle() == 2)) + { // Write + write(m_ha, m_hd); + } + } + } + else if (!m_e.current_edge()) + { + if (m_e.cycle() == 2) + { + // reset host access state + m_hd = 0; + m_host_intf.clear_strobe(); + } + } + } + } + } +} + +// less cycle accurate, but less CPU heavy routine +void es5505_core::tick_perf() +{ + m_voice_update = false; + m_voice_end = false; + // output + for (int c = 0; c < 4; c++) + { + m_output[c] = m_ch[c]; + } + + // update + // falling edge + m_e.edge().set(false); + m_intf.e_pin(false); + m_host_intf.clear_host_access(); + m_host_intf.clear_strobe(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.edge().set(true); + m_intf.e_pin(true); + m_host_intf.update_strobe(); + // falling edge + m_e.edge().set(false); + m_intf.e_pin(false); + m_host_intf.clear_host_access(); + m_host_intf.clear_strobe(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.edge().set(true); + m_intf.e_pin(true); + m_host_intf.update_strobe(); +} + +void es5505_core::voice_tick() +{ + // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) + { + // Update voice + m_voice[m_voice_cycle].tick(m_voice_cycle); + + // Refresh output + if ((++m_voice_cycle) > clamp(m_active, 7, 31)) // 8 ~ 32 voices + { + m_voice_end = true; + m_voice_cycle = 0; + for (auto &elem : m_ch) + { + elem.reset(); + } + + for (auto &elem : m_voice) + { + m_ch[bitfield(elem.cr().ca(), 0, 2)] += elem.ch(); + elem.ch().reset(); + } + } + m_voice_fetch = 0; + } +} + +void es5505_core::voice_t::fetch(u8 voice, u8 cycle) +{ + m_alu.set_sample( + cycle, + m_host.m_intf.read_sample(voice, + bitfield(m_cr.bs(), 0), + bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer))); +} + +void es5505_core::voice_t::tick(u8 voice) +{ + m_ch.reset(); + + // Filter execute + m_filter.tick(m_alu.interpolation()); + + if (m_alu.busy()) + { + // Send to output + m_ch.set_left(volume_calc(m_lvol, sign_ext(m_filter.o4_1(), 16))); + m_ch.set_right(volume_calc(m_rvol, sign_ext(m_filter.o4_1(), 16))); + + // ALU execute + if (m_alu.tick()) + { + m_alu.loop_exec(); + } + } + + // Update IRQ + m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); +} + +// volume calculation +s32 es5505_core::voice_t::volume_calc(u8 volume, s32 in) +{ + u8 exponent = bitfield(volume, 4, 4); + u8 mantissa = bitfield(volume, 0, 4); + return exponent ? (in * s32(0x10 | mantissa)) >> (19 - exponent) : 0; +} + +void es5505_core::reset() +{ + es550x_shared_core::reset(); + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_sermode.reset(); + m_bclk.reset(); + m_lrclk.reset(); + m_wclk = 0; + m_wclk_lr = false; + m_output_bit = 0; + for (auto &elem : m_ch) + { + elem.reset(); + } + for (auto &elem : m_output) + { + elem.reset(); + } + for (auto &elem : m_output_temp) + { + elem.reset(); + } + for (auto &elem : m_output_latch) + { + elem.reset(); + } +} + +void es5505_core::voice_t::reset() +{ + es550x_shared_core::es550x_voice_t::reset(); + m_lvol = 0; + m_rvol = 0; + m_ch.reset(); +} + +// Accessors +u16 es5505_core::host_r(u8 address) +{ + if (!m_host_intf.host_access()) + { + m_ha = address; + if (m_e.rising_edge()) + { // update directly + m_hd = read(m_ha, true); + } + else + { + m_host_intf.set_strobe(true); + } + } + return m_hd; +} + +void es5505_core::host_w(u8 address, u16 data) +{ + if (!m_host_intf.host_access()) + { + m_ha = address; + m_hd = data; + if (m_e.rising_edge()) + { // update directly + write(m_ha, m_hd, true); + } + else + { + m_host_intf.set_strobe(false); + } + } +} + +u16 es5505_core::read(u8 address, bool cpu_access) { return regs_r(m_page, address, cpu_access); } + +void es5505_core::write(u8 address, u16 data, bool cpu_access) +{ + regs_w(m_page, address, data, cpu_access); +} + +u16 es5505_core::regs_r(u8 page, u8 address, bool cpu_access) +{ + u16 ret = 0xffff; + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 13) // Global registers + { + switch (address) + { + case 13: // ACT (Number of voices) + ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); + break; + case 14: // IRQV (Interrupting voice vector) + ret = (ret & ~0x9f) | m_irqv.get(); + if (cpu_access) + { + m_irqv.clear(); + if (bool(bitfield(ret, 7)) != m_irqv.irqb()) + { + m_voice[m_irqv.voice()].alu().irq_update(m_intf, m_irqv); + } + } + break; + case 15: // PAGE (Page select register) + ret = (ret & ~0x7f) | bitfield(m_page, 0, 7); + break; + } + } + else + { + if (bitfield(page, 6)) // Channel registers + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + case 2: // CH1L (Channel 1 Left) + case 4: // CH2L (Channel 2 Left) + if (!cpu_access) + { // CPU can't read here + ret = m_ch[bitfield(address, 0, 2)].left(); + } + break; + case 1: // CH0R (Channel 0 Right) + case 3: // CH1R (Channel 1 Right) + case 5: // CH2R (Channel 2 Right) + if (!cpu_access) + { // CPU can't read here + ret = m_ch[bitfield(address, 0, 2)].right(); + } + break; + case 6: // CH3L (Channel 3 Left) + if ((!cpu_access) || m_sermode.adc()) + { + ret = m_ch[3].left(); + } + break; + case 7: // CH3R (Channel 3 Right) + if ((!cpu_access) || m_sermode.adc()) + { + ret = m_ch[3].right(); + } + break; + case 8: // SERMODE (Serial Mode) + ret = (ret & ~0xf807) | (m_sermode.adc() ? 0x01 : 0x00) | + (m_sermode.test() ? 0x02 : 0x00) | (m_sermode.sony_bb() ? 0x04 : 0x00) | + (bitfield(m_sermode.msb(), 0, 5) << 11); + break; + case 9: // PAR (Port A/D Register) + ret = (ret & ~0x3f) | (m_intf.adc_r() & ~0x3f); + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 63 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + ret = v.filter().o4_1(); + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + ret = v.filter().o3_2(); + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + ret = v.filter().o3_1(); + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + ret = v.filter().o2_2(); + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + ret = v.filter().o2_1(); + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + ret = v.filter().o1_1(); + break; + } + } + else // Page 0 - 31 + { + switch (address) + { + case 0: // CR (Control Register) + ret = (ret & ~0xfff) | (v.alu().stop() << 0) | + (bitfield(v.cr().bs(), 0) ? 0x04 : 0x00) | + (v.alu().lpe() ? 0x08 : 0x00) | (v.alu().ble() ? 0x10 : 0x00) | + (v.alu().irqe() ? 0x20 : 0x00) | (v.alu().dir() ? 0x40 : 0x00) | + (v.alu().irq() ? 0x80 : 0x00) | (bitfield(v.cr().ca(), 0, 2) << 8) | + (bitfield(v.filter().lp(), 0, 2) << 10); + break; + case 1: // FC (Frequency Control) + ret = (ret & ~0xfffe) | (bitfield(v.alu().fc(), 0, 15) << 1); + break; + case 2: // STRT-H (Loop Start Register High) + ret = (ret & ~0x1fff) | bitfield(v.alu().start(), 16, 13); + break; + case 3: // STRT-L (Loop Start Register Low) + ret = (ret & ~0xffe0) | (v.alu().start() & 0xffe0); + break; + case 4: // END-H (Loop End Register High) + ret = (ret & ~0x1fff) | bitfield(v.alu().end(), 16, 13); + break; + case 5: // END-L (Loop End Register Low) + ret = (ret & ~0xffe0) | (v.alu().end() & 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + ret = (ret & ~0xfff0) | (v.filter().k2() & 0xfff0); + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + ret = (ret & ~0xfff0) | (v.filter().k1() & 0xfff0); + break; + case 8: // LVOL (Left Volume) + ret = (ret & ~0xff00) | ((v.lvol() << 8) & 0xff00); + break; + case 9: // RVOL (Right Volume) + ret = (ret & ~0xff00) | ((v.rvol() << 8) & 0xff00); + break; + case 10: // ACCH (Accumulator High) + ret = (ret & ~0x1fff) | bitfield(v.alu().accum(), 16, 13); + break; + case 11: // ACCL (Accumulator Low) + ret = bitfield(v.alu().accum(), 0, 16); + break; + } + } + } + } + + return ret; +} + +void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) +{ + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 12) // Global registers + { + switch (address) + { + case 13: // ACT (Number of voices) + m_active = std::max(7, bitfield(data, 0, 5)); + break; + case 14: // IRQV (Interrupting voice vector) + // Read only + break; + case 15: // PAGE (Page select register) + m_page = bitfield(data, 0, 7); + break; + } + } + else // Voice specific registers + { + if (bitfield(page, 6)) // Channel registers + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + if (m_sermode.test()) + { + m_ch[0].set_left(data); + } + break; + case 1: // CH0R (Channel 0 Right) + if (m_sermode.test()) + { + m_ch[0].set_right(data); + } + break; + case 2: // CH1L (Channel 1 Left) + if (m_sermode.test()) + { + m_ch[1].set_left(data); + } + break; + case 3: // CH1R (Channel 1 Right) + if (m_sermode.test()) + { + m_ch[1].set_right(data); + } + break; + case 4: // CH2L (Channel 2 Left) + if (m_sermode.test()) + { + m_ch[2].set_left(data); + } + break; + case 5: // CH2R (Channel 2 Right) + if (m_sermode.test()) + { + m_ch[2].set_right(data); + } + break; + case 6: // CH3L (Channel 3 Left) + if (m_sermode.test()) + { + m_ch[3].set_left(data); + } + break; + case 7: // CH3R (Channel 3 Right) + if (m_sermode.test()) + { + m_ch[3].set_right(data); + } + break; + case 8: // SERMODE (Serial Mode) + m_sermode.write(data); + break; + case 9: // PAR (Port A/D Register) + // Read only + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 56 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + v.filter().set_o4_1(sign_ext(data, 16)); + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + v.filter().set_o3_2(sign_ext(data, 16)); + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + v.filter().set_o3_1(sign_ext(data, 16)); + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + v.filter().set_o2_2(sign_ext(data, 16)); + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + v.filter().set_o2_1(sign_ext(data, 16)); + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + v.filter().set_o1_1(sign_ext(data, 16)); + break; + } + } + else // Page 0 - 24 + { + switch (address) + { + case 0: // CR (Control Register) + v.alu().set_stop(bitfield(data, 0, 2)); + v.cr().set_bs(bitfield(data, 2)); + v.alu().set_lpe(bitfield(data, 3)); + v.alu().set_ble(bitfield(data, 4)); + v.alu().set_irqe(bitfield(data, 5)); + v.alu().set_dir(bitfield(data, 6)); + v.alu().set_irq(bitfield(data, 7)); + v.cr().set_ca(bitfield(data, 8, 2)); + v.filter().set_lp(bitfield(data, 10, 2)); + break; + case 1: // FC (Frequency Control) + v.alu().set_fc(bitfield(data, 1, 15)); + break; + case 2: // STRT-H (Loop Start Register High) + v.alu().set_start(bitfield(data, 0, 13) << 16, 0x1fff0000); + break; + case 3: // STRT-L (Loop Start Register Low) + v.alu().set_start(data & 0xffe0, 0xffe0); + break; + case 4: // END-H (Loop End Register High) + v.alu().set_end(bitfield(data, 0, 13) << 16, 0x1fff0000); + break; + case 5: // END-L (Loop End Register Low) + v.alu().set_end(data & 0xffe0, 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + v.filter().set_k2(data & 0xfff0); + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + v.filter().set_k1(data & 0xfff0); + break; + case 8: // LVOL (Left Volume) + v.set_lvol(bitfield(data, 8, 8)); + break; + case 9: // RVOL (Right Volume) + v.set_rvol(bitfield(data, 8, 8)); + break; + case 10: // ACCH (Accumulator High) + v.alu().set_accum(bitfield(data, 0, 13) << 16, 0x1fff0000); + break; + case 11: // ACCL (Accumulator Low) + v.alu().set_accum(data, 0xffff); + break; + } + } + } + } +} diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp new file mode 100644 index 000000000..34782f104 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp @@ -0,0 +1,304 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_ES5505_HPP +#define _VGSOUND_EMU_SRC_ES5505_HPP + +#pragma once + +#include "es550x.hpp" + +// ES5505 specific +class es5505_core : public es550x_shared_core +{ + private: + class output_t : public vgsound_emu_core + { + public: + output_t(s32 left = 0, s32 right = 0) + : vgsound_emu_core("es5505_output") + , m_left(left) + , m_right(right) + { + } + + void reset() + { + m_left = 0; + m_right = 0; + }; + + inline s32 clamp16(s32 in) { return clamp(in, -0x8000, 0x7fff); } + + inline void clamp16(output_t src) + { + m_left = clamp16(src.left()); + m_right = clamp16(src.right()); + } + + inline void clamp16() + { + m_left = clamp16(m_left); + m_right = clamp16(m_right); + } + + // setters + inline void set_left(s32 left) { m_left = left; } + + inline void set_right(s32 right) { m_right = right; } + + inline void serial_in(bool ch, u8 in) + { + if (ch) // Right output + { + m_right = (m_right << 1) | (in ? 1 : 0); + } + else // Left output + { + m_left = (m_left << 1) | (in ? 1 : 0); + } + } + + // getters + inline u32 left() { return m_left; } + + inline u32 right() { return m_right; } + + output_t &operator+=(output_t &src) + { + m_left = clamp16(m_left + src.left()); + m_right = clamp16(m_right + src.right()); + return *this; + } + + output_t &operator=(output_t src) + { + clamp16(src); + return *this; + } + + output_t &operator=(s32 val) + { + m_left = m_right = clamp16(val); + return *this; + } + + output_t &operator>>(s32 shift) + { + m_left >>= shift; + m_right >>= shift; + return *this; + } + + private: + s32 m_left = 0; + s32 m_right = 0; + }; + + // es5505 voice classes + class voice_t : public es550x_voice_t + { + public: + // constructor + voice_t(es5505_core &host) + : es550x_voice_t("es5505_voice", 20, 9, false) + , m_host(host) + , m_lvol(0) + , m_rvol(0) + , m_ch(output_t()) + { + } + + // internal state + virtual void reset() override; + virtual void fetch(u8 voice, u8 cycle) override; + virtual void tick(u8 voice) override; + + // setters + inline void set_lvol(u8 lvol) { m_lvol = lvol; } + + inline void set_rvol(u8 rvol) { m_rvol = rvol; } + + // getters + inline u8 lvol() { return m_lvol; } + + inline u8 rvol() { return m_rvol; } + + output_t &ch() { return m_ch; } + + private: + s32 volume_calc(u8 volume, s32 in); + + // registers + es5505_core &m_host; + u8 m_lvol = 0; // Left volume + u8 m_rvol = 0; // Right volume + output_t m_ch; // channel output + }; + + class sermode_t : public vgsound_emu_core + { + public: + sermode_t() + : vgsound_emu_core("es5505_sermode") + , m_adc(0) + , m_test(0) + , m_sony_bb(0) + , m_msb(0) + { + } + + void reset() + { + m_adc = 0; + m_test = 0; + m_sony_bb = 0; + m_msb = 0; + } + + // setters + void write(u16 data) + { + m_adc = (data >> 0) & 1; + m_test = (data >> 1) & 1; + m_sony_bb = (data >> 2) & 1; + m_msb = (data >> 11) & 0x1f; + } + + void set_adc(bool adc) { m_adc = adc ? 1 : 0; } + + void set_test(bool test) { m_test = test ? 1 : 0; } + + void set_sony_bb(bool sony_bb) { m_sony_bb = sony_bb ? 1 : 0; } + + void set_msb(u8 msb) { m_msb = msb & 0x1f; } + + // getters + bool adc() { return m_adc; } + + bool test() { return m_test; } + + bool sony_bb() { return m_sony_bb; } + + u8 msb() { return m_msb; } + + private: + u8 m_adc : 1; // A/D + u8 m_test : 1; // Test + u8 m_sony_bb : 1; // Sony/BB format serial output + u8 m_msb : 5; // Serial output MSB + }; + + public: + // constructor + es5505_core(es550x_intf &intf) + : es550x_shared_core("es5505", 32, intf) + , m_voice{*this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, + *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, + *this, *this, *this, *this, *this, *this, *this, *this, *this, *this} + , m_sermode(sermode_t()) + , m_bclk(clock_pulse_t(4, 0)) + , m_lrclk(clock_pulse_t(16, 1)) + , m_wclk(0) + , m_wclk_lr(false) + , m_output_bit(0) + , m_ch{output_t()} + , m_output{output_t()} + , m_output_temp{output_t()} + , m_output_latch{output_t()} + { + } + + // host interface + u16 host_r(u8 address); + void host_w(u8 address, u16 data); + + // internal state + virtual void reset() override; + virtual void tick() override; + + // less cycle accurate, but also less cpu heavy update routine + void tick_perf(); + + // clock outputs + inline bool bclk() { return m_bclk.current_edge(); } + + inline bool bclk_rising_edge() { return m_bclk.rising_edge(); } + + inline bool bclk_falling_edge() { return m_bclk.falling_edge(); } + + // Input mode for Channel 3 + inline void lin(s32 in) + { + if (m_sermode.adc()) + { + m_ch[3].set_left(in); + } + } + + inline void rin(s32 in) + { + if (m_sermode.adc()) + { + m_ch[3].set_right(in); + } + } + + // 4 stereo output channels + inline s32 lout(u8 ch) { return m_ch[ch & 0x3].left(); } + + inline s32 rout(u8 ch) { return m_ch[ch & 0x3].right(); } + + //----------------------------------------------------------------- + // + // for preview/debug purpose only, not for serious emulators + // + //----------------------------------------------------------------- + + // bypass chips host interface for debug purpose only + u16 read(u8 address, bool cpu_access = false); + void write(u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address, bool cpu_access = false); + void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address) + { + u8 prev = m_page; + m_page = page; + u16 ret = read(address, false); + m_page = prev; + return ret; + } + + // per-voice outputs + inline s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].ch().left() : 0; } + + inline s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].ch().right() : 0; } + + protected: + virtual inline u8 max_voices() override { return 32; } + + virtual void voice_tick() override; + + private: + std::array m_voice; // 32 voices + // Serial related stuffs + sermode_t m_sermode; // Serial mode register + clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock + clock_pulse_t m_lrclk; // LRCLK + s16 m_wclk = 0; // WCLK + bool m_wclk_lr = false; // WCLK, L/R output select + s8 m_output_bit = 0; // Bit position in output + std::array m_ch; // 4 stereo output channels + std::array m_output; // Serial outputs + std::array m_output_temp; // temporary signal for serial output + std::array m_output_latch; // output latch +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp new file mode 100644 index 000000000..ebb9a62d9 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp @@ -0,0 +1,870 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5506 emulation core +*/ + +#include "es5506.hpp" + +// Internal functions +void es5506_core::tick() +{ + m_voice_update = false; + m_voice_end = false; + // CLKIN + if (m_clkin.tick()) + { + // BCLK + if (m_clkin.edge().changed() && (!m_mode.bclk_en())) // BCLK is freely running clock + { + if (m_bclk.tick()) + { + m_intf.bclk(m_bclk.current_edge()); + // Serial output + if (!m_mode.lrclk_en()) + { + if (m_bclk.falling_edge()) + { + // LRCLK + if (m_lrclk.tick()) + { + m_intf.lrclk(m_lrclk.current_edge()); + if (m_lrclk.rising_edge()) + { + m_w_st_curr = m_w_st; + m_w_end_curr = m_w_end; + } + if (m_lrclk.falling_edge()) + { // update width + m_lrclk.set_width_latch(m_lr_end); + } + } + } + } + // WCLK + if (!m_mode.wclk_en()) + { + if (!m_mode.lrclk_en()) + { + if (m_lrclk.edge().changed()) + { + m_wclk = 0; + } + } + if (m_bclk.falling_edge()) + { + if (m_wclk == m_w_st_curr) + { + m_intf.wclk(true); + if (m_lrclk.current_edge()) + { + for (int i = 0; i < 6; i++) + { + // copy output + m_output[i] = m_output_temp[i]; + m_output_latch[i] = m_ch[i]; + m_output_temp[i].reset(); + // clamp to 20 bit (upper 3 bits are + // overflow guard bits) + m_output_latch[i].clamp20(); + // set signed + if (m_output_latch[i].left() < 0) + { + m_output_temp[i].set_left(-1); + } + if (m_output_latch[i].right() < 0) + { + m_output_temp[i].set_right(-1); + } + } + } + m_wclk_lr = m_lrclk.current_edge(); + m_output_bit = 20; + } + if (m_wclk < m_w_end_curr) + { + s8 output_bit = --m_output_bit; + if (m_output_bit >= 0) + { + for (int i = 0; i < 6; i++) + { + if (m_wclk_lr) + { + // Right output + m_output_temp[i].serial_in( + m_wclk_lr, + bitfield(m_output_latch[i].right(), output_bit)); + } + else + { + // Left output + m_output_temp[i].serial_in( + m_wclk_lr, + bitfield(m_output_latch[i].left(), output_bit)); + } + } + } + } + if (m_wclk == m_w_end_curr) + { + m_intf.wclk(false); + } + + m_wclk++; + } + } + } + } + // /CAS, E + if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock + { + // /CAS + if (m_cas.tick()) + { + // single OTTO master mode, /CAS high, E low: get sample address + // single OTTO early mode, /CAS falling, E high: get sample + // address + if (m_cas.falling_edge()) + { + if (!m_e.current_edge()) + { + // single OTTO master mode, /CAS low, E low: fetch + // sample + if (m_mode.master()) + { + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + else if (m_e.current_edge()) + { + // dual OTTO slave mode, /CAS low, E high: fetch sample + if (m_mode.dual() && (!m_mode.master())) + { // Dual OTTO, slave mode + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + } + } + // E + if (m_e.tick()) + { + m_intf.e_pin(m_e.current_edge()); + if (m_e.rising_edge()) + { + m_host_intf.update_strobe(); + } + else if (m_e.falling_edge()) + { + m_host_intf.clear_host_access(); + voice_tick(); + } + if (m_e.current_edge()) // Host interface + { + if (m_host_intf.host_access()) + { + if (m_host_intf.rw() && (m_e.cycle() == 0)) // Read + { + m_hd = read(m_ha); + m_host_intf.clear_host_access(); + } + else if ((!m_host_intf.rw()) && (m_e.cycle() == 2)) + { // Write + write(m_ha, m_hd); + } + } + } + else if (!m_e.current_edge()) + { + if (m_e.cycle() == 2) + { + // reset host access state + m_hd = 0; + m_host_intf.clear_strobe(); + } + } + } + } + } +} + +// less cycle accurate, but less CPU heavy routine +void es5506_core::tick_perf() +{ + m_voice_update = false; + m_voice_end = false; + // output + if (((!m_mode.lrclk_en()) && (!m_mode.bclk_en()) && (!m_mode.wclk_en())) && (m_w_st < m_w_end)) + { + const int output_bits = 20 - (m_w_end - m_w_st); + if (output_bits < 20) + { + for (int c = 0; c < 6; c++) + { + m_output[c] = m_ch[c] >> output_bits; + } + } + } + else + { + for (int c = 0; c < 6; c++) + { + m_output[c] = 0; + } + } + + // update + // falling edge + m_e.edge().set(false); + m_intf.e_pin(false); + m_host_intf.clear_host_access(); + m_host_intf.clear_strobe(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.edge().set(true); + m_intf.e_pin(true); + m_host_intf.update_strobe(); + // falling edge + m_e.edge().set(false); + m_intf.e_pin(false); + m_host_intf.clear_host_access(); + m_host_intf.clear_strobe(); + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.edge().set(true); + m_intf.e_pin(true); + m_host_intf.update_strobe(); +} + +void es5506_core::voice_tick() +{ + // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) + { + // Update voice + m_voice[m_voice_cycle].tick(m_voice_cycle); + + // Refresh output + if ((++m_voice_cycle) > clamp(m_active, 4, 31)) // 5 ~ 32 voices + { + m_voice_end = true; + m_voice_cycle = 0; + for (output_t &elem : m_ch) + { + elem.reset(); + } + + for (voice_t &elem : m_voice) + { + const u8 ca = bitfield(elem.cr().ca(), 0, 3); + if (ca < 6) + { + m_ch[ca] += elem.ch(); + } + elem.ch().reset(); + } + } + m_voice_fetch = 0; + } +} + +void es5506_core::voice_t::fetch(u8 voice, u8 cycle) +{ + m_alu.set_sample( + cycle, + m_host.m_intf.read_sample(voice, + m_cr.bs(), + bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer))); + if (m_cr.cmpd()) + { // Decompress (Upper 8 bit is used for compressed format) + m_alu.set_sample(cycle, decompress(bitfield(m_alu.sample(cycle), 8, 8))); + } +} + +void es5506_core::voice_t::tick(u8 voice) +{ + m_ch.reset(); + + // Filter execute + m_filter.tick(m_alu.interpolation()); + + if (m_alu.busy()) + { + // Send to output + m_ch.set_left(volume_calc(m_lvol, sign_ext(m_filter.o4_1(), 16))); + m_ch.set_right(volume_calc(m_rvol, sign_ext(m_filter.o4_1(), 16))); + + // ALU execute + if (m_alu.tick()) + { + m_alu.loop_exec(); + } + } + // Envelope + if (m_ecount != 0) + { + // Left and Right volume + if (bitfield(m_lvramp, 0, 8) != 0) + { + m_lvol = clamp(m_lvol + sign_ext(bitfield(m_lvramp, 0, 8), 8), 0, 0xffff); + } + if (bitfield(m_rvramp, 0, 8) != 0) + { + m_rvol = clamp(m_rvol + sign_ext(bitfield(m_rvramp, 0, 8), 8), 0, 0xffff); + } + + // Filter coeffcient + if ((m_k1ramp.ramp() != 0) && + ((m_k1ramp.slow() == 0) || (bitfield(m_filtcount, 0, 3) == 0))) + { + m_filter.set_k1( + clamp(m_filter.k1() + sign_ext(m_k1ramp.ramp(), 8), 0, 0xffff)); + } + if ((m_k2ramp.ramp() != 0) && + ((m_k2ramp.slow() == 0) || (bitfield(m_filtcount, 0, 3) == 0))) + { + m_filter.set_k2( + clamp(m_filter.k2() + sign_ext(m_k2ramp.ramp(), 8), 0, 0xffff)); + } + + m_ecount--; + } + m_filtcount = bitfield(m_filtcount + 1, 0, 3); + + // Update IRQ + m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); +} + +// Compressed format +s16 es5506_core::voice_t::decompress(u8 sample) +{ + u8 exponent = bitfield(sample, 5, 3); + u8 mantissa = bitfield(sample, 0, 5); + return (exponent > 0) + ? s16(((bitfield(mantissa, 4) ? 0x10 : ~0x1f) | bitfield(mantissa, 0, 4)) + << (4 + (exponent - 1))) + : s16(((bitfield(mantissa, 4) ? ~0xf : 0) | bitfield(mantissa, 0, 4)) << 4); +} + +// volume calculation +s32 es5506_core::voice_t::volume_calc(u16 volume, s32 in) +{ + u8 exponent = bitfield(volume, 12, 4); + u8 mantissa = bitfield(volume, 4, 8); + return (in * s32(0x100 | mantissa)) >> (20 - exponent); +} + +void es5506_core::reset() +{ + es550x_shared_core::reset(); + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_read_latch = 0xffffffff; + m_write_latch = 0xffffffff; + m_w_st = 0; + m_w_end = 0; + m_lr_end = 0; + m_w_st_curr = 0; + m_w_end_curr = 0; + m_mode.reset(); + m_bclk.reset(); + m_lrclk.reset(32); + m_wclk = 0; + m_wclk_lr = false; + m_output_bit = 0; + for (auto &elem : m_ch) + { + elem.reset(); + } + for (auto &elem : m_output) + { + elem.reset(); + } + for (auto &elem : m_output_temp) + { + elem.reset(); + } + for (auto &elem : m_output_latch) + { + elem.reset(); + } +} + +void es5506_core::voice_t::reset() +{ + es550x_shared_core::es550x_voice_t::reset(); + m_lvol = 0; + m_rvol = 0; + m_lvramp = 0; + m_rvramp = 0; + m_ecount = 0; + m_k2ramp.reset(); + m_k1ramp.reset(); + m_filtcount = 0; + m_ch.reset(); + m_mute = false; +} + +// Accessors +u8 es5506_core::host_r(u8 address) +{ + if (!m_host_intf.host_access()) + { + m_ha = address; + if (m_e.rising_edge()) + { // update directly + m_hd = read(m_ha, true); + } + else + { + m_host_intf.set_strobe(true); + } + } + return m_hd; +} + +void es5506_core::host_w(u8 address, u8 data) +{ + if (!m_host_intf.host_access()) + { + m_ha = address; + m_hd = data; + if (m_e.rising_edge()) + { // update directly + write(m_ha, m_hd, true); + } + else + { + m_host_intf.set_strobe(false); + } + } +} + +u8 es5506_core::read(u8 address, bool cpu_access) +{ + const u8 byte = bitfield(address, 0, 2); // byte select + const u8 shift = 24 - (byte << 3); + if (byte != 0) + { // Return already latched register if not highest byte is accessing + return bitfield(m_read_latch, shift, 8); + } + + address = bitfield(address, 2, 4); // 4 bit address for CPU access + + // get read register + m_read_latch = regs_r(m_page, address, cpu_access); + + return bitfield(m_read_latch, 24, 8); +} + +void es5506_core::write(u8 address, u8 data, bool cpu_access) +{ + const u8 byte = bitfield(address, 0, 2); // byte select + const u8 shift = 24 - (byte << 3); + address = bitfield(address, 2, 4); // 4 bit address for CPU access + + // Update register latch + m_write_latch = (m_write_latch & ~(0xff << shift)) | (u32(data) << shift); + + if (byte != 3) + { // Wait until lowest byte is writed + return; + } + + regs_w(m_page, address, m_write_latch, cpu_access); + + // Reset latch + m_write_latch = 0; +} + +u32 es5506_core::regs_r(u8 page, u8 address, bool cpu_access) +{ + u32 read_latch = 0xffffffff; + // Global registers + if (address >= 13) + { + switch (address) + { + case 13: // POT (Pot A/D Register) + read_latch = (read_latch & ~0x3ff) | bitfield(m_intf.adc_r(), 0, 10); + break; + case 14: // IRQV (Interrupting voice vector) + read_latch = (read_latch & ~0x9f) | (m_irqv.irqb() ? 0x80 : 0) | + bitfield(m_irqv.voice(), 0, 5); + if (cpu_access) + { + m_irqv.clear(); + if (bool(bitfield(read_latch, 7)) != m_irqv.irqb()) + { + m_voice[m_irqv.voice()].irq_update(m_intf, m_irqv); + } + } + break; + case 15: // PAGE (Page select register) + read_latch = (read_latch & ~0x7f) | bitfield(m_page, 0, 7); + break; + } + } + else + { + // Channel registers are Write only + if (bitfield(page, 6)) + { + if (!cpu_access) // CPU can't read here + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + case 2: // CH1L (Channel 1 Left) + case 4: // CH2L (Channel 2 Left) + case 6: // CH3L (Channel 3 Left) + case 8: // CH4L (Channel 4 Left) + case 10: // CH5L (Channel 5 Left) + read_latch = m_ch[bitfield(address, 1, 3)].left(); + break; + case 1: // CH0R (Channel 0 Right) + case 3: // CH1R (Channel 1 Right) + case 5: // CH2R (Channel 2 Right) + case 7: // CH3R (Channel 3 Right) + case 9: // CH4R (Channel 4 Right) + case 11: // CH5R (Channel 5 Right) + read_latch = m_ch[bitfield(address, 1, 3)].right(); + break; + } + } + } + else + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 63 + { + switch (address) + { + case 0: // CR (Control Register) + read_latch = (read_latch & ~0xffff) | (v.alu().stop() << 0) | + (v.alu().lei() ? 0x0004 : 0x0000) | (v.alu().loop() << 3) | + (v.alu().irqe() ? 0x0020 : 0x0000) | + (v.alu().dir() ? 0x0040 : 0x0000) | + (v.alu().irq() ? 0x0080 : 0x0000) | + (bitfield(v.filter().lp(), 0, 2) << 8) | (v.cr().ca() << 10) | + (v.cr().cmpd() ? 0x2000 : 0x0000) | (v.cr().bs() << 14); + break; + case 1: // START (Loop Start Register) + read_latch = (read_latch & ~0xfffff800) | (v.alu().start() & 0xfffff800); + break; + case 2: // END (Loop End Register) + read_latch = (read_latch & ~0xffffff80) | (v.alu().end() & 0xffffff80); + break; + case 3: // ACCUM (Accumulator Register) + read_latch = v.alu().accum(); + break; + case 4: // O4(n-1) (Filter 4 Temp Register) + if (cpu_access) + { + read_latch = + (read_latch & ~0x3ffff) | bitfield(v.filter().o4_1(), 0, 18); + } + else + { + read_latch = v.filter().o4_1(); + } + break; + case 5: // O3(n-2) (Filter 3 Temp Register #2) + if (cpu_access) + { + read_latch = + (read_latch & ~0x3ffff) | bitfield(v.filter().o3_2(), 0, 18); + } + else + { + read_latch = v.filter().o3_2(); + } + break; + case 6: // O3(n-1) (Filter 3 Temp Register #1) + if (cpu_access) + { + read_latch = + (read_latch & ~0x3ffff) | bitfield(v.filter().o3_1(), 0, 18); + } + else + { + read_latch = v.filter().o3_1(); + } + break; + case 7: // O2(n-2) (Filter 2 Temp Register #2) + if (cpu_access) + { + read_latch = + (read_latch & ~0x3ffff) | bitfield(v.filter().o2_2(), 0, 18); + } + else + { + read_latch = v.filter().o2_2(); + } + break; + case 8: // O2(n-1) (Filter 2 Temp Register #1) + if (cpu_access) + { + read_latch = + (read_latch & ~0x3ffff) | bitfield(v.filter().o2_1(), 0, 18); + } + else + { + read_latch = v.filter().o2_1(); + } + break; + case 9: // O1(n-1) (Filter 1 Temp Register) + if (cpu_access) + { + read_latch = + (read_latch & ~0x3ffff) | bitfield(v.filter().o1_1(), 0, 18); + } + else + { + read_latch = v.filter().o1_1(); + } + break; + case 10: // W_ST (Word Clock Start Register) + read_latch = (read_latch & ~0x7f) | bitfield(m_w_st, 0, 7); + break; + case 11: // W_END (Word Clock End Register) + read_latch = (read_latch & ~0x7f) | bitfield(m_w_end, 0, 7); + break; + case 12: // LR_END (Left/Right Clock End Register) + read_latch = (read_latch & ~0x7f) | bitfield(m_lr_end, 0, 7); + break; + } + } + else // Page 0 - 31 + { + switch (address) + { + case 0: // CR (Control Register) + read_latch = (read_latch & ~0xffff) | (v.alu().stop() << 0) | + (v.alu().lei() ? 0x0004 : 0x0000) | (v.alu().loop() << 3) | + (v.alu().irqe() ? 0x0020 : 0x0000) | + (v.alu().dir() ? 0x0040 : 0x0000) | + (v.alu().irq() ? 0x0080 : 0x0000) | + (bitfield(v.filter().lp(), 0, 2) << 8) | (v.cr().ca() << 10) | + (v.cr().cmpd() ? 0x2000 : 0x0000) | (v.cr().bs() << 14); + break; + case 1: // FC (Frequency Control) + read_latch = (read_latch & ~0x1ffff) | bitfield(v.alu().fc(), 0, 17); + break; + case 2: // LVOL (Left Volume) + read_latch = (read_latch & ~0xffff) | bitfield(v.lvol(), 0, 16); + break; + case 3: // LVRAMP (Left Volume Ramp) + read_latch = (read_latch & ~0xff00) | (bitfield(v.lvramp(), 0, 8) << 8); + break; + case 4: // RVOL (Right Volume) + read_latch = (read_latch & ~0xffff) | bitfield(v.rvol(), 0, 16); + break; + case 5: // RVRAMP (Right Volume Ramp) + read_latch = (read_latch & ~0xff00) | (bitfield(v.rvramp(), 0, 8) << 8); + break; + case 6: // ECOUNT (Envelope Counter) + read_latch = (read_latch & ~0x01ff) | bitfield(v.ecount(), 0, 9); + break; + case 7: // K2 (Filter Cutoff Coefficient #2) + read_latch = (read_latch & ~0xffff) | bitfield(v.filter().k2(), 0, 16); + break; + case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) + read_latch = (read_latch & ~0xff01) | + (bitfield(v.k2ramp().ramp(), 0, 8) << 8) | + (v.k2ramp().slow() ? 0x0001 : 0x0000); + break; + case 9: // K1 (Filter Cutoff Coefficient #1) + read_latch = (read_latch & ~0xffff) | bitfield(v.filter().k1(), 0, 16); + break; + case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) + read_latch = (read_latch & ~0xff01) | + (bitfield(v.k1ramp().ramp(), 0, 8) << 8) | + (v.k1ramp().slow() ? 0x0001 : 0x0000); + break; + case 11: // ACT (Number of voices) + read_latch = (read_latch & ~0x1f) | bitfield(m_active, 0, 5); + break; + case 12: // MODE (Global Mode) + read_latch = + (read_latch & ~0x1f) | (m_mode.lrclk_en() ? 0x01 : 0x00) | + (m_mode.wclk_en() ? 0x02 : 0x00) | (m_mode.bclk_en() ? 0x04 : 0x00) | + (m_mode.master() ? 0x08 : 0x00) | (m_mode.dual() ? 0x10 : 0x00); + break; + } + } + } + } + + return read_latch; +} + +void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access) +{ + // Global registers + if (address >= 13) + { + switch (address) + { + case 13: // POT (Pot A/D Register) + // Read only + break; + case 14: // IRQV (Interrupting voice vector) + // Read only + break; + case 15: // PAGE (Page select register) + m_page = bitfield(data, 0, 7); + break; + } + } + else + { + // Channel registers are Write only, and for test purposes + if (bitfield(page, 6)) + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + case 2: // CH1L (Channel 1 Left) + case 4: // CH2L (Channel 2 Left) + case 6: // CH3L (Channel 3 Left) + case 8: // CH4L (Channel 4 Left) + case 10: // CH5L (Channel 5 Left) + m_ch[bitfield(address, 1, 3)].set_left( + sign_ext(bitfield(data, 0, 23), 23)); + break; + case 1: // CH0R (Channel 0 Right) + case 3: // CH1R (Channel 1 Right) + case 5: // CH2R (Channel 2 Right) + case 7: // CH3R (Channel 3 Right) + case 9: // CH4R (Channel 4 Right) + case 11: // CH5R (Channel 5 Right) + m_ch[bitfield(address, 1, 3)].set_right( + sign_ext(bitfield(data, 0, 23), 23)); + break; + } + } + else + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 63 + { + switch (address) + { + case 0: // CR (Control Register) + v.alu().set_stop(bitfield(data, 0, 2)); + v.alu().set_lei(bitfield(data, 2)); + v.alu().set_loop(bitfield(data, 3, 2)); + v.alu().set_irqe(bitfield(data, 5)); + v.alu().set_dir(bitfield(data, 6)); + v.alu().set_irq(bitfield(data, 7)); + v.filter().set_lp(bitfield(data, 8, 2)); + v.cr().set_ca(std::min(5, bitfield(data, 10, 3))); + v.cr().set_cmpd(bitfield(data, 13)); + v.cr().set_bs(bitfield(data, 14, 2)); + break; + case 1: // START (Loop Start Register) + v.alu().set_start(data & 0xfffff800); + break; + case 2: // END (Loop End Register) + v.alu().set_end(data & 0xffffff80); + break; + case 3: // ACCUM (Accumulator Register) + v.alu().set_accum(data); + break; + case 4: // O4(n-1) (Filter 4 Temp Register) + v.filter().set_o4_1(sign_ext(bitfield(data, 0, 18), 18)); + break; + case 5: // O3(n-2) (Filter 3 Temp Register #2) + v.filter().set_o3_2(sign_ext(bitfield(data, 0, 18), 18)); + break; + case 6: // O3(n-1) (Filter 3 Temp Register #1) + v.filter().set_o3_1(sign_ext(bitfield(data, 0, 18), 18)); + break; + case 7: // O2(n-2) (Filter 2 Temp Register #2) + v.filter().set_o2_2(sign_ext(bitfield(data, 0, 18), 18)); + break; + case 8: // O2(n-1) (Filter 2 Temp Register #1) + v.filter().set_o2_1(sign_ext(bitfield(data, 0, 18), 18)); + break; + case 9: // O1(n-1) (Filter 1 Temp Register) + v.filter().set_o1_1(sign_ext(bitfield(data, 0, 18), 18)); + break; + case 10: // W_ST (Word Clock Start Register) + m_w_st = bitfield(data, 0, 7); + break; + case 11: // W_END (Word Clock End Register) + m_w_end = bitfield(data, 0, 7); + break; + case 12: // LR_END (Left/Right Clock End Register) + m_lr_end = bitfield(data, 0, 7); + m_lrclk.set_width(m_lr_end); + break; + } + } + else // Page 0 - 31 + { + switch (address) + { + case 0: // CR (Control Register) + v.alu().set_stop(bitfield(data, 0, 2)); + v.alu().set_lei(bitfield(data, 2)); + v.alu().set_loop(bitfield(data, 3, 2)); + v.alu().set_irqe(bitfield(data, 5)); + v.alu().set_dir(bitfield(data, 6)); + v.alu().set_irq(bitfield(data, 7)); + v.filter().set_lp(bitfield(data, 8, 2)); + v.cr().set_ca(std::min(5, bitfield(data, 10, 3))); + v.cr().set_cmpd(bitfield(data, 13)); + v.cr().set_bs(bitfield(data, 14, 2)); + break; + case 1: // FC (Frequency Control) + v.alu().set_fc(bitfield(data, 0, 17)); + break; + case 2: // LVOL (Left Volume) + v.set_lvol(bitfield(data, 0, 16)); + break; + case 3: // LVRAMP (Left Volume Ramp) + v.set_lvramp(bitfield(data, 8, 8)); + break; + case 4: // RVOL (Right Volume) + v.set_rvol(bitfield(data, 0, 16)); + break; + case 5: // RVRAMP (Right Volume Ramp) + v.set_rvramp(bitfield(data, 8, 8)); + break; + case 6: // ECOUNT (Envelope Counter) + v.set_ecount(bitfield(data, 0, 9)); + break; + case 7: // K2 (Filter Cutoff Coefficient #2) + v.filter().set_k2(bitfield(data, 0, 16)); + break; + case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) + v.k2ramp().write(data); + break; + case 9: // K1 (Filter Cutoff Coefficient #1) + v.filter().set_k1(bitfield(data, 0, 16)); + break; + case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) + v.k1ramp().write(data); + break; + case 11: // ACT (Number of voices) + m_active = std::max(4, bitfield(data, 0, 5)); + break; + case 12: // MODE (Global Mode) + m_mode.write(data); + break; + } + } + } + } +} diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp new file mode 100644 index 000000000..84a6077de --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp @@ -0,0 +1,385 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5506 emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_ES5506_HPP +#define _VGSOUND_EMU_SRC_ES5506_HPP + +#pragma once + +#include "es550x.hpp" + +// ES5506 specific +class es5506_core : public es550x_shared_core +{ + private: + class output_t : public vgsound_emu_core + { + public: + output_t(s32 left = 0, s32 right = 0) + : vgsound_emu_core("es5506_output") + , m_left(left) + , m_right(right) + { + } + + void reset() + { + m_left = 0; + m_right = 0; + }; + + inline s32 clamp20(s32 in) { return clamp(in, -0x80000, 0x7ffff); } + + inline void clamp20(output_t src) + { + m_left = clamp20(src.left()); + m_right = clamp20(src.right()); + } + + inline void clamp20() + { + m_left = clamp20(m_left); + m_right = clamp20(m_right); + } + + // setters + inline void set_left(s32 left) { m_left = clamp20(left); } + + inline void set_right(s32 right) { m_right = clamp20(right); } + + void serial_in(bool ch, u8 in) + { + if (ch) // Right output + { + m_right = (m_right << 1) | (in ? 1 : 0); + } + else // Left output + { + m_left = (m_left << 1) | (in ? 1 : 0); + } + } + + // getters + inline u32 left() { return m_left; } + + inline u32 right() { return m_right; } + + output_t &operator+=(output_t &src) + { + m_left = clamp20(m_left + src.left()); + m_right = clamp20(m_right + src.right()); + return *this; + } + + output_t &operator=(output_t src) + { + clamp20(src); + return *this; + } + + output_t &operator=(s32 val) + { + m_left = m_right = clamp20(val); + return *this; + } + + output_t &operator>>(s32 shift) + { + m_left >>= shift; + m_right >>= shift; + return *this; + } + + private: + s32 m_left = 0; + s32 m_right = 0; + }; + + // es5506 voice classes + class voice_t : public es550x_voice_t + { + private: + // es5506 Filter ramp class + class filter_ramp_t : public vgsound_emu_core + { + public: + filter_ramp_t() + : vgsound_emu_core("es5506_filter_ramp") + , m_slow(0) + , m_ramp(0) + { + } + + void reset() + { + m_slow = 0; + m_ramp = 0; + }; + + // Setters + inline void write(u16 data) + { + m_slow = data & 1; + m_ramp = (data >> 8) & 0xff; + } + + // Getters + inline bool slow() { return m_slow; } + + inline u16 ramp() { return m_ramp; } + + private: + u16 m_slow : 1; // Slow mode flag + u16 m_ramp = 8; // Ramp value + }; + + public: + // constructor + voice_t(es5506_core &host) + : es550x_voice_t("es5506_voice", 21, 11, true) + , m_host(host) + , m_lvol(0) + , m_rvol(0) + , m_lvramp(0) + , m_rvramp(0) + , m_ecount(0) + , m_k2ramp(filter_ramp_t()) + , m_k1ramp(filter_ramp_t()) + , m_filtcount(0) + , m_ch(output_t()) + , m_mute(false) + { + } + + // internal state + virtual void reset() override; + virtual void fetch(u8 voice, u8 cycle) override; + virtual void tick(u8 voice) override; + + // Setters + inline void set_lvol(s32 lvol) { m_lvol = lvol; } + + inline void set_rvol(s32 rvol) { m_rvol = rvol; } + + inline void set_lvramp(s32 lvramp) { m_lvramp = lvramp; } + + inline void set_rvramp(s32 rvramp) { m_rvramp = rvramp; } + + inline void set_ecount(s16 ecount) { m_ecount = ecount; } + + // Getters + inline s32 lvol() { return m_lvol; } + + inline s32 rvol() { return m_rvol; } + + inline s32 lvramp() { return m_lvramp; } + + inline s32 rvramp() { return m_rvramp; } + + inline s16 ecount() { return m_ecount; } + + inline filter_ramp_t &k2ramp() { return m_k2ramp; } + + inline filter_ramp_t &k1ramp() { return m_k1ramp; } + + output_t &ch() { return m_ch; } + + // for debug/preview only + inline void set_mute(bool mute) { m_mute = mute; } + + inline s32 left_out() { return m_mute ? 0 : m_ch.left(); } + + inline s32 right_out() { return m_mute ? 0 : m_ch.right(); } + + private: + // accessors, getters, setters + s16 decompress(u8 sample); + s32 volume_calc(u16 volume, s32 in); + + // registers + es5506_core &m_host; + // Volume register: 4 bit exponent, 8 bit mantissa + // 4 LSBs are used for fine control of ramp increment for hardware envelope + s32 m_lvol = 0; // Left volume + s32 m_rvol = 0; // Right volume + // Envelope + s32 m_lvramp = 0; // Left volume ramp + s32 m_rvramp = 0; // Righr volume ramp + s16 m_ecount = 0; // Envelope counter + filter_ramp_t m_k2ramp; // Filter coefficient 2 Ramp + filter_ramp_t m_k1ramp; // Filter coefficient 1 Ramp + u8 m_filtcount = 0; // Internal counter for slow mode + output_t m_ch; // channel output + bool m_mute = false; // mute flag (for debug purpose) + }; + + // 5 bit mode + class mode_t : public vgsound_emu_core + { + public: + mode_t() + : vgsound_emu_core("es5506_mode") + , m_lrclk_en(1) + , m_wclk_en(1) + , m_bclk_en(1) + , m_master(0) + , m_dual(0) + { + } + + // internal states + void reset() + { + m_lrclk_en = 1; + m_wclk_en = 1; + m_bclk_en = 1; + m_master = 0; + m_dual = 0; + } + + // accessors + void write(u8 data) + { + m_lrclk_en = (data >> 0) & 1; + m_wclk_en = (data >> 1) & 1; + m_bclk_en = (data >> 2) & 1; + m_master = (data >> 3) & 1; + m_dual = (data >> 4) & 1; + } + + // getters + bool lrclk_en() { return m_lrclk_en; } + + bool wclk_en() { return m_wclk_en; } + + bool bclk_en() { return m_bclk_en; } + + bool master() { return m_master; } + + bool dual() { return m_dual; } + + private: + u8 m_lrclk_en : 1; // Set LRCLK to output + u8 m_wclk_en : 1; // Set WCLK to output + u8 m_bclk_en : 1; // Set BCLK to output + u8 m_master : 1; // Set memory mode to master + u8 m_dual : 1; // Set dual chip config + }; + + public: + // constructor + es5506_core(es550x_intf &intf) + : es550x_shared_core("es5506", 32, intf) + , m_voice{*this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, + *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, *this, + *this, *this, *this, *this, *this, *this, *this, *this, *this, *this} + , m_read_latch(0) + , m_write_latch(0) + , m_w_st(0) + , m_w_end(0) + , m_lr_end(0) + , m_mode(mode_t()) + , m_w_st_curr(0) + , m_w_end_curr(0) + , m_bclk(clock_pulse_t(4, 0)) + , m_lrclk(clock_pulse_t(32, 1)) + , m_wclk(0) + , m_wclk_lr(false) + , m_output_bit(0) + , m_ch{output_t()} + , m_output{output_t()} + , m_output_temp{output_t()} + , m_output_latch{output_t()} + { + } + + // host interface + u8 host_r(u8 address); + void host_w(u8 address, u8 data); + + // internal state + virtual void reset() override; + virtual void tick() override; + + // less cycle accurate, but also less cpu heavy update routine + void tick_perf(); + + // clock outputs + inline bool bclk() { return m_bclk.current_edge(); } + + inline bool bclk_rising_edge() { return m_bclk.rising_edge(); } + + inline bool bclk_falling_edge() { return m_bclk.falling_edge(); } + + // 6 stereo output channels + inline s32 lout(u8 ch) { return m_output[std::min(5, ch & 0x7)].left(); } + + inline s32 rout(u8 ch) { return m_output[std::min(5, ch & 0x7)].right(); } + + //----------------------------------------------------------------- + // + // for preview/debug purpose only, not for serious emulators + // + //----------------------------------------------------------------- + + // bypass chips host interface for debug purpose only + u8 read(u8 address, bool cpu_access = false); + void write(u8 address, u8 data, bool cpu_access = false); + + u32 regs_r(u8 page, u8 address, bool cpu_access = false); + void regs_w(u8 page, u8 address, u32 data, bool cpu_access = false); + + u8 regs8_r(u8 page, u8 address) + { + u8 prev = m_page; + m_page = page; + u8 ret = read(address, false); + m_page = prev; + return ret; + } + + inline void set_mute(u8 ch, bool mute) { m_voice[ch & 0x1f].set_mute(mute); } + + // per-voice outputs + inline s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].left_out() : 0; } + + inline s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].right_out() : 0; } + + protected: + virtual inline u8 max_voices() override { return 32; } + + virtual void voice_tick() override; + + private: + std::array m_voice; // 32 voices + + // Host interfaces + u32 m_read_latch = 0; // 32 bit register latch for host read + u32 m_write_latch = 0; // 32 bit register latch for host write + + // Serial register + u8 m_w_st = 0; // Word clock start register + u8 m_w_end = 0; // Word clock end register + u8 m_lr_end = 0; // Left/Right clock end register + mode_t m_mode; // Global mode + + // Serial related stuffs + u8 m_w_st_curr = 0; // Word clock start, current status + u8 m_w_end_curr = 0; // Word clock end register + clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock + clock_pulse_t m_lrclk; // LRCLK + s16 m_wclk = 0; // WCLK + bool m_wclk_lr = false; // WCLK, L/R output select + s8 m_output_bit = 0; // Bit position in output + std::array m_ch; // 6 stereo output channels + std::array m_output; // Serial outputs + std::array m_output_temp; // temporary signal for serial output + std::array m_output_latch; // output latch +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp new file mode 100644 index 000000000..7de7f0497 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp @@ -0,0 +1,34 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 emulation core +*/ + +#include "es550x.hpp" + +// Shared functions +void es550x_shared_core::reset() +{ + m_host_intf.reset(); + m_ha = 0; + m_hd = 0; + m_page = 0; + m_irqv.reset(); + m_active = max_voices() - 1; + m_voice_cycle = 0; + m_voice_fetch = 0; + m_voice_update = false; + m_voice_end = false; + m_clkin.reset(); + m_cas.reset(); + m_e.reset(); +} + +void es550x_shared_core::es550x_voice_t::reset() +{ + m_cr.reset(); + m_alu.reset(); + m_filter.reset(); +} diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp new file mode 100644 index 000000000..4457c2440 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp @@ -0,0 +1,610 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_ES550X_HPP +#define _VGSOUND_EMU_SRC_ES550X_HPP + +#pragma once + +#include "../core/util.hpp" + +// ES5504/ES5505/ES5506 interface +class es550x_intf : public vgsound_emu_core +{ + public: + es550x_intf() + : vgsound_emu_core("es550x_intf") + { + } + + virtual void e_pin(bool state) {} // E output + + virtual void bclk(bool state) {} // BCLK output (serial specific) + + virtual void lrclk(bool state) {} // LRCLK output (serial specific) + + virtual void wclk(bool state) {} // WCLK output (serial specific) + + virtual void irqb(bool state) {} // irqb output + + virtual u16 adc_r() { return 0; } // ADC input + + virtual void adc_w(u16 data) {} // ADC output + + virtual s16 read_sample(u8 voice, u8 bank, u32 address) { return 0; } +}; + +// Shared functions for ES5504/ES5505/ES5506 +class es550x_shared_core : public vgsound_emu_core +{ + friend class es550x_intf; // es550x specific memory interface + + private: + const u8 m_max_voices = 32; + + protected: + // Interrupt bits + class es550x_irq_t : public vgsound_emu_core + { + public: + es550x_irq_t() + : vgsound_emu_core("es550x_irq") + , m_voice(0) + , m_irqb(1) + { + } + + void reset() + { + m_voice = 0; + m_irqb = 1; + } + + // setter + void set(u8 index) + { + m_irqb = 0; + m_voice = index & 0x1f; + } + + void clear() + { + m_irqb = 1; + m_voice = 0; + } + + // getter + inline bool irqb() { return m_irqb; } + + inline u8 voice() { return m_voice; } + + inline u8 get() { return (m_irqb << 7) | (m_voice & 0x1f); } + + u8 m_voice : 5; + u8 m_irqb : 1; + }; + + // Common voice class + class es550x_voice_t : public vgsound_emu_core + { + private: + // Common control bits + class es550x_control_t : public vgsound_emu_core + { + public: + es550x_control_t() + : vgsound_emu_core("es550x_voice_control") + , m_ca(0) + , m_adc(0) + , m_bs(0) + , m_cmpd(0) + { + } + + void reset() + { + m_ca = 0; + m_adc = 0; + m_bs = 0; + m_cmpd = 0; + } + + // setters + inline void set_ca(u8 ca) { m_ca = ca & 0xf; } + + inline void set_adc(bool adc) { m_adc = adc ? 1 : 0; } + + inline void set_bs(u8 bs) { m_bs = bs & 0x3; } + + inline void set_cmpd(bool cmpd) { m_cmpd = cmpd ? 1 : 0; } + + // getters + inline u8 ca() { return m_ca; } + + inline bool adc() { return m_adc; } + + inline u8 bs() { return m_bs; } + + inline bool cmpd() { return m_cmpd; } + + protected: + // Channel assign - + // 4 bit (16 channel or Bank) for ES5504 + // 2 bit (4 stereo channels) for ES5505 + // 3 bit (6 stereo channels) for ES5506 + u8 m_ca : 4; + + // ES5504 Specific + u8 m_adc : 1; // Start ADC + + // ES5505/ES5506 Specific + u8 m_bs : 2; // Bank bit (1 bit for ES5505, 2 bit for ES5506) + u8 m_cmpd : 1; // Use compressed sample format (ES5506) + }; + + // Accumulator + class es550x_alu_t : public vgsound_emu_core + { + public: + es550x_alu_t(u8 integer, u8 fraction, bool transwave) + : vgsound_emu_core("es550x_voice_alu") + , m_integer(integer) + , m_fraction(fraction) + , m_total_bits(integer + fraction) + , m_accum_mask( + u32(std::min(~0, u64(u64(1) << u64(integer + fraction)) - 1))) + , m_transwave(transwave) + , m_fc(0) + , m_start(0) + , m_end(0) + , m_accum(0) + , m_sample({0}) + { + } + + // configurations + const u8 m_integer; + const u8 m_fraction; + const u8 m_total_bits; + const u32 m_accum_mask; + const bool m_transwave; + + // internal states + void reset(); + bool tick(); + + void loop_exec(); + bool busy(); + s32 interpolation(); + u32 get_accum_integer(); + + void irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index); + + void irq_update(es550x_intf &intf, es550x_irq_t &irqv) + { + intf.irqb(irqv.irqb() ? false : true); + } + + // setters + inline void set_stop0(bool stop0) { m_cr.set_stop0(stop0); } + + inline void set_stop1(bool stop1) { m_cr.set_stop1(stop1); } + + inline void set_lpe(bool lpe) { m_cr.set_lpe(lpe); } + + inline void set_ble(bool ble) { m_cr.set_ble(ble); } + + inline void set_irqe(bool irqe) { m_cr.set_irqe(irqe); } + + inline void set_dir(bool dir) { m_cr.set_dir(dir); } + + inline void set_irq(bool irq) { m_cr.set_irq(irq); } + + inline void set_lei(bool lei) { m_cr.set_lei(lei); } + + inline void set_stop(u8 stop) { m_cr.set_stop(stop); } + + inline void set_loop(u8 loop) { m_cr.set_loop(loop); } + + inline void set_fc(u32 fc) { m_fc = fc; } + + inline void set_start(u32 start, u32 mask = ~0) + { + m_start = (m_start & ~mask) | (start & mask); + } + + inline void set_end(u32 end, u32 mask = ~0) + { + m_end = (m_end & ~mask) | (end & mask); + } + + inline void set_accum(u32 accum, u32 mask = ~0) + { + m_accum = (m_accum & ~mask) | (accum & mask); + } + + inline void set_sample(u8 slot, s32 sample) { m_sample[slot & 1] = sample; } + + // getters + inline bool stop0() { return m_cr.stop0(); } + + inline bool stop1() { return m_cr.stop1(); } + + inline bool lpe() { return m_cr.lpe(); } + + inline bool ble() { return m_cr.ble(); } + + inline bool irqe() { return m_cr.irqe(); } + + inline bool dir() { return m_cr.dir(); } + + inline bool irq() { return m_cr.irq(); } + + inline bool lei() { return m_cr.lei(); } + + inline u8 stop() { return m_cr.stop(); } + + inline u8 loop() { return m_cr.loop(); } + + inline u32 fc() { return m_fc; } + + inline u32 start() { return m_start; } + + inline u32 end() { return m_end; } + + inline u32 accum() { return m_accum; } + + inline s32 sample(u8 slot) { return m_sample[slot & 1]; } + + private: + class es550x_alu_cr_t : public vgsound_emu_core + { + public: + es550x_alu_cr_t() + : vgsound_emu_core("es550x_voice_alu_cr") + , m_stop0(0) + , m_stop1(0) + , m_lpe(0) + , m_ble(0) + , m_irqe(0) + , m_dir(0) + , m_irq(0) + , m_lei(0) + { + } + + void reset() + { + m_stop0 = 0; + m_stop1 = 0; + m_lpe = 0; + m_ble = 0; + m_irqe = 0; + m_dir = 0; + m_irq = 0; + m_lei = 0; + } + + // setters + inline void set_stop0(bool stop0) { m_stop0 = stop0 ? 1 : 0; } + + inline void set_stop1(bool stop1) { m_stop1 = stop1 ? 1 : 0; } + + inline void set_lpe(bool lpe) { m_lpe = lpe ? 1 : 0; } + + inline void set_ble(bool ble) { m_ble = ble ? 1 : 0; } + + inline void set_irqe(bool irqe) { m_irqe = irqe ? 1 : 0; } + + inline void set_dir(bool dir) { m_dir = dir ? 1 : 0; } + + inline void set_irq(bool irq) { m_irq = irq ? 1 : 0; } + + inline void set_lei(bool lei) { m_lei = lei ? 1 : 0; } + + inline void set_stop(u8 stop) + { + m_stop0 = (stop >> 0) & 1; + m_stop1 = (stop >> 1) & 1; + } + + inline void set_loop(u8 loop) + { + m_lpe = (loop >> 0) & 1; + m_ble = (loop >> 1) & 1; + } + + // getters + inline bool stop0() { return m_stop0; } + + inline bool stop1() { return m_stop1; } + + inline bool lpe() { return m_lpe; } + + inline bool ble() { return m_ble; } + + inline bool irqe() { return m_irqe; } + + inline bool dir() { return m_dir; } + + inline bool irq() { return m_irq; } + + inline bool lei() { return m_lei; } + + inline u8 stop() { return (m_stop0 << 0) | (m_stop1 << 1); } + + inline u8 loop() { return (m_lpe << 0) | (m_ble << 1); } + + private: + u8 m_stop0 : 1; // Stop with ALU + u8 m_stop1 : 1; // Stop with processor + u8 m_lpe : 1; // Loop enable + u8 m_ble : 1; // Bidirectional loop enable + u8 m_irqe : 1; // IRQ enable + u8 m_dir : 1; // Playback direction + u8 m_irq : 1; // IRQ bit + u8 m_lei : 1; // Loop end ignore (ES5506 specific) + }; + + es550x_alu_cr_t m_cr; + // Frequency - + // 6 integer, 9 fraction for ES5504/ES5505 + // 6 integer, 11 fraction for ES5506 + u32 m_fc = 0; + u32 m_start = 0; // Start register + u32 m_end = 0; // End register + + // Accumulator - + // 20 integer, 9 fraction for ES5504/ES5505 + // 21 integer, 11 fraction for ES5506 + u32 m_accum = 0; + // Samples + std::array m_sample = {0}; + }; + + // Filter + class es550x_filter_t : public vgsound_emu_core + { + public: + es550x_filter_t() + : vgsound_emu_core("es550x_voice_filter") + , m_lp(0) + , m_k2(0) + , m_k1(0) + { + for (std::array &elem : m_o) + { + std::fill(elem.begin(), elem.end(), 0); + } + } + + void reset(); + void tick(s32 in); + + // setters + inline void set_lp(u8 lp) { m_lp = lp & 3; } + + inline void set_k2(s32 k2) { m_k2 = k2; } + + inline void set_k1(s32 k1) { m_k1 = k1; } + + inline void set_o1_1(s32 o1_1) { m_o[1][0] = o1_1; } + + inline void set_o2_1(s32 o2_1) { m_o[2][0] = o2_1; } + + inline void set_o2_2(s32 o2_2) { m_o[2][1] = o2_2; } + + inline void set_o3_1(s32 o3_1) { m_o[3][0] = o3_1; } + + inline void set_o3_2(s32 o3_2) { m_o[3][1] = o3_2; } + + inline void set_o4_1(s32 o4_1) { m_o[4][0] = o4_1; } + + // getters + inline u8 lp() { return m_lp; } + + inline s32 k2() { return m_k2; } + + inline s32 k1() { return m_k1; } + + inline s32 o1_1() { return m_o[1][0]; } + + inline s32 o2_1() { return m_o[2][0]; } + + inline s32 o2_2() { return m_o[2][1]; } + + inline s32 o3_1() { return m_o[3][0]; } + + inline s32 o3_2() { return m_o[3][1]; } + + inline s32 o4_1() { return m_o[4][0]; } + + private: + void lp_exec(s32 coeff, s32 in, s32 out); + void hp_exec(s32 coeff, s32 in, s32 out); + + // Registers + u8 m_lp = 0; // Filter mode + // Filter coefficient registers + // 12 bit for filter calculation, 4 + // LSBs are used for fine control of ramp increment for + // hardware envelope (ES5506) + s32 m_k2 = 0; // Filter coefficient 2 + s32 m_k1 = 0; // Filter coefficient 1 + + // Filter storage registers + std::array, 5> m_o; + }; + + public: + es550x_voice_t(std::string tag, u8 integer, u8 fraction, bool transwave) + : vgsound_emu_core(tag) + , m_cr(es550x_control_t()) + , m_alu(integer, fraction, transwave) + , m_filter(es550x_filter_t()) + { + } + + // internal state + virtual void reset(); + virtual void fetch(u8 voice, u8 cycle) = 0; + virtual void tick(u8 voice) = 0; + + void irq_update(es550x_intf &intf, es550x_irq_t &irqv) + { + m_alu.irq_update(intf, irqv); + } + + // Getters + es550x_control_t &cr() { return m_cr; } + + es550x_alu_t &alu() { return m_alu; } + + es550x_filter_t &filter() { return m_filter; } + + protected: + es550x_control_t m_cr; + es550x_alu_t m_alu; + es550x_filter_t m_filter; + }; + + // Host interfaces + class host_interface_flag_t : public vgsound_emu_core + { + public: + host_interface_flag_t() + : vgsound_emu_core("es550x_host_interface_flag") + , m_host_access(0) + , m_host_access_strobe(0) + , m_rw(0) + , m_rw_strobe(0) + { + } + + // Accessors + void reset() + { + m_host_access = 0; + m_host_access_strobe = 0; + m_rw = 0; + m_rw_strobe = 0; + } + + // Setters + void set_strobe(bool rw) + { + m_rw_strobe = rw ? 1 : 0; + m_host_access_strobe = 1; + } + + void clear_strobe() { m_host_access_strobe = 0; } + + void clear_host_access() { m_host_access = 0; } + + void update_strobe() + { + m_rw = m_rw_strobe; + m_host_access = m_host_access_strobe; + } + + // Getters + bool host_access() { return m_host_access; } + + bool rw() { return m_rw; } + + private: + u8 m_host_access : 1; // Host access trigger + u8 m_host_access_strobe : 1; // Host access strobe + u8 m_rw : 1; // R/W state + u8 m_rw_strobe : 1; // R/W strobe + }; + + public: + // internal state + virtual void reset(); + + virtual void tick() {} + + // clock outputs + inline bool _cas() { return m_cas.current_edge(); } + + inline bool _cas_rising_edge() { return m_cas.rising_edge(); } + + inline bool _cas_falling_edge() { return m_cas.falling_edge(); } + + inline bool e() { return m_e.current_edge(); } + + inline bool e_rising_edge() { return m_e.rising_edge(); } + + inline bool e_falling_edge() { return m_e.falling_edge(); } + + //----------------------------------------------------------------- + // + // for preview/debug purpose only, not for serious emulators + // + //----------------------------------------------------------------- + + // voice cycle + inline u8 voice_cycle() { return m_voice_cycle; } + + // voice update flag + inline bool voice_update() { return m_voice_update; } + + inline bool voice_end() { return m_voice_end; } + + protected: + // constructor + es550x_shared_core(std::string tag, const u8 voice, es550x_intf &intf) + : vgsound_emu_core(tag) + , m_max_voices(voice) + , m_intf(intf) + , m_host_intf(host_interface_flag_t()) + , m_ha(0) + , m_hd(0) + , m_page(0) + , m_irqv(es550x_irq_t()) + , m_active(m_max_voices - 1) + , m_voice_cycle(0) + , m_voice_fetch(0) + , m_voice_update(0) + , m_voice_end(0) + , m_clkin(clock_pulse_t(1, 0)) + , m_cas(clock_pulse_t(2, 1)) + , m_e(clock_pulse_t(4, 0)) + { + } + + // Constants + virtual inline u8 max_voices() { return m_max_voices; } + + // Shared registers, functions + virtual void voice_tick() {} // voice tick + + es550x_intf &m_intf; // es550x specific memory interface + host_interface_flag_t m_host_intf; // Host interface flag + u8 m_ha = 0; // Host address (4 bit) + u16 m_hd = 0; // Host data (16 bit for ES5504/ES5505, 8 bit for ES5506) + u8 m_page = 0; // Page + es550x_irq_t m_irqv; // Voice interrupt vector registers + + // Internal states + u8 m_active = 31; // Activated voices + // -1, ~25 for ES5504, + // ~32 for ES5505/ES5506 + u8 m_voice_cycle = 0; // Voice cycle + u8 m_voice_fetch = 0; // Voice fetch cycle + bool m_voice_update = false; // Voice update flag + bool m_voice_end = false; // End of one voice cycle flag + clock_pulse_t m_clkin; // CLKIN clock + clock_pulse_t m_cas; // /CAS clock (CLKIN / 4), falling edge of + // CLKIN trigger this clock + clock_pulse_t m_e; // E clock (CLKIN / 8), + // falling edge of CLKIN trigger this clock +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp new file mode 100644 index 000000000..f058f0546 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp @@ -0,0 +1,131 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core +*/ + +#include "es550x.hpp" + +// Accumulator functions +void es550x_shared_core::es550x_voice_t::es550x_alu_t::reset() +{ + m_cr.reset(); + m_fc = 0; + m_start = 0; + m_end = 0; + m_accum = 0; + m_sample[0] = m_sample[1] = 0; +} + +bool es550x_shared_core::es550x_voice_t::es550x_alu_t::busy() { return m_cr.stop() == 0; } + +bool es550x_shared_core::es550x_voice_t::es550x_alu_t::tick() +{ + if (m_cr.dir()) + { + m_accum -= m_fc; + } + else + { + m_accum += m_fc; + } + + m_accum &= m_accum_mask; + return ((!m_cr.lei()) && + (((m_cr.dir()) && (m_accum < m_start)) || ((!m_cr.dir()) && (m_accum > m_end)))) + ? true + : false; +} + +void es550x_shared_core::es550x_voice_t::es550x_alu_t::loop_exec() +{ + if (m_cr.irqe()) + { // Set IRQ + m_cr.set_irq(true); + } + + if (m_cr.dir()) // Reverse playback + { + if (m_cr.lpe()) // Loop enable + { + if (m_cr.ble()) // Bidirectional + { + m_cr.set_dir(false); + m_accum = m_start + (m_start - m_accum); + } + else + { // Normal + m_accum = m_end - (m_start - m_accum); + } + } + else if (m_cr.ble() && m_transwave) // m_transwave + { + m_cr.set_loop(0); + m_cr.set_lei(true); // Loop end ignore + m_accum = m_end - (m_start - m_accum); + } + else + { // Stop + m_cr.set_stop0(true); + } + } + else + { + if (m_cr.lpe()) // Loop enable + { + if (m_cr.ble()) // Bidirectional + { + m_cr.set_dir(true); + m_accum = m_end - (m_end - m_accum); + } + else + { // Normal + m_accum = (m_accum - m_end) + m_start; + } + } + else if (m_cr.ble() && m_transwave) // m_transwave + { + m_cr.set_loop(0); + m_cr.set_lei(true); // Loop end ignore + m_accum = (m_accum - m_end) + m_start; + } + else + { // Stop + m_cr.set_stop0(true); + } + } +} + +s32 es550x_shared_core::es550x_voice_t::es550x_alu_t::interpolation() +{ + // SF = S1 + ACCfr * (S2 - S1) + return m_sample[0] + ((bitfield(m_accum, std::max(0, m_fraction - 9), 9) * + (m_sample[1] - m_sample[0])) >> + 9); +} + +u32 es550x_shared_core::es550x_voice_t::es550x_alu_t::get_accum_integer() +{ + return bitfield(m_accum, m_fraction, m_integer); +} + +void es550x_shared_core::es550x_voice_t::es550x_alu_t::irq_exec(es550x_intf &intf, + es550x_irq_t &irqv, + u8 index) +{ + const bool prev = irqv.irqb(); + if (m_cr.irq()) + { + if (irqv.irqb()) + { + irqv.set(index); + m_cr.set_irq(false); + } + } + if (prev != irqv.irqb()) + { + irq_update(intf, irqv); + } +} diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp new file mode 100644 index 000000000..360cab813 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp @@ -0,0 +1,72 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 Shared Filter emulation core +*/ + +#include "es550x.hpp" + +// Filter functions +void es550x_shared_core::es550x_voice_t::es550x_filter_t::reset() +{ + m_lp = 0; + m_k2 = 0; + m_k1 = 0; + for (std::array &elem : m_o) + { + std::fill(elem.begin(), elem.end(), 0); + } +} + +void es550x_shared_core::es550x_voice_t::es550x_filter_t::tick(s32 in) +{ + // set sample input + m_o[0][0] = in; + + s32 coeff_k1 = s32(bitfield(m_k1, 4, 12)); // 12 MSB used + s32 coeff_k2 = s32(bitfield(m_k2, 4, 12)); // 12 MSB used + + // First and second stage: LP/K1, LP/K1 Fixed + lp_exec(coeff_k1, 0, 1); + lp_exec(coeff_k1, 1, 2); + switch (m_lp) + { + case 0: // LP3 = 0, LP4 = 0: HP/K2, HP/K2 + default: + hp_exec(coeff_k2, 2, 3); + hp_exec(coeff_k2, 3, 4); + break; + case 1: // LP3 = 0, LP4 = 1: HP/K2, LP/K1 + lp_exec(coeff_k1, 2, 3); + hp_exec(coeff_k2, 3, 4); + break; + case 2: // LP3 = 1, LP4 = 0: LP/K2, LP/K2 + lp_exec(coeff_k2, 2, 3); + lp_exec(coeff_k2, 3, 4); + break; + case 3: // LP3 = 1, LP4 = 1: LP/K2, LP/K1 + lp_exec(coeff_k1, 2, 3); + lp_exec(coeff_k2, 3, 4); + break; + } +} + +void es550x_shared_core::es550x_voice_t::es550x_filter_t::lp_exec(s32 coeff, s32 in, s32 out) +{ + // Store previous filter data + m_o[out][1] = m_o[out][0]; + + // Yn = K*(Xn - Yn-1) + Yn-1 + m_o[out][0] = ((coeff * (m_o[in][0] - m_o[out][0])) / 4096) + m_o[out][0]; +} + +void es550x_shared_core::es550x_voice_t::es550x_filter_t::hp_exec(s32 coeff, s32 in, s32 out) +{ + // Store previous filter data + m_o[out][1] = m_o[out][0]; + + // Yn = Xn - Xn-1 + K*Yn-1 + m_o[out][0] = m_o[in][0] - m_o[in][1] + ((coeff * m_o[out][0]) / 8192) + (m_o[out][0] / 2); +} diff --git a/vgsound_emu-modified/vgsound_emu/src/k005289/README.md b/vgsound_emu-modified/vgsound_emu/src/k005289/README.md new file mode 100644 index 000000000..cc297b2f4 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k005289/README.md @@ -0,0 +1,23 @@ +# Konami K005289 + +## Summary + +- 2 12 bit timer +- Address generator + +## Source code + +- k005289.hpp: Base header + - k005289.cpp: Source emulation core + +## Description + +This chip is used at infamous Konami Bubble System, for part of Wavetable sound generator. But seriously, It is just to 2 internal 12 bit timer and address generators, rather than sound generator. + +Everything except for internal counter and address are done by external logic, the chip is only has external address, frequency registers and its update pins. + +## Frequency calculation + +``` +Input clock / (4096 - Pitch input) +``` diff --git a/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp b/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp new file mode 100644 index 000000000..464ce5bc9 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp @@ -0,0 +1,42 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami K005289 emulation core +*/ + +#include "k005289.hpp" + +void k005289_core::tick() +{ + for (timer_t &elem : m_timer) + { + elem.tick(); + } +} + +void k005289_core::reset() +{ + for (timer_t &elem : m_timer) + { + elem.reset(); + } +} + +void k005289_core::timer_t::tick() +{ + if (bitfield(++m_counter, 0, 12) == 0) + { + m_addr = bitfield(m_addr + 1, 0, 5); + m_counter = m_freq; + } +} + +void k005289_core::timer_t::reset() +{ + m_addr = 0; + m_pitch = 0; + m_freq = 0; + m_counter = 0; +} diff --git a/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp b/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp new file mode 100644 index 000000000..6fae1f2cb --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp @@ -0,0 +1,83 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami K005289 emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_K005289_HPP +#define _VGSOUND_EMU_SRC_K005289_HPP + +#pragma once + +#include "../core/util.hpp" + +class k005289_core : public vgsound_emu_core +{ + private: + // k005289 timer classes + class timer_t : public vgsound_emu_core + { + public: + timer_t() + : vgsound_emu_core("k005289_timer") + , m_addr(0) + , m_pitch(0) + , m_freq(0) + , m_counter(0) + { + } + + // internal state + void reset(); + void tick(); + + // accessors + // Replace current frequency to lastest loaded pitch + inline void update() { m_freq = m_pitch; } + + // setters + // Load pitch data (address pin) + inline void load(u16 pitch) { m_pitch = pitch; } + + // getters + inline u8 addr() { return m_addr; } + + private: + // registers + u8 m_addr = 0; // external address pin + u16 m_pitch = 0; // pitch + u16 m_freq = 0; // current frequency + s16 m_counter = 0; // frequency counter + }; + + public: + // constructor + k005289_core() + : vgsound_emu_core("k005289") + , m_timer{timer_t()} + { + } + + // internal state + void reset(); + void tick(); + + // accessors + // TG1/2 pin + inline void update(int voice) { m_timer[voice & 1].update(); } + + // setters + // LD1/2 pin, A0...11 pin + inline void load(int voice, u16 addr) { m_timer[voice & 1].load(addr); } + + // getters + // 1QA...E/2QA...E pin + inline u8 addr(int voice) { return m_timer[voice & 1].addr(); } + + private: + std::array m_timer; +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/k007232/README.md b/vgsound_emu-modified/vgsound_emu/src/k007232/README.md new file mode 100644 index 000000000..790d31077 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k007232/README.md @@ -0,0 +1,75 @@ +# Konami K007232 + +## Summary + +- 2 voice PCM + - 7 bit unsigned, with end marker + - total accessible memory: 128 Kbyte per bank + - Per-voice bankswitchable via E clock +- External 8 bit I/O (usually for volume) + +## Source code + +- k007232.hpp: Base header + - k007232.cpp: Source emulation core + +## Description + +It's Konami's one of custom PCM sound chip, Used at their arcade hardware at mid-80s to early-90s. + +It has 2 channel of PCM, these are has its own output pins...just 7 LSB of currently fetched data. + +PCM Sample format is unique, 1 MSB is end marker and 7 LSB is actually output. (unsigned format) + +The chip itself is DACless, so Sound output and mixing control needs external logics and sound DAC. + +## Register layout + +``` + Address Bits R/W Description + 7654 3210 + + 0x0 xxxx xxxx W Channel 0 Pitch bit 0-7 + 0x1 --x- ---- W Channel 0 4 bit Frequency mode + ---x ---- W Channel 0 8 bit Frequency mode + ---- xxxx W Channel 0 Pitch bit 8-11 + + 0x2 xxxx xxxx W Channel 0 Start address bit 0-7 + 0x3 xxxx xxxx W Channel 0 Start address bit 8-15 + 0x4 ---- ---x W Channel 0 Start address bit 16 + + 0x5 R/W Channel 0 Key on trigger (R/W) + + 0x6 xxxx xxxx W Channel 1 Pitch bit 0-7 + 0x7 --x- ---- W Channel 1 4 bit Frequency mode + ---x ---- W Channel 1 8 bit Frequency mode + ---- xxxx W Channel 1 Pitch bit 8-11 + + 0x8 xxxx xxxx W Channel 1 Start address bit 0-7 + 0x9 xxxx xxxx W Channel 1 Start address bit 8-15 + 0xa ---- ---x W Channel 1 Start address bit 16 + + 0xb R/W Channel 1 Key on trigger (R/W) + + 0xc xxxx xxxx W External port write (w/SLEV pin, Usually for volume control) + + 0xd ---- --x- W Channel 1 Loop enable + ---- ---x W Channel 0 Loop enable +``` + +## Frequency calculation + +(Guesswork in 8/4 bit Frequency mode) + +``` + if 8 bit Frequency mode then + Frequency: Input clock / 4 * (256 - (Pitch bit 0 - 7)) + else if 4 bit Frequency mode then + Frequency: Input clock / 4 * (16 - (Pitch bit 8 - 11)) + else + Frequency: Input clock / 4 * (4096 - (Pitch bit 0 - 11)) +``` + +## Reference + + diff --git a/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp b/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp new file mode 100644 index 000000000..3798f4c81 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp @@ -0,0 +1,169 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami K007232 core +*/ + +#include "k007232.hpp" + +void k007232_core::tick() +{ + for (int i = 0; i < 2; i++) + { + m_voice[i].tick(i); + } +} + +void k007232_core::voice_t::tick(u8 ne) +{ + if (m_busy) + { + const bool is4bit = bitfield(m_pitch, 13); // 4 bit frequency divider flag + const bool is8bit = bitfield(m_pitch, 12); // 8 bit frequency divider flag + + // update counter + if (is4bit) + { + m_counter = (m_counter & ~0x0ff) | (bitfield(bitfield(m_counter, 0, 8) + 1, 0, 8) << 0); + m_counter = (m_counter & ~0xf00) | (bitfield(bitfield(m_counter, 8, 4) + 1, 0, 4) << 8); + } + else + { + m_counter++; + } + + // handle counter carry + bool carry = + is8bit ? (bitfield(m_counter, 0, 8) == 0) + : (is4bit ? (bitfield(m_counter, 8, 4) == 0) : (bitfield(m_counter, 0, 12) == 0)); + if (carry) + { + m_counter = bitfield(m_pitch, 0, 12); + if (is4bit) // 4 bit frequency has different behavior for address + { + m_addr = (m_addr & ~0x0000f) | (bitfield(bitfield(m_addr, 0, 4) + 1, 0, 4) << 0); + m_addr = (m_addr & ~0x000f0) | (bitfield(bitfield(m_addr, 4, 4) + 1, 0, 4) << 4); + m_addr = (m_addr & ~0x00f00) | (bitfield(bitfield(m_addr, 8, 4) + 1, 0, 4) << 8); + m_addr = (m_addr & ~0x1f000) | (bitfield(bitfield(m_addr, 12, 5) + 1, 0, 5) << 12); + } + else + { + m_addr = bitfield(m_addr + 1, 0, 17); + } + } + + m_data = m_host.m_intf.read_sample(ne, bitfield(m_addr, 0, 17)); // fetch ROM + if (bitfield(m_data, 7)) // check end marker + { + if (m_loop) + { + m_addr = m_start; + } + else + { + m_busy = false; + } + } + + m_out = s8(m_data) - 0x40; // send to output (ASD/BSD) pin + } + else + { + m_out = 0; + } +} + +void k007232_core::write(u8 address, u8 data) +{ + address &= 0xf; // 4 bit for CPU write + + switch (address) + { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: // voice 0 + case 0x6: + case 0x7: + case 0x8: + case 0x9: + case 0xa: + case 0xb: // voice 1 + m_voice[(address / 6) & 1].write(address % 6, data); + break; + case 0xc: // external register with SLEV pin + m_intf.write_slev(data); + break; + case 0xd: // loop flag + m_voice[0].set_loop(bitfield(data, 0)); + m_voice[1].set_loop(bitfield(data, 1)); + break; + default: break; + } + + m_reg[address] = data; +} + +// write registers on each voices +void k007232_core::voice_t::write(u8 address, u8 data) +{ + switch (address) + { + case 0: // pitch LSB + m_pitch = (m_pitch & ~0x00ff) | data; + break; + case 1: // pitch MSB, divider + m_pitch = (m_pitch & ~0x3f00) | (u16(bitfield(data, 0, 6)) << 8); + break; + case 2: // start address bit 0-7 + m_start = (m_start & ~0x000ff) | data; + break; + case 3: // start address bit 8-15 + m_start = (m_start & ~0x0ff00) | (u32(data) << 8); + break; + case 4: // start address bit 16 + m_start = (m_start & ~0x10000) | (u32(bitfield(data, 16)) << 16); + break; + case 5: // keyon trigger + keyon(); + break; + } +} + +// key on trigger (write OR read 0x05/0x11 register) +void k007232_core::voice_t::keyon() +{ + m_busy = true; + m_counter = bitfield(m_pitch, 0, 12); + m_addr = m_start; +} + +// reset chip +void k007232_core::reset() +{ + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_intf.write_slev(0); + + std::fill(m_reg.begin(), m_reg.end(), 0); +} + +// reset voice +void k007232_core::voice_t::reset() +{ + m_busy = false; + m_loop = false; + m_pitch = 0; + m_start = 0; + m_counter = 0; + m_addr = 0; + m_data = 0; + m_out = 0; +} diff --git a/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp b/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp new file mode 100644 index 000000000..d500f091a --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp @@ -0,0 +1,115 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami K007232 core +*/ + +#ifndef _VGSOUND_EMU_SRC_K007232_HPP +#define _VGSOUND_EMU_SRC_K007232_HPP + +#pragma once + +#include "../core/util.hpp" + +class k007232_intf : public vgsound_emu_core +{ + public: + k007232_intf() + : vgsound_emu_core("k007232_intf") + { + } + + // NE pin is executing voice number, and used for per-voice sample bank. + virtual u8 read_sample(u8 ne, u32 address) { return 0; } + + // SLEV pin actived when 0x0c register accessed + virtual void write_slev(u8 out) {} +}; + +class k007232_core : public vgsound_emu_core +{ + friend class k007232_intf; // k007232 specific interface + + private: + class voice_t : public vgsound_emu_core + { + public: + // constructor + voice_t(k007232_core &host) + : vgsound_emu_core("k007232_voice") + , m_host(host) + , m_busy(false) + , m_loop(false) + , m_pitch(0) + , m_start(0) + , m_counter(0) + , m_addr(0) + , m_data(0) + , m_out(0) + { + } + + // internal state + void reset(); + void tick(u8 ne); + + // accessors + void write(u8 address, u8 data); + void keyon(); + + // setters + inline void set_loop(bool loop) { m_loop = loop; } + + // getters + inline s8 out() { return m_out; } + + private: + // registers + k007232_core &m_host; + bool m_busy = false; // busy status + bool m_loop = false; // loop flag + u16 m_pitch = 0; // pitch, frequency divider + u32 m_start = 0; // start position when keyon or loop start position at + // when reach end marker if loop enabled + u16 m_counter = 0; // frequency counter + u32 m_addr = 0; // current address + u8 m_data = 0; // current data + s8 m_out = 0; // current output (7 bit unsigned) + }; + + public: + // constructor + k007232_core(k007232_intf &intf) + : vgsound_emu_core("k007232") + , m_voice{*this, *this} + , m_intf(intf) + , m_reg{0} + { + } + + // host accessors + void keyon(u8 voice) { m_voice[voice & 1].keyon(); } + + void write(u8 address, u8 data); + + // internal state + void reset(); + void tick(); + + // output for each voices, ASD/BSD pin + inline s32 output(u8 voice) { return m_voice[voice & 1].out(); } + + // getters for debug, trackers, etc + inline u8 reg_r(u8 address) { return m_reg[address & 0xf]; } + + private: + std::array m_voice; + + k007232_intf &m_intf; // common memory interface + + std::array m_reg = {0}; // register pool +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/k053260/README.md b/vgsound_emu-modified/vgsound_emu/src/k053260/README.md new file mode 100644 index 000000000..e34947f97 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k053260/README.md @@ -0,0 +1,109 @@ +# Konami K053260 + +## Summary + +- 4 voice DPCM or PCM + - 8 bit signed PCM or 4 bit DPCM (unique type) + - total accessible memory: 2 MByte, 64 KByte per sample +- CPU to CPU Communication +- CPU can be accessible k053260 memory through voice register +- 2 Stereo sound input, 1 Stereo output (YM3012 DAC compatible) + +## Source code + +- k053260.hpp: Base header + - k053260.cpp: Source emulation core + +## Description + +It's one of Konami's custom PCM playback chip with CPU to CPU communication feature, and built in timer. + +It's architecture is successed from K007232, but it features various enhancements: + +it's expanded to 4 channels, Supports more memory space, 4 bit DPCM, Built in volume and stereo panning support, and Dual chip configurations. + +There's 2 stereo inputs and single stereo output, Both format is YM3012 compatible. + +## Register layout + +``` +Address Bits R/W Description + 7654 3210 + +00...03 Communication Registers + +00 xxxx xxxx R Answer from host CPU LSB +01 xxxx xxxx R Answer from host CPU MSB + +02 xxxx xxxx W Reply to host CPU LSB +03 xxxx xxxx W Reply to host CPU MSB + +08...0f Voice 0 Register + +08 xxxx xxxx W Pitch bit 0-7 +09 ---- xxxx W Pitch bit 8-11 + +0a xxxx xxxx W Source length bit 0-7 (byte wide) +0b xxxx xxxx W Source length bit 8-15 (byte wide) + +0c xxxx xxxx W Start address/ROM readback base bit 0-7 +0d xxxx xxxx W Start address/ROM readback base bit 8-15 +0e ---x xxxx W Start address/ROM readback base bit 16-20 + +0f -xxx xxxx W Volume + +10...17 Voice 1 Register +18...1f Voice 2 Register +20...27 Voice 3 Register + +28 ---- x--- W Voice 3 Key on/off trigger + ---- -x-- W Voice 2 Key on/off trigger + ---- --x- W Voice 1 Key on/off trigger + ---- ---x W Voice 0 Key on/off trigger + +29 ---- x--- R Voice 3 busy + ---- -x-- R Voice 2 busy + ---- --x- R Voice 1 busy + ---- ---x R Voice 0 busy + +2a x--- ---- W Voice 3 source format + 0--- ---- 8 bit signed PCM + 1--- ---- 4 bit ADPCM + -x-- ---- W Voice 2 source format + --x- ---- W Voice 1 source format + ---x ---- W Voice 0 source format + + ---- x--- W Voice 3 Loop enable + ---- -x-- W Voice 2 Loop enable + ---- --x- W Voice 1 Loop enable + ---- ---x W Voice 0 Loop enable + +2c --xx x--- W Voice 1 Pan angle in degrees*1 + --00 0--- Mute + --00 1--- 0 degrees + --01 0--- 24 degrees + --01 1--- 35 degrees + --10 0--- 45 degrees + --10 1--- 55 degrees + --11 0--- 66 degrees + --11 1--- 90 degrees + ---- -xxx W Voice 0 Pan angle in degrees*1 + +2d --xx x--- W Voice 3 Pan angle in degrees*1 + ---- -xxx W Voice 2 Pan angle in degrees*1 + +2e xxxx xxxx R ROM readback (use Voice 0 register) + +2f ---- x--- W AUX2 input enable + ---- -x-- W AUX1 input enable + ---- --x- W Sound enable + ---- ---x W ROM readbank enable + +*1 Actually fomula unknown, Use floating point type until explained that. +``` + +## Frequency calculation + +``` + Frequency: Input clock / (4096 - Pitch) +``` diff --git a/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp b/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp new file mode 100644 index 000000000..6fe759ac2 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp @@ -0,0 +1,290 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami K053260 core +*/ + +#include "k053260.hpp" + +void k053260_core::tick() +{ + m_out[0] = m_out[1] = 0; + if (m_ctrl.sound_en()) + { + for (int i = 0; i < 4; i++) + { + m_voice[i].tick(i); + m_out[0] += m_voice[i].out(0); + m_out[1] += m_voice[i].out(1); + } + } + // dac clock (YM3012 format) + u8 dac_clock = m_dac.clock(); + if (bitfield(++dac_clock, 0, 4) == 0) + { + m_intf.write_int(m_dac.state()); + u8 dac_state = m_dac.state(); + if (bitfield(++dac_state, 0) == 0) + { + m_ym3012.tick(bitfield(dac_state, 1), m_out[bitfield(dac_state, 1) ^ 1]); + } + + m_dac.set_state(bitfield(dac_state, 0, 2)); + } + m_dac.set_clock(bitfield(dac_clock, 0, 4)); +} + +void k053260_core::voice_t::tick(u8 ne) +{ + if (m_enable && m_busy) + { + bool update = false; + // update counter + if (bitfield(++m_counter, 0, 12) == 0) + { + if (m_bitpos < 8) + { + m_bitpos += 8; + m_addr = bitfield(m_addr + 1, 0, 21); + m_remain--; + } + if (m_adpcm) + { + m_bitpos -= 4; + update = true; + } + else + { + m_bitpos -= 8; + } + } + m_data = m_host.m_intf.read_sample(bitfield(m_addr, 0, 21)); // fetch ROM + if (update) + { + const u8 nibble = bitfield(m_data, m_bitpos & 4, 4); // get nibble from ROM + if (nibble) + { + m_adpcm_buf += bitfield(nibble, 3) ? s8(0x80 >> bitfield(nibble, 0, 3)) + : (1 << bitfield(nibble - 1, 0, 3)); + } + } + + if (m_remain < 0) // check end flag + { + if (m_loop) + { + m_addr = m_start; + m_adpcm_buf = 0; + } + else + { + m_busy = false; + } + } + // calculate output + s32 output = m_adpcm ? m_adpcm_buf : sign_ext(m_data, 8) * s32(m_volume); + // use math for now; actually fomula unknown + m_out[0] = (m_pan >= 0) ? s32(output * cos(f64(m_pan) * PI / 180)) : 0; + m_out[1] = (m_pan >= 0) ? s32(output * sin(f64(m_pan) * PI / 180)) : 0; + } + else + { + m_out[0] = m_out[1] = 0; + } +} + +u8 k053260_core::read(u8 address) +{ + address &= 0x3f; // 6 bit for CPU read + + switch (address) + { + case 0x0: + case 0x1: // Answer from host + return m_host2snd[address & 1]; + break; + case 0x29: // Voice playing status + return (m_voice[0].busy() ? 0x1 : 0x0) | (m_voice[1].busy() ? 0x2 : 0x0) | + (m_voice[2].busy() ? 0x4 : 0x0) | (m_voice[3].busy() ? 0x8 : 0x0); + case 0x2e: // ROM readback + { + if (!m_ctrl.rom_read()) + { + return 0xff; + } + + const u32 rom_addr = m_voice[0].start() + m_voice[0].length(); + m_voice[0].length_inc(); + return m_intf.read_sample(rom_addr); + } + } + return 0xff; +} + +void k053260_core::write(u8 address, u8 data) +{ + address &= 0x3f; // 6 bit for CPU write + + switch (address) + { + case 0x2: + case 0x3: // Reply to host + m_snd2host[address & 1] = data; + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: // voice 0 + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: // voice 1 + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: // voice 2 + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: // voice 3 + m_voice[bitfield(address - 0x8, 3, 2)].write(bitfield(address, 0, 3), data); + break; + case 0x28: // keyon/off toggle + for (int i = 0; i < 4; i++) + { + if (bitfield(data, i) && (!m_voice[i].enable())) + { // rising edge (keyon) + m_voice[i].keyon(); + } + else if ((!bitfield(data, i)) && m_voice[i].enable()) + { // falling edge (keyoff) + m_voice[i].keyoff(); + } + } + break; + case 0x2a: // loop/adpcm flag + for (int i = 0; i < 4; i++) + { + m_voice[i].set_loop(bitfield(data, i)); + m_voice[i].set_adpcm(bitfield(data, i + 4)); + } + break; + case 0x2c: + m_voice[0].set_pan(bitfield(data, 0, 3)); + m_voice[1].set_pan(bitfield(data, 3, 3)); + break; + case 0x2d: + m_voice[2].set_pan(bitfield(data, 0, 3)); + m_voice[3].set_pan(bitfield(data, 3, 3)); + break; + case 0x2f: m_ctrl.write(data); break; + default: break; + } + + m_reg[address] = data; +} + +// write registers on each voices +void k053260_core::voice_t::write(u8 address, u8 data) +{ + switch (address) + { + case 0: // pitch LSB + m_pitch = (m_pitch & ~0x00ff) | data; + break; + case 1: // pitch MSB + m_pitch = (m_pitch & ~0x0f00) | (u16(bitfield(data, 0, 4)) << 8); + break; + case 2: // source length LSB + m_length = (m_length & ~0x000ff) | data; + break; + case 3: // source length MSB + m_length = (m_length & ~0x0ff00) | (u16(data) << 8); + break; + case 4: // start address bit 0-7 + m_start = (m_start & ~0x0000ff) | data; + break; + case 5: // start address bit 8-15 + m_start = (m_start & ~0x00ff00) | (u32(data) << 8); + break; + case 6: // start address bit 16-20 + m_start = (m_start & ~0x1f0000) | (u32(bitfield(data, 16, 5)) << 16); + break; + case 7: // volume + m_volume = bitfield(data, 0, 7); + break; + } +} + +// key on trigger +void k053260_core::voice_t::keyon() +{ + m_enable = m_busy = 1; + m_counter = bitfield(m_pitch, 0, 12); + m_addr = m_start; + m_remain = m_length; + m_bitpos = 4; + m_adpcm_buf = 0; + std::fill(m_out.begin(), m_out.end(), 0); +} + +// key off trigger +void k053260_core::voice_t::keyoff() { m_enable = m_busy = 0; } + +// reset chip +void k053260_core::reset() +{ + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_intf.write_int(0); + + std::fill(m_host2snd.begin(), m_host2snd.end(), 0); + std::fill(m_snd2host.begin(), m_snd2host.end(), 0); + m_ctrl.reset(); + m_dac.reset(); + + std::fill(m_reg.begin(), m_reg.end(), 0); + std::fill(m_out.begin(), m_out.end(), 0); +} + +// reset voice +void k053260_core::voice_t::reset() +{ + m_enable = 0; + m_busy = 0; + m_loop = 0; + m_adpcm = 0; + m_pitch = 0; + m_start = 0; + m_length = 0; + m_volume = 0; + m_pan = -1; + m_counter = 0; + m_addr = 0; + m_remain = 0; + m_bitpos = 4; + m_data = 0; + m_adpcm_buf = 0; + m_out[0] = m_out[1] = 0; +} diff --git a/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp b/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp new file mode 100644 index 000000000..de39e35ec --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp @@ -0,0 +1,262 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami K053260 core +*/ + +#ifndef _VGSOUND_EMU_SRC_K053260_HPP +#define _VGSOUND_EMU_SRC_K053260_HPP + +#pragma once + +#include "../core/util.hpp" + +class k053260_intf : public vgsound_emu_core +{ + public: + k053260_intf() + : vgsound_emu_core("k053260_intf") + { + } + + virtual u8 read_sample(u32 address) { return 0; } // sample fetch + + virtual void write_int(u8 out) {} // timer interrupt +}; + +class k053260_core : public vgsound_emu_core +{ + friend class k053260_intf; // k053260 specific interface + + private: + const int pan_dir[8] = {-1, 0, 24, 35, 45, 55, 66, 90}; // pan direction + + class voice_t : public vgsound_emu_core + { + public: + // constructor + voice_t(k053260_core &host) + : vgsound_emu_core("k053260_voice") + , m_host(host) + , m_enable(0) + , m_busy(0) + , m_loop(0) + , m_adpcm(0) + , m_pitch(0) + , m_start(0) + , m_length(0) + , m_volume(0) + , m_pan(-1) + , m_counter(0) + , m_addr(0) + , m_remain(0) + , m_bitpos(4) + , m_data(0) + , m_adpcm_buf(0) + , m_out{0} + { + } + + // internal state + void reset(); + void tick(u8 ne); + + // accessors + void write(u8 address, u8 data); + void keyon(); + void keyoff(); + + // setters + inline void set_enable(bool enable) { m_enable = enable ? 1 : 0; } + + inline void set_busy(bool busy) { m_busy = busy ? 1 : 0; } + + inline void set_loop(bool loop) { m_loop = loop ? 1 : 0; } + + inline void set_adpcm(bool adpcm) { m_adpcm = adpcm ? 1 : 0; } + + inline void length_inc() { m_length = (m_length + 1) & 0xffff; } + + inline void set_pan(u8 pan) { m_pan = m_host.pan_dir[pan & 7]; } + + // getters + inline bool enable() { return m_enable; } + + inline bool busy() { return m_busy; } + + inline u32 start() { return m_start; } + + inline u16 length() { return m_length; } + + inline s32 out(u8 ch) { return m_out[ch & 1]; } + + private: + // registers + k053260_core &m_host; + u16 m_enable : 1; // enable flag + u16 m_busy : 1; // busy status + u16 m_loop : 1; // loop flag + u16 m_adpcm : 1; // ADPCM flag + u16 m_pitch : 12; // pitch + u32 m_start = 0; // start position + u16 m_length = 0; // source length + u8 m_volume = 0; // master volume + int m_pan = -1; // master pan + u16 m_counter = 0; // frequency counter + u32 m_addr = 0; // current address + s32 m_remain = 0; // remain for end sample + u8 m_bitpos = 4; // bit position for ADPCM decoding + u8 m_data = 0; // current data + s8 m_adpcm_buf = 0; // ADPCM buffer + std::array m_out = {0}; // current output + }; + + class ctrl_t + { + public: + ctrl_t() + : m_rom_read(0) + , m_sound_en(0) + , m_input_en(0) + { + } + + void reset() + { + m_rom_read = 0; + m_sound_en = 0; + m_input_en = 0; + } + + void write(u8 data) + { + m_rom_read = (data >> 0) & 1; + m_sound_en = (data >> 1) & 1; + m_input_en = (data >> 2) & 3; + } + + // getters + inline bool rom_read() { return m_rom_read; } + + inline bool sound_en() { return m_sound_en; } + + inline u8 input_en() { return m_input_en; } + + private: + u8 m_rom_read : 1; // ROM readback + u8 m_sound_en : 1; // Sound enable + u8 m_input_en : 2; // Input enable + }; + + class ym3012_t + { + public: + ym3012_t() + : m_in{0} + , m_out{0} + { + } + + void reset() + { + std::fill(m_in.begin(), m_in.end(), 0); + std::fill(m_out.begin(), m_out.end(), 0); + } + + void tick(u8 ch, s32 in) + { + m_out[(ch & 1)] = m_in[(ch & 1)]; + m_in[(ch & 1) ^ 1] = in; + } + + private: + std::array m_in = {0}; + std::array m_out = {0}; + }; + + class dac_t + { + public: + dac_t() + : m_clock(0) + , m_state(0) + { + } + + void reset() + { + m_clock = 0; + m_state = 0; + } + + inline void set_clock(u8 clock) { m_clock = clock; } + + inline void set_state(u8 state) { m_state = state; } + + inline u8 clock() { return m_clock; } + + inline u8 state() { return m_state; } + + private: + u8 m_clock : 4; // DAC clock (16 clock) + u8 m_state : 2; // DAC state (4 state - SAM1, SAM2) + }; + + public: + // constructor + k053260_core(k053260_intf &intf) + : vgsound_emu_core("k053260") + , m_voice{*this, *this, *this, *this} + , m_intf(intf) + , m_host2snd{0} + , m_snd2host{0} + , m_ctrl(ctrl_t()) + , m_ym3012(ym3012_t()) + , m_dac(dac_t()) + , m_reg{0} + , m_out{0} + { + } + + // communications + inline u8 snd2host_r(u8 address) { return m_snd2host[address & 1]; } + + inline void host2snd_w(u8 address, u8 data) { m_host2snd[address & 1] = data; } + + // sound accessors + u8 read(u8 address); + void write(u8 address, u8 data); + + // internal state + void reset(); + void tick(); + + // getters for debug, trackers, etc + inline s32 output(u8 ch) { return m_out[ch & 1]; } // output for each channels + + inline u8 reg_r(u8 address) { return m_reg[address & 0x3f]; } + + inline s32 voice_out(u8 voice, u8 ch) + { + return (voice < 4) ? m_voice[voice].out(ch & 1) : 0; + } + + private: + std::array m_voice; + k053260_intf &m_intf; // common memory interface + + std::array m_host2snd = {0}; + std::array m_snd2host = {0}; + + ctrl_t m_ctrl; // chip control + + ym3012_t m_ym3012; // YM3012 output + dac_t m_dac; // YM3012 interface + + std::array m_reg = {0}; // register pool + std::array m_out = {0}; // stereo output +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/msm6295/README.md b/vgsound_emu-modified/vgsound_emu/src/msm6295/README.md new file mode 100644 index 000000000..626b69187 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/msm6295/README.md @@ -0,0 +1,67 @@ +# OKI MSM6295 + +## Summary + +- 4 voice Dialogic ADPCM + - total accessible memory: 256 KByte +- Clock divider via SS pin + +## Source code + +- msm6295.hpp: Base header + - msm6295.cpp: Source emulation core + +### Dependencies + +- vox.hpp: Dialogic ADPCM decoder header + - vox.cpp: Dialogic ADPCM decoder source + +## Description + +It is 4 channel ADPCM playback chip from OKI semiconductor. It was becomes de facto standard for ADPCM playback in arcade machine, due to cost performance. + +The chip itself is pretty barebone: there is no "register" in chip. It can't control volume and pitch in currently playing channels, only stopable them. And volume is must be determined at playback start command. + +## Command format + + Playback command (2 byte): + +``` +Byte Bit Description + 76543210 +0 1xxxxxxx Phrase select (Header stored in ROM) +1 x000---- Play channel 4 + 0x00---- Play channel 3 + 00x0---- Play channel 2 + 000x---- Play channel 1 + ----xxxx Volume + ----0000 0.0dB + ----0001 -3.2dB + ----0010 -6.0dB + ----0011 -9.2dB + ----0100 -12.0dB + ----0101 -14.5dB + ----0110 -18.0dB + ----0111 -20.5dB + ----1000 -24.0dB +``` + + Suspend command (1 byte): + +``` +Byte Bit Description + 76543210 +0 0x------ Suspend channel 4 + 0-x----- Suspend channel 3 + 0--x---- Suspend channel 2 + 0---x--- Suspend channel 1 +``` + +## Frequency calculation + +``` + if (SS) then + Frequency = Input clock / 165 + else then + Frequency = Input clock / 132 +``` diff --git a/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp b/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp new file mode 100644 index 000000000..e09c45d90 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp @@ -0,0 +1,179 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + OKI MSM6295 emulation core +*/ + +#include "msm6295.hpp" + +void msm6295_core::tick() +{ + if (m_counter < 4) + { + m_voice[m_counter].tick(); + m_out_temp += m_voice[m_counter].out(); + } + if ((++m_counter) >= (m_ss ? 5 : 4)) + { + // command handler + if (m_command_pending) + { + if (bitfield(m_command, 7)) // play voice + { + if ((++m_clock) >= 15) + { + if (bitfield(m_next_command, 4, 4) != 0) + { + for (int i = 0; i < 4; i++) + { + if (bitfield(m_next_command, 4 + i)) + { + if (!m_voice[i].busy()) + { + m_voice[i].set_command(m_command); + m_voice[i].set_volume(bitfield(m_next_command, 0, 4)); + } + // voices aren't be playable simultaneously at once + break; + } + } + } + m_command = 0; + m_command_pending = false; + m_clock = 0; + } + } + else if (bitfield(m_next_command, 7)) // select phrase + { + if ((++m_clock) >= 15) + { + m_command = m_next_command; + m_command_pending = false; + m_clock = 0; + } + } + else + { + if (bitfield(m_next_command, 3, 4) != 0) // suspend voices + { + for (int i = 0; i < 4; i++) + { + if (bitfield(m_next_command, 3 + i)) + { + if (m_voice[i].busy()) + { + m_voice[i].set_command(m_next_command); + } + } + } + m_next_command &= ~0x78; + } + m_command_pending = false; + } + } + m_out = m_out_temp; + m_out_temp = 0; + m_counter = 0; + } +} + +void msm6295_core::reset() +{ + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_command = 0; + m_next_command = 0; + m_command_pending = false; + m_clock = 0; + m_counter = 0; + m_out = 0; + m_out_temp = 0; +} + +void msm6295_core::voice_t::tick() +{ + if (!m_busy) + { + if (bitfield(m_command, 7)) + { + // get phrase header (stored in data memory) + const u32 phrase = bitfield(m_command, 0, 7) << 3; + // Start address + m_addr = (bitfield(m_host.m_intf.read_byte(phrase | 0), 0, 2) << 16) | + (m_host.m_intf.read_byte(phrase | 1) << 8) | + (m_host.m_intf.read_byte(phrase | 2) << 0); + // End address + m_end = (bitfield(m_host.m_intf.read_byte(phrase | 3), 0, 2) << 16) | + (m_host.m_intf.read_byte(phrase | 4) << 8) | + (m_host.m_intf.read_byte(phrase | 5) << 0); + m_nibble = 4; // MSB first, LSB second + m_command = 0; + m_busy = true; + vox_decoder_t::reset(); + } + m_out = 0; + } + else + { + // playback + if ((++m_clock) >= 33) + { + bool is_end = (m_command != 0); // suspend + decode(bitfield(m_host.m_intf.read_byte(m_addr), m_nibble, 4)); + if (m_nibble <= 0) + { + m_nibble = 4; + if (++m_addr > m_end) + { + is_end = true; + } + } + else + { + m_nibble -= 4; + } + if (is_end) + { + m_command = 0; + m_busy = false; + } + m_out = (step() * m_volume) >> 7; // scale out to 12 bit output + m_clock = 0; + } + } +} + +void msm6295_core::voice_t::reset() +{ + vox_decoder_t::reset(); + m_clock = 0; + m_busy = false; + m_command = 0; + m_addr = 0; + m_nibble = 0; + m_end = 0; + m_volume = 0; + m_out = 0; + m_mute = false; +} + +// accessors +u8 msm6295_core::busy_r() +{ + return (m_voice[0].busy() ? 0x01 : 0x00) | (m_voice[1].busy() ? 0x02 : 0x00) | + (m_voice[2].busy() ? 0x04 : 0x00) | (m_voice[3].busy() ? 0x08 : 0x00); +} + +void msm6295_core::command_w(u8 data) +{ + if (!m_command_pending) + { + m_next_command = data; + m_command_pending = true; + } +} diff --git a/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp b/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp new file mode 100644 index 000000000..04326ae6d --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp @@ -0,0 +1,142 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + OKI MSM6295 emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_MSM6295_HPP +#define _VGSOUND_EMU_SRC_MSM6295_HPP + +#pragma once + +#include "../core/util.hpp" +#include "../core/vox/vox.hpp" + +class msm6295_core : public vox_core +{ + friend class vgsound_emu_mem_intf; // common memory interface + + private: + // Internal volume table, 9 step + const s32 m_volume_table[9] = {32 /* 0.0dB */, + 22 /* -3.2dB */, + 16 /* -6.0dB */, + 11 /* -9.2dB */, + 8 /* -12.0dB */, + 6 /* -14.5dB */, + 4 /* -18.0dB */, + 3 /* -20.5dB */, + 2 /* -24.0dB */}; // scale out to 5 bit for optimization + + // msm6295 voice classes + class voice_t : vox_decoder_t + { + public: + // constructor + voice_t(msm6295_core &host) + : vox_decoder_t(host, false) + , m_host(host) + , m_clock(0) + , m_busy(false) + , m_command(0) + , m_addr(0) + , m_nibble(0) + , m_end(0) + , m_volume(0) + , m_out(0) + , m_mute(false) + { + } + + // internal state + virtual void reset() override; + void tick(); + + // Setters + inline void set_command(u8 command) { m_command = command; } + + inline void set_volume(s32 volume) + { + m_volume = (volume < 9) ? m_host.m_volume_table[volume] : 0; + } + + inline void set_mute(bool mute) { m_mute = mute; } + + // Getters + inline bool busy() { return m_busy; } + + inline s32 out() { return m_mute ? 0 : m_out; } + + private: + // accessors, getters, setters + // registers + msm6295_core &m_host; // host core + u16 m_clock = 0; // clock counter + bool m_busy = false; // busy status + u8 m_command = 0; // current command + u32 m_addr = 0; // current address + s8 m_nibble = 0; // current nibble + u32 m_end = 0; // end address + s32 m_volume = 0; // volume + s32 m_out = 0; // output + // for preview only + bool m_mute = false; // mute flag + }; + + public: + // constructor + msm6295_core(vgsound_emu_mem_intf &intf) + : vox_core("msm6295") + , m_voice{*this, *this, *this, *this} + , m_intf(intf) + , m_ss(false) + , m_command(0) + , m_next_command(0) + , m_command_pending(false) + , m_clock(0) + , m_counter(0) + , m_out(0) + , m_out_temp(0) + { + } + + // accessors, getters, setters + u8 busy_r(); + void command_w(u8 data); + + inline void ss_w(bool ss) { m_ss = ss; } // SS pin + + // internal state + void reset(); + void tick(); + + inline s32 out() { return m_out; } // built in 12 bit DAC + + // for preview + inline void voice_mute(u8 voice, bool mute) + { + if (voice < 4) + { + m_voice[voice].set_mute(mute); + } + } + + inline s32 voice_out(u8 voice) { return (voice < 4) ? m_voice[voice].out() : 0; } + + private: + std::array m_voice; + vgsound_emu_mem_intf &m_intf; // common memory interface + + bool m_ss = false; // SS pin controls divider, input clock / 33 * (SS ? 5 : 4) + u8 m_command = 0; // Command byte + u8 m_next_command = 0; // Next command + bool m_command_pending = false; // command pending flag + u16 m_clock = 0; // clock counter + u16 m_counter = 0; // another clock counter + s32 m_out = 0; // 12 bit output + s32 m_out_temp = 0; // temporary buffer of above +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/n163/README.md b/vgsound_emu-modified/vgsound_emu/src/n163/README.md new file mode 100644 index 000000000..984356be7 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/n163/README.md @@ -0,0 +1,88 @@ +# Namco 163 + +## Summary + +- 1 to 8 voice wavetable + - 4 bit unsigned + - each waveforms are can be placed to anywhere in internal RAM, and its size is can be variable. +- activated voice count can be changed any time, multiplexed output + +## Source code + +- n163.hpp: Base header + - n163.cpp: Source emulation core + +## Description + +This chip is one of NES mapper with sound expansion, This one is by Namco. + +It has 1 to 8 wavetable channels, All channel registers and waveforms are stored to internal RAM. 4 bit Waveforms are freely allocatable, and its length is variables; its can be stores many short waveforms or few long waveforms in RAM. + +But waveforms are needs to squash, reallocate to avoid conflict with channel register area, each channel register size is 8 bytes per channels. + +Sound output is time division multiplexed, it's can be captured only single channels output at once. in reason, More activated channels are less sound quality. + +## Sound register layout + +``` +Address Bit Description + 7654 3210 + +78-7f Channel 0 +78 xxxx xxxx Channel 0 Pitch input bit 0-7 +79 xxxx xxxx Channel 0 Accumulator bit 0-7 +7a xxxx xxxx Channel 0 Pitch input bit 8-15 +7b xxxx xxxx Channel 0 Accumulator bit 8-15 +7c xxxx xx-- Channel 0 Waveform length, 256 - (x * 4) + ---- --xx Channel 0 Pitch input bit 16-17 +7d xxxx xxxx Channel 0 Accumulator bit 16-23 +7e xxxx xxxx Channel 0 Waveform base offset + xxxx xxx- RAM byte (0 to 127) + ---- ---x RAM nibble + ---- ---0 Low nibble + ---- ---1 High nibble +7f ---- xxxx Channel 0 Volume + +7f Number of active channels +7f -xxx ---- Number of active channels + -000 ---- Channel 0 activated + -001 ---- Channel 1 activated + -010 ---- Channel 2 activated + ... + -110 ---- Channel 6 activated + -111 ---- Channel 7 activated + +70-77 Channel 1 (Optional if activated) +68-6f Channel 2 (Optional if activated) +... +48-4f Channel 6 (Optional if activated) +40-47 Channel 7 (Optional if activated) +``` + +Rest of RAM area are for 4 bit Waveform and/or scratchpad. + +## Waveform format + +Each waveform byte has 2 nibbles packed, fetches LSB first, MSB next. + +``` + ---- xxxx 4 bit waveform, LSB + xxxx ---- Same as above, MSB +``` + +Waveform address: Waveform base offset + Bit 16 to 23 of Accumulator, 1 LSB of result is nibble select, 7 MSB of result is Byte address in RAM. + +## Frequency calculation + +``` + Frequency: Pitch input * ((Input clock * 15 * Number of activated voices) / 65536) +``` + +## Technical notice + +This core only outputs raw output from chip (or accumulated output, see below); any kind of off-chip stuff needs to implemented outside core. + +There's to way for reduce N163 noises: reduce channel limit and demultiplex: + +- Channel limit is runtime changeable and it makes some usable effects. +- Demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered) This core is support both, You can choose output behavior diff --git a/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp b/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp new file mode 100644 index 000000000..783bf2df3 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp @@ -0,0 +1,120 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Namco 163 Sound emulation core +*/ + +#include "n163.hpp" + +void n163_core::tick() +{ + if (m_multiplex) + { + m_out = 0; + } + // 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank + // 0x8000-0x9fff select.) + if (m_disable) + { + if (!m_multiplex) + { + m_out = 0; + } + return; + } + + // tick per each clock + const u32 freq = m_ram[m_voice_cycle + 0] | (u32(m_ram[m_voice_cycle + 2]) << 8) | + (bitfield(m_ram[m_voice_cycle + 4], 0, 2) << 16); // 18 bit frequency + + u32 accum = m_ram[m_voice_cycle + 1] | (u32(m_ram[m_voice_cycle + 3]) << 8) | + (u32(m_ram[m_voice_cycle + 5]) << 16); // 24 bit accumulator + + const u16 length = 256 - (m_ram[m_voice_cycle + 4] & 0xfc); + const u8 addr = m_ram[m_voice_cycle + 6] + bitfield(accum, 16, 8); + const s16 wave = (bitfield(m_ram[bitfield(addr, 1, 7)], bitfield(addr, 0) << 2, 4) - 8); + const s16 volume = bitfield(m_ram[m_voice_cycle + 7], 0, 4); + + // get per-voice output + const s16 voice_out = (wave * volume); + m_voice_out[(m_voice_cycle >> 3) & 7] = voice_out; + + // accumulate address + accum = bitfield(accum + freq, 0, 24); + if (bitfield(accum, 16, 8) >= length) + { + accum = bitfield(accum, 0, 18); + } + + // writeback to register + m_ram[m_voice_cycle + 1] = bitfield(accum, 0, 8); + m_ram[m_voice_cycle + 3] = bitfield(accum, 8, 8); + m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8); + + // update voice cycle + bool flush = m_multiplex ? true : false; + m_voice_cycle -= 0x8; + if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3))) + { + if (!m_multiplex) + { + flush = true; + } + m_voice_cycle = 0x78; + } + + // output 4 bit waveform and volume, multiplexed + m_acc += voice_out; + if (flush) + { + m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1)); + m_acc = 0; + } +} + +void n163_core::reset() +{ + // reset this chip + m_disable = false; + m_multiplex = true; + std::fill(m_ram.begin(), m_ram.end(), 0); + m_voice_cycle = 0x78; + m_addr_latch.reset(); + m_out = 0; + m_acc = 0; +} + +// accessor +void n163_core::addr_w(u8 data) +{ + // 0xf800-0xffff Sound address, increment + m_addr_latch.write(data); +} + +void n163_core::data_w(u8 data, bool cpu_access) +{ + // 0x4800-0x4fff Sound data write + m_ram[m_addr_latch.addr()] = data; + + // address latch increment + if (cpu_access && m_addr_latch.incr()) + { + m_addr_latch.addr_inc(); + } +} + +u8 n163_core::data_r(bool cpu_access) +{ + // 0x4800-0x4fff Sound data read + const u8 ret = m_ram[m_addr_latch.addr()]; + + // address latch increment + if (cpu_access && m_addr_latch.incr()) + { + m_addr_latch.addr_inc(); + } + + return ret; +} diff --git a/vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp b/vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp new file mode 100644 index 000000000..1c04d1f36 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp @@ -0,0 +1,109 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Namco 163 Sound emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_N163_HPP +#define _VGSOUND_EMU_SRC_N163_HPP + +#pragma once + +#include "../core/util.hpp" + +class n163_core : public vgsound_emu_core +{ + private: + // Address latch + class addr_latch_t : public vgsound_emu_core + { + public: + addr_latch_t() + : vgsound_emu_core("namco_163_addr_latch") + , m_addr(0) + , m_incr(0) + { + } + + void reset() + { + m_addr = 0; + m_incr = 0; + } + + // accessors + inline void write(u8 data) + { + m_addr = (data >> 0) & 0x7f; + m_incr = (data >> 7) & 0x01; + } + + inline void addr_inc() { m_addr = (m_addr + 1) & 0x7f; } + + // getters + inline u8 addr() { return m_addr; } + + inline bool incr() { return m_incr; } + + private: + u8 m_addr : 7; + u8 m_incr : 1; + }; + + public: + n163_core() + : vgsound_emu_core("namco_163") + , m_disable(false) + , m_ram{0} + , m_voice_cycle(0x78) + , m_addr_latch(addr_latch_t()) + , m_out(0) + , m_voice_out{0} + , m_multiplex(true) + , m_acc(0) + { + } + + // accessors, getters, setters + void addr_w(u8 data); + void data_w(u8 data, bool cpu_access = false); + u8 data_r(bool cpu_access = false); + + inline void set_disable(bool disable) { m_disable = disable; } + + // internal state + void reset(); + void tick(); + + // sound output pin + inline s16 out() { return m_out; } + + // register pool + inline u8 reg(u8 addr) { return m_ram[addr & 0x7f]; } + + inline void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; } + + // preview only + inline u8 voice_cycle() { return m_voice_cycle; } + + inline s16 voice_out(u8 voice) + { + return (voice <= ((m_ram[0x7f] >> 4) & 7)) ? m_voice_out[7 - voice] : 0; + } + + private: + bool m_disable = false; + std::array m_ram = {0}; // internal 128 byte RAM + u8 m_voice_cycle = 0x78; // Voice cycle for processing + addr_latch_t m_addr_latch; // address latch + s16 m_out = 0; // output + + std::array m_voice_out = {0}; // per-voice output, for preview only + // demultiplex related + bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate! + s16 m_acc = 0; // accumulated output +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/scc/README.md b/vgsound_emu-modified/vgsound_emu/src/scc/README.md new file mode 100644 index 000000000..2a66bd8cb --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/scc/README.md @@ -0,0 +1,314 @@ +# Konami SCC + +## Summary + +- 5 voice wavetable + - 8 bit signed, 32 width long for each voice + - each voice has separated waveform space + - 4th and 5th voice shares waveform (K051649) +- MegaROM mapper (K051649) or MegaRAM mapper (K052539) + +## Source code + +- scc.hpp: Base header + - scc.cpp: Source emulation core + +## Description + +Konami SCC means "Sound Creative Chip", it's actually MSX MegaROM/RAM Mapper with 5 channel Wavetable sound generator. + +It was first appeared at 1987, F-1 Spirit and Nemesis 2/Gradius 2 for MSX. then several MSX cartridges used that until 1990, Metal Gear 2: Solid Snake. Even after MSX is discontinued, it was still used at some low-end arcade and amusement hardwares. and some Third-party MSX utilities still support this due to its market shares. + +There's 2 SCC types: + +- K051649 (or simply known as SCC) + This chip is used for MSX MegaROM Mapper, some arcade machines. + Channel 4 and 5 must be share waveform, other channels has its own waveforms. + +- K052539 (also known as SCC+) + This chip is used for MSX MegaRAM Mapper (Konami Sound Cartridges for Snatcher/SD Snatcher). All channels can be has its own waveforms, and also has backward compatibility mode with K051649. + +## Register layout + +### K051649 + +- 4000-bfff MegaROM Mapper + +``` +Address Bit R/W Description + 7654 3210 + +4000-5fff xxxx xxxx R Bank page 0 +c000-dfff mirror of 4000-5fff + +6000-7fff xxxx xxxx R Bank page 1 +e000-ffff mirror of 6000-7fff + +8000-9fff xxxx xxxx R Bank page 2 +0000-1fff mirror of 8000-9fff + +a000-bfff xxxx xxxx R Bank page 3 +2000-3fff mirror of a000-bfff +``` + +- 5000-57ff, 7000-77ff, 9000-97ff, b000-b7ff Bank select + +``` +Address Bit R/W Description + 7654 3210 + +5000 --xx xxxx W Bank select, Page 0 +5001-57ff Mirror of 5000 + +7000 --xx xxxx W Bank select, Page 1 +7001-77ff Mirror of 7000 + +9000 --xx xxxx W Bank select, Page 2 + --11 1111 W SCC Enable +9001-97ff Mirror of 9000 + +b000 --xx xxxx W Bank select, Page 3 +b001-b7ff Mirror of b000 +``` + +- 9800-9fff SCC register + +``` +9800-987f Waveform + +Address Bit R/W Description + 7654 3210 + +9800-981f xxxx xxxx R/W Channel 0 Waveform (32 byte, 8 bit signed) +9820-983f xxxx xxxx R/W Channel 1 "" +9840-985f xxxx xxxx R/W Channel 2 "" +9860-987f xxxx xxxx R/W Channel 3/4 "" + +9880-9889 Pitch + +9880 xxxx xxxx W Channel 0 Pitch LSB +9881 ---- xxxx W Channel 0 Pitch MSB +9882 xxxx xxxx W Channel 1 Pitch LSB +9883 ---- xxxx W Channel 1 Pitch MSB +9884 xxxx xxxx W Channel 2 Pitch LSB +9885 ---- xxxx W Channel 2 Pitch MSB +9886 xxxx xxxx W Channel 3 Pitch LSB +9887 ---- xxxx W Channel 3 Pitch MSB +9888 xxxx xxxx W Channel 4 Pitch LSB +9889 ---- xxxx W Channel 4 Pitch MSB + +9888-988e Volume + +988a ---- xxxx W Channel 0 Volume +988b ---- xxxx W Channel 1 Volume +988c ---- xxxx W Channel 2 Volume +988d ---- xxxx W Channel 3 Volume +988e ---- xxxx W Channel 4 Volume + +988f ---x ---- W Channel 4 Output enable/disable flag + ---- x--- W Channel 3 Output enable/disable flag + ---- -x-- W Channel 2 Output enable/disable flag + ---- --x- W Channel 1 Output enable/disable flag + ---- ---x W Channel 0 Output enable/disable flag + +9890-989f Mirror of 9880-988f + +98a0-98bf xxxx xxxx R Channel 4 Waveform + +98e0 x--- ---- W Waveform rotate flag for channel 4 + -x-- ---- W Waveform rotate flag for all channels + --x- ---- W Reset waveform position after pitch writes + ---- --x- W 8 bit frequency + ---- --0x W 4 bit frequency + +98e1-98ff Mirror of 98e0 + +9900-9fff Mirror of 9800-98ff +``` + +### K052539 + +- 4000-bfff MegaRAM Mapper + +``` +Address Bit R/W Description + 7654 3210 + +4000-5fff xxxx xxxx R/W Bank page 0 +c000-dfff xxxx xxxx R/W "" + +6000-7fff xxxx xxxx R/W Bank page 1 +e000-ffff xxxx xxxx R/W "" + +8000-9fff xxxx xxxx R/W Bank page 2 +0000-1fff xxxx xxxx R/W "" + +a000-bfff xxxx xxxx R/W Bank page 3 +2000-3fff xxxx xxxx R/W "" +``` + +- 5000-57ff, 7000-77ff, 9000-97ff, b000-b7ff Bank select + +``` +Address Bit R/W Description + 7654 3210 + +5000 xxxx xxxx W Bank select, Page 0 +5001-57ff Mirror of 5000 + +7000 xxxx xxxx W Bank select, Page 1 +7001-77ff Mirror of 7000 + +9000 xxxx xxxx W Bank select, Page 2 + --11 1111 W SCC Enable (SCC Compatible mode) +9001-97ff Mirror of 9000 + +b000 xxxx xxxx W Bank select, Page 3 + 1--- ---- W SCC+ Enable (SCC+ mode) +b001-b7ff Mirror of b000 +``` + +- bffe-bfff Mapper configuration + +``` +Address Bit R/W Description + 7654 3210 + +bffe --x- ---- W SCC operation mode + --0- ---- W SCC Compatible mode + --1- ---- W SCC+ mode + ---x ---- W RAM write/Bank select toggle for all Bank pages + ---0 ---- W Bank select enable + ---1 ---- W RAM write enable + ---0 -x-- W RAM write/Bank select toggle for Bank page 2 + ---0 --x- W RAM write/Bank select toggle for Bank page 1 + ---0 ---x W RAM write/Bank select toggle for Bank page 0 + +bfff Mirror of bffe +``` + +- 9800-9fff SCC Compatible mode register + +``` +9800-987f Waveform + +Address Bit R/W Description + 7654 3210 + +9800-981f xxxx xxxx R/W Channel 0 Waveform (32 byte, 8 bit signed) +9820-983f xxxx xxxx R/W Channel 1 "" +9840-985f xxxx xxxx R/W Channel 2 "" +9860-987f xxxx xxxx R/W Channel 3/4 "" + +9880-9889 Pitch + +9880 xxxx xxxx W Channel 0 Pitch LSB +9881 ---- xxxx W Channel 0 Pitch MSB +9882 xxxx xxxx W Channel 1 Pitch LSB +9883 ---- xxxx W Channel 1 Pitch MSB +9884 xxxx xxxx W Channel 2 Pitch LSB +9885 ---- xxxx W Channel 2 Pitch MSB +9886 xxxx xxxx W Channel 3 Pitch LSB +9887 ---- xxxx W Channel 3 Pitch MSB +9888 xxxx xxxx W Channel 4 Pitch LSB +9889 ---- xxxx W Channel 4 Pitch MSB + +9888-988e Volume + +988a ---- xxxx W Channel 0 Volume +988b ---- xxxx W Channel 1 Volume +988c ---- xxxx W Channel 2 Volume +988d ---- xxxx W Channel 3 Volume +988e ---- xxxx W Channel 4 Volume + +988f ---x ---- W Channel 4 Output enable/disable flag + ---- x--- W Channel 3 Output enable/disable flag + ---- -x-- W Channel 2 Output enable/disable flag + ---- --x- W Channel 1 Output enable/disable flag + ---- ---x W Channel 0 Output enable/disable flag + +9890-989f Mirror of 9880-988f + +98a0-98bf xxxx xxxx R Channel 4 Waveform + +98c0 -x-- ---- W Waveform rotate flag for all channels + --x- ---- W Reset waveform position after pitch writes + ---- --x- W 8 bit frequency + ---- --0x W 4 bit frequency + +98c1-98df Mirror of 98c0 + + 9900-9fff Mirror of 9800-98ff +``` + +- b800-bfff SCC+ mode register + +``` +b800-b89f Waveform + +Address Bit R/W Description + 7654 3210 + +b800-b81f xxxx xxxx R/W Channel 0 Waveform (32 byte, 8 bit signed) +b820-b83f xxxx xxxx R/W Channel 1 "" +b840-b85f xxxx xxxx R/W Channel 2 "" +b860-b87f xxxx xxxx R/W Channel 3 "" +b880-b89f xxxx xxxx R/W Channel 3 "" + +b8a0-b8a9 Pitch + +b8a0 xxxx xxxx W Channel 0 Pitch LSB +b8a1 ---- xxxx W Channel 0 Pitch MSB +b8a2 xxxx xxxx W Channel 1 Pitch LSB +b8a3 ---- xxxx W Channel 1 Pitch MSB +b8a4 xxxx xxxx W Channel 2 Pitch LSB +b8a5 ---- xxxx W Channel 2 Pitch MSB +b8a6 xxxx xxxx W Channel 3 Pitch LSB +b8a7 ---- xxxx W Channel 3 Pitch MSB +b8a8 xxxx xxxx W Channel 4 Pitch LSB +b8a9 ---- xxxx W Channel 4 Pitch MSB + +b8a8-b8ae Volume + +b8aa ---- xxxx W Channel 0 Volume +b8ab ---- xxxx W Channel 1 Volume +b8ac ---- xxxx W Channel 2 Volume +b8ad ---- xxxx W Channel 3 Volume +b8ae ---- xxxx W Channel 4 Volume + +b8af ---x ---- W Channel 4 Output enable/disable flag + ---- x--- W Channel 3 Output enable/disable flag + ---- -x-- W Channel 2 Output enable/disable flag + ---- --x- W Channel 1 Output enable/disable flag + ---- ---x W Channel 0 Output enable/disable flag + +b8b0-b8bf Mirror of b8a0-b8af + +b8c0 -x-- ---- W Waveform rotate flag for all channels + --x- ---- W Reset waveform position after pitch writes + ---- --x- W 8 bit frequency + ---- --0x W 4 bit frequency + +b8c1-b8df Mirror of b8c0 + +b900-bfff Mirror of b800-b8ff +``` + +## Frequency calculation + +``` + if 8 bit frequency then + Frequency = Input clock / ((bit 0 to 7 of Pitch input) + 1) + else if 4 bit frequency then + Frequency = Input clock / ((bit 8 to 11 of Pitch input) + 1) + else + Frequency = Input clock / (Pitch input + 1) +``` + +## Reference + + + + + + diff --git a/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp b/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp new file mode 100644 index 000000000..07cbb60e8 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp @@ -0,0 +1,461 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst + Konami SCC emulation core +*/ + +#include "scc.hpp" + +// shared SCC features +void scc_core::tick() +{ + m_out = 0; + for (auto &elem : m_voice) + { + elem.tick(); + m_out += elem.out(); + } +} + +void scc_core::voice_t::tick() +{ + if (m_pitch >= 9) // or voice is halted + { + // update counter - Post decrement + const u16 temp = m_counter; + if (m_host.m_test.freq_4bit()) // 4 bit frequency mode + { + m_counter = (m_counter & ~0x0ff) | (bitfield(bitfield(m_counter, 0, 8) - 1, 0, 8) << 0); + m_counter = (m_counter & ~0xf00) | (bitfield(bitfield(m_counter, 8, 4) - 1, 0, 4) << 8); + } + else + { + m_counter = bitfield(m_counter - 1, 0, 12); + } + + // handle counter carry + const bool carry = m_host.m_test.freq_8bit() + ? (bitfield(temp, 0, 8) == 0) + : (m_host.m_test.freq_4bit() ? (bitfield(temp, 8, 4) == 0) + : (bitfield(temp, 0, 12) == 0)); + if (carry) + { + m_addr = bitfield(m_addr + 1, 0, 5); + m_counter = m_pitch; + } + } + // get output + if (m_enable) + { + m_out = (m_wave[m_addr] * m_volume) >> 4; // scale to 11 bit digital output + } + else + { + m_out = 0; + } +} + +void scc_core::reset() +{ + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_test.reset(); + m_out = 0; + std::fill(m_reg.begin(), m_reg.end(), 0); +} + +void scc_core::voice_t::reset() +{ + std::fill(m_wave.begin(), m_wave.end(), 0); + m_enable = false; + m_pitch = 0; + m_volume = 0; + m_addr = 0; + m_counter = 0; + m_out = 0; +} + +// SCC accessors +u8 scc_core::wave_r(bool is_sccplus, u8 address) +{ + u8 ret = 0xff; + const u8 voice = bitfield(address, 5, 3); + if (voice > 4) + { + return ret; + } + + u8 wave_addr = bitfield(address, 0, 5); + + if (m_test.rotate()) + { // rotate flag + wave_addr = bitfield(wave_addr + m_voice[voice].addr(), 0, 5); + } + + if (!is_sccplus) + { + if (voice == 3) // rotate voice 3~4 flag + { + if (m_test.rotate4() || m_test.rotate()) + { // rotate flag + wave_addr = + bitfield(bitfield(address, 0, 5) + m_voice[3 + m_test.rotate()].addr(), 0, 5); + } + } + } + ret = m_voice[voice].wave(wave_addr); + + return ret; +} + +void scc_core::wave_w(bool is_sccplus, u8 address, u8 data) +{ + if (m_test.rotate()) + { // write protected + return; + } + + const u8 voice = bitfield(address, 5, 3); + if (voice > 4) + { + return; + } + + const u8 wave_addr = bitfield(address, 0, 5); + + if (!is_sccplus) + { + if (((voice >= 3) && m_test.rotate4()) || (voice >= 4)) + { // Ignore if write protected, or voice 4 + return; + } + if (voice >= 3) // voice 3, 4 shares waveform + { + m_voice[3].set_wave(wave_addr, data); + m_voice[4].set_wave(wave_addr, data); + } + else + { + m_voice[voice].set_wave(wave_addr, data); + } + } + else + { + m_voice[voice].set_wave(wave_addr, data); + } +} + +void scc_core::freq_vol_enable_w(u8 address, u8 data) +{ + // *0-*f Pitch, Volume, Enable + address = bitfield(address, 0, 4); // mask address to 4 bit + const u8 voice_freq = bitfield(address, 1, 3); + switch (address) + { + case 0x0: // 0x*0 Voice 0 Pitch LSB + case 0x2: // 0x*2 Voice 1 Pitch LSB + case 0x4: // 0x*4 Voice 2 Pitch LSB + case 0x6: // 0x*6 Voice 3 Pitch LSB + case 0x8: // 0x*8 Voice 4 Pitch LSB + if (m_test.resetpos()) + { // Reset address + m_voice[voice_freq].reset_addr(); + } + m_voice[voice_freq].set_pitch(data, 0x0ff); + break; + case 0x1: // 0x*1 Voice 0 Pitch MSB + case 0x3: // 0x*3 Voice 1 Pitch MSB + case 0x5: // 0x*5 Voice 2 Pitch MSB + case 0x7: // 0x*7 Voice 3 Pitch MSB + case 0x9: // 0x*9 Voice 4 Pitch MSB + if (m_test.resetpos()) + { // Reset address + m_voice[voice_freq].reset_addr(); + } + m_voice[voice_freq].set_pitch(u16(bitfield(data, 0, 4)) << 8, 0xf00); + break; + case 0xa: // 0x*a Voice 0 Volume + case 0xb: // 0x*b Voice 1 Volume + case 0xc: // 0x*c Voice 2 Volume + case 0xd: // 0x*d Voice 3 Volume + case 0xe: // 0x*e Voice 4 Volume + m_voice[address - 0xa].set_volume(bitfield(data, 0, 4)); + break; + case 0xf: // 0x*f Enable/Disable flag + m_voice[0].set_enable(bitfield(data, 0)); + m_voice[1].set_enable(bitfield(data, 1)); + m_voice[2].set_enable(bitfield(data, 2)); + m_voice[3].set_enable(bitfield(data, 3)); + m_voice[4].set_enable(bitfield(data, 4)); + break; + } +} + +void k051649_scc_core::scc_w(bool is_sccplus, u8 address, u8 data) +{ + const u8 voice = bitfield(address, 5, 3); + switch (voice) + { + case 0b000: // 0x00-0x1f Voice 0 Waveform + case 0b001: // 0x20-0x3f Voice 1 Waveform + case 0b010: // 0x40-0x5f Voice 2 Waveform + case 0b011: // 0x60-0x7f Voice 3/4 Waveform + wave_w(false, address, data); + break; + case 0b100: // 0x80-0x9f Pitch, Volume, Enable + freq_vol_enable_w(address, data); + break; + case 0b111: // 0xe0-0xff Test register + m_test.set_freq_4bit(bitfield(data, 0)); + m_test.set_freq_8bit(bitfield(data, 1)); + m_test.set_resetpos(bitfield(data, 5)); + m_test.set_rotate(bitfield(data, 6)); + m_test.set_rotate4(bitfield(data, 7)); + break; + } + m_reg[address] = data; +} + +void k052539_scc_core::scc_w(bool is_sccplus, u8 address, u8 data) +{ + const u8 voice = bitfield(address, 5, 3); + if (is_sccplus) + { + switch (voice) + { + case 0b000: // 0x00-0x1f Voice 0 Waveform + case 0b001: // 0x20-0x3f Voice 1 Waveform + case 0b010: // 0x40-0x5f Voice 2 Waveform + case 0b011: // 0x60-0x7f Voice 3 Waveform + case 0b100: // 0x80-0x9f Voice 4 Waveform + wave_w(true, address, data); + break; + case 0b101: // 0xa0-0xbf Pitch, Volume, Enable + freq_vol_enable_w(address, data); + break; + case 0b110: // 0xc0-0xdf Test register + m_test.set_freq_4bit(bitfield(data, 0)); + m_test.set_freq_8bit(bitfield(data, 1)); + m_test.set_resetpos(bitfield(data, 5)); + m_test.set_rotate(bitfield(data, 6)); + break; + default: break; + } + } + else + { + switch (voice) + { + case 0b000: // 0x00-0x1f Voice 0 Waveform + case 0b001: // 0x20-0x3f Voice 1 Waveform + case 0b010: // 0x40-0x5f Voice 2 Waveform + case 0b011: // 0x60-0x7f Voice 3/4 Waveform + wave_w(false, address, data); + break; + case 0b100: // 0x80-0x9f Pitch, Volume, Enable + freq_vol_enable_w(address, data); + break; + case 0b110: // 0xc0-0xdf Test register + m_test.set_freq_4bit(bitfield(data, 0)); + m_test.set_freq_8bit(bitfield(data, 1)); + m_test.set_resetpos(bitfield(data, 5)); + m_test.set_rotate(bitfield(data, 6)); + break; + default: break; + } + } + m_reg[address] = data; +} + +u8 k051649_scc_core::scc_r(bool is_sccplus, u8 address) +{ + const u8 voice = bitfield(address, 5, 3); + const u8 wave = bitfield(address, 0, 5); + u8 ret = 0xff; + switch (voice) + { + case 0b000: // 0x00-0x1f Voice 0 Waveform + case 0b001: // 0x20-0x3f Voice 1 Waveform + case 0b010: // 0x40-0x5f Voice 2 Waveform + case 0b011: // 0x60-0x7f Voice 3 Waveform + case 0b101: // 0xa0-0xbf Voice 4 Waveform + ret = wave_r(false, (std::min(4, voice) << 5) | wave); + break; + } + return ret; +} + +u8 k052539_scc_core::scc_r(bool is_sccplus, u8 address) +{ + const u8 voice = bitfield(address, 5, 3); + const u8 wave = bitfield(address, 0, 5); + u8 ret = 0xff; + if (is_sccplus) + { + switch (voice) + { + case 0b000: // 0x00-0x1f Voice 0 Waveform + case 0b001: // 0x20-0x3f Voice 1 Waveform + case 0b010: // 0x40-0x5f Voice 2 Waveform + case 0b011: // 0x60-0x7f Voice 3 Waveform + case 0b100: // 0x80-0x9f Voice 4 Waveform + ret = wave_r(true, address); + break; + } + } + else + { + switch (voice) + { + case 0b000: // 0x00-0x1f Voice 0 Waveform + case 0b001: // 0x20-0x3f Voice 1 Waveform + case 0b010: // 0x40-0x5f Voice 2 Waveform + case 0b011: // 0x60-0x7f Voice 3 Waveform + case 0b101: // 0xa0-0xbf Voice 4 Waveform + ret = wave_r(false, (std::min(4, voice) << 5) | wave); + break; + } + } + return ret; +} + +// Mapper +void k051649_core::reset() +{ + k051649_scc_core::reset(); + m_mapper.reset(); + m_scc_enable = false; +} + +void k052539_core::reset() +{ + k052539_scc_core::reset(); + m_mapper.reset(); + m_scc_enable = false; + m_is_sccplus = false; +} + +void k051649_core::k051649_mapper_t::reset() +{ + m_bank[0] = 0; + m_bank[1] = 1; + m_bank[2] = 2; + m_bank[3] = 3; +} + +void k052539_core::k052539_mapper_t::reset() +{ + m_bank[0] = 0; + m_bank[1] = 1; + m_bank[2] = 2; + m_bank[3] = 3; + std::fill(m_ram_enable.begin(), m_ram_enable.end(), false); +} + +// Mapper accessors +u8 k051649_core::read(u16 address) +{ + if ((bitfield(address, 11, 5) == 0b10011) && m_scc_enable) + { + return scc_r(false, u8(address)); + } + + return m_intf.read_byte((u32(m_mapper.bank(bitfield(address, 13, 2) ^ 2)) << 13) | + bitfield(address, 0, 13)); +} + +u8 k052539_core::read(u16 address) +{ + if ((bitfield(address, 11, 5) == 0b10011) && m_scc_enable && (!m_is_sccplus)) + { + return scc_r(false, u8(address)); + } + + if ((bitfield(address, 11, 5) == 0b10111) && m_scc_enable && m_is_sccplus) + { + return scc_r(true, u8(address)); + } + + return m_intf.read_byte((u32(m_mapper.bank(bitfield(address, 13, 2) ^ 2)) << 13) | + bitfield(address, 0, 13)); +} + +void k051649_core::write(u16 address, u8 data) +{ + const u16 bank = bitfield(address, 13, 2) ^ 2; + switch (bitfield(address, 11, 5)) + { + case 0b01010: // 0x5000-0x57ff Bank 0 + case 0b01110: // 0x7000-0x77ff Bank 1 + case 0b10010: // 0x9000-0x97ff Bank 2 + case 0b10110: // 0xb000-0xb7ff Bank 3 + m_mapper.set_bank(bank, data); + m_scc_enable = (bitfield(m_mapper.bank(2), 0, 6) == 0x3f); + break; + case 0b10011: // 0x9800-9fff SCC + if (m_scc_enable) + { + scc_w(false, u8(address), data); + } + break; + } +} + +void k052539_core::write(u16 address, u8 data) +{ + u8 prev = 0; + bool update = false; + const u16 bank = bitfield(address, 13, 2) ^ 2; + const bool ram_enable = m_mapper.ram_enable(bank); + if (ram_enable) + { + m_intf.write_byte((u32(m_mapper.bank(bank)) << 13) | bitfield(address, 0, 13), data); + } + switch (bitfield(address, 11, 5)) + { + case 0b01010: // 0x5000-0x57ff Bank 0 + case 0b01110: // 0x7000-0x77ff Bank 1 + case 0b10010: // 0x9000-0x97ff Bank 2 + case 0b10110: // 0xb000-0xb7ff Bank 3 + if (!ram_enable) + { + prev = m_mapper.bank(bank); + m_mapper.set_bank(bank, data); + update = prev ^ m_mapper.bank(bank); + } + break; + case 0b10011: // 0x9800-0x9fff SCC + if ((!ram_enable) && m_scc_enable && (!m_is_sccplus)) + { + scc_w(false, u8(address), data); + } + break; + case 0b10111: // 0xb800-0xbfff SCC+, Mapper configuration + if (bitfield(address, 1, 10) == 0x3ff) + { + m_mapper.set_ram_enable(0, bitfield(data, 4) || bitfield(data, 0)); + m_mapper.set_ram_enable(1, bitfield(data, 4) || bitfield(data, 1)); + m_mapper.set_ram_enable(2, bitfield(data, 4) || bitfield(data, 2)); + m_mapper.set_ram_enable(3, bitfield(data, 4)); + prev = (m_is_sccplus ? 1 : 0); + m_is_sccplus = bitfield(data, 5); + update = prev ^ (m_is_sccplus ? 1 : 0); + } + else if ((!ram_enable) && m_scc_enable && m_is_sccplus) + { + scc_w(true, u8(address), data); + } + break; + } + if (update) + { + m_scc_enable = + m_is_sccplus ? bitfield(m_mapper.bank(3), 7) : (bitfield(m_mapper.bank(2), 0, 6) == 0x3f); + } +} diff --git a/vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp b/vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp new file mode 100644 index 000000000..8824d2535 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp @@ -0,0 +1,320 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst + Konami SCC emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_SCC_HPP +#define _VGSOUND_EMU_SRC_SCC_HPP + +#pragma once + +#include "../core/util.hpp" + +// shared for SCCs +class scc_core : public vgsound_emu_core +{ + private: + // classes + class voice_t : public vgsound_emu_core + { + public: + // constructor + voice_t(scc_core &host) + : vgsound_emu_core("scc_voice") + , m_host(host) + , m_wave{0} + , m_enable(false) + , m_pitch(0) + , m_volume(0) + , m_addr(0) + , m_counter(0) + , m_out(0) + { + } + + // internal state + void reset(); + void tick(); + + // accessors + inline void reset_addr() { m_addr = 0; } + + // setters + inline void set_wave(u8 addr, s8 wave) { m_wave[addr & 0x1f] = wave; } + + inline void set_enable(bool enable) { m_enable = enable; } + + inline void set_pitch(u16 pitch, u16 mask = 0xfff) + { + m_pitch = (m_pitch & ~(mask & 0xfff)) | (pitch & (mask & 0xfff)); + m_counter = m_pitch; + } + + inline void set_volume(u8 volume) { m_volume = volume & 0xf; } + + // getters + inline s8 wave(u8 addr) { return m_wave[addr & 0x1f]; } + + inline u8 addr() { return m_addr; } + + inline s32 out() { return m_out; } + + private: + // registers + scc_core &m_host; + std::array m_wave = {0}; // internal waveform + bool m_enable = false; // output enable flag + u16 m_pitch : 12; // pitch + u16 m_volume : 4; // volume + u8 m_addr = 0; // waveform pointer + u16 m_counter = 0; // frequency counter + s32 m_out = 0; // current output + }; + + class test_t : public vgsound_emu_core + { + public: + // constructor + test_t() + : vgsound_emu_core("scc_test") + , m_freq_4bit(0) + , m_freq_8bit(0) + , m_resetpos(0) + , m_rotate(0) + , m_rotate4(0) + { + } + + void reset() + { + m_freq_4bit = 0; + m_freq_8bit = 0; + m_resetpos = 0; + m_rotate = 0; + m_rotate4 = 0; + } + + // setters + inline void set_freq_4bit(bool freq_4bit) { m_freq_4bit = freq_4bit; } + + inline void set_freq_8bit(bool freq_8bit) { m_freq_8bit = freq_8bit; } + + inline void set_resetpos(bool resetpos) { m_resetpos = resetpos; } + + inline void set_rotate(bool rotate) { m_rotate = rotate; } + + inline void set_rotate4(bool rotate4) { m_rotate4 = rotate4; } + + // getters + inline bool freq_4bit() { return m_freq_4bit; } + + inline bool freq_8bit() { return m_freq_8bit; } + + inline bool resetpos() { return m_resetpos; } + + inline bool rotate() { return m_rotate; } + + inline bool rotate4() { return m_rotate4; } + + private: + u8 m_freq_4bit : 1; // 4 bit frequency + u8 m_freq_8bit : 1; // 8 bit frequency + u8 m_resetpos : 1; // reset counter after pitch writes + u8 m_rotate : 1; // rotate and write protect waveform for all channels + u8 m_rotate4 : 1; // same as above but for channel 4 only + }; + + public: + // constructor + scc_core(std::string tag) + : vgsound_emu_core(tag) + , m_voice{*this, *this, *this, *this, *this} + , m_test(test_t()) + , m_out(0) + , m_reg{0} + { + } + + // destructor + virtual ~scc_core() {} + + // accessors + virtual u8 scc_r(bool is_sccplus, u8 address) = 0; + virtual void scc_w(bool is_sccplus, u8 address, u8 data) = 0; + + // internal state + virtual void reset(); + void tick(); + + // getters + inline s32 out() { return m_out; } // output to DA0...DA10 pin + + inline u8 reg(u8 address) { return m_reg[address]; } + + // for preview + inline s32 voice_out(u8 voice) { return (voice < 5) ? m_voice[voice].out() : 0; } + + protected: + // accessor + u8 wave_r(bool is_sccplus, u8 address); + void wave_w(bool is_sccplus, u8 address, u8 data); + void freq_vol_enable_w(u8 address, u8 data); + + // internal values + std::array m_voice; // 5 voices + + test_t m_test; // test register + s32 m_out = 0; // output to DA0...10 + + std::array m_reg = {0}; // register pool +}; + +// SCC core +class k051649_scc_core : public scc_core +{ + public: + // constructor + k051649_scc_core(std::string tag = "k051649_scc") + : scc_core(tag) + { + } + + // accessors + virtual u8 scc_r(bool is_sccplus, u8 address) override; + virtual void scc_w(bool is_sccplus, u8 address, u8 data) override; +}; + +class k052539_scc_core : public k051649_scc_core +{ + public: + // constructor + k052539_scc_core(std::string tag = "k052539_scc") + : k051649_scc_core(tag) + { + } + + // accessors + virtual u8 scc_r(bool is_sccplus, u8 address) override; + virtual void scc_w(bool is_sccplus, u8 address, u8 data) override; +}; + +// MegaROM Mapper with SCC +class k051649_core : public k051649_scc_core +{ + friend class vgsound_emu_mem_intf; // for megaROM mapper + + private: + // mapper classes + class k051649_mapper_t : public vgsound_emu_core + { + public: + k051649_mapper_t() + : vgsound_emu_core("k051649_mapper") + , m_bank{0, 1, 2, 3} + { + } + + // internal state + void reset(); + + // setters + inline void set_bank(u8 slot, u8 bank) { m_bank[slot & 3] = bank; } + + // getters + inline u8 bank(u8 slot) { return m_bank[slot & 3]; } + + private: + // registers + u8 m_bank[4] = {0, 1, 2, 3}; + }; + + public: + // constructor + k051649_core(vgsound_emu_mem_intf &intf) + : k051649_scc_core("k051649") + , m_intf(intf) + , m_mapper(k051649_mapper_t()) + , m_scc_enable(false) + { + } + + // accessors + u8 read(u16 address); + void write(u16 address, u8 data); + + virtual void reset() override; + + private: + vgsound_emu_mem_intf m_intf; + k051649_mapper_t m_mapper; + bool m_scc_enable = false; +}; + +// MegaRAM Mapper with SCC +class k052539_core : public k052539_scc_core +{ + friend class vgsound_emu_mem_intf; // for megaRAM mapper + + private: + // mapper classes + class k052539_mapper_t : public vgsound_emu_core + { + public: + k052539_mapper_t() + : vgsound_emu_core("k052539_mapper") + , m_bank{0, 1, 2, 3} + , m_ram_enable{false} + { + } + + // internal state + void reset(); + + // setters + inline void set_bank(u8 slot, u8 bank) { m_bank[slot & 3] = bank; } + + inline void set_ram_enable(u8 slot, bool ram_enable) + { + m_ram_enable[slot & 3] = ram_enable; + } + + // getters + inline u8 bank(u8 slot) { return m_bank[slot & 3]; } + + inline bool ram_enable(u8 slot) { return m_ram_enable[slot & 3]; } + + private: + // registers + std::array m_bank = {0, 1, 2, 3}; + std::array m_ram_enable = {false}; + }; + + public: + // constructor + k052539_core(vgsound_emu_mem_intf &intf) + : k052539_scc_core("k052539") + , m_intf(intf) + , m_mapper(k052539_mapper_t()) + , m_scc_enable(false) + , m_is_sccplus(false) + { + } + + // accessors + u8 read(u16 address); + void write(u16 address, u8 data); + + virtual void reset() override; + + private: + vgsound_emu_mem_intf m_intf; + k052539_mapper_t m_mapper; + bool m_scc_enable = false; + bool m_is_sccplus = false; +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/template/template.cpp b/vgsound_emu-modified/vgsound_emu/src/template/template.cpp new file mode 100644 index 000000000..d927860a0 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/template/template.cpp @@ -0,0 +1,33 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): (Author name) + Template for sound emulation core +*/ + +#include "template.hpp" + +void template_core::tick() +{ + // tick per each clock +} + +void template_core::reset() +{ + // reset this chip + std::fill(m_array.begin(), m_array.end(), 0); // std::fill() for fill std::array, std::vector +} + +/* +template voice function +void template_core::voice_t::tick() +{ + // tick per each voice +} + +void template_core::voice_t::reset() +{ + // reset this voice +} +*/ diff --git a/vgsound_emu-modified/vgsound_emu/src/template/template.hpp b/vgsound_emu-modified/vgsound_emu/src/template/template.hpp new file mode 100644 index 000000000..ca8f91b53 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/template/template.hpp @@ -0,0 +1,88 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): (Author name) + Template for sound emulation core, also guideline +*/ + +#ifndef _VGSOUND_EMU_SRC_TEMPLATE_HPP // _VGSOUND_EMU_ABSOLUTE_PATH_OF_THIS_FILE +#define _VGSOUND_EMU_SRC_TEMPLATE_HPP + +#pragma once + +#include "../core/util.hpp" + +class template_core : public vgsound_emu_core +{ + friend class vgsound_emu_mem_intf; // common memory interface if exists + + private: // protected: if shares between inheritances + // place classes and local constants here if exists + + // template voice classes + class voice_t : public vgsound_emu_core + { + public: + // constructor + voice_t(template_core &host) + : vgsound_emu_core("your_voice_tag_here") + , m_host(host) + , m_something(0) + { + } + + // internal state + void reset(); + void tick(); + + // accessors, getters, setters + + // setters + void set_something(s32 something) { m_something = something; } + + // getters + s32 something() { return m_something; } + + private: + // registers + template_core &m_host; + s32 m_something = 0; // register + }; + + public: + // place constructor and destructor, getter and setter for local variables, + // off-chip interfaces, update routine here only if can't be local + + // constructor + template_core(vgsound_emu_mem_intf &intf) + : vgsound_emu_core("your_core_tag_here") + // initialize all variables in constructor, because constructor is also executable + // anywhere, and it works as initializer. + , m_voice{*this} + , m_intf(intf) + , m_array{0} + , m_vector{0} + { + } + + // accessors, getters, setters + + // internal state + void reset(); + void tick(); + + protected: + // place local variables and functions here if shares between inheritances + + private: + // place local variables and functions here + + std::array m_voice; // voice classes + vgsound_emu_mem_intf &m_intf; // common memory interface + std::array m_array = { + 0}; // std::array for static size array + std::vector m_vector = {0}; // std::vector for variable size array +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md b/vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md new file mode 100644 index 000000000..5b2db0519 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md @@ -0,0 +1,97 @@ + +# Konami VRC VI + +## Summary + +- 2 voice pulse wave + - 8 level duty or volume only mode +- 1 voice sawtooth wave +- Internal mapper and timer + +## Source code + +- vrcvi.hpp: Base header + - vrcvi.cpp: Source emulation core + +## Description + +It's one of NES mapper with built-in sound chip, and also one of 2 Konami VRCs with this feature. (rest one has OPLL derivatives.) + +It's also DACless like other sound chip and mapper-with-sound manufactured by konami, the Chips 6 bit digital sound output is needs converted to analog sound output when you it want to make some sounds, or send to sound mixer. + +Its are used for Akumajou Densetsu (Japan release of Castlevania III), Madara, Esper Dream 2. + +The chip is installed in 351951 PCB and 351949A PCB. + +351951 PCB is used exclusivly for Akumajou Densetsu, Small board has VRC VI, PRG and CHR ROM. + +- It's configuration also calls VRC6a, iNES mapper 024. + +351949A PCB is for Last 2 titles with VRC VI, Bigger board has VRC VI, PRG and CHR ROM, and Battery Backed 8K x 8 bit SRAM. + +- Additionally, It's PRG A0 and A1 bit to VRC VI input is swapped, compare to above. +- It's configuration also calls VRC6b, iNES mapper 026. + +The chip itself has 053328, 053329, 053330 Revision, but Its difference between revision is unknown. + +Like other mappers for NES, It has internal timer - Its timer can be sync with scanline like other Konami mapper in this era. + +## Register layout + +- Sound and Timer only; 351951 PCB case, 351949A swaps xxx1 and xxx2 + +``` +Address Bits Description + 7654 3210 + +9000-9002 Pulse 1 + +9000 x--- ---- Pulse 1 Duty ignore + -xxx ---- Pulse 1 Duty cycle + ---- xxxx Pulse 1 Volume +9001 xxxx xxxx Pulse 1 Pitch bit 0-7 +9002 x--- ---- Pulse 1 Enable + ---- xxxx Pulse 1 Pitch bit 8-11 + +9003 Sound control + +9003 ---- -x-- 4 bit Frequency mode + ---- -0x- 8 bit Frequency mode + ---- ---x Halt + +a000-a002 Pulse 2 + +a000 x--- ---- Pulse 2 Duty ignore + -xxx ---- Pulse 2 Duty cycle + ---- xxxx Pulse 2 Volume +a001 xxxx xxxx Pulse 2 Pitch bit 0-7 +a002 x--- ---- Pulse 2 Enable + ---- xxxx Pulse 2 Pitch bit 8-11 + +b000-b002 Sawtooth + +b000 --xx xxxx Sawtooth Accumulate Rate +b001 xxxx xxxx Sawtooth Pitch bit 0-7 +b002 x--- ---- Sawtooth Enable + ---- xxxx Sawtooth Pitch bit 8-11 + +f000-f002 IRQ Timer + +f000 xxxx xxxx IRQ Timer latch +f001 ---- -0-- Sync with scanline + ---- --x- Enable timer + ---- ---x Enable timer after IRQ Acknowledge +f002 ---- ---- IRQ Acknowledge +``` + +# Frequency calculation + +``` + if 4 bit Frequency Mode then + Frequency: Input clock / (bit 8 to 11 of Pitch + 1) + end else if 8 bit Frequency Mode then + Frequency: Input clock / (bit 4 to 11 of Pitch + 1) + end else then + Frequency: Input clock / (Pitch + 1) + end +``` diff --git a/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp b/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp new file mode 100644 index 000000000..dc59120f3 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp @@ -0,0 +1,260 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami VRC VI sound emulation core +*/ + +#include "vrcvi.hpp" + +void vrcvi_core::tick() +{ + m_out = 0; + if (!m_control.halt()) // Halt flag + { + // tick per each clock + for (auto &elem : m_pulse) + { + m_out += elem.get_output(); // add 4 bit pulse output + } + m_out += m_sawtooth.get_output(); // add 5 bit sawtooth output + } + if (m_timer.tick()) + { + m_timer.counter_tick(); + } +} + +void vrcvi_core::reset() +{ + for (auto &elem : m_pulse) + { + elem.reset(); + } + + m_sawtooth.reset(); + m_timer.reset(); + m_control.reset(); + m_out = 0; +} + +bool vrcvi_core::alu_t::tick() +{ + if (m_divider.enable()) + { + const u16 temp = m_counter; + // post decrement + if (bitfield(m_host.m_control.shift(), 1)) + { + m_counter = (m_counter & 0x0ff) | (bitfield(bitfield(m_counter, 8, 4) - 1, 0, 4) << 8); + m_counter = (m_counter & 0xf00) | (bitfield(bitfield(m_counter, 0, 8) - 1, 0, 8) << 0); + } + else if (bitfield(m_host.m_control.shift(), 0)) + { + m_counter = (m_counter & 0x00f) | (bitfield(bitfield(m_counter, 4, 8) - 1, 0, 8) << 4); + m_counter = (m_counter & 0xff0) | (bitfield(bitfield(m_counter, 0, 4) - 1, 0, 4) << 0); + } + else + { + m_counter = bitfield(bitfield(m_counter, 0, 12) - 1, 0, 12); + } + + // carry handling + bool carry = bitfield(m_host.m_control.shift(), 1) + ? (bitfield(temp, 8, 4) == 0) + : (bitfield(m_host.m_control.shift(), 0) ? (bitfield(temp, 4, 8) == 0) + : (bitfield(temp, 0, 12) == 0)); + if (carry) + { + m_counter = m_divider.divider(); + } + + return carry; + } + return false; +} + +bool vrcvi_core::pulse_t::tick() +{ + if (!m_divider.enable()) + { + return false; + } + + if (vrcvi_core::alu_t::tick()) + { + m_cycle = bitfield(m_cycle + 1, 0, 4); + } + + return m_control.mode() ? true : ((m_cycle > m_control.duty()) ? true : false); +} + +bool vrcvi_core::sawtooth_t::tick() +{ + if (!m_divider.enable()) + { + return false; + } + + if (vrcvi_core::alu_t::tick()) + { + if (bitfield(m_cycle++, 0)) + { // Even step only + m_accum += m_rate; + } + if (m_cycle >= 14) // Reset accumulator at every 14 cycles + { + m_accum = 0; + m_cycle = 0; + } + } + return (m_accum == 0) ? false : true; +} + +s8 vrcvi_core::pulse_t::get_output() +{ + // add 4 bit pulse output + m_out = tick() ? m_control.volume() : 0; + return m_out; +} + +s8 vrcvi_core::sawtooth_t::get_output() +{ + // add 5 bit sawtooth output + m_out = tick() ? bitfield(m_accum, 3, 5) : 0; + return m_out; +} + +void vrcvi_core::alu_t::reset() +{ + m_divider.reset(); + m_counter = 0; + m_cycle = 0; + m_out = 0; +} + +void vrcvi_core::pulse_t::reset() +{ + vrcvi_core::alu_t::reset(); + m_control.reset(); +} + +void vrcvi_core::sawtooth_t::reset() +{ + vrcvi_core::alu_t::reset(); + m_rate = 0; + m_accum = 0; +} + +bool vrcvi_core::timer_t::tick() +{ + if (m_timer_control.enable()) + { + if (!m_timer_control.sync()) // scanline sync mode + { + m_prescaler -= 3; + if (m_prescaler <= 0) + { + m_prescaler += 341; + return true; + } + } + } + return (m_timer_control.enable() && m_timer_control.sync()) ? true : false; +} + +void vrcvi_core::timer_t::counter_tick() +{ + if (bitfield(++m_counter, 0, 8) == 0) + { + m_counter = m_counter_latch; + irq_set(); + } +} + +void vrcvi_core::timer_t::reset() +{ + m_timer_control.reset(); + m_prescaler = 341; + m_counter = m_counter_latch = 0; + irq_clear(); +} + +// Accessors + +void vrcvi_core::alu_t::divider_t::write(bool msb, u8 data) +{ + if (msb) + { + m_divider = (m_divider & ~0xf00) | (bitfield(data, 0, 4) << 8); + m_enable = bitfield(data, 7); + } + else + { + m_divider = (m_divider & ~0x0ff) | data; + } +} + +void vrcvi_core::pulse_w(u8 voice, u8 address, u8 data) +{ + pulse_t &v = m_pulse[voice]; + switch (address) + { + case 0x00: // Control - 0x9000 (Pulse 1), 0xa000 (Pulse 2) + v.control().write(data); + break; + case 0x01: // Pitch LSB - 0x9001/0x9002 (Pulse 1), 0xa001/0xa002 (Pulse 2) + v.divider().write(false, data); + break; + case 0x02: // Pitch MSB, Enable/Disable - 0x9002/0x9001 (Pulse 1), 0xa002/0xa001 (Pulse 2) + v.divider().write(true, data); + if (!v.divider().enable()) + { // Reset duty cycle + v.clear_cycle(); + } + break; + } +} + +void vrcvi_core::saw_w(u8 address, u8 data) +{ + switch (address) + { + case 0x00: // Sawtooth Accumulate - 0xb000 + m_sawtooth.set_rate(bitfield(data, 0, 6)); + break; + case 0x01: // Pitch LSB - 0xb001/0xb002 (Sawtooth) + m_sawtooth.divider().write(false, data); + break; + case 0x02: // Pitch MSB, Enable/Disable - 0xb002/0xb001 (Sawtooth) + m_sawtooth.divider().write(true, data); + if (!m_sawtooth.divider().enable()) + { // Reset accumulator + m_sawtooth.clear_accum(); + } + break; + } +} + +void vrcvi_core::timer_w(u8 address, u8 data) +{ + switch (address) + { + case 0x00: // Timer latch - 0xf000 + m_timer.set_counter_latch(data); + break; + case 0x01: // Timer control - 0xf001/0xf002 + m_timer.timer_control_w(data); + break; + case 0x02: // IRQ Acknowledge - 0xf002/0xf001 + m_timer.irq_ack(); + break; + } +} + +void vrcvi_core::control_w(u8 data) +{ + // Global control - 0x9003 + m_control.write(data); +} diff --git a/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp b/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp new file mode 100644 index 000000000..f163114c0 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp @@ -0,0 +1,407 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Konami VRC VI sound emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_VRCVI_HPP +#define _VGSOUND_EMU_SRC_VRCVI_HPP + +#pragma once + +#include "../core/util.hpp" + +class vrcvi_intf : public vgsound_emu_core +{ + public: + vrcvi_intf() + : vgsound_emu_core("vrc_vi_intf") + { + } + + virtual void irq_w(bool irq) {} +}; + +class vrcvi_core : public vgsound_emu_core +{ + friend class vrcvi_intf; + + private: + // Common ALU for sound channels + class alu_t : public vgsound_emu_core + { + private: + class divider_t : public vgsound_emu_core + { + public: + divider_t() + : vgsound_emu_core("vrc_vi_frequency_divider") + , m_divider(0) + , m_enable(0) + { + } + + void reset() + { + m_divider = 0; + m_enable = 0; + } + + void write(bool msb, u8 data); + + // getters + inline u16 divider() { return m_divider; } + + inline bool enable() { return m_enable; } + + private: + u16 m_divider : 12; // divider (pitch) + u16 m_enable : 1; // channel disable flag + }; + + public: + alu_t(std::string tag, vrcvi_core &host) + : vgsound_emu_core(tag) + , m_host(host) + , m_divider(divider_t()) + , m_counter(0) + , m_cycle(0) + , m_out(0) + { + } + + virtual void reset(); + virtual bool tick(); + + virtual s8 get_output() + { + m_out = 0; + return 0; + } + + // accessors + inline void clear_cycle() { m_cycle = 0; } + + // getters + divider_t ÷r() { return m_divider; } + + inline u16 counter() { return m_counter; } + + inline u8 cycle() { return m_cycle; } + + // for previwe/debug only + inline s8 out() { return m_out; } + + protected: + vrcvi_core &m_host; + divider_t m_divider; + u16 m_counter = 0; // clock counter + u8 m_cycle = 0; // clock cycle + s8 m_out = 0; // output per channel + }; + + // 2 Pulse channels + class pulse_t : public alu_t + { + private: + // Control bits + class pulse_control_t + { + public: + pulse_control_t() + : m_mode(0) + , m_duty(0) + , m_volume(0) + { + } + + void reset() + { + m_mode = 0; + m_duty = 0; + m_volume = 0; + } + + // accessors + inline void write(u8 data) + { + m_mode = (data >> 7) & 0x1; + m_duty = (data >> 4) & 0x7; + m_volume = (data >> 0) & 0xf; + } + + // getters + inline bool mode() { return m_mode; } + + inline u8 duty() { return m_duty; } + + inline u8 volume() { return m_volume; } + + private: + u8 m_mode : 1; // duty toggle flag + u8 m_duty : 3; // 3 bit duty cycle + u8 m_volume : 4; // 4 bit volume + }; + + public: + pulse_t(vrcvi_core &host) + : alu_t("vrc_vi_pulse", host) + , m_control(pulse_control_t()) + { + } + + virtual void reset() override; + virtual bool tick() override; + virtual s8 get_output() override; + + // getters + pulse_control_t &control() { return m_control; } + + private: + pulse_control_t m_control; + }; + + // 1 Sawtooth channel + class sawtooth_t : public alu_t + { + public: + sawtooth_t(vrcvi_core &host) + : alu_t("vrc_vi_sawtooth", host) + , m_rate(0) + , m_accum(0) + { + } + + virtual void reset() override; + virtual bool tick() override; + virtual s8 get_output() override; + + // accessors + inline void clear_accum() { m_accum = 0; } + + // setters + inline void set_rate(u8 rate) { m_rate = rate; } + + // getters + inline u8 rate() { return m_rate; } + + inline u8 accum() { return m_accum; } + + private: + u8 m_rate = 0; // sawtooth accumulate rate + u8 m_accum = 0; // sawtooth accumulator, high 5 bit is accumulated to output + }; + + // Internal timer + class timer_t : public vgsound_emu_core + { + private: + // Control bits + class timer_control_t : public vgsound_emu_core + { + public: + timer_control_t() + : vgsound_emu_core("vrc_vi_timer_control") + , m_irq_trigger(0) + , m_enable_ack(0) + , m_enable(0) + , m_sync(0) + { + } + + void reset() + { + m_irq_trigger = 0; + m_enable_ack = 0; + m_enable = 0; + m_sync = 0; + } + + // accessors + inline void irq_set(bool irq) { m_irq_trigger = irq ? 1 : 0; } + + // setters + inline void set_enable_ack(bool enable_ack) + { + m_enable_ack = enable_ack ? 1 : 0; + } + + inline void set_enable(bool enable) { m_enable = enable ? 1 : 0; } + + inline void set_sync(bool sync) { m_sync = sync ? 1 : 0; } + + // getters + inline bool irq_trigger() { return m_irq_trigger; } + + inline bool enable_ack() { return m_enable_ack; } + + inline bool enable() { return m_enable; } + + inline bool sync() { return m_sync; } + + private: + u8 m_irq_trigger : 1; + u8 m_enable_ack : 1; + u8 m_enable : 1; + u8 m_sync : 1; + }; + + public: + timer_t(vrcvi_core &host) + : vgsound_emu_core("vrc_vi_timer") + , m_host(host) + , m_timer_control(timer_control_t()) + , m_prescaler(341) + , m_counter(0) + , m_counter_latch(0) + { + } + + void reset(); + bool tick(); + void counter_tick(); + + // IRQ update + void update() { m_host.m_intf.irq_w(m_timer_control.irq_trigger()); } + + void irq_set() + { + if (!m_timer_control.irq_trigger()) + { + m_timer_control.irq_set(true); + update(); + } + } + + void irq_clear() + { + if (m_timer_control.irq_trigger()) + { + m_timer_control.irq_set(false); + update(); + } + } + + // accessors + void reset_counter() + { + m_counter = m_counter_latch; + m_prescaler = 341; + } + + void timer_control_w(u8 data) + { + m_timer_control.set_enable_ack((data >> 0) & 1); + m_timer_control.set_enable((data >> 1) & 1); + m_timer_control.set_sync((data >> 2) & 1); + if (m_timer_control.enable()) + { + reset_counter(); + } + irq_clear(); + } + + void irq_ack() + { + irq_clear(); + m_timer_control.set_enable(m_timer_control.enable_ack()); + } + + // setters + inline void set_counter_latch(u8 counter_latch) { m_counter_latch = counter_latch; } + + // getters + timer_control_t &timer_control() { return m_timer_control; } + + inline s16 prescaler() { return m_prescaler; } + + inline u8 counter() { return m_counter; } + + inline u8 counter_latch() { return m_counter_latch; } + + private: + vrcvi_core &m_host; // host core + timer_control_t m_timer_control; // timer control bits + s16 m_prescaler = 341; // prescaler + u8 m_counter = 0; // clock counter + u8 m_counter_latch = 0; // clock counter latch + }; + + class global_control_t : public vgsound_emu_core + { + public: + global_control_t() + : vgsound_emu_core("vrc_vi_global_control") + , m_halt(0) + , m_shift(0) + { + } + + void reset() + { + m_halt = 0; + m_shift = 0; + } + + // accessors + inline void write(u8 data) + { + m_halt = (data >> 0) & 1; + m_shift = (data >> 1) & 3; + } + + // getters + inline bool halt() { return m_halt; } + + inline u8 shift() { return m_shift; } + + private: + u8 m_halt : 1; // halt sound + u8 m_shift : 2; // 4/8 bit right shift + }; + + public: + // constructor + vrcvi_core(vrcvi_intf &intf) + : vgsound_emu_core("vrc_vi") + , m_intf(intf) + , m_pulse{*this, *this} + , m_sawtooth(*this) + , m_timer(*this) + , m_control(global_control_t()) + , m_out(0) + { + } + + // accessors, getters, setters + void pulse_w(u8 voice, u8 address, u8 data); + void saw_w(u8 address, u8 data); + void timer_w(u8 address, u8 data); + void control_w(u8 data); + + // internal state + void reset(); + void tick(); + + // 6 bit output + inline s8 out() { return m_out; } + + // for debug/preview only + inline s8 pulse_out(u8 pulse) { return (pulse < 2) ? m_pulse[pulse].out() : 0; } + + inline s8 sawtooth_out() { return m_sawtooth.out(); } + + private: + vrcvi_intf &m_intf; + + std::array m_pulse; // 2 pulse channels + sawtooth_t m_sawtooth; // sawtooth channel + timer_t m_timer; // internal timer + global_control_t m_control; // control + + s8 m_out = 0; // 6 bit output +}; + +#endif diff --git a/vgsound_emu-modified/vgsound_emu/src/x1_010/README.md b/vgsound_emu-modified/vgsound_emu/src/x1_010/README.md new file mode 100644 index 000000000..656e5c60f --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/x1_010/README.md @@ -0,0 +1,97 @@ + +# Seta/Allumer X1-010 + +## Summary + +- 16 voice wavetable or PCM + - 8 bit signed for both wavetable and PCM + - 128 width long waveform + - wavetable playback must be paired with envelope + - envelope shape is 4 bit stereo, 128 width long waveform + - waveform and envelope shape stored at each half area on RAM space + - total accessible memory for PCM: 1 MByte + +## Source code + +- x1_010.hpp: Base header + - x1_010.cpp: Source emulation core + +## Description + +the chip has 16 voices, all voices can be switchable to Wavetable or PCM sample playback mode. It has also 2 output channels, but no known hardware using this feature for stereo sound. + +Wavetable needs to paired with envelope, it's always enabled and similar as AY PSG's one but its shape is stored at RAM. + +PCM volume is stored by each register. + +Both volume is 4bit per output. + +Everything except PCM sample is stored at paired 8 bit RAM. + +## RAM layout + +common case: Address bit 12 is swapped when RAM is shared with CPU + +### Voice registers (0000...007f) + +0000...0007 Voice #0 Register + +``` +Address Bits Description + 7654 3210 +0 x--- ---- Frequency divider* + ---- -x-- Envelope one-shot mode + ---- --x- Sound format + ---- --0- PCM + ---- --1- Wavetable + ---- ---x Keyon/off +PCM case: +1 xxxx xxxx Volume (Each nibble is for each output) + +2 xxxx xxxx Frequency + +4 xxxx xxxx Start address / 4096 + +5 xxxx xxxx 0x100 - (End address / 4096) +Wavetable case: +1 ---x xxxx Wavetable data select + +2 xxxx xxxx Frequency LSB +3 xxxx xxxx "" MSB + +4 xxxx xxxx Envelope period + +5 ---x xxxx Envelope shape select (!= 0 : Reserved for Voice registers) +``` + +0008...000f Voice #1 Register +... +0078...007f Voice #15 Register + +### Envelope shape data (0080...0fff) + +Same format as volume; Each nibble is for each output + +0080...00ff Envelope shape #1 data +0100...017f Envelope shape #2 data +... +0f80...0fff Envelope shape #31 data + +### Waveform data (1000...1fff) + +1000...107f Waveform #0 data +1080...10ff Waveform #1 data +... +1f80...1fff Waveform #31 data + +## Frequency calculation + +``` +Wavetable, Divider Clear: Frequency value * (Input clock / 524288) +Wavetable, Divider Set: Frequency value * (Input clock / 1048576) +PCM, Divider Clear: Frequency value * (Input clock / 8192) +PCM, Divider Set: Frequency value * (Input clock / 16384) +Envelope: Envelope period * (Input clock / 524288) - Frequency divider not affected? +``` + +Frequency divider is higher precision or just right shift? needs verification. diff --git a/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp b/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp new file mode 100644 index 000000000..c249e5548 --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp @@ -0,0 +1,163 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Seta/Allumer X1-010 Emulation core +*/ + +#include "x1_010.hpp" + +void x1_010_core::tick() +{ + // reset output + m_out[0] = m_out[1] = 0; + for (voice_t &elem : m_voice) + { + elem.tick(); + m_out[0] += elem.out(0); + m_out[1] += elem.out(1); + } +} + +void x1_010_core::voice_t::tick() +{ + m_out[0] = m_out[1] = 0; + if (m_flag.keyon()) + { + if (m_flag.wavetable()) // Wavetable + { + // envelope, each nibble is for each output + u8 vol = + m_host.m_envelope[(bitfield(m_end_envshape, 0, 5) << 7) | bitfield(m_env_acc, 10, 7)]; + m_vol_out[0] = bitfield(vol, 4, 4); + m_vol_out[1] = bitfield(vol, 0, 4); + m_env_acc += m_start_envfreq; + if (m_flag.env_oneshot() && bitfield(m_env_acc, 17)) + { + m_flag.set_keyon(false); + } + else + { + m_env_acc = bitfield(m_env_acc, 0, 17); + } + // get wavetable data + m_data = m_host.m_wave[(bitfield(m_vol_wave, 0, 5) << 7) | bitfield(m_acc, 11, 7)]; + m_acc = bitfield(m_acc + (m_freq << (1 - m_flag.div())), 0, 18); + } + else // PCM sample + { + // volume register, each nibble is for each output + m_vol_out[0] = bitfield(m_vol_wave, 4, 4); + m_vol_out[1] = bitfield(m_vol_wave, 0, 4); + // get PCM sample + m_data = m_host.m_intf.read_byte(bitfield(m_acc, 5, 20)); + m_acc += u32(bitfield(m_freq, 0, 8)) << (1 - m_flag.div()); + if ((m_acc >> 17) > u32(0xff ^ m_end_envshape)) + { + m_flag.set_keyon(false); + } + } + m_out[0] = m_data * m_vol_out[0]; + m_out[1] = m_data * m_vol_out[1]; + } +} + +u8 x1_010_core::ram_r(u16 offset) +{ + if (offset & 0x1000) + { // wavetable data + return m_wave[offset & 0xfff]; + } + else if (offset & 0xf80) + { // envelope shape data + return m_envelope[offset & 0xfff]; + } + else + { // channel register + return m_voice[bitfield(offset, 3, 4)].reg_r(offset & 0x7); + } +} + +void x1_010_core::ram_w(u16 offset, u8 data) +{ + if (offset & 0x1000) + { // wavetable data + m_wave[offset & 0xfff] = data; + } + else if (offset & 0xf80) + { // envelope shape data + m_envelope[offset & 0xfff] = data; + } + else + { // channel register + m_voice[bitfield(offset, 3, 4)].reg_w(offset & 0x7, data); + } +} + +u8 x1_010_core::voice_t::reg_r(u8 offset) +{ + switch (offset & 0x7) + { + case 0x00: + return (m_flag.div() << 7) | (m_flag.env_oneshot() << 2) | (m_flag.wavetable() << 1) | + (m_flag.keyon() << 0); + case 0x01: return m_vol_wave; + case 0x02: return bitfield(m_freq, 0, 8); + case 0x03: return bitfield(m_freq, 8, 8); + case 0x04: return m_start_envfreq; + case 0x05: return m_end_envshape; + default: break; + } + return 0; +} + +void x1_010_core::voice_t::reg_w(u8 offset, u8 data) +{ + switch (offset & 0x7) + { + case 0x00: + { + const bool prev_keyon = m_flag.keyon(); + m_flag.write(data); + if (!prev_keyon && m_flag.keyon()) // Key on + { + m_acc = m_flag.wavetable() ? 0 : (u32(m_start_envfreq) << 16); + m_env_acc = 0; + } + break; + } + case 0x01: m_vol_wave = data; break; + case 0x02: m_freq = (m_freq & 0xff00) | data; break; + case 0x03: m_freq = (m_freq & 0x00ff) | (u16(data) << 8); break; + case 0x04: m_start_envfreq = data; break; + case 0x05: m_end_envshape = data; break; + default: break; + } +} + +void x1_010_core::voice_t::reset() +{ + m_flag.reset(); + m_vol_wave = 0; + m_freq = 0; + m_start_envfreq = 0; + m_end_envshape = 0; + m_acc = 0; + m_env_acc = 0; + m_data = 0; + m_vol_out.fill(0); + m_out.fill(0); +} + +void x1_010_core::reset() +{ + for (auto &elem : m_voice) + { + elem.reset(); + } + + m_envelope.fill(0); + m_wave.fill(0); + m_out.fill(0); +} diff --git a/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp b/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp new file mode 100644 index 000000000..34a4ab99a --- /dev/null +++ b/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp @@ -0,0 +1,179 @@ +/* + License: Zlib + see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details + + Copyright holder(s): cam900 + Seta/Allumer X1-010 Emulation core +*/ + +#ifndef _VGSOUND_EMU_SRC_X1_010_HPP +#define _VGSOUND_EMU_SRC_X1_010_HPP + +#pragma once + +#include "../core/util.hpp" + +class x1_010_core : public vgsound_emu_core +{ + friend class vgsound_emu_mem_intf; + + private: + // 16 voices in chip + class voice_t : public vgsound_emu_core + { + private: + class flag_t : public vgsound_emu_core + { + public: + flag_t() + : vgsound_emu_core("x1_010_voice_flag") + , m_div(0) + , m_env_oneshot(0) + , m_wavetable(0) + , m_keyon(0) + { + } + + // internal state + void reset() + { + m_div = 0; + m_env_oneshot = 0; + m_wavetable = 0; + m_keyon = 0; + } + + // register accessor + inline void write(u8 data) + { + m_div = (data >> 7) & 1; + m_env_oneshot = (data >> 2) & 1; + m_wavetable = (data >> 1) & 1; + m_keyon = (data >> 0) & 1; + } + + // Setters + inline void set_keyon(bool keyon) { m_keyon = keyon; } + + // Getters + inline bool div() { return m_div; } + + inline bool env_oneshot() { return m_env_oneshot; } + + inline bool wavetable() { return m_wavetable; } + + inline bool keyon() { return m_keyon; } + + private: + u8 m_div : 1; + u8 m_env_oneshot : 1; + u8 m_wavetable : 1; + u8 m_keyon : 1; + }; + + public: + // constructor + voice_t(x1_010_core &host) + : vgsound_emu_core("x1_010_voice") + , m_host(host) + , m_flag(flag_t()) + , m_vol_wave(0) + , m_freq(0) + , m_start_envfreq(0) + , m_end_envshape(0) + , m_acc(0) + , m_env_acc(0) + , m_data(0) + , m_vol_out{0} + , m_out{0} + { + } + + // internal state + void reset(); + void tick(); + + // register accessor + u8 reg_r(u8 offset); + void reg_w(u8 offset, u8 data); + + // getters + inline s32 out(u8 ch) { return m_out[ch & 1]; } + + private: + // host flag + x1_010_core &m_host; + // registers + flag_t m_flag; + u8 m_vol_wave = 0; + u16 m_freq = 0; + u8 m_start_envfreq = 0; + u8 m_end_envshape = 0; + + // internal registers + u32 m_acc = 0; + u32 m_env_acc = 0; + s8 m_data = 0; + std::array m_vol_out = {0}; + + // for preview only + std::array m_out = {0}; + }; + + public: + // constructor + x1_010_core(vgsound_emu_mem_intf &intf) + : vgsound_emu_core("x1_010") + , m_voice{*this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this, + *this} + , m_intf(intf) + , m_envelope{0} + , m_wave{0} + , m_out{0} + { + } + + // register accessor + u8 ram_r(u16 offset); + void ram_w(u16 offset, u8 data); + + // getters + inline s32 output(u8 ch) { return m_out[ch & 1]; } + + // internal state + void reset(); + void tick(); + + // for preview only + inline s32 voice_out(u8 voice, u8 ch) + { + return (voice < 16) ? m_voice[voice].out(ch & 1) : 0; + } + + private: + std::array m_voice; + vgsound_emu_mem_intf &m_intf; + + // RAM + std::array m_envelope = {0}; + std::array m_wave = {0}; + + // output data + std::array m_out = {0}; +}; + +#endif From 2582ec17ed082cb7ef1ff5655ab251fe93739565 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 00:15:04 +0900 Subject: [PATCH 421/515] Temporary workaround for accidently removed libs --- extern/vgsound_emu-modified | 1 - 1 file changed, 1 deletion(-) delete mode 160000 extern/vgsound_emu-modified diff --git a/extern/vgsound_emu-modified b/extern/vgsound_emu-modified deleted file mode 160000 index 7b988a671..000000000 --- a/extern/vgsound_emu-modified +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7b988a6714ebf61e8a5fad5c9ccbda2b85853fe1 From 5034b3623d8721722a3bb4832a2fc7205586d29d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 00:16:20 +0900 Subject: [PATCH 422/515] Take 2 --- .../vgsound_emu-modified}/.clang-format | 0 {vgsound_emu-modified => extern/vgsound_emu-modified}/.gitignore | 0 .../vgsound_emu-modified}/CHANGELOG.md | 0 .../vgsound_emu-modified}/CMakeLists.txt | 0 {vgsound_emu-modified => extern/vgsound_emu-modified}/LICENSE | 0 {vgsound_emu-modified => extern/vgsound_emu-modified}/MODIFIED.md | 0 {vgsound_emu-modified => extern/vgsound_emu-modified}/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/core/util.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/core/vox/vox.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/core/vox/vox.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es5504.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es5504.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es5505.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es5505.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es5506.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es5506.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es550x.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es550x.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/es550x/es550x_alu.cpp | 0 .../vgsound_emu/src/es550x/es550x_filter.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/k005289/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/k005289/k005289.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/k005289/k005289.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/k007232/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/k007232/k007232.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/k007232/k007232.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/k053260/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/k053260/k053260.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/k053260/k053260.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/msm6295/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/msm6295/msm6295.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/msm6295/msm6295.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/n163/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/n163/n163.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/n163/n163.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/scc/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/scc/scc.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/scc/scc.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/template/template.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/template/template.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/vrcvi/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/vrcvi/vrcvi.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/vrcvi/vrcvi.hpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/x1_010/README.md | 0 .../vgsound_emu-modified}/vgsound_emu/src/x1_010/x1_010.cpp | 0 .../vgsound_emu-modified}/vgsound_emu/src/x1_010/x1_010.hpp | 0 47 files changed, 0 insertions(+), 0 deletions(-) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/.clang-format (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/.gitignore (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/CHANGELOG.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/CMakeLists.txt (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/LICENSE (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/MODIFIED.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/core/util.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/core/vox/vox.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/core/vox/vox.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es5504.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es5504.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es5505.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es5505.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es5506.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es5506.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es550x.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es550x.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es550x_alu.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/es550x/es550x_filter.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k005289/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k005289/k005289.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k005289/k005289.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k007232/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k007232/k007232.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k007232/k007232.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k053260/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k053260/k053260.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/k053260/k053260.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/msm6295/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/msm6295/msm6295.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/msm6295/msm6295.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/n163/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/n163/n163.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/n163/n163.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/scc/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/scc/scc.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/scc/scc.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/template/template.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/template/template.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/vrcvi/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/vrcvi/vrcvi.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/vrcvi/vrcvi.hpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/x1_010/README.md (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/x1_010/x1_010.cpp (100%) rename {vgsound_emu-modified => extern/vgsound_emu-modified}/vgsound_emu/src/x1_010/x1_010.hpp (100%) diff --git a/vgsound_emu-modified/.clang-format b/extern/vgsound_emu-modified/.clang-format similarity index 100% rename from vgsound_emu-modified/.clang-format rename to extern/vgsound_emu-modified/.clang-format diff --git a/vgsound_emu-modified/.gitignore b/extern/vgsound_emu-modified/.gitignore similarity index 100% rename from vgsound_emu-modified/.gitignore rename to extern/vgsound_emu-modified/.gitignore diff --git a/vgsound_emu-modified/CHANGELOG.md b/extern/vgsound_emu-modified/CHANGELOG.md similarity index 100% rename from vgsound_emu-modified/CHANGELOG.md rename to extern/vgsound_emu-modified/CHANGELOG.md diff --git a/vgsound_emu-modified/CMakeLists.txt b/extern/vgsound_emu-modified/CMakeLists.txt similarity index 100% rename from vgsound_emu-modified/CMakeLists.txt rename to extern/vgsound_emu-modified/CMakeLists.txt diff --git a/vgsound_emu-modified/LICENSE b/extern/vgsound_emu-modified/LICENSE similarity index 100% rename from vgsound_emu-modified/LICENSE rename to extern/vgsound_emu-modified/LICENSE diff --git a/vgsound_emu-modified/MODIFIED.md b/extern/vgsound_emu-modified/MODIFIED.md similarity index 100% rename from vgsound_emu-modified/MODIFIED.md rename to extern/vgsound_emu-modified/MODIFIED.md diff --git a/vgsound_emu-modified/README.md b/extern/vgsound_emu-modified/README.md similarity index 100% rename from vgsound_emu-modified/README.md rename to extern/vgsound_emu-modified/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/core/util.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/util.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/core/util.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/core/util.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_alu.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/es550x/es550x_filter.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/k005289/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/k005289/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k005289/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/k005289/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/k005289/k005289.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/k007232/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/k007232/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k007232/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/k007232/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/k053260/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k053260/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/k053260/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/msm6295/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/msm6295/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/msm6295/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/msm6295/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/msm6295/msm6295.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/n163/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/n163/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/n163/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/n163/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/n163/n163.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/n163/n163.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/scc/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/scc/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/scc/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/scc/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/scc/scc.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/scc/scc.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/template/template.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/template/template.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/template/template.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/template/template.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/template/template.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/template/template.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/template/template.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/template/template.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/vrcvi/vrcvi.hpp diff --git a/vgsound_emu-modified/vgsound_emu/src/x1_010/README.md b/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/README.md similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/x1_010/README.md rename to extern/vgsound_emu-modified/vgsound_emu/src/x1_010/README.md diff --git a/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp rename to extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp diff --git a/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp similarity index 100% rename from vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp rename to extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.hpp From 74bf0171f0668e03a83a952897d0ef96a9d46b0c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 12:36:36 +0900 Subject: [PATCH 423/515] Modifier disclaimer --- extern/vgsound_emu-modified/MODIFIED.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extern/vgsound_emu-modified/MODIFIED.md b/extern/vgsound_emu-modified/MODIFIED.md index 432d014f9..00a7e727d 100644 --- a/extern/vgsound_emu-modified/MODIFIED.md +++ b/extern/vgsound_emu-modified/MODIFIED.md @@ -5,3 +5,7 @@ this is a modified version of vgsound_emu emulation core library tailored for Fu it should not and shall NOT be mistaken for the original, authentic or actual version and revision of the library. you can get original software from [here](https://gitlab.com/cam900/vgsound_emu/). + +## Modifier + +- [cam900](https://gitlab.com/cam900) \ No newline at end of file From c9813192953959a6f821012cdf7df27c5b4a8e70 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 12:48:03 +0900 Subject: [PATCH 424/515] Sync with master --- extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp | 2 +- extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp index ef06c1511..0eb97ab00 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp @@ -16,7 +16,7 @@ void vox_core::vox_decoder_t::decoder_state_t::reset() } // copy from source -void vox_core::vox_decoder_t::decoder_state_t::copy(decoder_state_t src) +void vox_core::vox_decoder_t::decoder_state_t::copy_state(decoder_state_t src) { m_index = src.index(); m_step = src.step(); diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp index f3ae6d4c1..167d0fedd 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp @@ -42,14 +42,14 @@ class vox_core : public vgsound_emu_core decoder_state_t &operator=(decoder_state_t src) { - copy(src); + copy_state(src); return *this; } private: const bool m_wraparound = false; // wraparound or clamp? - void copy(decoder_state_t src); + void copy_state(decoder_state_t src); vox_core &m_vox; s8 m_index = 0; From 4eaf5ce9a6a74c8f2a59ccfc4980f47a7ff74ea8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 12:55:05 +0900 Subject: [PATCH 425/515] Sync with master --- extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp | 2 +- extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp index 0eb97ab00..ec16ca2b0 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.cpp @@ -16,7 +16,7 @@ void vox_core::vox_decoder_t::decoder_state_t::reset() } // copy from source -void vox_core::vox_decoder_t::decoder_state_t::copy_state(decoder_state_t src) +void vox_core::vox_decoder_t::decoder_state_t::copy_state(decoder_state_t &src) { m_index = src.index(); m_step = src.step(); diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp index 167d0fedd..ead2ca753 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp @@ -40,7 +40,7 @@ class vox_core : public vgsound_emu_core s32 step() { return m_step; } - decoder_state_t &operator=(decoder_state_t src) + decoder_state_t &operator=(decoder_state_t &src) { copy_state(src); return *this; @@ -49,7 +49,7 @@ class vox_core : public vgsound_emu_core private: const bool m_wraparound = false; // wraparound or clamp? - void copy_state(decoder_state_t src); + void copy_state(decoder_state_t &src); vox_core &m_vox; s8 m_index = 0; From e9bdd356da4c9e7cc6742884cb9872b777f1c7f1 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 13:02:10 +0900 Subject: [PATCH 426/515] Sync with master --- extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp | 4 ++-- extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp index 34782f104..4c8454c88 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp @@ -35,7 +35,7 @@ class es5505_core : public es550x_shared_core inline s32 clamp16(s32 in) { return clamp(in, -0x8000, 0x7fff); } - inline void clamp16(output_t src) + inline void clamp16(output_t &src) { m_left = clamp16(src.left()); m_right = clamp16(src.right()); @@ -76,7 +76,7 @@ class es5505_core : public es550x_shared_core return *this; } - output_t &operator=(output_t src) + output_t &operator=(output_t &src) { clamp16(src); return *this; diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp index 84a6077de..53713cfbe 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp @@ -35,7 +35,7 @@ class es5506_core : public es550x_shared_core inline s32 clamp20(s32 in) { return clamp(in, -0x80000, 0x7ffff); } - inline void clamp20(output_t src) + inline void clamp20(output_t &src) { m_left = clamp20(src.left()); m_right = clamp20(src.right()); @@ -76,7 +76,7 @@ class es5506_core : public es550x_shared_core return *this; } - output_t &operator=(output_t src) + output_t &operator=(output_t &src) { clamp20(src); return *this; From 146da2ce7649fcea31f76502b4307461b1a70f23 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 13:05:58 +0900 Subject: [PATCH 427/515] Forgot to sync --- extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp | 4 ++-- extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp index 4c8454c88..d1c70614a 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp @@ -65,9 +65,9 @@ class es5505_core : public es550x_shared_core } // getters - inline u32 left() { return m_left; } + inline s32 left() { return m_left; } - inline u32 right() { return m_right; } + inline s32 right() { return m_right; } output_t &operator+=(output_t &src) { diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp index 53713cfbe..524e754e1 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp @@ -65,9 +65,9 @@ class es5506_core : public es550x_shared_core } // getters - inline u32 left() { return m_left; } + inline s32 left() { return m_left; } - inline u32 right() { return m_right; } + inline s32 right() { return m_right; } output_t &operator+=(output_t &src) { From 5af02d068e62a589f83fd787a646a3746f4d9a40 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 13:33:21 +0900 Subject: [PATCH 428/515] Sync with master --- .../vgsound_emu/src/es550x/es5504.cpp | 5 ++++- .../vgsound_emu/src/es550x/es5505.cpp | 8 ++++---- .../vgsound_emu/src/es550x/es5505.hpp | 4 ++-- .../vgsound_emu/src/es550x/es5506.cpp | 8 ++++---- .../vgsound_emu/src/es550x/es5506.hpp | 4 ++-- .../vgsound_emu/src/k053260/k053260.cpp | 4 ++-- .../vgsound_emu/src/k053260/k053260.hpp | 2 +- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp index 586f15f30..b31a13b20 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5504.cpp @@ -357,7 +357,10 @@ void es5504_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) if (bitfield(m_adc, 0)) // Writam_ble ADC { m_adc = (m_adc & 7) | (data & ~7); - m_intf.adc_w(m_adc & ~7); + if (cpu_access) + { + m_intf.adc_w(m_adc & ~7); + } } m_adc = (m_adc & ~3) | (data & 3); break; diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp index 07a7b7046..6b2712248 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp @@ -319,7 +319,7 @@ void es5505_core::host_w(u8 address, u16 data) m_hd = data; if (m_e.rising_edge()) { // update directly - write(m_ha, m_hd, true); + write(m_ha, m_hd); } else { @@ -330,9 +330,9 @@ void es5505_core::host_w(u8 address, u16 data) u16 es5505_core::read(u8 address, bool cpu_access) { return regs_r(m_page, address, cpu_access); } -void es5505_core::write(u8 address, u16 data, bool cpu_access) +void es5505_core::write(u8 address, u16 data) { - regs_w(m_page, address, data, cpu_access); + regs_w(m_page, address, data); } u16 es5505_core::regs_r(u8 page, u8 address, bool cpu_access) @@ -488,7 +488,7 @@ u16 es5505_core::regs_r(u8 page, u8 address, bool cpu_access) return ret; } -void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) +void es5505_core::regs_w(u8 page, u8 address, u16 data) { address = bitfield(address, 0, 4); // 4 bit address for CPU access diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp index d1c70614a..4cbd25813 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp @@ -262,10 +262,10 @@ class es5505_core : public es550x_shared_core // bypass chips host interface for debug purpose only u16 read(u8 address, bool cpu_access = false); - void write(u8 address, u16 data, bool cpu_access = false); + void write(u8 address, u16 data); u16 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); + void regs_w(u8 page, u8 address, u16 data); u16 regs_r(u8 page, u8 address) { diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp index ebb9a62d9..b0f887da5 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp @@ -438,7 +438,7 @@ void es5506_core::host_w(u8 address, u8 data) m_hd = data; if (m_e.rising_edge()) { // update directly - write(m_ha, m_hd, true); + write(m_ha, m_hd); } else { @@ -464,7 +464,7 @@ u8 es5506_core::read(u8 address, bool cpu_access) return bitfield(m_read_latch, 24, 8); } -void es5506_core::write(u8 address, u8 data, bool cpu_access) +void es5506_core::write(u8 address, u8 data) { const u8 byte = bitfield(address, 0, 2); // byte select const u8 shift = 24 - (byte << 3); @@ -478,7 +478,7 @@ void es5506_core::write(u8 address, u8 data, bool cpu_access) return; } - regs_w(m_page, address, m_write_latch, cpu_access); + regs_w(m_page, address, m_write_latch); // Reset latch m_write_latch = 0; @@ -707,7 +707,7 @@ u32 es5506_core::regs_r(u8 page, u8 address, bool cpu_access) return read_latch; } -void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access) +void es5506_core::regs_w(u8 page, u8 address, u32 data) { // Global registers if (address >= 13) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp index 524e754e1..f54a03c3e 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp @@ -329,10 +329,10 @@ class es5506_core : public es550x_shared_core // bypass chips host interface for debug purpose only u8 read(u8 address, bool cpu_access = false); - void write(u8 address, u8 data, bool cpu_access = false); + void write(u8 address, u8 data); u32 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u32 data, bool cpu_access = false); + void regs_w(u8 page, u8 address, u32 data); u8 regs8_r(u8 page, u8 address) { diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp index 6fe759ac2..cccdbbf58 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp @@ -15,7 +15,7 @@ void k053260_core::tick() { for (int i = 0; i < 4; i++) { - m_voice[i].tick(i); + m_voice[i].tick(); m_out[0] += m_voice[i].out(0); m_out[1] += m_voice[i].out(1); } @@ -36,7 +36,7 @@ void k053260_core::tick() m_dac.set_clock(bitfield(dac_clock, 0, 4)); } -void k053260_core::voice_t::tick(u8 ne) +void k053260_core::voice_t::tick() { if (m_enable && m_busy) { diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp index de39e35ec..bca78a1f4 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp @@ -61,7 +61,7 @@ class k053260_core : public vgsound_emu_core // internal state void reset(); - void tick(u8 ne); + void tick(); // accessors void write(u8 address, u8 data); From 81f812b2160063ce40f54571c8dd69c0c0f85914 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 13:56:09 +0900 Subject: [PATCH 429/515] Sync with master --- .../vgsound_emu/src/es550x/es5505.cpp | 9 ++++----- .../vgsound_emu/src/es550x/es5505.hpp | 20 +++++++------------ .../vgsound_emu/src/es550x/es5506.cpp | 10 +++++----- .../vgsound_emu/src/es550x/es5506.hpp | 20 +++++++------------ 4 files changed, 23 insertions(+), 36 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp index 6b2712248..6172a8665 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.cpp @@ -45,12 +45,11 @@ void es5505_core::tick() for (int i = 0; i < 4; i++) { // copy output - m_output[i] = m_output_temp[i]; - m_output_latch[i] = m_ch[i]; - m_output_temp[i].reset(); + m_output[i].copy_output(m_output_temp[i]); // clamp to 16 bit (upper 5 bits are overflow // guard bits) - m_output_latch[i].clamp16(); + m_output_latch[i].clamp16(m_ch[i]); + m_output_temp[i].reset(); // set signed if (m_output_latch[i].left() < 0) { @@ -155,7 +154,7 @@ void es5505_core::tick_perf() // output for (int c = 0; c < 4; c++) { - m_output[c] = m_ch[c]; + m_output[c].clamp16(m_ch[c]); } // update diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp index 4cbd25813..52a3b5f36 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5505.hpp @@ -31,7 +31,13 @@ class es5505_core : public es550x_shared_core { m_left = 0; m_right = 0; - }; + } + + inline void copy_output(output_t &src) + { + m_left = src.left(); + m_right = src.right(); + } inline s32 clamp16(s32 in) { return clamp(in, -0x8000, 0x7fff); } @@ -76,18 +82,6 @@ class es5505_core : public es550x_shared_core return *this; } - output_t &operator=(output_t &src) - { - clamp16(src); - return *this; - } - - output_t &operator=(s32 val) - { - m_left = m_right = clamp16(val); - return *this; - } - output_t &operator>>(s32 shift) { m_left >>= shift; diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp index b0f887da5..83e43cac9 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.cpp @@ -63,11 +63,11 @@ void es5506_core::tick() for (int i = 0; i < 6; i++) { // copy output - m_output[i] = m_output_temp[i]; - m_output_latch[i] = m_ch[i]; - m_output_temp[i].reset(); + m_output[i].copy_output(m_output_temp[i]); // clamp to 20 bit (upper 3 bits are // overflow guard bits) + m_output_latch[i].clamp20(m_ch[i]); + m_output_temp[i].reset(); m_output_latch[i].clamp20(); // set signed if (m_output_latch[i].left() < 0) @@ -202,7 +202,7 @@ void es5506_core::tick_perf() { for (int c = 0; c < 6; c++) { - m_output[c] = m_ch[c] >> output_bits; + m_output[c].clamp20(m_ch[c] >> output_bits); } } } @@ -210,7 +210,7 @@ void es5506_core::tick_perf() { for (int c = 0; c < 6; c++) { - m_output[c] = 0; + m_output[c].reset(); } } diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp index f54a03c3e..b59a96dcf 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/es550x/es5506.hpp @@ -31,7 +31,13 @@ class es5506_core : public es550x_shared_core { m_left = 0; m_right = 0; - }; + } + + inline void copy_output(output_t &src) + { + m_left = src.left(); + m_right = src.right(); + } inline s32 clamp20(s32 in) { return clamp(in, -0x80000, 0x7ffff); } @@ -76,18 +82,6 @@ class es5506_core : public es550x_shared_core return *this; } - output_t &operator=(output_t &src) - { - clamp20(src); - return *this; - } - - output_t &operator=(s32 val) - { - m_left = m_right = clamp20(val); - return *this; - } - output_t &operator>>(s32 shift) { m_left >>= shift; From eeb09c703147a0845c7eb4886dfe60caac23b45b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Sep 2022 14:02:43 +0900 Subject: [PATCH 430/515] Sync with master --- .../vgsound_emu/src/core/vox/vox.hpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp index ead2ca753..231f9b638 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/core/vox/vox.hpp @@ -40,17 +40,11 @@ class vox_core : public vgsound_emu_core s32 step() { return m_step; } - decoder_state_t &operator=(decoder_state_t &src) - { - copy_state(src); - return *this; - } + void copy_state(decoder_state_t &src); private: const bool m_wraparound = false; // wraparound or clamp? - void copy_state(decoder_state_t &src); - vox_core &m_vox; s8 m_index = 0; s32 m_step = 16; @@ -76,7 +70,7 @@ class vox_core : public vgsound_emu_core { if (!m_loop_saved) { - m_loop = m_curr; + m_loop.copy_state(m_curr); m_loop_saved = true; } } @@ -85,7 +79,7 @@ class vox_core : public vgsound_emu_core { if (m_loop_saved) { - m_curr = m_loop; + m_curr.copy_state(m_loop); } } From 8ba53999bc710e51594c42e0c1d844f77474248c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 18 Sep 2022 12:09:54 +0900 Subject: [PATCH 431/515] Less confused naming --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 885a4c49e..634cf584f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -183,7 +183,7 @@ TAParamResult pVersion(String) { printf("- reSID by Dag Lem (GPLv2)\n"); printf("- reSIDfp by Dag Lem, Antti Lankila and Leandro Nini (GPLv2)\n"); printf("- Stella by Stella Team (GPLv2)\n"); - printf("- vgsound_emu (second version) by cam900 (zlib)\n"); + printf("- vgsound_emu (second version) by cam900 (zlib license)\n"); return TA_PARAM_QUIT; } From 6bf6a854efc9d6d702699a48484e689396b3b993 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 17 Sep 2022 22:55:58 -0500 Subject: [PATCH 432/515] GUI: comfortable wave macro height --- src/gui/doAction.cpp | 3 +++ src/gui/gui.cpp | 1 + src/gui/gui.h | 6 ++++++ src/gui/insEdit.cpp | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 92e12a742..468b7e37c 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -645,6 +645,7 @@ void FurnaceGUI::doAction(int what) { } else { wantScrollList=true; MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } break; case GUI_ACTION_WAVE_LIST_DUPLICATE: @@ -657,6 +658,7 @@ void FurnaceGUI::doAction(int what) { (*e->song.wave[curWave])=(*e->song.wave[prevWave]); wantScrollList=true; MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } } break; @@ -1326,6 +1328,7 @@ void FurnaceGUI::doAction(int what) { } nextWindow=GUI_WINDOW_WAVE_EDIT; MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } } break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5153e1f6a..06fc65f08 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3884,6 +3884,7 @@ bool FurnaceGUI::loop() { showError("cannot load wavetable! ("+e->getLastError()+")"); } else { MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } } break; diff --git a/src/gui/gui.h b/src/gui/gui.h index 1c8ee713f..6499c4d19 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -47,6 +47,12 @@ #define MARK_MODIFIED modified=true; #define WAKE_UP drawHalt=16; +#define RESET_WAVE_MACRO_ZOOM \ + for (DivInstrument* _wi: e->song.ins) { \ + _wi->std.waveMacro.vZoom=-1; \ + _wi->std.waveMacro.vScroll=-1; \ + } + #define BIND_FOR(x) getKeyName(actionKeys[x],true).c_str() // TODO: diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index b5347cbee..50fd286b8 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4227,7 +4227,7 @@ void FurnaceGUI::drawInsEdit() { } const char* waveLabel="Waveform"; - int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255; + int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:(MAX(1,e->song.waveLen-1)); bool bitMode=false; if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) { bitMode=true; From 635bcf1c6d461d938f667a6dc210cba21ddd5756 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 18 Sep 2022 13:19:08 +0900 Subject: [PATCH 433/515] Fix disclaimer --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 634cf584f..142454b81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -183,7 +183,7 @@ TAParamResult pVersion(String) { printf("- reSID by Dag Lem (GPLv2)\n"); printf("- reSIDfp by Dag Lem, Antti Lankila and Leandro Nini (GPLv2)\n"); printf("- Stella by Stella Team (GPLv2)\n"); - printf("- vgsound_emu (second version) by cam900 (zlib license)\n"); + printf("- vgsound_emu (second version, modified version) by cam900 (zlib license)\n"); return TA_PARAM_QUIT; } From ca224632a1109a960c691b0186be6f4824f7212c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Sep 2022 00:26:51 -0500 Subject: [PATCH 434/515] further polish Namco 163 doc --- papers/doc/7-systems/n163.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 90f432289..efdc3c506 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -2,7 +2,7 @@ This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 128 nibbles (64 bytes) can be dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. -Namco 163 does not internally mix its channels. Because of that, only one channel can be output at the time, when multiple channels are used it will cycle between them, similarily to OPLL. Therefore, its sound quality gets more crunchy as more channels are activated. +Namco 163 uses time-division multiplexing for its output. this means that only one channel is output per sample (like OPLL and OPN2). therefore, its sound quality gets worse as more channels are activated. Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. From 75bcad558aa9058fbc0a4a2e27a6d3ed315a7046 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Sep 2022 03:51:10 -0500 Subject: [PATCH 435/515] GUI: channel customization, part 1 --- TODO.md | 4 ++-- src/gui/gui.cpp | 32 ++++++++++++++++++++++++++++++++ src/gui/gui.h | 4 ++++ src/gui/guiConst.cpp | 2 ++ src/gui/pattern.cpp | 39 ++++++++++++++++++++++++++++++++------- src/gui/settings.cpp | 14 ++++++++------ 6 files changed, 80 insertions(+), 15 deletions(-) diff --git a/TODO.md b/TODO.md index 859ad68c2..a0da2bbdd 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,6 @@ - stereo separation control for AY - "paste with instrument" -- FM operator muting -- FM operator swap +- channel appearance settings +- auto-detect system - bug fixes diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 06fc65f08..40869c425 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -584,6 +584,38 @@ void FurnaceGUI::updateWindowTitle() { if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str()); } +ImVec4 FurnaceGUI::channelColor(int ch) { + switch (settings.channelColors) { + case 0: + return uiColors[GUI_COLOR_CHANNEL_BG]; + break; + case 1: + return uiColors[GUI_COLOR_CHANNEL_FM+e->getChannelType(ch)]; + break; + case 2: + return uiColors[GUI_COLOR_INSTR_STD+e->getPreferInsType(ch)]; + break; + } + // invalid + return uiColors[GUI_COLOR_TEXT]; +} + +ImVec4 FurnaceGUI::channelTextColor(int ch) { + switch (settings.channelTextColors) { + case 0: + return uiColors[GUI_COLOR_CHANNEL_FG]; + break; + case 1: + return uiColors[GUI_COLOR_CHANNEL_FM+e->getChannelType(ch)]; + break; + case 2: + return uiColors[GUI_COLOR_INSTR_STD+e->getPreferInsType(ch)]; + break; + } + // invalid + return uiColors[GUI_COLOR_TEXT]; +} + const char* defaultLayout="[Window][DockSpaceViewport_11111111]\n\ Pos=0,24\n\ Size=1280,731\n\ diff --git a/src/gui/gui.h b/src/gui/gui.h index 6499c4d19..b9784f3f6 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -161,6 +161,8 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_OPL_DRUMS, GUI_COLOR_INSTR_UNKNOWN, + GUI_COLOR_CHANNEL_BG, + GUI_COLOR_CHANNEL_FG, GUI_COLOR_CHANNEL_FM, GUI_COLOR_CHANNEL_PULSE, GUI_COLOR_CHANNEL_NOISE, @@ -1604,6 +1606,8 @@ class FurnaceGUI { void updateWindowTitle(); void prepareLayout(); + ImVec4 channelColor(int ch); + ImVec4 channelTextColor(int ch); void readOsc(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index e79de4106..7c987358e 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -774,6 +774,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,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)), + D(GUI_COLOR_CHANNEL_FG,"",ImVec4(1.0f,1.0f,1.0f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), D(GUI_COLOR_CHANNEL_PULSE,"",ImVec4(0.4f,1.0f,0.2f,1.0f)), D(GUI_COLOR_CHANNEL_NOISE,"",ImVec4(0.8f,0.8f,0.8f,1.0f)), diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index ec65101df..e6bbc72fa 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -468,20 +468,44 @@ void FurnaceGUI::drawPattern() { snprintf(chanID,2048," %s##_CH%d",chName,i); } } + bool muted=e->isChannelMuted(i); - ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:uiColors[GUI_COLOR_CHANNEL_FM+e->getChannelType(i)]; + ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:channelColor(i); ImVec4 chanHeadActive=chanHead; ImVec4 chanHeadHover=chanHead; + if (e->keyHit[i]) { - keyHit[i]=0.2; - if (!muted) { - int note=e->getChanState(i)->note+60; - if (note>=0 && note<180) { - pianoKeyHit[note]=1.0; + if (settings.channelFeedbackStyle==1) { + keyHit[i]=0.2; + if (!muted) { + int note=e->getChanState(i)->note+60; + if (note>=0 && note<180) { + pianoKeyHit[note]=1.0; + } } } e->keyHit[i]=false; } + if (settings.channelFeedbackStyle==2 && e->isRunning()) { + float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i)); + if (!e->getChanState(i)->keyOn) amount=0.0f; + keyHit[i]=amount*0.2f; + if (!muted) { + int note=e->getChanState(i)->note+60; + if (note>=0 && note<180) { + pianoKeyHit[note]=amount; + } + } + } else if (settings.channelFeedbackStyle==3 && e->isRunning()) { + bool active=e->getChanState(i)->keyOn; + keyHit[i]=active?0.2f:0.0f; + if (!muted) { + int note=e->getChanState(i)->note+60; + if (note>=0 && note<180) { + pianoKeyHit[note]=active?1.0f:0.0f; + } + } + } if (settings.guiColorsBase) { chanHead.x*=1.0-keyHit[i]; chanHead.y*=1.0-keyHit[i]; chanHead.z*=1.0-keyHit[i]; chanHeadActive.x*=0.5; chanHeadActive.y*=0.5; chanHeadActive.z*=0.5; @@ -496,6 +520,7 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Header,chanHead); ImGui::PushStyleColor(ImGuiCol_HeaderActive,chanHeadActive); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,chanHeadHover); + ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(channelTextColor(i))); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); @@ -513,7 +538,7 @@ void FurnaceGUI::drawPattern() { } } if (muted) ImGui::PopStyleColor(); - ImGui::PopStyleColor(3); + ImGui::PopStyleColor(4); if (settings.soloAction!=2) if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { inhibitMenu=true; e->toggleSolo(i); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 54da8e893..1bb946522 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1284,14 +1284,14 @@ void FurnaceGUI::drawSettings() { } ImGui::Text("Channel name colors:"); - if (ImGui::RadioButton("Single##CTC0",settings.channelColors==0)) { - settings.channelColors=0; + if (ImGui::RadioButton("Single##CTC0",settings.channelTextColors==0)) { + settings.channelTextColors=0; } - if (ImGui::RadioButton("Channel type##CTC1",settings.channelColors==1)) { - settings.channelColors=1; + if (ImGui::RadioButton("Channel type##CTC1",settings.channelTextColors==1)) { + settings.channelTextColors=1; } - if (ImGui::RadioButton("Instrument type##CTC2",settings.channelColors==2)) { - settings.channelColors=2; + if (ImGui::RadioButton("Instrument type##CTC2",settings.channelTextColors==2)) { + settings.channelTextColors=2; } ImGui::Text("Channel style:"); @@ -1659,6 +1659,8 @@ void FurnaceGUI::drawSettings() { ImGui::TreePop(); } if (ImGui::TreeNode("Channel")) { + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_BG,"Single color (background)"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_FG,"Single color (text)"); UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_FM,"FM"); UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_PULSE,"Pulse"); UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_NOISE,"Noise"); From ebb939c1896d4f0c5f075b0e61920d806e1000b9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Sep 2022 04:20:08 -0500 Subject: [PATCH 436/515] GUI: add channel font option --- src/gui/gui.h | 2 ++ src/gui/pattern.cpp | 5 +++++ src/gui/settings.cpp | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/src/gui/gui.h b/src/gui/gui.h index b9784f3f6..09155f9be 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1178,6 +1178,7 @@ class FurnaceGUI { int channelStyle; int channelVolStyle; int channelFeedbackStyle; + int channelFont; int maxRecentFile; unsigned int maxUndoSteps; String mainFontPath; @@ -1299,6 +1300,7 @@ class FurnaceGUI { channelStyle(0), channelVolStyle(0), channelFeedbackStyle(1), + channelFont(1), maxRecentFile(10), maxUndoSteps(100), mainFontPath(""), diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index e6bbc72fa..4fbb99977 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -523,10 +523,15 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(channelTextColor(i))); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); + if (settings.channelFont==0) ImGui::PushFont(mainFont); + + // TODO: appearance ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); + if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); } + if (settings.channelFont==0) ImGui::PopFont(); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { if (settings.soloAction!=1 && soloTimeout>0 && soloChan==i) { e->toggleSolo(i); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1bb946522..c771f6a16 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1343,6 +1343,15 @@ void FurnaceGUI::drawSettings() { settings.channelFeedbackStyle=3; } + ImGui::Text("Channel font:"); + + if (ImGui::RadioButton("Regular##CHFont0",settings.channelFont==0)) { + settings.channelFont=0; + } + if (ImGui::RadioButton("Monospace##CHFont1",settings.channelFont==1)) { + settings.channelFont=1; + } + ImGui::Separator(); bool insEditColorizeB=settings.insEditColorize; @@ -2282,6 +2291,7 @@ void FurnaceGUI::syncSettings() { settings.channelStyle=e->getConfInt("channelStyle",0); settings.channelVolStyle=e->getConfInt("channelVolStyle",0); settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1); + settings.channelFont=e->getConfInt("channelFont",1); settings.maxRecentFile=e->getConfInt("maxRecentFile",10); clampSetting(settings.mainFontSize,2,96); @@ -2381,6 +2391,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelStyle,0,5); clampSetting(settings.channelVolStyle,0,3); clampSetting(settings.channelFeedbackStyle,0,3); + clampSetting(settings.channelFont,0,1); clampSetting(settings.maxRecentFile,0,30); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); @@ -2536,6 +2547,7 @@ void FurnaceGUI::commitSettings() { e->setConf("channelStyle",settings.channelStyle); e->setConf("channelVolStyle",settings.channelVolStyle); e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle); + e->setConf("channelFont",settings.channelFont); e->setConf("maxRecentFile",settings.maxRecentFile); // colors From 73c6adb82159ba98547aa7f6ac35f8a3e1d3c7f5 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Sun, 12 Jun 2022 14:42:16 +0700 Subject: [PATCH 437/515] wip snes 3 --- .gitignore | 1 + src/engine/platform/snes.cpp | 2 +- src/engine/platform/snes.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 25bd6d0e0..52fc43f4b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ winbuild/ win32build/ macbuild/ linuxbuild/ +webbuild/ *.swp .cache/ .DS_Store diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 8f930342a..c13fa6bf8 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -87,7 +87,7 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len } } -void DivPlatformSNES::tick() { +void DivPlatformSNES::tick(bool sysTick) { // KON/KOFF can't be written several times per one sample // so they have to be accumulated unsigned char kon=0; diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 2b49a68c2..7e8d6882b 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -82,7 +82,7 @@ class DivPlatformSNES: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); void notifyInsChange(int ins); From 7956d41f1bcf5d96461b92dfcdc80f35569d469e Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Sun, 18 Sep 2022 17:59:58 +0700 Subject: [PATCH 438/515] SNES: Get wavesynth and envelope working No samples, inverted volumes and E/P/N yet It's been 3 months... --- .gitignore | 1 - src/engine/instrument.cpp | 9 +- src/engine/instrument.h | 18 +--- src/engine/platform/snes.cpp | 142 ++++++++++++++++++++++------ src/engine/platform/snes.h | 15 ++- src/gui/insEdit.cpp | 178 ++++++++++++++++++----------------- 6 files changed, 224 insertions(+), 139 deletions(-) diff --git a/.gitignore b/.gitignore index 52fc43f4b..25bd6d0e0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ winbuild/ win32build/ macbuild/ linuxbuild/ -webbuild/ *.swp .cache/ .DS_Store diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 22cdddf4b..b6470fc5f 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -558,9 +558,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(es5506.envelope.k2Slow); // SNES + // @tildearrow please update this w->writeC(snes.useEnv); - w->writeC(snes.gainMode); - w->writeC(snes.gain); + w->writeC(0); + w->writeC(0); w->writeC(snes.a); w->writeC(snes.d); w->writeC(snes.s); @@ -1250,8 +1251,8 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // SNES if (version>=109) { snes.useEnv=reader.readC(); - snes.gainMode=(DivInstrumentSNES::GainMode)reader.readC(); - snes.gain=reader.readC(); + reader.readC(); + reader.readC(); snes.a=reader.readC(); snes.d=reader.readC(); snes.s=reader.readC(); diff --git a/src/engine/instrument.h b/src/engine/instrument.h index e5372933d..d0dc78f31 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -501,25 +501,17 @@ struct DivInstrumentES5506 { }; struct DivInstrumentSNES { - enum GainMode: unsigned char { - GAIN_MODE_DIRECT=0, - GAIN_MODE_DEC_LINEAR=4, - GAIN_MODE_DEC_LOG=5, - GAIN_MODE_INC_LINEAR=6, - GAIN_MODE_INC_INVLOG=7 - }; - bool useEnv; - GainMode gainMode; - unsigned char gain; + bool useEnv, applyFIR; unsigned char a, d, s, r; + signed char fir[8]; DivInstrumentSNES(): useEnv(true), - gainMode(GAIN_MODE_DIRECT), - gain(127), + applyFIR(false), a(15), d(7), s(7), - r(0) {} + r(0), + fir{127, 0, 0, 0, 0, 0, 0, 0} {} }; struct DivInstrument { diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index c13fa6bf8..c4239c603 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -22,9 +22,12 @@ #include "../../ta-log.h" #include -#define CHIP_FREQBASE 4096 +#define CHIP_FREQBASE 131072 #define rWrite(a,v) {dsp.write(a,v); regPool[(a)&0x7f]=v; } +#define chWrite(c,a,v) {rWrite((a)+(c)*16,v)} +#define sampleTableAddr(c) (sampleTableBase+(c)*4) +#define waveTableAddr(c) (sampleTableBase+8*4+(c)*9*16) const char* regCheatSheetSNESDSP[]={ "VxVOLL", "x0", @@ -62,16 +65,6 @@ const char** DivPlatformSNES::getRegisterSheet() { return regCheatSheetSNESDSP; } -const char* DivPlatformSNES::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Set echo feedback level (signed 8-bit)"; - break; - // TODO - } - return NULL; -} - void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len) { short out[2]; short chOut[16]; @@ -90,12 +83,23 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len void DivPlatformSNES::tick(bool sysTick) { // KON/KOFF can't be written several times per one sample // so they have to be accumulated + // TODO due to pipelining, KON/KOFF writes need to be delayed to accomodate sample address changes in the table unsigned char kon=0; unsigned char koff=0; for (int i=0; i<8; i++) { + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); + bool hadGain=chan[i].std.vol.had || chan[i].std.ex1.had || chan[i].std.ex2.had; chan[i].std.next(); - if (chan[i].std.vol.had) { - // TODO handle gain writes + if (ins->type==DIV_INS_AMIGA && chan[i].std.vol.had) { + chWrite(i,7,MIN(127,chan[i].std.vol.val*2)); + } else if (!chan[i].useEnv && hadGain) { + if (chan[i].std.ex1.val==0) { + // direct gain + chWrite(i,7,chan[i].std.vol.val); + } else { + // inc/dec + chWrite(i,7,chan[i].std.ex2.val|((chan[i].std.ex1.val-1)<<5)|0x80); + } } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { @@ -112,6 +116,12 @@ void DivPlatformSNES::tick(bool sysTick) { chan[i].freqChanged=true; } } + if (chan[i].useWave && chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; + chan[i].ws.changeWave1(chan[i].wave); + } + } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { chan[i].pitch2+=chan[i].std.pitch.val; @@ -139,13 +149,46 @@ void DivPlatformSNES::tick(bool sysTick) { } else { chan[i].audPos=0; } + if (chan[i].useWave && chan[i].active) { + if (chan[i].ws.tick()) { + updateWave(i); + } + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { DivSample* s=parent->getSample(chan[i].sample); double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; chan[i].freq=(unsigned int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE)); if (chan[i].freq>16383) chan[i].freq=16383; if (chan[i].keyOn) { - // TODO handle sample offsets + unsigned int start, end, loop; + size_t tabAddr=sampleTableAddr(i); + if (chan[i].useEnv) { + chWrite(i,5,ins->snes.a|(ins->snes.d<<4)|0x80); + chWrite(i,6,ins->snes.r|(ins->snes.s<<5)); + } else { + chWrite(i,5,0); + } + if (chan[i].useWave) { + start=waveTableAddr(i); + loop=start; + } else { + start=s->offSNES; + end=MIN(start+MAX(s->lengthBRR,1),getSampleMemCapacity()); + loop=MAX(start,end-1); + if (chan[i].audPos>0) { + start=start+MIN(chan[i].audPos,s->lengthBRR-1)/16*9; + } + if (s->loopStart>=0) { + loop=start+s->loopStart/16*9; + } + } + sampleMem[tabAddr+0]=start&0xff; + sampleMem[tabAddr+1]=start>>8; + sampleMem[tabAddr+2]=loop&0xff; + sampleMem[tabAddr+3]=loop>>8; + if (!hadGain) { + chWrite(i,7,0x7f); + } kon|=(1<>8); + chWrite(i,2,chan[i].freq&0xff); + chWrite(i,3,chan[i].freq>>8); chan[i].freqChanged=false; } } @@ -168,20 +211,36 @@ int DivPlatformSNES::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); - chan[c.chan].sample=ins->amiga.getSample(c.value); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value)); + if (ins->amiga.useWave) { + chan[c.chan].useWave=true; + chan[c.chan].wtLen=(unsigned int)(ins->amiga.waveLen)+1; + if (chan[c.chan].insChanged) { + if (chan[c.chan].wave<0) { + chan[c.chan].wave=0; + chan[c.chan].ws.setWidth(chan[c.chan].wtLen); + chan[c.chan].ws.changeWave1(chan[c.chan].wave); + } + } + } else { + chan[c.chan].sample=ins->amiga.getSample(c.value); + chan[c.chan].useWave=false; } if (chan[c.chan].useWave || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { chan[c.chan].sample=-1; } if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=round(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; chan[c.chan].macroInit(ins); + if (ins->type==DIV_INS_SNES) { + // initialize to max gain in case of direct gain mode macro without gain level macro + chan[c.chan].std.vol.val=0x7f; + chan[c.chan].useEnv=ins->snes.useEnv; + } chan[c.chan].insChanged=false; break; } @@ -274,6 +333,20 @@ int DivPlatformSNES::dispatch(DivCommand c) { return 1; } +void DivPlatformSNES::updateWave(int ch) { + // Due to the overflow bug in hardware's resampler, the written amplitude here is half of maximum + size_t pos=waveTableAddr(ch); + for (int i=0; i>8); rWrite(0x0c,127); // global volume left rWrite(0x1c,127); // global volume right + rWrite(0x6c,0); // get DSP out of reset for (int i=0; i<8; i++) { chan[i]=Channel(); chan[i].std.setEngine(parent); + chan[i].ws.setEngine(parent); + chan[i].ws.init(NULL,32,255); writeOutVol(i); + chWrite(i,4,i); // source number } } @@ -353,6 +431,17 @@ void DivPlatformSNES::notifyInsChange(int ins) { } } +void DivPlatformSNES::notifyWaveChange(int wave) { + for (int i=0; i<8; i++) { + if (chan[i].useWave && chan[i].wave==wave) { + chan[i].ws.changeWave1(wave); + if (chan[i].active) { + updateWave(i); + } + } + } +} + void DivPlatformSNES::notifyInsDeletion(void* ins) { for (int i=0; i<8; i++) { chan[i].std.notifyInsDeletion((DivInstrument*)ins); @@ -383,21 +472,14 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) { void DivPlatformSNES::renderSamples() { memset(sampleMem,0,getSampleMemCapacity()); - // skip past sample table - size_t memPos=sampleTableBase+0x400; + // skip past sample table and wavetable buffer + size_t memPos=sampleTableBase+8*4+8*9*16; for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; int length=s->lengthBRR; int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length); if (actualLength>0) { - size_t tabAddr=sampleTableBase+i*4; - size_t loopPos=memPos; - if (s->loopStart>=0) loopPos+=s->loopStart; s->offSNES=memPos; - sampleMem[tabAddr+0]=memPos&0xff; - sampleMem[tabAddr+1]=memPos>>8; - sampleMem[tabAddr+2]=loopPos&0xff; - sampleMem[tabAddr+3]=loopPos>>8; memcpy(&sampleMem[memPos],s->data8,actualLength); memPos+=actualLength; } diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 7e8d6882b..058df21fc 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -22,19 +22,22 @@ #include "../dispatch.h" #include "../macroInt.h" +#include "../waveSynth.h" #include #include "sound/snes/SPC_DSP.h" class DivPlatformSNES: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2; - unsigned int audPos; - int sample, ins; + unsigned int audPos, wtLen; + int sample, wave, ins; int note; int panL, panR; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos; signed char vol; + bool useEnv; DivMacroInt std; + DivWaveSynth ws; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -45,7 +48,9 @@ class DivPlatformSNES: public DivDispatch { pitch(0), pitch2(0), audPos(0), + wtLen(16), sample(-1), + wave(-1), ins(-1), note(0), panL(255), @@ -58,7 +63,8 @@ class DivPlatformSNES: public DivDispatch { inPorta(false), useWave(false), setPos(false), - vol(127) {} + vol(127), + useEnv(false) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; @@ -86,11 +92,11 @@ class DivPlatformSNES: public DivDispatch { void muteChannel(int ch, bool mute); bool isStereo(); void notifyInsChange(int ins); + void notifyWaveChange(int wave); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const char* getEffectName(unsigned char effect); const void* getSampleMem(int index = 0); size_t getSampleMemCapacity(int index = 0); size_t getSampleMemUsage(int index = 0); @@ -98,6 +104,7 @@ class DivPlatformSNES: public DivDispatch { int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); private: + void updateWave(int ch); void writeOutVol(int ch); }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 50fd286b8..a2558a604 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -306,6 +306,14 @@ const char* gbHWSeqCmdTypes[6]={ "Loop until Release" }; +const char* snesGainModes[5]={ + "Direct", + "Decrease (linear)", + "Decrease (logarithmic)", + "Increase (linear)", + "Increase (bent line)" +}; + // do not change these! // anything other than a checkbox will look ugly! // @@ -3603,6 +3611,18 @@ void FurnaceGUI::drawInsEdit() { } } } + if (ins->type==DIV_INS_SNES) { + P(ImGui::Checkbox("Use wavetable",&ins->amiga.useWave)); + if (ins->amiga.useWave) { + int len=ins->amiga.waveLen+1; + if (ImGui::InputInt("Width",&len,16,64)) { + if (len<16) len=16; + if (len>256) len=256; + ins->amiga.waveLen=(len&(~15))-1; + PARAMETER + } + } + } ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { @@ -3868,95 +3888,62 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv)); ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); - if (ins->snes.useEnv) { - if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); + if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - CENTER_TEXT("A"); - ImGui::TextUnformatted("A"); - ImGui::TableNextColumn(); - CENTER_TEXT("D"); - ImGui::TextUnformatted("D"); - ImGui::TableNextColumn(); - CENTER_TEXT("S"); - ImGui::TextUnformatted("S"); - ImGui::TableNextColumn(); - CENTER_TEXT("R"); - ImGui::TextUnformatted("R"); - ImGui::TableNextColumn(); - CENTER_TEXT("Envelope"); - ImGui::TextUnformatted("Envelope"); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("A"); + ImGui::TextUnformatted("A"); + ImGui::TableNextColumn(); + CENTER_TEXT("D"); + ImGui::TextUnformatted("D"); + ImGui::TableNextColumn(); + CENTER_TEXT("S"); + ImGui::TextUnformatted("S"); + ImGui::TableNextColumn(); + CENTER_TEXT("R"); + ImGui::TextUnformatted("R"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); - ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); - ImGui::TableNextColumn(); - P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); - ImGui::TableNextColumn(); - P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); - ImGui::TableNextColumn(); - drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); + ImGui::TableNextColumn(); + drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); - ImGui::EndTable(); + ImGui::EndTable(); + } + P(ImGui::Checkbox("Apply echo filter",&ins->snes.applyFIR)); + if (ins->snes.applyFIR) { + double inBuf[8]; + fftw_complex outBuf[8]; + float curve[5]; + fftw_plan plan=fftw_plan_dft_r2c_1d(8,inBuf,outBuf,FFTW_ESTIMATE); + + ImGui::Text("Coefficients"); + ImGui::SameLine(); + P(ImGui::DragScalarN("##FIRCoeff",ImGuiDataType_S8,ins->snes.fir,8,1,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + for (int i=0; i<8; i++) { + inBuf[i] = ins->snes.fir[i]; } - } else { - if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - CENTER_TEXT("Gain Mode"); - ImGui::TextUnformatted("Gain Mode"); - ImGui::TableNextColumn(); - CENTER_TEXT("Gain"); - ImGui::TextUnformatted("Gain"); - ImGui::TableNextColumn(); - CENTER_TEXT("Envelope"); - ImGui::TextUnformatted("Envelope"); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; - PARAMETER; - } - if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; - PARAMETER; - } - if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; - PARAMETER; - } - if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; - PARAMETER; - } - if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; - PARAMETER; - } - - ImGui::TableNextColumn(); - unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; - if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; - P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); - - ImGui::TableNextColumn(); - ImGui::Text("Envelope goes here..."); - - ImGui::EndTable(); + fftw_execute(plan); + for (int i=0; i<5; i++) { + curve[i] = sqrtf(powf(outBuf[i][0],2)+powf(outBuf[i][1],2))/128.f; } + ImGui::PlotLines("##FIRResponse",curve,5,0,"Frequency response",0.0,8.0,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale)); } ImGui::EndTabItem(); } @@ -4159,6 +4146,14 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_ES5506) { volMax=65535; } + if (ins->type==DIV_INS_SNES) { + if (ins->snes.useEnv) { + volMax=0; + } else { + volumeLabel="Gain Level"; + volMax=127; + } + } const char* dutyLabel="Duty/Noise"; int dutyMin=0; @@ -4203,7 +4198,7 @@ void FurnaceGUI::drawInsEdit() { dutyLabel="Noise"; dutyMax=8; } - if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { + if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SNES) { dutyMax=0; } if (ins->type==DIV_INS_VERA) { @@ -4244,7 +4239,7 @@ void FurnaceGUI::drawInsEdit() { waveMax=8; bitMode=true; } - + if (ins->type==DIV_INS_OPLL) { waveLabel="Patch"; } @@ -4284,6 +4279,10 @@ void FurnaceGUI::drawInsEdit() { ex1Max=65535; ex2Max=65535; } + if (ins->type==DIV_INS_SNES && !ins->snes.useEnv) { + ex1Max=4; + ex2Max=31; + } int panMin=0; int panMax=0; @@ -4373,7 +4372,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_MIKEY || - ins->type==DIV_INS_ES5506) { + ins->type==DIV_INS_ES5506 || + ins->type==DIV_INS_SNES) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ex1Max>0) { @@ -4391,6 +4391,8 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode==1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + } else if (ins->type==DIV_INS_SNES) { + macroList.push_back(FurnaceGUIMacroDesc("Gain Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,snesGainModes)); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4406,6 +4408,8 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_ES5506) { macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode==1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + } else if (ins->type==DIV_INS_SNES) { + macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } else { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } From 18d793dc2051c09354e9213c2cae3d7c8b81a96d Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Mon, 19 Sep 2022 01:01:46 +0700 Subject: [PATCH 439/515] SNES: Fix wavesynth and channel 1 --- src/engine/platform/snes.cpp | 11 +++++++---- src/engine/platform/snes.h | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index c4239c603..2f3e972f9 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -83,7 +83,6 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len void DivPlatformSNES::tick(bool sysTick) { // KON/KOFF can't be written several times per one sample // so they have to be accumulated - // TODO due to pipelining, KON/KOFF writes need to be delayed to accomodate sample address changes in the table unsigned char kon=0; unsigned char koff=0; for (int i=0; i<8; i++) { @@ -203,7 +202,10 @@ void DivPlatformSNES::tick(bool sysTick) { } } } - rWrite(0x4c,kon); + if (kon!=0) { + rWrite(0x4c,kon); + } + // always write KOFF as it's constantly polled rWrite(0x5c,koff); } @@ -213,7 +215,7 @@ int DivPlatformSNES::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); if (ins->amiga.useWave) { chan[c.chan].useWave=true; - chan[c.chan].wtLen=(unsigned int)(ins->amiga.waveLen)+1; + chan[c.chan].wtLen=ins->amiga.waveLen+1; if (chan[c.chan].insChanged) { if (chan[c.chan].wave<0) { chan[c.chan].wave=0; @@ -221,6 +223,7 @@ int DivPlatformSNES::dispatch(DivCommand c) { chan[c.chan].ws.changeWave1(chan[c.chan].wave); } } + chan[c.chan].ws.init(ins,chan[c.chan].wtLen,15,chan[c.chan].insChanged); } else { chan[c.chan].sample=ins->amiga.getSample(c.value); chan[c.chan].useWave=false; @@ -404,7 +407,7 @@ void DivPlatformSNES::reset() { dsp.set_output(NULL,0); memset(regPool,0,128); // TODO more initial values - sampleTableBase=0; + sampleTableBase=0x100; // hack: this can't be 0 or channel 1 won't play?? rWrite(0x5d,sampleTableBase>>8); rWrite(0x0c,127); // global volume left rWrite(0x1c,127); // global volume right diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 058df21fc..65c8a6656 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -29,12 +29,13 @@ class DivPlatformSNES: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2; - unsigned int audPos, wtLen; + unsigned int audPos; int sample, wave, ins; int note; int panL, panR; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos; signed char vol; + int wtLen; bool useEnv; DivMacroInt std; DivWaveSynth ws; @@ -48,7 +49,6 @@ class DivPlatformSNES: public DivDispatch { pitch(0), pitch2(0), audPos(0), - wtLen(16), sample(-1), wave(-1), ins(-1), @@ -64,6 +64,7 @@ class DivPlatformSNES: public DivDispatch { useWave(false), setPos(false), vol(127), + wtLen(16), useEnv(false) {} }; Channel chan[8]; From 3cb1571fb6c85794d19ec3c9f459f9113fb57a04 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 01:00:31 -0500 Subject: [PATCH 440/515] GUI: implement channel style settings --- extern/imgui_patched/imgui.h | 2 + extern/imgui_patched/imgui_tables.cpp | 2 +- src/gui/pattern.cpp | 135 +++++++++++++++++++++++++- src/gui/sysEx.cpp | 1 + 4 files changed, 135 insertions(+), 5 deletions(-) diff --git a/extern/imgui_patched/imgui.h b/extern/imgui_patched/imgui.h index 7249c5402..e9ccea9b1 100644 --- a/extern/imgui_patched/imgui.h +++ b/extern/imgui_patched/imgui.h @@ -1220,6 +1220,8 @@ enum ImGuiTableFlags_ // Sorting ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + // tildearrow + ImGuiTableFlags_NoBordersInFrozenArea = 1 << 28, // Disable vertical borders in frozen area. // [Internal] Combinations and masks ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame diff --git a/extern/imgui_patched/imgui_tables.cpp b/extern/imgui_patched/imgui_tables.cpp index 5a21a0b13..46bf0b132 100644 --- a/extern/imgui_patched/imgui_tables.cpp +++ b/extern/imgui_patched/imgui_tables.cpp @@ -2532,7 +2532,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) // Draw inner border and resizing feedback ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); const float border_size = TABLE_BORDER_SIZE; - const float draw_y1 = table->InnerRect.Min.y; + const float draw_y1 = table->InnerRect.Min.y + ((table->Flags & ImGuiTableFlags_NoBordersInFrozenArea)?table_instance->LastFirstRowHeight:0.0f); const float draw_y2_body = table->InnerRect.Max.y; const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1; if (table->Flags & ImGuiTableFlags_BordersInnerV) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 4fbb99977..b986cedc6 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +// for suck's fake Clang extension! #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" @@ -400,7 +401,7 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_SELECTION_HOVER]); ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_SELECTION_ACTIVE]); - if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX)) { + if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea)) { ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed); char chanID[2048]; float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale); @@ -473,6 +474,7 @@ void FurnaceGUI::drawPattern() { ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:channelColor(i); ImVec4 chanHeadActive=chanHead; ImVec4 chanHeadHover=chanHead; + ImVec4 chanHeadBase=chanHead; if (e->keyHit[i]) { if (settings.channelFeedbackStyle==1) { @@ -515,18 +517,140 @@ void FurnaceGUI::drawPattern() { chanHeadActive.x*=0.8; chanHeadActive.y*=0.8; chanHeadActive.z*=0.8; chanHeadHover.x*=0.4+keyHit[i]; chanHeadHover.y*=0.4+keyHit[i]; chanHeadHover.z*=0.4+keyHit[i]; } - keyHit[i]-=0.02*60.0*ImGui::GetIO().DeltaTime; + keyHit[i]-=((settings.channelStyle==0)?0.02:0.01)*60.0*ImGui::GetIO().DeltaTime; if (keyHit[i]<0) keyHit[i]=0; ImGui::PushStyleColor(ImGuiCol_Header,chanHead); ImGui::PushStyleColor(ImGuiCol_HeaderActive,chanHeadActive); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,chanHeadHover); ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(channelTextColor(i))); - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); + if (settings.channelStyle==0) ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); if (settings.channelFont==0) ImGui::PushFont(mainFont); // TODO: appearance - ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + ImVec2 size=ImVec2( + 1.0f, + lineHeight+1.0f*dpiScale+6.0*dpiScale + ); + ImDrawList* dl=ImGui::GetWindowDrawList(); + + if (settings.channelStyle==2) { + size.y+=6.0f*dpiScale; + } + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+window->WorkRect.Max.x-window->WorkRect.Min.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + switch (settings.channelStyle) { + case 0: // classic + ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); + break; + case 1: { // line + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol0=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.25f:0.0f + )); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.5f:MIN(1.0f,chanHeadBase.w*keyHit[i]*4.0f) + )); + dl->AddRectFilledMultiColor(rect.Min,rect.Max,fadeCol0,fadeCol0,fadeCol,fadeCol); + dl->AddLine(ImVec2(rect.Min.x,rect.Max.y),ImVec2(rect.Max.x,rect.Max.y),ImGui::GetColorU32(chanHeadBase),2.0f*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + case 2: { // round + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol0=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.5f:MIN(1.0f,0.3f+chanHeadBase.w*keyHit[i]*1.5f) + )); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.3f:MIN(1.0f,0.2f+chanHeadBase.w*keyHit[i]*1.2f) + )); + ImVec2 rMin=rect.Min; + ImVec2 rMax=rect.Max; + rMin.x+=3.0f*dpiScale; + rMin.y+=6.0f*dpiScale; + rMax.x-=3.0f*dpiScale; + rMax.y-=6.0f*dpiScale; + dl->AddRectFilledMultiColor(rMin,rMax,fadeCol0,fadeCol0,fadeCol,fadeCol,4.0f*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + case 3: // split button + ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); + ImGui::TextUnformatted(chanID,strstr(chanID,"##")); + ImGui::SameLine(); + ImGui::PushFont(mainFont); + ImGui::PushID(chanID); + ImGui::SmallButton(muted?ICON_FA_VOLUME_OFF:ICON_FA_VOLUME_UP); + ImGui::PopID(); + ImGui::PopFont(); + break; + case 4: { // square border + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?1.0f:MIN(1.0f,0.2f+chanHeadBase.w*keyHit[i]*4.0f) + )); + ImVec2 rMin=rect.Min; + ImVec2 rMax=rect.Max; + rMin.x+=2.0f*dpiScale; + rMin.y+=3.0f*dpiScale; + rMax.x-=3.0f*dpiScale; + rMax.y-=3.0f*dpiScale; + dl->AddRect(rMin,rMax,fadeCol,0.0f,2.0*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + case 5: { // round border + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?1.0f:MIN(1.0f,0.2f+chanHeadBase.w*keyHit[i]*4.0f) + )); + ImVec2 rMin=rect.Min; + ImVec2 rMax=rect.Max; + rMin.x+=2.0f*dpiScale; + rMin.y+=3.0f*dpiScale; + rMax.x-=3.0f*dpiScale; + rMax.y-=3.0f*dpiScale; + dl->AddRect(rMin,rMax,fadeCol,4.0f*dpiScale,ImDrawFlags_RoundCornersAll,2.0*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + } if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); @@ -548,6 +672,9 @@ void FurnaceGUI::drawPattern() { inhibitMenu=true; e->toggleSolo(i); } + if (settings.channelStyle==3) { + ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); + } if (extraChannelButtons==2) { DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][ord],true); ImGui::PushFont(mainFont); diff --git a/src/gui/sysEx.cpp b/src/gui/sysEx.cpp index f8849b562..5a72649ee 100644 --- a/src/gui/sysEx.cpp +++ b/src/gui/sysEx.cpp @@ -60,6 +60,7 @@ bool FurnaceGUI::parseSysEx(unsigned char* data, size_t len) { op.rs=reader.readC(); reader.readC(); // EBS - ignore op.am=reader.readC(); + // TODO: don't ignore after I add KVS to Furnace reader.readC(); // KVS - ignore op.tl=3+((99-reader.readC())*124)/99; unsigned char freq=reader.readC(); From 1a84812a1ddfaac14be9a294d743b71c99e6b82b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 01:03:44 -0500 Subject: [PATCH 441/515] OPNA: fix forceIns RSS/ADPCM volume --- src/engine/platform/ym2608.cpp | 5 +++++ src/engine/platform/ym2608ext.cpp | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index ec90c1c6b..42bea41b2 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1114,6 +1114,11 @@ void DivPlatformYM2608::forceIns() { } for (int i=9; i<16; i++) { chan[i].insChanged=true; + if (i>14) { // ADPCM-B + immWrite(0x10b,chan[i].outVol); + } else { + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + } } ay->forceIns(); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index c6d7e03b6..116f6b95c 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -472,8 +472,13 @@ void DivPlatformYM2608Ext::forceIns() { chan[i].freqChanged=true; } } - for (int i=6; i<16; i++) { + for (int i=9; i<16; i++) { chan[i].insChanged=true; + if (i>14) { // ADPCM-B + immWrite(0x10b,chan[i].outVol); + } else { + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + } } ay->forceIns(); ay->flushWrites(); From e1890173b266efa2bb95d6648eb21f4f2deaf077 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 02:32:23 -0500 Subject: [PATCH 442/515] GUI: implement channel volume bar --- TODO.md | 1 - src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- src/engine/platform/sms.cpp | 4 +-- src/gui/chanOsc.cpp | 34 +++++++++++++++++++- src/gui/gui.cpp | 8 +++++ src/gui/gui.h | 2 ++ src/gui/pattern.cpp | 58 +++++++++++++++++++++++++++++++++- src/gui/settings.cpp | 5 ++- 9 files changed, 108 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index a0da2bbdd..028f21077 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,5 @@ - stereo separation control for AY - "paste with instrument" -- channel appearance settings - auto-detect system - bug fixes diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 23f20c2a0..f475b4750 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -126,7 +126,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l } for (int ch=0; ch<3; ch++) { for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]; + oscBuf[ch]->data[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; } } } diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index d77457d66..123dc68ac 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -111,7 +111,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l for (int ch=0; ch<3; ch++) { for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]; + oscBuf[ch]->data[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; } } } diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d4d77f171..e4d408f7b 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -78,7 +78,7 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]]; + oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]]*3; } } } @@ -104,7 +104,7 @@ void DivPlatformSMS::acquire_mame(short* bufL, short* bufR, size_t start, size_t if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i); + oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i)*3; } } } diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 547e59a17..08174b0b6 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -69,6 +69,39 @@ float FurnaceGUI::computeGradPos(int type, int chan) { return 0.0f; } +void FurnaceGUI::calcChanOsc() { + std::vector oscBufs; + std::vector oscFFTs; + std::vector oscChans; + + int chans=e->getTotalChannelCount(); + + for (int i=0; igetOscBuffer(i); + if (buf!=NULL && e->curSubSong->chanShow[i]) { + // 30ms should be enough + int displaySize=(float)(buf->rate)*0.03f; + if (e->isRunning()) { + float minLevel=1.0f; + float maxLevel=-1.0f; + unsigned short needlePos=buf->needle; + needlePos-=displaySize; + for (unsigned short i=0; i<512; i++) { + float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + if (minLevel>y) minLevel=y; + if (maxLevel1.0f) estimate=1.0f; + chanOscVol[i]=MAX(chanOscVol[i]*0.87f,estimate); + } + } else { + chanOscVol[i]=MAX(chanOscVol[i]*0.87f,0.0f); + } + if (chanOscVol[i]<0.00001f) chanOscVol[i]=0.0f; + } +} + void FurnaceGUI::drawChanOsc() { if (nextWindow==GUI_WINDOW_CHAN_OSC) { chanOscOpen=true; @@ -361,7 +394,6 @@ void FurnaceGUI::drawChanOsc() { if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 40869c425..d42ec0f88 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3471,6 +3471,8 @@ bool FurnaceGUI::loop() { ImGui::EndMainMenuBar(); } + calcChanOsc(); + if (mobileUI) { globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; //globalWinFlags=ImGuiWindowFlags_NoTitleBar; @@ -3546,6 +3548,12 @@ bool FurnaceGUI::loop() { drawEffectList(); } + for (int i=0; igetTotalChannelCount(); i++) { + if (e->keyHit[i]) { + e->keyHit[i]=false; + } + } + if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); if (firstFrame) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 09155f9be..bbfb3cf5b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1558,6 +1558,7 @@ class FurnaceGUI { // visualizer float keyHit[DIV_MAX_CHANS]; + float keyHit1[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; // log window @@ -1612,6 +1613,7 @@ class FurnaceGUI { ImVec4 channelTextColor(int ch); void readOsc(); + void calcChanOsc(); void pushAccentColors(const ImVec4& one, const ImVec4& two, const ImVec4& border, const ImVec4& borderShadow); void popAccentColors(); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index b986cedc6..f35f828c0 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -486,7 +486,6 @@ void FurnaceGUI::drawPattern() { } } } - e->keyHit[i]=false; } if (settings.channelFeedbackStyle==2 && e->isRunning()) { float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i)); @@ -547,6 +546,10 @@ void FurnaceGUI::drawPattern() { ImRect rect=ImRect(minArea,maxArea); switch (settings.channelStyle) { case 0: // classic + if (settings.channelVolStyle!=0) { + // sorry... + ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + } ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); break; case 1: { // line @@ -672,9 +675,62 @@ void FurnaceGUI::drawPattern() { inhibitMenu=true; e->toggleSolo(i); } + if (settings.channelStyle==3) { ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); } + + // volume bar + if (settings.channelVolStyle!=0) { + ImVec2 sizeV=ImVec2( + 1.0f, + 6.0*dpiScale + ); + ImVec2 minAreaV=window->DC.CursorPos; + ImVec2 maxAreaV=ImVec2( + minAreaV.x+window->WorkRect.Max.x-window->WorkRect.Min.x, + minAreaV.y+sizeV.y + ); + ImRect rectV=ImRect(minAreaV,maxAreaV); + ImGui::ItemSize(sizeV,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rectV,ImGui::GetID(chanID))) { + float xLeft=0.0f; + float xRight=1.0f; + + if (e->keyHit[i]) { + keyHit1[i]=1.0f; + } + + if (e->isRunning()) { + switch (settings.channelVolStyle) { + case 1: // simple + xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); + break; + case 2: // stereo + xRight=0.5+((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); + xLeft=1.0-xRight; + break; + case 3: // real + xRight=chanOscVol[i]; + break; + case 4: // real (stereo) + xRight=0.5+chanOscVol[i]*0.5; + xLeft=1.0-xRight; + break; + } + + dl->AddRectFilled( + ImLerp(rectV.Min,rectV.Max,ImVec2(xLeft,0.0f)), + ImLerp(rectV.Min,rectV.Max,ImVec2(xRight,1.0f)), + ImGui::GetColorU32(chanHeadBase) + ); + } + keyHit1[i]-=0.2f; + if (keyHit1[i]<0.0f) keyHit1[i]=0.0f; + } + } + + // extra buttons if (extraChannelButtons==2) { DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][ord],true); ImGui::PushFont(mainFont); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index c771f6a16..e5c609829 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1327,6 +1327,9 @@ void FurnaceGUI::drawSettings() { if (ImGui::RadioButton("Real##CHV3",settings.channelVolStyle==3)) { settings.channelVolStyle=3; } + if (ImGui::RadioButton("Real (stereo)##CHV4",settings.channelVolStyle==4)) { + settings.channelVolStyle=4; + } ImGui::Text("Channel feedback style:"); @@ -2389,7 +2392,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelColors,0,2); clampSetting(settings.channelTextColors,0,2); clampSetting(settings.channelStyle,0,5); - clampSetting(settings.channelVolStyle,0,3); + clampSetting(settings.channelVolStyle,0,4); clampSetting(settings.channelFeedbackStyle,0,3); clampSetting(settings.channelFont,0,1); clampSetting(settings.maxRecentFile,0,30); From a58529a49b4dcd8728d5e73472476e99e5febf27 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 02:57:56 -0500 Subject: [PATCH 443/515] GUI: fix some thread problems with keyHit --- src/gui/chanOsc.cpp | 2 +- src/gui/gui.cpp | 9 +++------ src/gui/pattern.cpp | 3 +++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 08174b0b6..89b89801b 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -63,7 +63,7 @@ float FurnaceGUI::computeGradPos(int type, int chan) { return chanOscBright[chan]; break; case GUI_OSCREF_NOTE_TRIGGER: - return keyHit[chan]*5.0f; + return keyHit1[chan]; break; } return 0.0f; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index d42ec0f88..a2eb9c920 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3548,12 +3548,6 @@ bool FurnaceGUI::loop() { drawEffectList(); } - for (int i=0; igetTotalChannelCount(); i++) { - if (e->keyHit[i]) { - e->keyHit[i]=false; - } - } - if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); if (firstFrame) { @@ -5462,6 +5456,9 @@ FurnaceGUI::FurnaceGUI(): waveGenFMCon2[0]=true; waveGenFMCon3[0]=true; + memset(keyHit,0,sizeof(float)*DIV_MAX_CHANS); + memset(keyHit1,0,sizeof(float)*DIV_MAX_CHANS); + memset(pianoKeyHit,0,sizeof(float)*180); memset(pianoKeyPressed,0,sizeof(bool)*180); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index f35f828c0..add285f64 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -477,6 +477,7 @@ void FurnaceGUI::drawPattern() { ImVec4 chanHeadBase=chanHead; if (e->keyHit[i]) { + keyHit1[i]=1.0f; if (settings.channelFeedbackStyle==1) { keyHit[i]=0.2; if (!muted) { @@ -486,6 +487,7 @@ void FurnaceGUI::drawPattern() { } } } + e->keyHit[i]=false; } if (settings.channelFeedbackStyle==2 && e->isRunning()) { float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i)); @@ -699,6 +701,7 @@ void FurnaceGUI::drawPattern() { if (e->keyHit[i]) { keyHit1[i]=1.0f; + e->keyHit[i]=false; } if (e->isRunning()) { From 980f970809cd26a810f6236e30741ba2e352f0de Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 20 Sep 2022 21:13:29 +0000 Subject: [PATCH 444/515] fix opll bbc micro clock, improve some presets --- src/gui/presets.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++-- src/gui/sysConf.cpp | 2 +- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 1bd637a23..da1c4d51f 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -960,11 +960,27 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-86)", { // -73 also has OPNA DIV_SYSTEM_PC98, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), // 2x 16-bit Burr Brown DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), 0 } )); cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-86; extended channel 3)", { // -73 also has OPNA + DIV_SYSTEM_PC98_EXT, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with PC-9801-73)", { + DIV_SYSTEM_PC98, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with PC-9801-73; extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 1, 0 } @@ -972,6 +988,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3, 64, 0, 0, 0 } @@ -979,6 +996,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3, 64, 0, 0, 0 } @@ -986,6 +1004,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, 0 } @@ -993,6 +1012,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, 0 } @@ -1092,6 +1112,20 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Atari ST", { + DIV_SYSTEM_AY8910, 64, 0, 3, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Atari STE", { + DIV_SYSTEM_AY8910, 64, 0, 3, + DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), + DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "SAM Coupé", { DIV_SYSTEM_SAA1099, 64, 0, 0, @@ -1146,17 +1180,33 @@ void FurnaceGUI::initSystemPresets() { 0 } )); - cat.systems.push_back(FurnaceGUISysDef( - "PC + AdLib/Sound Blaster", { + cat.systems.push_back(FurnaceGUISysDef( + "PC + AdLib", { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } + )); + cat.systems.push_back(FurnaceGUISysDef( + "PC + AdLib (drums mode)", { + DIV_SYSTEM_OPL2, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "PC + Sound Blaster", { + DIV_SYSTEM_OPL2, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), + 0 + } )); cat.systems.push_back(FurnaceGUISysDef( "PC + AdLib/Sound Blaster (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), 0 } )); @@ -1165,6 +1215,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1174,6 +1225,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1182,6 +1234,7 @@ void FurnaceGUI::initSystemPresets() { "PC + Sound Blaster Pro", { DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1190,6 +1243,7 @@ void FurnaceGUI::initSystemPresets() { "PC + Sound Blaster Pro (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1197,6 +1251,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2", { DIV_SYSTEM_OPL3, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1204,6 +1259,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2 (drums mode)", { DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index ba3ded1a6..3a0c1098e 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -217,7 +217,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("PAL (3.55MHz)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; } - if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&15)==2)) { + if (ImGui::RadioButton("Arcade (4MHz)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; } if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&15)==3)) { From eb0aac0f54f3cfae1a847edc65de463d5629d394 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 19:07:17 -0500 Subject: [PATCH 445/515] GUI: more work on it --- src/gui/gui.h | 4 +- src/gui/pattern.cpp | 100 +++++++++++++++++++++++++++++-------------- src/gui/settings.cpp | 10 ++++- 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index bbfb3cf5b..5bf8adfe7 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1179,6 +1179,7 @@ class FurnaceGUI { int channelVolStyle; int channelFeedbackStyle; int channelFont; + int channelTextCenter; int maxRecentFile; unsigned int maxUndoSteps; String mainFontPath; @@ -1297,10 +1298,11 @@ class FurnaceGUI { saveUnusedPatterns(0), channelColors(1), channelTextColors(0), - channelStyle(0), + channelStyle(1), channelVolStyle(0), channelFeedbackStyle(1), channelFont(1), + channelTextCenter(1), maxRecentFile(10), maxUndoSteps(100), mainFontPath(""), diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index add285f64..103ecbbe2 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -18,6 +18,7 @@ */ // for suck's fake Clang extension! +#include #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" @@ -25,6 +26,7 @@ #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" #include "guiConst.h" +#include "../utfutils.h" #include inline float randRange(float min, float max) { @@ -448,27 +450,6 @@ void FurnaceGUI::drawPattern() { if (!e->curSubSong->chanShow[i]) continue; ImGui::TableNextColumn(); bool displayTooltip=false; - if (e->curSubSong->chanCollapse[i]) { - const char* chName=e->getChannelShortName(i); - if (strlen(chName)>3) { - snprintf(chanID,2048,"...##_CH%d",i); - } else { - snprintf(chanID,2048,"%s##_CH%d",chName,i); - } - displayTooltip=true; - } else { - const char* chName=e->getChannelName(i); - size_t chNameLimit=6+4*e->curPat[i].effectCols; - if (strlen(chName)>chNameLimit) { - String shortChName=chName; - shortChName.resize(chNameLimit-3); - shortChName+="..."; - snprintf(chanID,2048," %s##_CH%d",shortChName.c_str(),i); - displayTooltip=true; - } else { - snprintf(chanID,2048," %s##_CH%d",chName,i); - } - } bool muted=e->isChannelMuted(i); ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:channelColor(i); @@ -532,10 +513,14 @@ void FurnaceGUI::drawPattern() { ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 size=ImVec2( 1.0f, - lineHeight+1.0f*dpiScale+6.0*dpiScale + lineHeight+1.0f*dpiScale ); ImDrawList* dl=ImGui::GetWindowDrawList(); + if (settings.channelStyle!=0) { + size.y+=6.0f*dpiScale; + } + if (settings.channelStyle==2) { size.y+=6.0f*dpiScale; } @@ -546,13 +531,63 @@ void FurnaceGUI::drawPattern() { minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); + float padding=ImGui::CalcTextSize("A").x; + + ImVec2 minLabelArea=minArea; + ImVec2 maxLabelArea=maxArea; + + if (e->curSubSong->chanCollapse[i]) { + const char* chName=e->getChannelShortName(i); + if (strlen(chName)>3) { + snprintf(chanID,2048,"..."); + } else { + snprintf(chanID,2048,"%s",chName); + } + displayTooltip=true; + } else { + minLabelArea.x+=padding; + maxLabelArea.x-=padding; + const char* chName=e->getChannelName(i); + float chNameLimit=maxLabelArea.x-minLabelArea.x; + if (ImGui::CalcTextSize(chName).x>chNameLimit) { + String shortChName; + float totalAdvanced=0.0f; + float ellipsisSize=ImGui::CalcTextSize("...").x; + for (const char* j=chName; *j;) { + signed char l; + int ch=decodeUTF8((const unsigned char*)j,l); + + totalAdvanced+=ImGui::GetFont()->GetCharAdvance(ch); + if (totalAdvanced>(chNameLimit-ellipsisSize)) break; + + for (int k=0; kAddRectFilled(rect.Min,rect.Max,col); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y),ImGui::GetColorU32(channelTextColor(i)),chanID); } - ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); break; case 1: { // line ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); @@ -572,7 +607,7 @@ void FurnaceGUI::drawPattern() { )); dl->AddRectFilledMultiColor(rect.Min,rect.Max,fadeCol0,fadeCol0,fadeCol,fadeCol); dl->AddLine(ImVec2(rect.Min.x,rect.Max.y),ImVec2(rect.Max.x,rect.Max.y),ImGui::GetColorU32(chanHeadBase),2.0f*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } @@ -599,18 +634,16 @@ void FurnaceGUI::drawPattern() { rMax.x-=3.0f*dpiScale; rMax.y-=6.0f*dpiScale; dl->AddRectFilledMultiColor(rMin,rMax,fadeCol0,fadeCol0,fadeCol,fadeCol,4.0f*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } case 3: // split button ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); - ImGui::TextUnformatted(chanID,strstr(chanID,"##")); + ImGui::TextUnformatted(chanID); ImGui::SameLine(); ImGui::PushFont(mainFont); - ImGui::PushID(chanID); ImGui::SmallButton(muted?ICON_FA_VOLUME_OFF:ICON_FA_VOLUME_UP); - ImGui::PopID(); ImGui::PopFont(); break; case 4: { // square border @@ -630,7 +663,7 @@ void FurnaceGUI::drawPattern() { rMax.x-=3.0f*dpiScale; rMax.y-=3.0f*dpiScale; dl->AddRect(rMin,rMax,fadeCol,0.0f,2.0*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } @@ -651,11 +684,12 @@ void FurnaceGUI::drawPattern() { rMax.x-=3.0f*dpiScale; rMax.y-=3.0f*dpiScale; dl->AddRect(rMin,rMax,fadeCol,4.0f*dpiScale,ImDrawFlags_RoundCornersAll,2.0*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } } + ImGui::PopID(); if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index e5c609829..bf360daed 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1355,6 +1355,11 @@ void FurnaceGUI::drawSettings() { settings.channelFont=1; } + bool channelTextCenterB=settings.channelTextCenter; + if (ImGui::Checkbox("Center channel name",&channelTextCenterB)) { + settings.channelTextCenter=channelTextCenterB; + } + ImGui::Separator(); bool insEditColorizeB=settings.insEditColorize; @@ -2291,10 +2296,11 @@ void FurnaceGUI::syncSettings() { settings.saveUnusedPatterns=e->getConfInt("saveUnusedPatterns",0); settings.channelColors=e->getConfInt("channelColors",1); settings.channelTextColors=e->getConfInt("channelTextColors",0); - settings.channelStyle=e->getConfInt("channelStyle",0); + settings.channelStyle=e->getConfInt("channelStyle",1); settings.channelVolStyle=e->getConfInt("channelVolStyle",0); settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1); settings.channelFont=e->getConfInt("channelFont",1); + settings.channelTextCenter=e->getConfInt("channelTextCenter",1); settings.maxRecentFile=e->getConfInt("maxRecentFile",10); clampSetting(settings.mainFontSize,2,96); @@ -2395,6 +2401,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelVolStyle,0,4); clampSetting(settings.channelFeedbackStyle,0,3); clampSetting(settings.channelFont,0,1); + clampSetting(settings.channelTextCenter,0,1); clampSetting(settings.maxRecentFile,0,30); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); @@ -2551,6 +2558,7 @@ void FurnaceGUI::commitSettings() { e->setConf("channelVolStyle",settings.channelVolStyle); e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle); e->setConf("channelFont",settings.channelFont); + e->setConf("channelTextCenter",settings.channelTextCenter); e->setConf("maxRecentFile",settings.maxRecentFile); // colors From 28d34171968dbdeff4b3221248fcff3e5a4bf6e6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 19:41:07 -0500 Subject: [PATCH 446/515] GUI: more channel bar polishing --- src/gui/pattern.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 103ecbbe2..ae194925d 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -547,6 +547,9 @@ void FurnaceGUI::drawPattern() { } else { minLabelArea.x+=padding; maxLabelArea.x-=padding; + if (settings.channelStyle==3) { // split button + maxLabelArea.x-=ImGui::GetFrameHeightWithSpacing(); + } const char* chName=e->getChannelName(i); float chNameLimit=maxLabelArea.x-minLabelArea.x; if (ImGui::CalcTextSize(chName).x>chNameLimit) { @@ -578,6 +581,8 @@ void FurnaceGUI::drawPattern() { minLabelArea.x+=0.5f*(maxLabelArea.x-minLabelArea.x-ImGui::CalcTextSize(chanID).x); } + if (extraChannelButtons==0 || settings.channelVolStyle!=0) ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0.0f,0.0f)); + ImGui::PushID(2048+i); switch (settings.channelStyle) { case 0: // classic @@ -640,6 +645,7 @@ void FurnaceGUI::drawPattern() { } case 3: // split button ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); + ImGui::SetCursorPosX(minLabelArea.x); ImGui::TextUnformatted(chanID); ImGui::SameLine(); ImGui::PushFont(mainFont); @@ -691,6 +697,8 @@ void FurnaceGUI::drawPattern() { } ImGui::PopID(); + if (extraChannelButtons==0 || settings.channelVolStyle!=0) ImGui::PopStyleVar(); + if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); } @@ -739,20 +747,24 @@ void FurnaceGUI::drawPattern() { } if (e->isRunning()) { + DivChannelState* cs=e->getChanState(i); + float stereoPan=(float)(e->convertPanSplitToLinearLR(cs->panL,cs->panR,256)-128)/128.0; switch (settings.channelVolStyle) { case 1: // simple xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); break; - case 2: // stereo - xRight=0.5+((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); - xLeft=1.0-xRight; + case 2: { // stereo + float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); + xRight=0.5+amount*(1.0+MIN(0.0,stereoPan)); + xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan)); break; + } case 3: // real xRight=chanOscVol[i]; break; case 4: // real (stereo) - xRight=0.5+chanOscVol[i]*0.5; - xLeft=1.0-xRight; + xRight=0.5+chanOscVol[i]*0.5*(1.0+MIN(0.0,stereoPan)); + xLeft=0.5-chanOscVol[i]*0.5*(1.0-MAX(0.0,stereoPan)); break; } From 24a40051352b5ef7b2953a8e0dc7018a65f8369f Mon Sep 17 00:00:00 2001 From: TheDuccinator <66538032+TheDuccinator@users.noreply.github.com> Date: Tue, 20 Sep 2022 18:53:48 -0700 Subject: [PATCH 447/515] Add new GB song "You're Doing Well!" --- demos/You're_Doing_Well!_GB.fur | Bin 0 -> 3855 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/You're_Doing_Well!_GB.fur diff --git a/demos/You're_Doing_Well!_GB.fur b/demos/You're_Doing_Well!_GB.fur new file mode 100644 index 0000000000000000000000000000000000000000..01cfff9d2cb81f9a3e8b9fe5f9a62e72bd2e5ff7 GIT binary patch literal 3855 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 WQ#4=iLekbwFCeJ{^0dFsE&LxqZU*oG literal 0 HcmV?d00001 From e1679e8ea68e6dd9dc56e414e1de77d0c56b824e Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 21 Sep 2022 13:22:04 +0900 Subject: [PATCH 448/515] Fix preset Atari ST series uses YM2419 or YM3439 --- src/gui/presets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index da1c4d51f..7d83dc3fb 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1114,13 +1114,13 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Atari ST", { - DIV_SYSTEM_AY8910, 64, 0, 3, + DIV_SYSTEM_AY8910, 64, 0, 19, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Atari STE", { - DIV_SYSTEM_AY8910, 64, 0, 3, + DIV_SYSTEM_AY8910, 64, 0, 19, DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), 0 From 0569af91037c894bc792238c587e38c93ba1ec52 Mon Sep 17 00:00:00 2001 From: nicco1690 <78063037+nicco1690@users.noreply.github.com> Date: Wed, 21 Sep 2022 14:18:12 -0400 Subject: [PATCH 449/515] DMF demo song submission reminder --- demos/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demos/README.md b/demos/README.md index ea3ef883e..43f29d793 100644 --- a/demos/README.md +++ b/demos/README.md @@ -11,4 +11,6 @@ contact me or send a pull request if you want your song to be added to this coll - Nintendo covers are frowned upon - big label music covers also are discouraged +tildearrow also accepts demo songs in the .DMF format as well as the .FUR format. + thank you for contributing! From 60abdd78a1c019b3d453366318fdd1bcd68788cd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 16:45:05 -0500 Subject: [PATCH 450/515] and yet another big endian fix --- src/engine/fileOps.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 10a4bcce9..41fc767af 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1772,14 +1772,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { #ifdef TA_BIG_ENDIAN // convert 16-bit samples to big-endian - if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { - unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); - size_t sampleBufLen=sample->getCurBufLen(); - for (size_t pos=0; pos>8)|((unsigned short)data[pos]<<8); } #endif From a17f499384201e1674e556e8576d9841aa78c56d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 16:52:04 -0500 Subject: [PATCH 451/515] ... --- src/engine/fileOps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 41fc767af..aac771e09 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1772,7 +1772,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { #ifdef TA_BIG_ENDIAN // convert 16-bit samples to big-endian - for (size_t pos=0; pos>8)|((unsigned short)data[pos]<<8); } #endif From e22d7484cb3d4344c404c58e9762a72fc5b6a5b4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 19:27:42 -0500 Subject: [PATCH 452/515] dev115 - automatic system detection --- papers/format.md | 11 ++++- src/engine/engine.h | 4 +- src/engine/fileOps.cpp | 14 ++++++- src/engine/instrument.cpp | 12 +++++- src/engine/instrument.h | 4 +- src/engine/song.h | 4 +- src/gui/gui.cpp | 87 +++++++++++++++++++++++++++++++++++++++ src/gui/gui.h | 3 +- src/gui/songInfo.cpp | 14 ++++++- src/gui/sysConf.cpp | 3 ++ src/gui/sysManager.cpp | 6 +++ 11 files changed, 150 insertions(+), 12 deletions(-) diff --git a/papers/format.md b/papers/format.md index da06488fa..acedd9945 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 115: Furnace dev115 - 114: Furnace dev114 - 113: Furnace dev113 - 112: Furnace dev112 @@ -342,7 +343,9 @@ size | description 1 | SN periods under 8 are treated as 1 (>=108) or reserved 1 | cut/delay effect policy (>=110) or reserved 1 | 0B/0D effect treatment (>=113) or reserved - 4 | reserved + 1 | automatic system name detection (>=115) or reserved + | - this one isn't a compatibility flag, but it's here for convenience... + 3 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved @@ -499,7 +502,11 @@ size | description 1 | ws 1 | ksr 1 | operator enabled (>=114) or reserved - 11 | reserved + 1 | KVS mode (>=115) or reserved + | - 0: off + | - 1: on + | - 2: auto (depending on alg) + 10 | reserved --- | **Game Boy instrument data** 1 | volume 1 | direction diff --git a/src/engine/engine.h b/src/engine/engine.h index 3047a8af7..40bbbbb90 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev114" -#define DIV_ENGINE_VERSION 114 +#define DIV_VERSION "dev115" +#define DIV_ENGINE_VERSION 115 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index aac771e09..4c213744b 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1085,6 +1085,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<113) { ds.jumpTreatment=1; } + if (ds.version<115) { + ds.autoSystem=false; + } ds.isDMF=false; reader.readS(); // reserved @@ -1512,7 +1515,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<4; i++) { + if (ds.version>=115) { + ds.autoSystem=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<3; i++) { reader.readC(); } } @@ -1549,6 +1557,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.categoryJ=reader.readString(); } else { ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); + ds.autoSystem=true; } // read subsongs @@ -3751,7 +3760,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.snNoLowPeriods); w->writeC(song.delayBehavior); w->writeC(song.jumpTreatment); - for (int i=0; i<4; i++) { + w->writeC(song.autoSystem); + for (int i=0; i<3; i++) { w->writeC(0); } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 22cdddf4b..3296994ba 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -72,9 +72,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(op.ksr); w->writeC(op.enable); + w->writeC(op.kvs); // reserved - for (int k=0; k<11; k++) { + for (int k=0; k<10; k++) { w->writeC(0); } } @@ -724,8 +725,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { reader.readC(); } + if (version>=115) { + op.kvs=reader.readC(); + } else { + op.kvs=2; + reader.readC(); + } + // reserved - for (int k=0; k<11; k++) reader.readC(); + for (int k=0; k<10; k++) reader.readC(); } // GB diff --git a/src/engine/instrument.h b/src/engine/instrument.h index e5372933d..5652301f4 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -87,6 +87,7 @@ struct DivInstrumentFM { bool enable; unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ + unsigned char kvs; Operator(): enable(true), am(0), @@ -108,7 +109,8 @@ struct DivInstrumentFM { sus(0), vib(0), ws(0), - ksr(0) {} + ksr(0), + kvs(2) {} } op[4]; DivInstrumentFM(): alg(0), diff --git a/src/engine/song.h b/src/engine/song.h index 493fc4125..09a89378c 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -511,6 +511,7 @@ struct DivSong { bool e1e2StopOnSameNote; bool brokenPortaArp; bool snNoLowPeriods; + bool autoSystem; std::vector ins; std::vector wave; @@ -614,7 +615,8 @@ struct DivSong { brokenOutVol(false), e1e2StopOnSameNote(false), brokenPortaArp(false), - snNoLowPeriods(false) { + snNoLowPeriods(false), + autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a2eb9c920..2e566bb1a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -584,6 +584,78 @@ void FurnaceGUI::updateWindowTitle() { if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str()); } +void FurnaceGUI::autoDetectSystem() { + std::map sysCountMap; + for (int i=0; isong.systemLen; i++) { + try { + sysCountMap.at(e->song.system[i])++; + } catch (std::exception& ex) { + sysCountMap[e->song.system[i]]=1; + } + } + + logV("sysCountMap:"); + for (std::pair k: sysCountMap) { + logV("%s: %d",e->getSystemName(k.first),k.second); + } + + bool isMatch=false; + std::map defCountMap; + for (FurnaceGUISysCategory& i: sysCategories) { + for (FurnaceGUISysDef& j: i.systems) { + defCountMap.clear(); + for (size_t k=0; k k: defCountMap) { + logV("- %s: %d",e->getSystemName(k.first),k.second); + } + for (std::pair k: defCountMap) { + try { + if (sysCountMap.at(k.first)!=k.second) { + isMatch=false; + break; + } + } catch (std::exception& ex) { + isMatch=false; + break; + } + } + if (isMatch) { + logV("match found!"); + e->song.systemName=j.name; + break; + } + } + if (isMatch) break; + } + + if (!isMatch) { + bool isFirst=true; + e->song.systemName=""; + for (std::pair k: sysCountMap) { + if (!isFirst) e->song.systemName+=" + "; + if (k.second>1) { + e->song.systemName+=fmt::sprintf("%d×",k.second); + } + if (k.first==DIV_SYSTEM_N163) { + e->song.systemName+=settings.c163Name; + } else { + e->song.systemName+=e->getSystemName(k.first); + } + isFirst=false; + } + } +} + ImVec4 FurnaceGUI::channelColor(int ch) { switch (settings.channelColors) { case 0: @@ -3262,6 +3334,9 @@ bool FurnaceGUI::loop() { showError("cannot add chip! ("+e->getLastError()+")"); } ImGui::CloseCurrentPopup(); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); } ImGui::EndMenu(); @@ -3282,6 +3357,9 @@ bool FurnaceGUI::loop() { DivSystem picked=systemPicker(); if (picked!=DIV_SYSTEM_NULL) { e->changeSystem(i,picked,preserveChanPos); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); ImGui::CloseCurrentPopup(); } @@ -3297,6 +3375,10 @@ bool FurnaceGUI::loop() { if (!e->removeSystem(i,preserveChanPos)) { showError("cannot remove chip! ("+e->getLastError()+")"); } + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } } } ImGui::EndMenu(); @@ -4415,6 +4497,10 @@ bool FurnaceGUI::loop() { case GUI_WARN_SYSTEM_DEL: if (ImGui::Button("Yes")) { e->removeSystem(sysToDelete,preserveChanPos); + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } ImGui::CloseCurrentPopup(); } ImGui::SameLine(); @@ -5069,6 +5155,7 @@ FurnaceGUI::FurnaceGUI(): macroPointSize(16), waveEditStyle(0), mobileMenuPos(0.0f), + autoButtonSize(0.0f), curSysSection(NULL), pendingRawSampleDepth(8), pendingRawSampleChannels(1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 5bf8adfe7..c44d4c122 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1018,7 +1018,7 @@ class FurnaceGUI { int drawHalt; int macroPointSize; int waveEditStyle; - float mobileMenuPos; + float mobileMenuPos, autoButtonSize; const int* curSysSection; String pendingRawSample; @@ -1610,6 +1610,7 @@ class FurnaceGUI { bool CWVSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format="%d", ImGuiSliderFlags flags=0); void updateWindowTitle(); + void autoDetectSystem(); void prepareLayout(); ImVec4 channelColor(int ch); ImVec4 channelTextColor(int ch); diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 44982abaf..5b113c641 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -77,11 +77,23 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); ImGui::Text("System"); ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); + ImGui::SetNextItemWidth(MAX(16.0f*dpiScale,avail-autoButtonSize-ImGui::GetStyle().ItemSpacing.x)); if (ImGui::InputText("##SystemName",&e->song.systemName)) { MARK_MODIFIED; updateWindowTitle(); + e->song.autoSystem=false; } + ImGui::SameLine(); + pushToggleColors(e->song.autoSystem); + if (ImGui::Button("Auto")) { + e->song.autoSystem=!e->song.autoSystem; + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } + } + popToggleColors(); + autoButtonSize=ImGui::GetItemRectSize().x; ImGui::EndTable(); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 3a0c1098e..900845a69 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -765,6 +765,9 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (copyOfFlags!=flags) { if (chan>=0) { e->setSysFlags(chan,copyOfFlags,restart); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); } else { flags=copyOfFlags; diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index 98f939d0f..386d26583 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -82,6 +82,9 @@ void FurnaceGUI::drawSysManager() { DivSystem picked=systemPicker(); if (picked!=DIV_SYSTEM_NULL) { e->changeSystem(i,picked,preserveChanPos); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); ImGui::CloseCurrentPopup(); } @@ -110,6 +113,9 @@ void FurnaceGUI::drawSysManager() { if (!e->addSystem(picked)) { showError("cannot add chip! ("+e->getLastError()+")"); } + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); ImGui::CloseCurrentPopup(); } From ad097e0526b15fa73c56cfb61aea10cfcf332f34 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 22:59:53 -0500 Subject: [PATCH 453/515] GUI: add paste with instrument like paste mix but changes the instrument --- TODO.md | 3 +-- src/gui/editing.cpp | 15 +++++++++------ src/gui/gui.cpp | 24 ++++++++++++++++++++++++ src/gui/gui.h | 6 ++++-- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index 028f21077..84bc08a73 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1.5 - stereo separation control for AY -- "paste with instrument" -- auto-detect system +- KVS - bug fixes diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 201c9be26..153d70da3 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -405,7 +405,7 @@ void FurnaceGUI::doCopy(bool cut) { } } -void FurnaceGUI::doPaste(PasteMode mode) { +void FurnaceGUI::doPaste(PasteMode mode, int arg) { finishSelection(); prepareUndo(GUI_UNDO_PATTERN_PASTE); char* clipText=SDL_GetClipboardText(); @@ -481,14 +481,16 @@ void FurnaceGUI::doPaste(PasteMode mode) { continue; } - if ((mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG) && strcmp(note,"...")==0) { + if ((mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG || + mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) && strcmp(note,"...")==0) { // do nothing. } else { - if (mode!=GUI_PASTE_MODE_MIX_BG || (pat->data[j][0]==0 && pat->data[j][1]==0)) { + if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || (pat->data[j][0]==0 && pat->data[j][1]==0)) { if (!decodeNote(note,pat->data[j][0],pat->data[j][1])) { invalidData=true; break; } + if (mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) pat->data[j][2]=arg; } } } else { @@ -505,7 +507,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { note[2]=0; if (iFine==1) { - if (!opMaskPaste.ins) { + if (!opMaskPaste.ins || mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) { iFine++; continue; } @@ -527,7 +529,8 @@ void FurnaceGUI::doPaste(PasteMode mode) { } if (strcmp(note,"..")==0) { - if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG)) { + if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG || + mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG)) { pat->data[j][iFine+1]=-1; } } else { @@ -536,7 +539,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { invalidData=true; break; } - if (mode!=GUI_PASTE_MODE_MIX_BG || pat->data[j][iFine+1]==-1) { + if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->data[j][iFine+1]==-1) { if (iFine<(3+e->curPat[iCoarse].effectCols*2)) pat->data[j][iFine+1]=val; } } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2e566bb1a..c374576ef 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2180,6 +2180,30 @@ void FurnaceGUI::editOptions(bool topMenu) { if (ImGui::BeginMenu("paste special...")) { if (ImGui::MenuItem("paste mix",BIND_FOR(GUI_ACTION_PAT_PASTE_MIX))) doPaste(GUI_PASTE_MODE_MIX_FG); if (ImGui::MenuItem("paste mix (background)",BIND_FOR(GUI_ACTION_PAT_PASTE_MIX_BG))) doPaste(GUI_PASTE_MODE_MIX_BG); + if (ImGui::BeginMenu("paste with ins (foreground)")) { + if (e->song.ins.empty()) { + ImGui::Text("no instruments available"); + } + for (size_t i=0; isong.ins.size(); i++) { + snprintf(id,4095,"%.2X: %s",(int)i,e->song.ins[i]->name.c_str()); + if (ImGui::MenuItem(id)) { + doPaste(GUI_PASTE_MODE_INS_FG,i); + } + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("paste with ins (background)")) { + if (e->song.ins.empty()) { + ImGui::Text("no instruments available"); + } + for (size_t i=0; isong.ins.size(); i++) { + snprintf(id,4095,"%.2X: %s",(int)i,e->song.ins[i]->name.c_str()); + if (ImGui::MenuItem(id)) { + doPaste(GUI_PASTE_MODE_INS_BG,i); + } + } + ImGui::EndMenu(); + } if (ImGui::MenuItem("paste flood",BIND_FOR(GUI_ACTION_PAT_PASTE_FLOOD))) doPaste(GUI_PASTE_MODE_FLOOD); if (ImGui::MenuItem("paste overflow",BIND_FOR(GUI_ACTION_PAT_PASTE_OVERFLOW))) doPaste(GUI_PASTE_MODE_OVERFLOW); ImGui::EndMenu(); diff --git a/src/gui/gui.h b/src/gui/gui.h index c44d4c122..77a127595 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -596,7 +596,9 @@ enum PasteMode { GUI_PASTE_MODE_MIX_FG, GUI_PASTE_MODE_MIX_BG, GUI_PASTE_MODE_FLOOD, - GUI_PASTE_MODE_OVERFLOW + GUI_PASTE_MODE_OVERFLOW, + GUI_PASTE_MODE_INS_FG, + GUI_PASTE_MODE_INS_BG }; #define FURKMOD_CTRL (1U<<31) @@ -1708,7 +1710,7 @@ class FurnaceGUI { void doInsert(); void doTranspose(int amount, OperationMask& mask); void doCopy(bool cut); - void doPaste(PasteMode mode=GUI_PASTE_MODE_NORMAL); + void doPaste(PasteMode mode=GUI_PASTE_MODE_NORMAL, int arg=0); void doChangeIns(int ins); void doInterpolate(); void doFade(int p0, int p1, bool mode); From 51c142169fb73d12b07cc726fd1e8f34b37c57f3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 23:25:57 -0500 Subject: [PATCH 454/515] GUI: OPZ compact editor fixes --- src/gui/insEdit.cpp | 96 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 50fd286b8..31dfdb357 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2928,6 +2928,14 @@ void FurnaceGUI::drawInsEdit() { } } + if (ins->type==DIV_INS_OPZ) { + ImGui::SameLine(); + bool fixedOn=op.egt; + if (ImGui::Checkbox("Fixed",&fixedOn)) { PARAMETER + op.egt=fixedOn; + } + } + //52.0 controls vert scaling; default 96 drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable @@ -3012,23 +3020,85 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_KSL)); } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_MULT)); - - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - int detune=(op.dt&7)-(settings.unsignedDetune?0:3); + if (ins->type==DIV_INS_OPZ) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##DT",&detune,-3,4)) { PARAMETER - op.dt=detune+(settings.unsignedDetune?0:3); - } rightClickable + P(CWSliderScalar(FM_NAME(FM_EGSHIFT),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DT)); + ImGui::Text("%s",FM_NAME(FM_EGSHIFT)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_REV),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_REV)); + } + + if (ins->type==DIV_INS_OPZ) { + if (op.egt) { + int block=op.dt; + int freqNum=(op.mult<<4)|(op.dvb&15); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt(FM_NAME(FM_MULT),&block,0,7)) { PARAMETER + if (block<0) block=0; + if (block>7) block=7; + op.dt=block; + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("Block"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt(FM_NAME(FM_FINE),&freqNum,0,255)) { PARAMETER + if (freqNum<0) freqNum=0; + if (freqNum>255) freqNum=255; + op.mult=freqNum>>4; + op.dvb=freqNum&15; + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("FreqNum"); + } else { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_MULT)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_FINE),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_FINE)); + } + } else { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_MULT)); + } + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (!(ins->type==DIV_INS_OPZ && op.egt)) { + int detune=(op.dt&7)-(settings.unsignedDetune?0:3); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##DT",&detune,-3,4)) { PARAMETER + op.dt=detune+(settings.unsignedDetune?0:3); + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DT)); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); From 401581e892d964afadc7573de4bc440f48879474 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 23:41:22 -0500 Subject: [PATCH 455/515] fix 116.5 --- src/engine/playback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 898bb2b05..f6baeb4dc 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -379,7 +379,7 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xed: // delay if (effectVal!=0) { - bool comparison=(song.delayBehavior==1)?(effectVal<=nextSpeed):(effectValtimeBase+1))); if (song.delayBehavior==2) comparison=true; if (comparison) { chan[i].rowDelay=effectVal+1; From 7bb7fa0c24e78c1608920179a2e68e679c6fcaa8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 23:45:32 -0500 Subject: [PATCH 456/515] Moon --- demos/Moon.fur | Bin 0 -> 16907 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Moon.fur diff --git a/demos/Moon.fur b/demos/Moon.fur new file mode 100644 index 0000000000000000000000000000000000000000..366de04523561f89d0767a4c274df2214e39079f GIT binary patch literal 16907 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 literal 0 HcmV?d00001 From 32cdd81919ba0aee534210791907ba999c79e9bf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 00:01:23 -0500 Subject: [PATCH 457/515] OPL: fix chan osc in 4-op mode --- src/engine/platform/opl.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 2dd6d1dcf..e1ad92f5f 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1421,6 +1421,15 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) { DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { if (ch>=18) return NULL; + if (oplType==3 && ch<12) { + if (chan[ch&(~1)].fourOp) { + if (ch&1) { + return oscBuf[ch-1]; + } else { + return oscBuf[ch+1]; + } + } + } return oscBuf[ch]; } From 9685a5c0d87f00c503a0e220e29fd3f9f92229bc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 00:18:40 -0500 Subject: [PATCH 458/515] AY: add stereo separation slider --- src/engine/platform/ay.cpp | 5 +++-- src/engine/platform/ay.h | 1 + src/engine/platform/ay8930.cpp | 5 +++-- src/engine/platform/ay8930.h | 1 + src/gui/sysConf.cpp | 8 ++++++++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index f475b4750..cf52f3d29 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -115,8 +115,8 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l ay->sound_stream_update(ayBuf,len); if (stereo) { for (size_t i=0; i>8); + bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; } } else { for (size_t i=0; idevice_reset(); stereo=(flags>>6)&1; + stereoSep=(flags>>8)&255; } int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 4b7ce1068..0537dadab 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -66,6 +66,7 @@ class DivPlatformAY8910: public DivDispatch { int dacPos; int dacSample; unsigned char sampleBank; + unsigned char stereoSep; int delay; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 123dc68ac..d5f01013d 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -99,8 +99,8 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l ay->sound_stream_update(ayBuf,len); if (stereo) { for (size_t i=0; i>8); + bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; } } else { for (size_t i=0; i>6)&1; + stereoSep=(flags>>8)&255; } int DivPlatformAY8930::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 81995f2de..75a5f6974 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -66,6 +66,7 @@ class DivPlatformAY8930: public DivDispatch { DivDispatchOscBuffer* oscBuf[3]; unsigned char regPool[32]; unsigned char ayNoiseAnd, ayNoiseOr; + unsigned char stereoSep; bool bank; int delay; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 900845a69..98b600286 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -358,6 +358,14 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) { copyOfFlags=(flags&(~0x40))|(stereo?0x40:0); } + if (stereo) { + int sep=256-((flags>>8)&255); + if (CWSliderInt("Separation",&sep,1,256)) { + if (sep<1) sep=1; + if (sep>256) sep=256; + copyOfFlags=(flags&(~0xff00))|((256-sep)<<8); + } + } ImGui::EndDisabled(); bool clockSel=flags&0x80; ImGui::BeginDisabled((type==DIV_SYSTEM_AY8910) && ((flags&0x30)!=16)); From ac68419b785dc2e3a8d6ffe6c7b0b01c6ef5105e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:18:41 -0500 Subject: [PATCH 459/515] implement KVS on YM2612 --- TODO.md | 4 --- src/engine/fileOps.cpp | 12 ++++++++ src/engine/platform/fmsharedbase.h | 2 ++ src/engine/platform/genesis.cpp | 16 +++++------ src/gui/gui.h | 1 + src/gui/insEdit.cpp | 46 ++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 12 deletions(-) diff --git a/TODO.md b/TODO.md index 84bc08a73..8b1378917 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1 @@ -# to-do for 0.6pre1.5 -- stereo separation control for AY -- KVS -- bug fixes diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 4c213744b..7da21f4fa 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -196,6 +196,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } */ + // Genesis detuned on Defle v10 and earlier + /*if (ds.version<19 && ds.system[0]==DIV_SYSTEM_GENESIS) { + ds.tuning=443.23; + }*/ + // C64 detuned on Defle v11 and earlier + /*if (ds.version<21 && (ds.system[0]==DIV_SYSTEM_C64_6581 || ds.system[0]==DIV_SYSTEM_C64_8580)) { + ds.tuning=433.2; + }*/ + logI("reading module data..."); if (ds.version>0x0c) { ds.subsong[0]->hilightA=reader.readC(); @@ -449,6 +458,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.op[j].ssgEnv=reader.readC(); } } + if (ds.version<0x12) { // before version 10 all ops were responsive to volume + ins->fm.op[j].kvs=1; + } logD("OP%d: AM %d AR %d DAM %d DR %d DVB %d EGT %d KSL %d MULT %d RR %d SL %d SUS %d TL %d VIB %d WS %d RS %d DT %d D2R %d SSG-EG %d",j, ins->fm.op[j].am, diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index 640997392..15baacefa 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -23,6 +23,8 @@ #include "../dispatch.h" #include +#define KVS(x,y) ((chan[x].state.op[y].kvs==2 && isOutput[chan[x].state.alg][y]) || chan[x].state.op[y].kvs==1) + class DivPlatformFMBase: public DivDispatch { protected: const bool isOutput[8][4]={ diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 515f0c0ae..d289a3515 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -254,7 +254,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -327,7 +327,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -384,7 +384,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -501,7 +501,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][j]) { + if (KVS(ch,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -614,7 +614,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -687,7 +687,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -860,7 +860,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1051,7 +1051,7 @@ void DivPlatformGenesis::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/gui/gui.h b/src/gui/gui.h index 77a127595..80b550401 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1603,6 +1603,7 @@ class FurnaceGUI { void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); void drawSysConf(int chan, DivSystem type, unsigned int& flags, bool modifyOnChange); + void kvsConfig(DivInstrument* ins); // these ones offer ctrl-wheel fine value changes. bool CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 31dfdb357..d08e276a7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1211,6 +1211,46 @@ inline bool enBit30(const int val) { return false; } + +void FurnaceGUI::kvsConfig(DivInstrument* ins) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("(click to configure KVS)"); + } + int opCount=4; + if (ins->type==DIV_INS_OPLL) opCount=2; + if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; + if (ImGui::BeginPopupContextItem("IKVSOpt",ImGuiPopupFlags_MouseButtonLeft)) { + ImGui::Text("operator level changes with volume?"); + if (ImGui::BeginTable("KVSTable",4,ImGuiTableFlags_BordersInner)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); + for (int i=0; i<4; i++) { + int o=(opCount==4)?orderedOps[i]:i; + if (!(i&1)) ImGui::TableNextRow(); + const char* label="AUTO##OPKVS"; + if (ins->fm.op[o].kvs==0) { + label="NO##OPKVS"; + } else if (ins->fm.op[o].kvs==1) { + label="YES##OPKVS"; + } + ImGui::TableNextColumn(); + ImGui::Text("%d",i+1); + ImGui::TableNextColumn(); + ImGui::PushID(o); + if (ImGui::Button(label,ImVec2(ImGui::GetContentRegionAvail().x,0.0f))) { + if (++ins->fm.op[o].kvs>2) ins->fm.op[o].kvs=0; + PARAMETER; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::EndPopup(); + } +} + void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; @@ -1769,6 +1809,7 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); break; case DIV_INS_OPZ: ImGui::TableNextColumn(); @@ -1781,6 +1822,8 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS2),ImGuiDataType_U8,&ins->fm.ams2,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); + if (ImGui::Button("Request from TX81Z")) { doAction(GUI_ACTION_TX81Z_REQUEST); } @@ -1813,6 +1856,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); break; } case DIV_INS_OPLL: { @@ -1837,6 +1881,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); ImGui::TableNextColumn(); drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); + kvsConfig(ins); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); bool isPresent[4]; From 89916de0672461e8c6208cd7cd9759ea6895fce6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:18:53 -0500 Subject: [PATCH 460/515] remove to-do list --- TODO.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 TODO.md diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 8b1378917..000000000 --- a/TODO.md +++ /dev/null @@ -1 +0,0 @@ - From b053d31a6dc629f2d0f3b312e7517cba0fc45441 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:30:51 -0500 Subject: [PATCH 461/515] implement KVS on the rest of FM chips --- src/engine/platform/arcade.cpp | 14 +++++++------- src/engine/platform/genesisext.cpp | 8 ++++---- src/engine/platform/opl.cpp | 25 ++++++++++++++++--------- src/engine/platform/tx81z.cpp | 16 ++++++++-------- src/engine/platform/ym2203.cpp | 16 ++++++++-------- src/engine/platform/ym2203ext.cpp | 2 +- src/engine/platform/ym2608.cpp | 14 +++++++------- src/engine/platform/ym2608ext.cpp | 4 ++-- src/engine/platform/ym2610.cpp | 14 +++++++------- src/engine/platform/ym2610b.cpp | 14 +++++++------- src/engine/platform/ym2610bext.cpp | 4 ++-- src/engine/platform/ym2610ext.cpp | 4 ++-- src/gui/insEdit.cpp | 1 - 13 files changed, 71 insertions(+), 65 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 6e925c9a0..c86f806e1 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -151,7 +151,7 @@ void DivPlatformArcade::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -231,7 +231,7 @@ void DivPlatformArcade::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -289,7 +289,7 @@ void DivPlatformArcade::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -390,7 +390,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -448,7 +448,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -545,7 +545,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -746,7 +746,7 @@ void DivPlatformArcade::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index a2df33c41..84b906bec 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -209,7 +209,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { op.tl=c.value2; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[2].state.alg][c.value]) { + } else if (KVS(2,c.value)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -392,7 +392,7 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { if (isOpMuted[ch-2]) { rWrite(baseAddr+0x40,127); immWrite(baseAddr+0x40,127); - } else if (isOutput[chan[2].state.alg][ordch]) { + } else if (KVS(2,ordch)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); immWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); } else { @@ -526,7 +526,7 @@ void DivPlatformGenesisExt::forceIns() { if (i==2 && extMode) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -535,7 +535,7 @@ void DivPlatformGenesisExt::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index e1ad92f5f..65a195048 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -26,6 +26,8 @@ #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} #define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } +#define KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1) + #define CHIP_FREQBASE chipFreqBase // N = invalid @@ -138,6 +140,11 @@ const bool isOutputL[2][4][4]={ #undef N +const int orderedOpsL1[2][4]={ + {0, 1, 0, 1}, // 2-op + {0, 2, 1, 3} // 4-op +}; + const int orderedOpsL[4]={ 0,2,1,3 }; @@ -288,7 +295,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { + if (KVSL(i,j) || i>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -406,7 +413,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { + if (KVSL(i,j) || i>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -610,7 +617,7 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[ch].state.alg][i] || ch>melodicChans) { + if (KVSL(ch,i) || ch>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -783,7 +790,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { + if (KVSL(c.chan,i) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -899,7 +906,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { + if (KVSL(c.chan,i) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1048,7 +1055,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) { + if (KVSL(c.chan,c.value) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1278,7 +1285,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { + if (KVSL(c.chan,i) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1295,7 +1302,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) { + if (KVSL(c.chan,c.value) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1372,7 +1379,7 @@ void DivPlatformOPL::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { + if (KVSL(i,j) || i>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 1c6470fc4..fa29cda60 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -112,7 +112,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -179,7 +179,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -232,7 +232,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -324,7 +324,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][i]) { + if (KVS(ch,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -353,7 +353,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -419,7 +419,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -519,7 +519,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -811,7 +811,7 @@ void DivPlatformTX81Z::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 1c3488006..13fc014d8 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -220,7 +220,7 @@ void DivPlatformYM2203::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -261,7 +261,7 @@ void DivPlatformYM2203::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -310,7 +310,7 @@ void DivPlatformYM2203::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -427,7 +427,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -487,7 +487,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -572,7 +572,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -764,7 +764,7 @@ void DivPlatformYM2203::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][j]) { + if (KVS(ch,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -781,7 +781,7 @@ void DivPlatformYM2203::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index c7080d431..527a8be6b 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2203Ext::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 42bea41b2..42a3235d9 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -376,7 +376,7 @@ void DivPlatformYM2608::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -421,7 +421,7 @@ void DivPlatformYM2608::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -475,7 +475,7 @@ void DivPlatformYM2608::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -698,7 +698,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -779,7 +779,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -890,7 +890,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1093,7 +1093,7 @@ void DivPlatformYM2608::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 116f6b95c..7f49ed9d6 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2608Ext::forceIns() { if (i==2) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -451,7 +451,7 @@ void DivPlatformYM2608Ext::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 6a8509d55..34a402e2b 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -417,7 +417,7 @@ void DivPlatformYM2610::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -462,7 +462,7 @@ void DivPlatformYM2610::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -516,7 +516,7 @@ void DivPlatformYM2610::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -742,7 +742,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -823,7 +823,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -934,7 +934,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1137,7 +1137,7 @@ void DivPlatformYM2610::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 31cd7b3ff..bbdb3c60d 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -400,7 +400,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -445,7 +445,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -499,7 +499,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -724,7 +724,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -805,7 +805,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -916,7 +916,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1119,7 +1119,7 @@ void DivPlatformYM2610B::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index f55e6561c..a13598554 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2610BExt::forceIns() { if (i==2 && extMode) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -451,7 +451,7 @@ void DivPlatformYM2610BExt::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 6cee242f4..66090514f 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2610Ext::forceIns() { if (i==1 && extMode) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -451,7 +451,7 @@ void DivPlatformYM2610Ext::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index d08e276a7..08b2f509c 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1881,7 +1881,6 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); ImGui::TableNextColumn(); drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); - kvsConfig(ins); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); From 02d207716270c9c76ef2e9889253addca461b7ba Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 02:46:55 -0500 Subject: [PATCH 462/515] MIDI out: turn notes off on reset() --- src/engine/engine.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bb03eda18..217cc977e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2000,6 +2000,14 @@ void DivEngine::recalcChans() { } void DivEngine::reset() { + if (output) if (output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0)); + for (int i=0; i=0) { + output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0)); + } + } + } for (int i=0; idispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff; From cec31b23de970448fc9bb857f24682302d7d7bde Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:04:32 -0500 Subject: [PATCH 463/515] GUI: temporarily disable InputText undo/redo issue #624 --- extern/imgui_patched/imgui_widgets.cpp | 15 +++++++++--- extern/imgui_patched/imstb_textedit.h | 33 ++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/extern/imgui_patched/imgui_widgets.cpp b/extern/imgui_patched/imgui_widgets.cpp index 93dfd5343..d6ddfdb88 100644 --- a/extern/imgui_patched/imgui_widgets.cpp +++ b/extern/imgui_patched/imgui_widgets.cpp @@ -3713,7 +3713,12 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const Im { const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int text_len = obj->CurLenW; - IM_ASSERT(pos <= text_len); + if (pos > text_len) { + printf("failing STB_TEXTEDIT_INSERTCHARS assertion! oh man...\n"); + obj->Edited = true; // ??? + obj->ClearText(); + return false; + } const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) @@ -3776,8 +3781,11 @@ static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* st state->cursor = text_len; state->has_preferred_x = 0; return; + } else { + state->cursor = 0; + printf("STB_TEXTEDIT_INSERTCHARS fail!\n"); } - IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() + //IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() } } // namespace ImStb @@ -3962,7 +3970,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; - const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + // https://github.com/tildearrow/furnace/issues/624 + const bool is_undoable = 0; //(flags & ImGuiInputTextFlags_NoUndoRedo) == 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! diff --git a/extern/imgui_patched/imstb_textedit.h b/extern/imgui_patched/imstb_textedit.h index 75a159dac..d93642305 100644 --- a/extern/imgui_patched/imstb_textedit.h +++ b/extern/imgui_patched/imstb_textedit.h @@ -717,6 +717,9 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta state->cursor += len; state->has_preferred_x = 0; return 1; + } else { + printf("stb_textedit_paste_internal failed.\n"); + state->cursor=0; } // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) return 0; @@ -746,6 +749,9 @@ retry: if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { ++state->cursor; state->has_preferred_x = 0; + } else { + printf("key failed: first section.\n"); + state->cursor=0; } } else { stb_textedit_delete_selection(str,state); // implicitly clamps @@ -753,6 +759,9 @@ retry: stb_text_makeundo_insert(state, state->cursor, 1); ++state->cursor; state->has_preferred_x = 0; + } else { + printf("key failed: second section.\n"); + state->cursor=0; } } } @@ -1275,14 +1284,22 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); } + bool steFailed=false; + // check type of recorded action: if (u.insert_length) { // easy case: was a deletion, so we need to insert n characters - STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); + if (!STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length)) { + printf("undo u.insert_length failed\n"); + state->cursor=0; + steFailed=true; + } s->undo_char_point -= u.insert_length; } - state->cursor = u.where + u.insert_length; + if (!steFailed) { + state->cursor = u.where + u.insert_length; + } s->undo_point--; s->redo_point--; @@ -1327,13 +1344,21 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); } + bool steFailed=false; + if (r.insert_length) { // easy case: need to insert n characters - STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); + if (!STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length)) { + printf("redo insert char failed\n"); + state->cursor=0; + steFailed=true; + } s->redo_char_point += r.insert_length; } - state->cursor = r.where + r.insert_length; + if (!steFailed) { + state->cursor = r.where + r.insert_length; + } s->undo_point++; s->redo_point++; From b9d8d91ca7b7e2b8e74b877487d63b4f5bf45de1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:10:12 -0500 Subject: [PATCH 464/515] GUI: I am done look I need to sleep --- extern/imgui_patched/imgui.h | 2 +- extern/imgui_patched/imgui_widgets.cpp | 3 +-- src/gui/songInfo.cpp | 8 ++++---- src/gui/songNotes.cpp | 2 +- src/gui/subSongs.cpp | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/extern/imgui_patched/imgui.h b/extern/imgui_patched/imgui.h index e9ccea9b1..3d600ea2b 100644 --- a/extern/imgui_patched/imgui.h +++ b/extern/imgui_patched/imgui.h @@ -1042,7 +1042,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' - ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + ImGuiInputTextFlags_UndoRedo = 1 << 16, // Enable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) ImGuiInputTextFlags_CallbackEdit = 1 << 19 // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) diff --git a/extern/imgui_patched/imgui_widgets.cpp b/extern/imgui_patched/imgui_widgets.cpp index d6ddfdb88..4579400d4 100644 --- a/extern/imgui_patched/imgui_widgets.cpp +++ b/extern/imgui_patched/imgui_widgets.cpp @@ -3970,8 +3970,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; - // https://github.com/tildearrow/furnace/issues/624 - const bool is_undoable = 0; //(flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + const bool is_undoable = (flags & ImGuiInputTextFlags_UndoRedo) != 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 5b113c641..8d4e0999e 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -39,7 +39,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED + if (ImGui::InputText("##Name",&e->song.name,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED updateWindowTitle(); } if (e->song.insLen==2) { @@ -61,7 +61,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("Author"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Author",&e->song.author)) { + if (ImGui::InputText("##Author",&e->song.author,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; } @@ -70,7 +70,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("Album"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Category",&e->song.category)) { + if (ImGui::InputText("##Category",&e->song.category,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; } ImGui::TableNextRow(); @@ -78,7 +78,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("System"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(MAX(16.0f*dpiScale,avail-autoButtonSize-ImGui::GetStyle().ItemSpacing.x)); - if (ImGui::InputText("##SystemName",&e->song.systemName)) { + if (ImGui::InputText("##SystemName",&e->song.systemName,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; updateWindowTitle(); e->song.autoSystem=false; diff --git a/src/gui/songNotes.cpp b/src/gui/songNotes.cpp index 74f4ed7ff..338c7da24 100644 --- a/src/gui/songNotes.cpp +++ b/src/gui/songNotes.cpp @@ -30,7 +30,7 @@ void FurnaceGUI::drawNotes() { } if (!notesOpen) return; if (ImGui::Begin("Song Comments",¬esOpen,globalWinFlags)) { - ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail()); + ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_NOTES; ImGui::End(); diff --git a/src/gui/subSongs.cpp b/src/gui/subSongs.cpp index c56bf6405..f076298f2 100644 --- a/src/gui/subSongs.cpp +++ b/src/gui/subSongs.cpp @@ -91,7 +91,7 @@ void FurnaceGUI::drawSubSongs() { ImGui::Text("Name"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputText("##SubSongName",&e->curSubSong->name)) { + if (ImGui::InputText("##SubSongName",&e->curSubSong->name,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; } } From 1ceca2a509ed31022d300ea8cf18afd20dffb20a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:13:26 -0500 Subject: [PATCH 465/515] release v0.6pre1.5 --- papers/format.md | 1 + src/engine/engine.h | 4 ++-- src/gui/about.cpp | 9 +++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/papers/format.md b/papers/format.md index acedd9945..1d4e7fc76 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 116: Furnace 0.6pre1.5 - 115: Furnace dev115 - 114: Furnace dev114 - 113: Furnace dev113 diff --git a/src/engine/engine.h b/src/engine/engine.h index 40bbbbb90..461c91c0b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev115" -#define DIV_ENGINE_VERSION 115 +#define DIV_VERSION "0.6pre1.5" +#define DIV_ENGINE_VERSION 116 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index b763ab97c..7e5dfdf26 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -23,16 +23,17 @@ const char* aboutLine[]={ "tildearrow", - "is proud to present", + "is not so happy to present", "", ("Furnace " DIV_VERSION), "", "the biggest multi-system chiptune tracker!", "featuring DefleMask song compatibility.", "", - "zero disassembly.", - "just clean-room design,", - "time and dedication.", + "what a mess of a versioning scheme we have...", + "I mean it! these pre-releases are like normal releases", + "by now but only because I promised you to have SNES in", + "0.6pre2 I am doing this whole mess...", "", "> CREDITS <", "", From d354f58a7c924567e62111999888aefca8d92d8d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:27:18 -0500 Subject: [PATCH 466/515] really release 0.6pre1.5 --- src/gui/gui.cpp | 76 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c374576ef..a57ccf396 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -690,11 +690,11 @@ ImVec4 FurnaceGUI::channelTextColor(int ch) { const char* defaultLayout="[Window][DockSpaceViewport_11111111]\n\ Pos=0,24\n\ -Size=1280,731\n\ +Size=1280,776\n\ Collapsed=0\n\ \n\ [Window][Debug##Default]\n\ -Pos=54,0\n\ +Pos=54,19\n\ Size=400,400\n\ Collapsed=0\n\ \n\ @@ -705,9 +705,9 @@ Collapsed=0\n\ \n\ [Window][Song Information]\n\ Pos=978,24\n\ -Size=302,217\n\ +Size=302,179\n\ Collapsed=0\n\ -DockId=0x00000004,0\n\ +DockId=0x0000000F,0\n\ \n\ [Window][Orders]\n\ Pos=0,24\n\ @@ -719,7 +719,7 @@ DockId=0x00000007,0\n\ Pos=653,24\n\ Size=323,217\n\ Collapsed=0\n\ -DockId=0x00000006,2\n\ +DockId=0x00000006,0\n\ \n\ [Window][Wavetables]\n\ Pos=653,24\n\ @@ -731,13 +731,13 @@ DockId=0x00000006,1\n\ Pos=653,24\n\ Size=323,217\n\ Collapsed=0\n\ -DockId=0x00000006,0\n\ +DockId=0x00000006,2\n\ \n\ [Window][Pattern]\n\ Pos=0,243\n\ -Size=1246,512\n\ +Size=1246,557\n\ Collapsed=0\n\ -DockId=0x0000000B,0\n\ +DockId=0x00000013,0\n\ \n\ [Window][Instrument Editor]\n\ Pos=372,102\n\ @@ -746,7 +746,7 @@ Collapsed=0\n\ \n\ [Window][Warning]\n\ Pos=481,338\n\ -Size=346,71\n\ +Size=264,86\n\ Collapsed=0\n\ \n\ [Window][Sample Editor]\n\ @@ -779,8 +779,8 @@ Size=514,71\n\ Collapsed=0\n\ \n\ [Window][Mixer]\n\ -Pos=63,55\n\ -Size=450,215\n\ +Pos=429,198\n\ +Size=453,355\n\ Collapsed=0\n\ \n\ [Window][Oscilloscope]\n\ @@ -791,7 +791,7 @@ DockId=0x0000000E,0\n\ \n\ [Window][Volume Meter]\n\ Pos=1248,243\n\ -Size=32,512\n\ +Size=32,557\n\ Collapsed=0\n\ DockId=0x0000000C,0\n\ \n\ @@ -866,9 +866,10 @@ Size=368,449\n\ Collapsed=0\n\ \n\ [Window][Register View]\n\ -Pos=847,180\n\ -Size=417,393\n\ +Pos=829,243\n\ +Size=417,557\n\ Collapsed=0\n\ +DockId=0x00000014,0\n\ \n\ [Window][New Song]\n\ Pos=267,110\n\ @@ -887,8 +888,40 @@ Size=304,40\n\ Collapsed=0\n\ DockId=0x0000000A,0\n\ \n\ +[Window][Subsongs]\n\ +Pos=978,205\n\ +Size=302,36\n\ +Collapsed=0\n\ +DockId=0x00000010,0\n\ +\n\ +[Window][Oscilloscope (per-channel)]\n\ +Pos=1095,243\n\ +Size=151,557\n\ +Collapsed=0\n\ +DockId=0x00000012,0\n\ +\n\ +[Window][Piano]\n\ +Pos=177,669\n\ +Size=922,118\n\ +Collapsed=0\n\ +\n\ +[Window][Log Viewer]\n\ +Pos=60,60\n\ +Size=541,637\n\ +Collapsed=0\n\ +\n\ +[Window][Pattern Manager]\n\ +Pos=60,60\n\ +Size=1099,366\n\ +Collapsed=0\n\ +\n\ +[Window][Chip Manager]\n\ +Pos=60,60\n\ +Size=490,407\n\ +Collapsed=0\n\ +\n\ [Docking][Data]\n\ -DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,24 Size=1280,731 Split=Y Selected=0x6C01C512\n\ +DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,24 Size=1280,776 Split=Y Selected=0x6C01C512\n\ DockNode ID=0x00000001 Parent=0x8B93E3BD SizeRef=1280,217 Split=X Selected=0xF3094A52\n\ DockNode ID=0x00000003 Parent=0x00000001 SizeRef=976,231 Split=X Selected=0x65CC51DC\n\ DockNode ID=0x00000007 Parent=0x00000003 SizeRef=345,231 HiddenTabBar=1 Selected=0x8F5BFC9A\n\ @@ -899,10 +932,17 @@ DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,24 Size=1280,731 Spl DockNode ID=0x0000000E Parent=0x00000009 SizeRef=292,105 HiddenTabBar=1 Selected=0x6D682373\n\ DockNode ID=0x0000000A Parent=0x00000005 SizeRef=292,40 HiddenTabBar=1 Selected=0x0DE44CFF\n\ DockNode ID=0x00000006 Parent=0x00000008 SizeRef=323,406 Selected=0xD2AD486B\n\ - DockNode ID=0x00000004 Parent=0x00000001 SizeRef=302,231 Selected=0x60B9D088\n\ + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=302,231 Split=Y Selected=0x60B9D088\n\ + DockNode ID=0x0000000F Parent=0x00000004 SizeRef=302,179 Selected=0x60B9D088\n\ + DockNode ID=0x00000010 Parent=0x00000004 SizeRef=302,36 HiddenTabBar=1 Selected=0x723A6369\n\ DockNode ID=0x00000002 Parent=0x8B93E3BD SizeRef=1280,512 Split=X Selected=0x6C01C512\n\ - DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1246,503 CentralNode=1 HiddenTabBar=1 Selected=0xB9ADD0D5\n\ - DockNode ID=0x0000000C Parent=0x00000002 SizeRef=32,503 HiddenTabBar=1 Selected=0x644DA2C1\n\n"; + DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1246,503 Split=X Selected=0xB9ADD0D5\n\ + DockNode ID=0x00000011 Parent=0x0000000B SizeRef=1093,557 Split=X Selected=0xB9ADD0D5\n\ + DockNode ID=0x00000013 Parent=0x00000011 SizeRef=827,557 CentralNode=1 HiddenTabBar=1 Selected=0xB9ADD0D5\n\ + DockNode ID=0x00000014 Parent=0x00000011 SizeRef=417,557 Selected=0x425428FB\n\ + DockNode ID=0x00000012 Parent=0x0000000B SizeRef=151,557 HiddenTabBar=1 Selected=0x4C07BC58\n\ + DockNode ID=0x0000000C Parent=0x00000002 SizeRef=32,503 HiddenTabBar=1 Selected=0x644DA2C1\n"; + void FurnaceGUI::prepareLayout() { FILE* check; From 52cd4f15de79715d96b36eeaad5a119ad998996d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 18:33:58 -0500 Subject: [PATCH 467/515] finally fix macro speed/delay issue --- src/engine/macroInt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 36850818f..955481ce0 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -34,6 +34,7 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic } if (delay>0) { delay--; + had=false; return; } if (began && source.delay>0) { From cbff5f190cca6292f7a4446540677081305baeea Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 18:43:48 -0500 Subject: [PATCH 468/515] NES: implement DPCM loop --- src/engine/platform/nes.cpp | 9 ++++++--- src/engine/platform/nes.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 50fcd5ca6..11e0fdddb 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -320,9 +320,10 @@ void DivPlatformNES::tick(bool sysTick) { unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM; unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4; if (dpcmLen>255) dpcmLen=255; + goingToLoop=parent->getSample(dacSample)->isLoopable(); // write DPCM rWrite(0x4015,15); - rWrite(0x4010,calcDPCMRate(dacRate)); + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); rWrite(0x4012,(dpcmAddr>>6)&0xff); rWrite(0x4013,dpcmLen&0xff); rWrite(0x4015,31); @@ -330,7 +331,7 @@ void DivPlatformNES::tick(bool sysTick) { } } else { if (dpcmMode) { - rWrite(0x4010,calcDPCMRate(dacRate)); + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); } } if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate); @@ -385,9 +386,10 @@ int DivPlatformNES::dispatch(DivCommand c) { unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM; unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4; if (dpcmLen>255) dpcmLen=255; + goingToLoop=parent->getSample(dacSample)->isLoopable(); // write DPCM rWrite(0x4015,15); - rWrite(0x4010,calcDPCMRate(dacRate)); + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); rWrite(0x4012,(dpcmAddr>>6)&0xff); rWrite(0x4013,dpcmLen&0xff); rWrite(0x4015,31); @@ -612,6 +614,7 @@ void DivPlatformNES::reset() { sampleBank=0; dpcmBank=0; dpcmMode=false; + goingToLoop=false; if (useNP) { nes1_NP->Reset(); diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index c00003305..85c14b0c9 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -73,6 +73,7 @@ class DivPlatformNES: public DivDispatch { bool dpcmMode; bool dacAntiClickOn; bool useNP; + bool goingToLoop; struct NESAPU* nes; xgm::NES_APU* nes1_NP; xgm::NES_DMC* nes2_NP; From 861b1cb9ca5d6a814cf137935a8a25502db02ca2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 19:02:25 -0500 Subject: [PATCH 469/515] OPLL: finally fix pitch macro --- src/engine/platform/opll.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 9485551aa..5c6981588 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -243,8 +243,9 @@ void DivPlatformOPLL::tick(bool sysTick) { if (chan[i].freqChanged) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE); if (chan[i].fixedFreq>0) chan[i].freq=chan[i].fixedFreq; - if (chan[i].freq>262143) chan[i].freq=262143; - int freqt=toFreq(chan[i].freq)+chan[i].pitch2; + if (chan[i].freq<0) chan[i].freq=0; + if (chan[i].freq>65535) chan[i].freq=65535; + int freqt=toFreq(chan[i].freq); chan[i].freqL=freqt&0xff; if (i>=6 && properDrums) { immWrite(0x10+drumSlot[i],freqt&0xff); From fa78877dfd1277f5edb68c36e4e3ef88946fb692 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 19:12:59 -0500 Subject: [PATCH 470/515] always do UTF-8 to UTF-16 when saving layout on W indows --- extern/imgui_patched/imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/imgui_patched/imgui.cpp b/extern/imgui_patched/imgui.cpp index 8b013816f..d52945d4e 100644 --- a/extern/imgui_patched/imgui.cpp +++ b/extern/imgui_patched/imgui.cpp @@ -1818,7 +1818,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed) ImFileHandle ImFileOpen(const char* filename, const char* mode) { -#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) +#if defined(_WIN32) // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); From 02ef001eb8104cb1255ea26f36bf228641c162f0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 19:41:36 -0500 Subject: [PATCH 471/515] MSM6295: fix mute issue --- src/engine/platform/msm6295.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 4d32f4319..bb002d1a4 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -255,6 +255,7 @@ void DivPlatformMSM6295::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformMSM6295::Channel(); chan[i].std.setEngine(parent); + msm.voice_mute(i,isMuted[i]); } for (int i=0; i<4; i++) { chan[i].vol=8; From ed7a48884464d1762c6a86216a19f764ee882459 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 19:46:17 -0500 Subject: [PATCH 472/515] MSM6295: reduce some CPU usage --- src/engine/platform/msm6295.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index bb002d1a4..e6e3d8a7a 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -68,9 +68,11 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t delay=w.delay; } } else { - delay--; + delay-=3; } + msm.tick(); + msm.tick(); msm.tick(); bufL[h]=msm.out()<<4; @@ -388,7 +390,7 @@ void DivPlatformMSM6295::setFlags(unsigned int flags) { chipClock=COLOR_NTSC/3.0; break; } - rate=chipClock; + rate=chipClock/3; for (int i=0; i<4; i++) { oscBuf[i]->rate=rate/22; } From 3eb37ded072b90c91e8b3f344bc7b63e52394fd3 Mon Sep 17 00:00:00 2001 From: nicco1690 <78063037+nicco1690@users.noreply.github.com> Date: Thu, 22 Sep 2022 22:28:09 -0400 Subject: [PATCH 473/515] Change extension names to be lower-case --- demos/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/README.md b/demos/README.md index 43f29d793..d07738e58 100644 --- a/demos/README.md +++ b/demos/README.md @@ -11,6 +11,6 @@ contact me or send a pull request if you want your song to be added to this coll - Nintendo covers are frowned upon - big label music covers also are discouraged -tildearrow also accepts demo songs in the .DMF format as well as the .FUR format. +tildearrow also accepts demo songs in the .dmf format as well as the .fur format. thank you for contributing! From 12d55ad99dcafb50ad3e2980aa58b3b278480635 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 13:50:46 +0900 Subject: [PATCH 474/515] Fix regression --- extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp index c249e5548..23b7df72b 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/x1_010/x1_010.cpp @@ -122,7 +122,7 @@ void x1_010_core::voice_t::reg_w(u8 offset, u8 data) m_flag.write(data); if (!prev_keyon && m_flag.keyon()) // Key on { - m_acc = m_flag.wavetable() ? 0 : (u32(m_start_envfreq) << 16); + m_acc = m_flag.wavetable() ? 0 : (u32(m_start_envfreq) << 17); m_env_acc = 0; } break; From 16e59bf0005c80718d5a335bd85e7ce9a9239729 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 14:14:06 +0900 Subject: [PATCH 475/515] Fix naming --- src/gui/guiConst.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index b4b18efe4..16c38962d 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -113,6 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", + "", // 33 + "", // 34 "MSM6258", "MSM6295", "ADPCM-A", From a23b0ff79018bd8cc4d30625306627000c030e0f Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 14:48:18 +0900 Subject: [PATCH 476/515] More consistent naming --- src/gui/guiConst.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 16c38962d..1827eb1a4 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -113,8 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", - "", // 33 - "", // 34 + "Reserved", // 33 + "Reserved", // 34 "MSM6258", "MSM6295", "ADPCM-A", From 5a84a35f3dd3bf98db737bc9c7d3c544bdd2d92c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 03:21:18 -0500 Subject: [PATCH 477/515] SegaPCM: fix regression --- src/engine/platform/segapcm.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 69e996b8b..53e844ebd 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -74,7 +74,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].isNewSegaPCM) { + if (parent->song.newSegaPCM) { if (chan[i].std.vol.had) { chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; @@ -93,7 +93,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { chan[i].freqChanged=true; } - if (chan[i].std.panL.had) { + if (parent->song.newSegaPCM) if (chan[i].std.panL.had) { if (chan[i].isNewSegaPCM) { chan[i].chPanL=chan[i].std.panL.val&127; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; @@ -105,7 +105,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } } - if (chan[i].std.panR.had) { + if (parent->song.newSegaPCM) if (chan[i].std.panR.had) { if (chan[i].isNewSegaPCM) { chan[i].chPanR=chan[i].std.panR.val&127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; @@ -212,7 +212,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SEGAPCM) { chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127; - chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM || parent->song.newSegaPCM); + chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM); chan[c.chan].pcm.sample=ins->amiga.getSample(c.value); if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) { chan[c.chan].pcm.sample=-1; @@ -278,7 +278,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (chan[c.chan].isNewSegaPCM) { + if (parent->song.newSegaPCM && chan[c.chan].isNewSegaPCM) { chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127; chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127; } else { @@ -302,7 +302,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].ins=c.value; break; case DIV_CMD_PANNING: { - if (chan[c.chan].isNewSegaPCM) { + if (parent->song.newSegaPCM && chan[c.chan].isNewSegaPCM) { chan[c.chan].chPanL=c.value>>1; chan[c.chan].chPanR=c.value2>>1; chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; From 764ae60740e9c0f3e44f6b000818a31f4b6bf9c3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 03:41:38 -0500 Subject: [PATCH 478/515] prepare for splitting OPN/OPM and NES/SN --- src/engine/instrument.h | 4 ++-- src/gui/dataList.cpp | 8 ++++++++ src/gui/gui.h | 2 ++ src/gui/guiConst.cpp | 10 ++++++---- src/gui/settings.cpp | 6 ++++-- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 5c3882e3b..01323d90f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,8 +60,8 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, - //33 - //34 + DIV_INS_OPM=33, + DIV_INS_NES=34, DIV_INS_MSM6258=35, DIV_INS_MSM6295=36, DIV_INS_ADPCMA=37, diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index e25f504dc..2a1c7a66a 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -338,6 +338,14 @@ void FurnaceGUI::drawInsList(bool asChild) { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]); name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i); break; + case DIV_INS_OPM: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPM]); + name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_NES: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_NES]); + name=fmt::sprintf(ICON_FA_GAMEPAD " %.2X: %s##_INS%d",i,ins->name,i); + break; case DIV_INS_MSM6258: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6258]); name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); diff --git a/src/gui/gui.h b/src/gui/gui.h index cb481f122..7f9c5924a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -159,6 +159,8 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, GUI_COLOR_INSTR_OPL_DRUMS, + GUI_COLOR_INSTR_OPM, + GUI_COLOR_INSTR_NES, GUI_COLOR_INSTR_MSM6258, GUI_COLOR_INSTR_MSM6295, GUI_COLOR_INSTR_ADPCMA, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 1827eb1a4..1ce78b5fa 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -80,8 +80,8 @@ const int vgmVersions[6]={ }; const char* insTypes[DIV_INS_MAX+1]={ - "Standard (SMS/NES)", - "FM (4-operator)", + "SN76489/Sega PSG", + "FM (OPN)", "Game Boy", "C64", "Generic Sample", @@ -113,8 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", - "Reserved", // 33 - "Reserved", // 34 + "FM (OPM)", // 33 + "NES", // 34 "MSM6258", "MSM6295", "ADPCM-A", @@ -788,6 +788,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)), D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), + D(GUI_COLOR_INSTR_OPM,"",ImVec4(0.2f,0.6f,1.0f,1.0f)), + D(GUI_COLOR_INSTR_NES,"",ImVec4(0.4f,1.0f,0.3f,1.0f)), D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 14ade83bd..4e292879b 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1636,8 +1636,8 @@ void FurnaceGUI::drawSettings() { ImGui::TreePop(); } if (ImGui::TreeNode("Instrument Types")) { - UI_COLOR_CONFIG(GUI_COLOR_INSTR_FM,"FM (4-operator)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_FM,"FM (OPN)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"SN76489/Sega PSG"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Generic Sample"); @@ -1673,6 +1673,8 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_NAMCO,"Namco WSG"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL_DRUMS,"FM (OPL Drums)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPM,"FM (OPM)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_NES,"NES"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6258,"MSM6258"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6295,"MSM6295"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMA,"ADPCM-A"); From cf1d4e55cf826e6bec182679e7022b4d2a5beded Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 23:24:02 +0900 Subject: [PATCH 479/515] Fix ADPCM-A playback Add per-chip debug function Add YM2203, YM2608, YM2610/B debug window Extend YM2612 debug window Remove unnecessary values in YM2151, Sega PCM platform --- src/engine/platform/amiga.h | 1 + src/engine/platform/arcade.cpp | 5 - src/engine/platform/arcade.h | 4 +- src/engine/platform/ay.h | 3 +- src/engine/platform/ay8930.h | 3 +- src/engine/platform/bubsyswsg.h | 3 +- src/engine/platform/c64.h | 3 +- src/engine/platform/dummy.h | 3 +- src/engine/platform/fds.h | 3 +- src/engine/platform/gb.h | 3 +- src/engine/platform/genesis.h | 3 +- src/engine/platform/genesisext.h | 3 +- src/engine/platform/lynx.h | 3 +- src/engine/platform/mmc5.h | 3 +- src/engine/platform/msm6258.h | 1 + src/engine/platform/msm6295.h | 1 + src/engine/platform/n163.h | 1 + src/engine/platform/namcowsg.h | 1 + src/engine/platform/nes.h | 1 + src/engine/platform/opl.h | 1 + src/engine/platform/opll.h | 1 + src/engine/platform/pce.h | 1 + src/engine/platform/pcmdac.h | 1 + src/engine/platform/pcspkr.h | 1 + src/engine/platform/pet.h | 1 + src/engine/platform/qsound.h | 1 + src/engine/platform/rf5c68.h | 1 + src/engine/platform/saa.h | 1 + src/engine/platform/scc.h | 1 + src/engine/platform/segapcm.cpp | 4 - src/engine/platform/segapcm.h | 6 +- src/engine/platform/sms.h | 1 + src/engine/platform/su.h | 1 + src/engine/platform/swan.h | 1 + src/engine/platform/tia.h | 1 + src/engine/platform/tx81z.h | 1 + src/engine/platform/vera.h | 1 + src/engine/platform/vic20.h | 1 + src/engine/platform/vrc6.h | 1 + src/engine/platform/x1_010.h | 1 + src/engine/platform/ym2203.h | 1 + src/engine/platform/ym2203ext.cpp | 17 - src/engine/platform/ym2203ext.h | 22 +- src/engine/platform/ym2608.cpp | 27 +- src/engine/platform/ym2608.h | 1 + src/engine/platform/ym2608ext.cpp | 2 +- src/engine/platform/ym2608ext.h | 22 +- src/engine/platform/ym2610.cpp | 22 +- src/engine/platform/ym2610.h | 1 + src/engine/platform/ym2610b.cpp | 20 +- src/engine/platform/ym2610b.h | 1 + src/engine/platform/ym2610bext.h | 1 + src/engine/platform/ym2610ext.h | 1 + src/engine/platform/ymz280b.h | 1 + src/engine/platform/zxbeeper.h | 1 + src/gui/debug.cpp | 583 +++++++++++++++++++++++++++++- src/gui/debug.h | 1 + src/gui/debugWindow.cpp | 16 + 58 files changed, 726 insertions(+), 91 deletions(-) diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index 59617ec36..a0a80d6ce 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -86,6 +86,7 @@ class DivPlatformAmiga: public DivDispatch { int sep1, sep2; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index c86f806e1..477430994 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -833,9 +833,6 @@ void DivPlatformArcade::reset() { } lastBusy=60; - pcmCycles=0; - pcmL=0; - pcmR=0; delay=0; amDepth=0x7f; pmDepth=0x7f; @@ -846,8 +843,6 @@ void DivPlatformArcade::reset() { immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); //rWrite(0x1b,0x00); - - extMode=false; } void DivPlatformArcade::setFlags(unsigned int flags) { diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 2a9c2b40c..70265be39 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -79,14 +79,13 @@ class DivPlatformArcade: public DivPlatformOPM { DivDispatchOscBuffer* oscBuf[8]; opm_t fm; int baseFreqOff; - int pcmL, pcmR, pcmCycles; unsigned char amDepth, pmDepth; ymfm::ym2151* fm_ymfm; ymfm::ym2151::output_data out_ymfm; DivArcadeInterface iface; - bool extMode, useYMFM; + bool useYMFM; bool isMuted[8]; @@ -96,6 +95,7 @@ class DivPlatformArcade: public DivPlatformOPM { void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index e87430e2e..4f77281de 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -146,7 +146,8 @@ class DivPlatformAY8910: public DivDispatch { size_t ayBufLen; void updateOutSel(bool immediate=false); - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 3447f5d47..c1a50e7a5 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -150,7 +150,8 @@ class DivPlatformAY8930: public DivDispatch { void updateOutSel(bool immediate=false); void immWrite(unsigned char a, unsigned char v); - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index f14b94a77..34bdad3dc 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -62,7 +62,8 @@ class DivPlatformBubSysWSG: public DivDispatch { k005289_core k005289; unsigned short regPool[4]; - void updateWave(int ch); + void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index 7587730b0..52685ce72 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -82,7 +82,8 @@ class DivPlatformC64: public DivDispatch { SID sid; reSIDfp::SID sid_fp; unsigned char regPool[32]; - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_classic(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/dummy.h b/src/engine/platform/dummy.h index b8601059b..0b5181f01 100644 --- a/src/engine/platform/dummy.h +++ b/src/engine/platform/dummy.h @@ -33,7 +33,8 @@ class DivPlatformDummy: public DivDispatch { Channel chan[128]; DivDispatchOscBuffer* oscBuf[128]; bool isMuted[128]; - unsigned char chans; + unsigned char chans; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/fds.h b/src/engine/platform/fds.h index 2bd983292..2721876e9 100644 --- a/src/engine/platform/fds.h +++ b/src/engine/platform/fds.h @@ -77,7 +77,8 @@ class DivPlatformFDS: public DivDispatch { unsigned char regPool[128]; void updateWave(); - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void doWrite(unsigned short addr, unsigned char data); diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 516e7d9f1..347f528bd 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -92,7 +92,8 @@ class DivPlatformGB: public DivDispatch { unsigned char regPool[128]; unsigned char procMute(); - void updateWave(); + void updateWave(); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 8588b21d4..6c6837c03 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -115,7 +115,8 @@ class DivPlatformGenesis: public DivPlatformOPN { bool ladder; unsigned char dacVolTable[128]; - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); inline void processDAC(); diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index d4dd93e77..352ebc293 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -51,7 +51,8 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { pan(3) {} }; OpChannel opChan[4]; - bool isOpMuted[4]; + bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index f7fdb62e3..a6c1c91c1 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -84,7 +84,8 @@ class DivPlatformLynx: public DivDispatch { Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; - std::unique_ptr mikey; + std::unique_ptr mikey; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 90da3eaa2..0da3da32e 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -67,7 +67,8 @@ class DivPlatformMMC5: public DivDispatch { unsigned char writeOscBuf; struct _mmc5* mmc5; unsigned char regPool[128]; - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index f6a351b5e..f06bdc261 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -87,6 +87,7 @@ class DivPlatformMSM6258: public DivDispatch { int delay, updateOsc, sample, samplePos; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index a37514685..5fc5ac7b8 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -74,6 +74,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { bool rateSel=false, rateSelInit=false; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index d4a9ee357..0ff969b64 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -89,6 +89,7 @@ class DivPlatformN163: public DivDispatch { unsigned char regPool[128]; void updateWave(int ch, int wave, int pos, int len); void updateWaveCh(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/namcowsg.h b/src/engine/platform/namcowsg.h index ede25e8e6..56a8ba3cd 100644 --- a/src/engine/platform/namcowsg.h +++ b/src/engine/platform/namcowsg.h @@ -74,6 +74,7 @@ class DivPlatformNamcoWSG: public DivDispatch { int devType, chans; unsigned char regPool[512]; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 85c14b0c9..2a9923fa6 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -79,6 +79,7 @@ class DivPlatformNES: public DivDispatch { xgm::NES_DMC* nes2_NP; unsigned char regPool[128]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void doWrite(unsigned short addr, unsigned char data); diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 49ea3b729..43f02790f 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -118,6 +118,7 @@ class DivPlatformOPL: public DivDispatch { int toFreq(int freq); double NOTE_ADPCMB(int note); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index 21a77b4e6..3f243057b 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -93,6 +93,7 @@ class DivPlatformOPLL: public DivDispatch { int octave(int freq); int toFreq(int freq); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 6f35f1797..ec0308340 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -91,6 +91,7 @@ class DivPlatformPCE: public DivDispatch { PCE_PSG* pce; unsigned char regPool[128]; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h index 127d39aae..7292f6ddf 100644 --- a/src/engine/platform/pcmdac.h +++ b/src/engine/platform/pcmdac.h @@ -77,6 +77,7 @@ class DivPlatformPCMDAC: public DivDispatch { int outDepth; bool outStereo; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index ba6275c32..48bf1bf56 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -84,6 +84,7 @@ class DivPlatformPCSpeaker: public DivDispatch { unsigned short freq, lastFreq; unsigned char regPool[2]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void beepFreq(int freq, int delay=0); diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index 8de217790..3046cc263 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -62,6 +62,7 @@ class DivPlatformPET: public DivDispatch { bool isMuted; unsigned char regPool[16]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 1d737de59..5e2a32fc7 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -72,6 +72,7 @@ class DivPlatformQSound: public DivDispatch { struct qsound_chip chip; unsigned short regPool[512]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 50324fbf3..bcbb3da2e 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -71,6 +71,7 @@ class DivPlatformRF5C68: public DivDispatch { size_t sampleMemLen; rf5c68_device rf5c68; unsigned char regPool[144]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 92855be7e..d2092efb9 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -72,6 +72,7 @@ class DivPlatformSAA1099: public DivDispatch { size_t saaBufLen; unsigned char saaEnv[2]; unsigned char saaNoise[2]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_saaSound(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/scc.h b/src/engine/platform/scc.h index b6117d4a1..20dcf4a97 100644 --- a/src/engine/platform/scc.h +++ b/src/engine/platform/scc.h @@ -65,6 +65,7 @@ class DivPlatformSCC: public DivDispatch { unsigned char regBase; unsigned char regPool[225]; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 53e844ebd..650f54c91 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -441,8 +441,6 @@ void DivPlatformSegaPCM::reset() { pcmR=0; sampleBank=0; delay=0; - amDepth=0x7f; - pmDepth=0x7f; if (dumpWrites) { for (int i=0; i<16; i++) { @@ -451,8 +449,6 @@ void DivPlatformSegaPCM::reset() { addWrite(0x10003+(i<<3),0x7f); } } - - extMode=false; } void DivPlatformSegaPCM::setFlags(unsigned int flags) { diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 01fd38c61..888a33848 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -80,21 +80,19 @@ class DivPlatformSegaPCM: public DivDispatch { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} }; std::queue writes; - int delay, baseFreqOff; + int delay; int pcmL, pcmR, pcmCycles; unsigned char sampleBank; unsigned char lastBusy; - unsigned char amDepth, pmDepth; unsigned char regPool[256]; - bool extMode, useYMFM; - bool isMuted[16]; short oldWrites[256]; short pendingWrites[256]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index eef54da1e..b382d38da 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -78,6 +78,7 @@ class DivPlatformSMS: public DivDispatch { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} }; std::queue writes; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index d76d07227..d94df8eac 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -113,6 +113,7 @@ class DivPlatformSoundUnit: public DivDispatch { void writeControl(int ch); void writeControlUpper(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index cf7926385..473667a93 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -74,6 +74,7 @@ class DivPlatformSwan: public DivDispatch { std::queue writes; WSwan* ws; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index b838e0682..3eb32b97a 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -46,6 +46,7 @@ class DivPlatformTIA: public DivDispatch { unsigned char chanOscCounter; TIA::Audio tia; unsigned char regPool[16]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); unsigned char dealWithFreq(unsigned char shape, int base, int pitch); diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index d1e427282..b1d09db90 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -88,6 +88,7 @@ class DivPlatformTX81Z: public DivPlatformOPM { int octave(int freq); int toFreq(int freq); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 53e766dcd..9cda01203 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -60,6 +60,7 @@ class DivPlatformVERA: public DivDispatch { struct VERA_PCM* pcm; int calcNoteFreq(int ch, int note); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index d4b56028c..834051ddb 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -63,6 +63,7 @@ class DivPlatformVIC20: public DivDispatch { unsigned char regPool[16]; sound_vic20_t* vic; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index 81c81016f..4c56bc797 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -78,6 +78,7 @@ class DivPlatformVRC6: public DivDispatch, public vrcvi_intf { vrcvi_core vrc6; unsigned char regPool[13]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 1844cf09a..19fb91350 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -120,6 +120,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf { double NoteX1_010(int ch, int note); void updateWave(int ch); void updateEnvelope(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: u8 read_byte(u32 address); diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 756603651..7a4aa7975 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -94,6 +94,7 @@ class DivPlatformYM2203: public DivPlatformOPN { bool extMode; unsigned char prescale; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 527a8be6b..f3b279c97 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -63,7 +63,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -103,22 +102,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { } opChan[ch].ins=c.value; break; - case DIV_CMD_PANNING: { - if (c.value==0 && c.value2==0) { - opChan[ch].pan=3; - } else { - opChan[ch].pan=(c.value2>0)|((c.value>0)<<1); - } - DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - if (parent->song.sharedExtStat) { - for (int i=0; i<4; i++) { - if (ch==i) continue; - opChan[i].pan=opChan[ch].pan; - } - } - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); - break; - } case DIV_CMD_PITCH: { opChan[ch].pitch=c.value; opChan[ch].freqChanged=true; diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index d25ca45d5..9bc460af4 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -29,13 +29,29 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; - unsigned char pan; // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), mask(true), vol(0), pan(3) {} + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + mask(true), + vol(0) {} }; OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index ff342eb79..b27f81ea3 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -546,14 +546,14 @@ void DivPlatformYM2608::tick(bool sysTick) { if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } - if (chan[i].keyOff) { - writeRSSOff|=(1<<(i-9)); - chan[i].keyOff=false; - } - if (chan[i].keyOn) { - writeRSSOn|=(1<<(i-9)); - chan[i].keyOn=false; - } + } + if (chan[i].keyOff) { + writeRSSOff|=(1<<(i-9)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + writeRSSOn|=(1<<(i-9)); + chan[i].keyOn=false; } } // ADPCM-B @@ -854,6 +854,13 @@ int DivPlatformYM2608::dispatch(DivCommand c) { } break; } + case DIV_CMD_ADPCMA_GLOBAL_VOLUME: { + if (globalRSSVolume!=(c.value&0x3f)) { + globalRSSVolume=c.value&0x3f; + immWrite(0x11,globalRSSVolume&0x3f); + } + break; + } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; break; @@ -1184,7 +1191,7 @@ void DivPlatformYM2608::forceIns() { if (i>14) { // ADPCM-B immWrite(0x10b,chan[i].outVol); } else { - immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } } @@ -1267,7 +1274,7 @@ void DivPlatformYM2608::reset() { immWrite(0x22,0x08); // PCM volume - immWrite(0x11,0x3f); // A + immWrite(0x11,globalRSSVolume); // A immWrite(0x10b,0xff); // B // ADPCM limit diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 8e2c4e407..073e381d8 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -110,6 +110,7 @@ class DivPlatformYM2608: public DivPlatformOPN { double NOTE_OPNB(int ch, int note); double NOTE_ADPCMB(int note); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 7f49ed9d6..66a4d252c 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -477,7 +477,7 @@ void DivPlatformYM2608Ext::forceIns() { if (i>14) { // ADPCM-B immWrite(0x10b,chan[i].outVol); } else { - immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } } ay->forceIns(); diff --git a/src/engine/platform/ym2608ext.h b/src/engine/platform/ym2608ext.h index 21c8a35c4..4792323cc 100644 --- a/src/engine/platform/ym2608ext.h +++ b/src/engine/platform/ym2608ext.h @@ -31,11 +31,29 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 { int vol; unsigned char pan; // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), mask(true), vol(0), pan(3) {} + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + mask(true), + vol(0), + pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index f80624f4c..b8882304c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -484,16 +484,16 @@ void DivPlatformYM2610::tick(bool sysTick) { if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { immWrite(0x108+(i-adpcmAChanOffs),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } - if (chan[i].keyOff) { - writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); - chan[i].keyOff=false; - } - if (chan[i].keyOn) { - if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); - } - chan[i].keyOn=false; + } + if (chan[i].keyOff) { + writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); } + chan[i].keyOn=false; } } // ADPCM-B @@ -1246,7 +1246,7 @@ void DivPlatformYM2610::reset() { immWrite(0x22,0x08); // PCM volume - immWrite(0x101,0x3f); // A + immWrite(0x101,globalADPCMAVolume); // A immWrite(0x1b,0xff); // B } @@ -1259,7 +1259,7 @@ bool DivPlatformYM2610::keyOffAffectsArp(int ch) { } void DivPlatformYM2610::notifyInsChange(int ins) { - for (int i=0; i<14; i++) { + for (int i=0; i { 1, 2, 4, 5 }; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 4ee8dea7b..9bcc45741 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -546,16 +546,16 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { immWrite(0x108+(i-adpcmAChanOffs),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } - if (chan[i].keyOff) { - writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); - chan[i].keyOff=false; - } - if (chan[i].keyOn) { - if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); - } - chan[i].keyOn=false; + } + if (chan[i].keyOff) { + writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); } + chan[i].keyOn=false; } } // ADPCM-B @@ -1325,7 +1325,7 @@ bool DivPlatformYM2610B::keyOffAffectsArp(int ch) { } void DivPlatformYM2610B::notifyInsChange(int ins) { - for (int i=0; i<16; i++) { + for (int i=0; i { 0, 1, 2, 4, 5, 6 }; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index c54586d36..fcb5e2b00 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -24,6 +24,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index ab7c060ff..5cc4432c5 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -24,6 +24,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index cd04186c6..72bf3791c 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -71,6 +71,7 @@ class DivPlatformYMZ280B: public DivDispatch { size_t sampleMemLen; ymz280b_device ymz280b; unsigned char regPool[256]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/zxbeeper.h b/src/engine/platform/zxbeeper.h index 226f556de..b02b1fb76 100644 --- a/src/engine/platform/zxbeeper.h +++ b/src/engine/platform/zxbeeper.h @@ -72,6 +72,7 @@ class DivPlatformZXBeeper: public DivDispatch { int tempR[32]; unsigned char regPool[128]; bool sampleOut; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 641df4d34..aff827718 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -28,6 +28,10 @@ #include "../engine/platform/c64.h" #include "../engine/platform/arcade.h" #include "../engine/platform/segapcm.h" +#include "../engine/platform/ym2203.h" +#include "../engine/platform/ym2203ext.h" +#include "../engine/platform/ym2608.h" +#include "../engine/platform/ym2608ext.h" #include "../engine/platform/ym2610.h" #include "../engine/platform/ym2610ext.h" #include "../engine/platform/ym2610b.h" @@ -45,7 +49,82 @@ #include "../engine/platform/pcmdac.h" #include "../engine/platform/dummy.h" -#define GENESIS_DEBUG \ +#define COMMON_CHIP_DEBUG \ + ImGui::Text("- rate: %d",ch->rate); \ + ImGui::Text("- chipClock: %.f",ch->chipClock); + +#define FM_CHIP_DEBUG \ + COMMON_CHIP_DEBUG; \ + ImGui::Text("- lastBusy: %d",ch->lastBusy); \ + ImGui::Text("- delay: %d",ch->delay); + +#define FM_OPN_CHIP_DEBUG \ + FM_CHIP_DEBUG; \ + ImGui::Text("- fmFreqBase: %.f",ch->fmFreqBase); \ + ImGui::Text("- fmDivBase: %d",ch->fmDivBase); \ + ImGui::Text("- ayDiv: %d",ch->ayDiv); + +#define COMMON_CHIP_DEBUG_BOOL \ + ImGui::TextColored(ch->skipRegisterWrites?colorOn:colorOff,">> SkipRegisterWrites"); \ + ImGui::TextColored(ch->dumpWrites?colorOn:colorOff,">> DumpWrites"); + +#define FM_CHIP_DEBUG_BOOL \ + COMMON_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->lastBusy?colorOn:colorOff,">> LastBusy"); \ + +#define FM_OPN_CHIP_DEBUG_BOOL \ + FM_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->extSys?colorOn:colorOff,">> ExtSys"); \ + +#define GENESIS_CHIP_DEBUG \ + DivPlatformGenesis* ch=(DivPlatformGenesis*)data; \ + ImGui::Text("> YM2612"); \ + FM_OPN_CHIP_DEBUG; \ + ImGui::Text("- lfoValue: %d",ch->lfoValue); \ + ImGui::Text("- softPCMTimer: %d",ch->softPCMTimer); \ + FM_OPN_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); \ + ImGui::TextColored(ch->softPCM?colorOn:colorOff,">> SoftPCM"); \ + ImGui::TextColored(ch->useYMFM?colorOn:colorOff,">> UseYMFM"); \ + ImGui::TextColored(ch->ladder?colorOn:colorOff,">> Ladder"); + +#define OPNB_CHIP_DEBUG \ + FM_OPN_CHIP_DEBUG; \ + ImGui::Text("- adpcmAMemLen: %d",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); \ + ImGui::Text("- sampleBank: %d",ch->sampleBank); \ + ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ + ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ + ImGui::Text("- globalADPCMAVolume: %d",ch->globalADPCMAVolume); \ + ImGui::Text("- extChanOffs: %d",ch->extChanOffs); \ + ImGui::Text("- psgChanOffs: %d",ch->psgChanOffs); \ + ImGui::Text("- adpcmAChanOffs: %d",ch->adpcmAChanOffs); \ + ImGui::Text("- adpcmBChanOffs: %d",ch->adpcmBChanOffs); \ + ImGui::Text("- chanNum: %d",ch->chanNum); \ + FM_OPN_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + +#define SMS_CHIP_DEBUG \ + DivPlatformSMS* sms=(DivPlatformSMS*)data; \ + ImGui::Text("> SMS"); \ + ImGui::Text("- rate: %d",sms->rate); \ + ImGui::Text("- chipClock: %.f",sms->chipClock); \ + ImGui::Text("- lastPan: %d",sms->lastPan); \ + ImGui::Text("- oldValue: %d",sms->oldValue); \ + ImGui::Text("- snNoiseMode: %d",sms->snNoiseMode); \ + ImGui::Text("- divider: %d",sms->divider); \ + ImGui::Text("- toneDivider: %.f",sms->toneDivider); \ + ImGui::Text("- noiseDivider: %.f",sms->noiseDivider); \ + ImGui::TextColored(sms->skipRegisterWrites?colorOn:colorOff,">> SkipRegisterWrites"); \ + ImGui::TextColored(sms->dumpWrites?colorOn:colorOff,">> DumpWrites"); \ + ImGui::TextColored(sms->updateSNMode?colorOn:colorOff,">> UpdateSNMode"); \ + ImGui::TextColored(sms->resetPhase?colorOn:colorOff,">> ResetPhase"); \ + ImGui::TextColored(sms->isRealSN?colorOn:colorOff,">> IsRealSN"); \ + ImGui::TextColored(sms->stereo?colorOn:colorOff,">> Stereo"); \ + ImGui::TextColored(sms->nuked?colorOn:colorOff,">> Nuked"); + + +#define GENESIS_CHAN_DEBUG \ DivPlatformGenesis::Channel* ch=(DivPlatformGenesis::Channel*)data; \ ImGui::Text("> YM2612"); \ ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ @@ -53,11 +132,21 @@ ImGui::Text(" - base: %d",ch->baseFreq); \ ImGui::Text(" - pitch: %d",ch->pitch); \ ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("* DAC:"); \ + ImGui::Text(" - period: %d",ch->dacPeriod); \ + ImGui::Text(" - rate: %d",ch->dacRate); \ + ImGui::Text(" - pos: %d",ch->dacPos); \ + ImGui::Text(" - sample: %d",ch->dacSample); \ + ImGui::Text(" - delay: %d",ch->dacDelay); \ + ImGui::Text(" - output: %d",ch->dacOutput); \ ImGui::Text("- note: %d",ch->note); \ ImGui::Text("- ins: %d",ch->ins); \ ImGui::Text("- vol: %.2x",ch->vol); \ ImGui::Text("- outVol: %.2x",ch->outVol); \ ImGui::Text("- pan: %x",ch->pan); \ + ImGui::Text("- opMask: %x",ch->opMask); \ + ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ @@ -65,9 +154,35 @@ ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); \ - ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ + ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ + ImGui::TextColored(ch->dacMode?colorOn:colorOff,">> DACMode"); \ + ImGui::TextColored(ch->dacReady?colorOn:colorOff,">> DACReady"); \ + ImGui::TextColored(ch->dacDirection?colorOn:colorOff,">> DACDirection"); -#define SMS_DEBUG \ +#define GENESIS_OPCHAN_DEBUG \ + DivPlatformGenesisExt::OpChannel* ch=(DivPlatformGenesisExt::OpChannel*)data; \ + ImGui::Text("> YM2612 (per operator)"); \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- pan: %x",ch->pan); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->mask?colorOn:colorOff,">> Mask"); + +#define SMS_CHAN_DEBUG \ DivPlatformSMS::Channel* ch=(DivPlatformSMS::Channel*)data; \ ImGui::Text("> SMS"); \ ImGui::Text("* freq: %d",ch->freq); \ @@ -84,31 +199,477 @@ ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); +#define OPN_CHAN_DEBUG \ + DivPlatformYM2203::Channel* ch=(DivPlatformYM2203::Channel*)data; \ + ImGui::Text("> YM2203"); \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("* PSG:"); \ + ImGui::Text(" - psgMode: %d",ch->psgMode); \ + ImGui::Text(" - autoEnvNum: %d",ch->autoEnvNum); \ + ImGui::Text(" - autoEnvDen: %d",ch->autoEnvDen); \ + ImGui::Text("- sample: %d",ch->sample); \ + ImGui::Text("- note: %d",ch->note); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- outVol: %.2x",ch->outVol); \ + ImGui::Text("- opMask: %x",ch->opMask); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ + ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ + ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); + +#define OPN_OPCHAN_DEBUG \ + DivPlatformYM2203Ext::OpChannel* ch=(DivPlatformYM2203Ext::OpChannel*)data; \ + ImGui::Text("> YM2203 (per operator)"); \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->mask?colorOn:colorOff,">> Mask"); + +#define OPNB_CHAN_DEBUG \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("* PSG:"); \ + ImGui::Text(" - psgMode: %d",ch->psgMode); \ + ImGui::Text(" - autoEnvNum: %d",ch->autoEnvNum); \ + ImGui::Text(" - autoEnvDen: %d",ch->autoEnvDen); \ + ImGui::Text("- sample: %d",ch->sample); \ + ImGui::Text("- note: %d",ch->note); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- outVol: %.2x",ch->outVol); \ + ImGui::Text("- pan: %x",ch->pan); \ + ImGui::Text("- opMask: %x",ch->opMask); \ + ImGui::Text("- macroVolMul: %x",ch->macroVolMul); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ + ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ + ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); + +#define OPNB_OPCHAN_DEBUG \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- pan: %x",ch->pan); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->mask?colorOn:colorOff,">> Mask"); + +void putDispatchChip(void* data, int type) { + ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f); + ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f); + switch (type) { + case DIV_SYSTEM_YM2612: + case DIV_SYSTEM_YM2612_EXT: + case DIV_SYSTEM_YM2612_FRAC: + case DIV_SYSTEM_YM2612_FRAC_EXT: { + GENESIS_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_GENESIS: + case DIV_SYSTEM_GENESIS_EXT: { + GENESIS_CHIP_DEBUG; + SMS_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_SMS: { + SMS_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_OPN: + case DIV_SYSTEM_OPN_EXT: { + DivPlatformYM2203* ch=(DivPlatformYM2203*)data; + ImGui::Text("> YM2203"); + FM_OPN_CHIP_DEBUG; + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- prescale: %d",ch->prescale); + FM_OPN_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + break; + } + case DIV_SYSTEM_PC98: + case DIV_SYSTEM_PC98_EXT: { + DivPlatformYM2608* ch=(DivPlatformYM2608*)data; + ImGui::Text("> YM2608"); + FM_OPN_CHIP_DEBUG; + ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); + ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); + ImGui::Text("- globalRSSVolume: %d",ch->globalRSSVolume); + ImGui::Text("- prescale: %d",ch->prescale); + FM_OPN_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + break; + } + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_EXT: + case DIV_SYSTEM_YM2610_FULL: + case DIV_SYSTEM_YM2610_FULL_EXT: { + DivPlatformYM2610* ch=(DivPlatformYM2610*)data; + ImGui::Text("> YM2610"); + OPNB_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_YM2610B: + case DIV_SYSTEM_YM2610B_EXT: { + DivPlatformYM2610B* ch=(DivPlatformYM2610B*)data; + ImGui::Text("> YM2610B"); + OPNB_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_GB: { + DivPlatformGB* ch=(DivPlatformGB*)data; + ImGui::Text("> GameBoy"); + COMMON_CHIP_DEBUG; + ImGui::Text("- lastPan: %d",ch->lastPan); + ImGui::Text("- antiClickPeriodCount: %d",ch->antiClickPeriodCount); + ImGui::Text("- antiClickWavePos: %d",ch->antiClickWavePos); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->antiClickEnabled?colorOn:colorOff,">> AntiClickEnabled"); + break; + } + case DIV_SYSTEM_PCE: { + DivPlatformPCE* ch=(DivPlatformPCE*)data; + ImGui::Text("> PCEngine"); + COMMON_CHIP_DEBUG; + ImGui::Text("- lastPan: %d",ch->lastPan); + ImGui::Text("- cycles: %d",ch->cycles); + ImGui::Text("- curChan: %d",ch->curChan); + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- lfoMode: %d",ch->lfoMode); + ImGui::Text("- lfoSpeed: %d",ch->lfoSpeed); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->antiClickEnabled?colorOn:colorOff,">> AntiClickEnabled"); + break; + } + case DIV_SYSTEM_NES: { + DivPlatformNES* ch=(DivPlatformNES*)data; + ImGui::Text("> NES"); + COMMON_CHIP_DEBUG; + ImGui::Text("* DAC:"); + ImGui::Text(" - Period: %d",ch->dacPeriod); + ImGui::Text(" - Rate: %d",ch->dacRate); + ImGui::Text(" - Pos: %d",ch->dacPos); + ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); + ImGui::Text(" - Sample: %d",ch->dacSample); + ImGui::Text("- dpcmMemLen: %d",ch->dpcmMemLen); + ImGui::Text("- dpcmBank: %d",ch->dpcmBank); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); + ImGui::Text("- apuType: %d",ch->apuType); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->dpcmMode?colorOn:colorOff,">> DPCMMode"); + ImGui::TextColored(ch->dacAntiClickOn?colorOn:colorOff,">> DACAntiClickOn"); + ImGui::TextColored(ch->useNP?colorOn:colorOff,">> UseNP"); + ImGui::TextColored(ch->goingToLoop?colorOn:colorOff,">> GoingToLoop"); + break; + } + case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: { + DivPlatformC64* ch=(DivPlatformC64*)data; + ImGui::Text("> C64"); + COMMON_CHIP_DEBUG; + ImGui::Text("- filtControl: %d",ch->filtControl); + ImGui::Text("- filtRes: %d",ch->filtRes); + ImGui::Text("- vol: %d",ch->vol); + ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); + ImGui::Text("- filtCut: %d",ch->filtCut); + ImGui::Text("- resetTime: %d",ch->resetTime); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->isFP?colorOn:colorOff,">> IsFP"); + break; + } + case DIV_SYSTEM_ARCADE: + case DIV_SYSTEM_YM2151: { + DivPlatformArcade* ch=(DivPlatformArcade*)data; + ImGui::Text("> YM2151"); + FM_CHIP_DEBUG; + ImGui::Text("- baseFreqOff: %d",ch->baseFreqOff); + ImGui::Text("- amDepth: %d",ch->amDepth); + ImGui::Text("- pmDepth: %d",ch->pmDepth); + FM_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->useYMFM?colorOn:colorOff,">> UseYMFM"); + break; + } + case DIV_SYSTEM_SEGAPCM: + case DIV_SYSTEM_SEGAPCM_COMPAT: { + DivPlatformSegaPCM* ch=(DivPlatformSegaPCM*)data; + ImGui::Text("> SegaPCM"); + COMMON_CHIP_DEBUG; + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- pcmL: %d",ch->pcmL); + ImGui::Text("- pcmR: %d",ch->pcmR); + ImGui::Text("- pcmCycles: %d",ch->pcmCycles); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- lastBusy: %d",ch->lastBusy); + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_AY8910: { + DivPlatformAY8910* ch=(DivPlatformAY8910*)data; + ImGui::Text("> AY-3-8910"); + COMMON_CHIP_DEBUG; + ImGui::Text("- lastBusy: %d",ch->lastBusy); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- stereoSep: %d",ch->stereoSep); + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- extClock: %d",ch->extClock); + ImGui::Text("- extDiv: %d",ch->extDiv); + ImGui::Text("- portAVal: %d",ch->portAVal); + ImGui::Text("- portBVal: %d",ch->portBVal); + ImGui::Text("* envelope:"); + ImGui::Text(" - mode: %d",ch->ayEnvMode); + ImGui::Text(" - period: %d",ch->ayEnvPeriod); + ImGui::Text(" * slide: %d",ch->ayEnvSlide); + ImGui::Text(" - slideLow: %d",ch->ayEnvSlideLow); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + ImGui::TextColored(ch->sunsoft?colorOn:colorOff,">> Sunsoft"); + ImGui::TextColored(ch->intellivision?colorOn:colorOff,">> Intellivision"); + ImGui::TextColored(ch->clockSel?colorOn:colorOff,">> ClockSel"); + ImGui::TextColored(ch->ioPortA?colorOn:colorOff,">> IoPortA"); + ImGui::TextColored(ch->ioPortB?colorOn:colorOff,">> IoPortB"); + break; + } + case DIV_SYSTEM_AY8930: { + DivPlatformAY8930* ch=(DivPlatformAY8930*)data; + ImGui::Text("> AY8930"); + COMMON_CHIP_DEBUG; + ImGui::Text("* noise:"); + ImGui::Text(" - and: %d",ch->ayNoiseAnd); + ImGui::Text(" - or: %d",ch->ayNoiseOr); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- stereoSep: %d",ch->stereoSep); + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- portAVal: %d",ch->portAVal); + ImGui::Text("- portBVal: %d",ch->portBVal); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->bank?colorOn:colorOff,">> Bank"); + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + ImGui::TextColored(ch->clockSel?colorOn:colorOff,">> ClockSel"); + ImGui::TextColored(ch->ioPortA?colorOn:colorOff,">> IoPortA"); + ImGui::TextColored(ch->ioPortB?colorOn:colorOff,">> IoPortB"); + break; + } + case DIV_SYSTEM_QSOUND: { + DivPlatformQSound* ch=(DivPlatformQSound*)data; + ImGui::Text("> QSound"); + COMMON_CHIP_DEBUG; + ImGui::Text("* echo:"); + ImGui::Text(" - delay: %d",ch->echoDelay); + ImGui::Text(" - feedback: %d",ch->echoFeedback); + ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_X1_010: { + DivPlatformX1_010* ch=(DivPlatformX1_010*)data; + ImGui::Text("> X1-010"); + COMMON_CHIP_DEBUG; + ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + ImGui::TextColored(ch->isBanked?colorOn:colorOff,">> IsBanked"); + break; + } + case DIV_SYSTEM_N163: { + DivPlatformN163* ch=(DivPlatformN163*)data; + ImGui::Text("> N163"); + COMMON_CHIP_DEBUG; + ImGui::Text("- initChanMax: %d",ch->initChanMax); + ImGui::Text("- chanMax: %d",ch->chanMax); + ImGui::Text("- loadWave: %d",ch->loadWave); + ImGui::Text("- loadPos: %d",ch->loadPos); + ImGui::Text("- loadLen: %d",ch->loadLen); + ImGui::Text("- loadMode: %d",ch->loadMode); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->multiplex?colorOn:colorOff,">> Multiplex"); + break; + } + case DIV_SYSTEM_VRC6: { + DivPlatformVRC6* ch=(DivPlatformVRC6*)data; + ImGui::Text("> VRC6"); + COMMON_CHIP_DEBUG; + ImGui::Text("- sampleBank: %.2x",ch->sampleBank); + ImGui::Text("- writeOscBuf: %.2x",ch->writeOscBuf); + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_LYNX: { + DivPlatformLynx* ch=(DivPlatformLynx*)data; + ImGui::Text("> Lynx"); + COMMON_CHIP_DEBUG; + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_PCM_DAC: { + DivPlatformPCMDAC* ch=(DivPlatformPCMDAC*)data; + ImGui::Text("> PCM DAC"); + COMMON_CHIP_DEBUG; + ImGui::Text("- outDepth: %d",ch->outDepth); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->outStereo?colorOn:colorOff,">> OutStereo"); + break; + } + default: + ImGui::Text("Unimplemented chip! Help!"); + break; + } +} void putDispatchChan(void* data, int chanNum, int type) { ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f); ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f); switch (type) { - case DIV_SYSTEM_GENESIS: - case DIV_SYSTEM_YM2612: { + case DIV_SYSTEM_GENESIS: { if (chanNum>5) { - SMS_DEBUG; + SMS_CHAN_DEBUG; } else { - GENESIS_DEBUG; + GENESIS_CHAN_DEBUG; } break; } case DIV_SYSTEM_GENESIS_EXT: { if (chanNum>8) { - SMS_DEBUG; + SMS_CHAN_DEBUG; } else if (chanNum>=2 && chanNum<=5) { - // TODO ext ch 3 debug + GENESIS_OPCHAN_DEBUG } else { - GENESIS_DEBUG; + GENESIS_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_YM2612: + case DIV_SYSTEM_YM2612_FRAC: { + GENESIS_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_YM2612_EXT: + case DIV_SYSTEM_YM2612_FRAC_EXT: { + if (chanNum>=2 && chanNum<=5) { + GENESIS_OPCHAN_DEBUG + } else { + GENESIS_CHAN_DEBUG; } break; } case DIV_SYSTEM_SMS: { - SMS_DEBUG; + SMS_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_OPN: { + OPN_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_OPN_EXT: { + if (chanNum>=2 && chanNum<=5) { + OPN_OPCHAN_DEBUG; + } else { + OPN_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_PC98: { + DivPlatformYM2608::Channel* ch=(DivPlatformYM2608::Channel*)data; + ImGui::Text("> YM2608"); + OPNB_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_PC98_EXT: { + if (chanNum>=2 && chanNum<=5) { + DivPlatformYM2608Ext::OpChannel* ch=(DivPlatformYM2608Ext::OpChannel*)data; + ImGui::Text("> YM2608 (per operator)"); + OPNB_OPCHAN_DEBUG; + } else { + DivPlatformYM2608Ext::Channel* ch=(DivPlatformYM2608Ext::Channel*)data; + ImGui::Text("> YM2608"); + OPNB_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_FULL: { + DivPlatformYM2610::Channel* ch=(DivPlatformYM2610::Channel*)data; + ImGui::Text("> YM2610"); + OPNB_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_YM2610B: { + DivPlatformYM2610B::Channel* ch=(DivPlatformYM2610B::Channel*)data; + ImGui::Text("> YM2610B"); + OPNB_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_YM2610_EXT: + case DIV_SYSTEM_YM2610_FULL_EXT: { + if (chanNum>=1 && chanNum<=4) { + DivPlatformYM2610Ext::OpChannel* ch=(DivPlatformYM2610Ext::OpChannel*)data; + ImGui::Text("> YM2610 (per operator)"); + OPNB_OPCHAN_DEBUG; + } else { + DivPlatformYM2610Ext::Channel* ch=(DivPlatformYM2610Ext::Channel*)data; + ImGui::Text("> YM2610"); + OPNB_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_YM2610B_EXT: { + if (chanNum>=2 && chanNum<=5) { + DivPlatformYM2610BExt::OpChannel* ch=(DivPlatformYM2610BExt::OpChannel*)data; + ImGui::Text("> YM2610B (per operator)"); + OPNB_OPCHAN_DEBUG; + } else { + DivPlatformYM2610BExt::Channel* ch=(DivPlatformYM2610BExt::Channel*)data; + ImGui::Text("> YM2610B"); + OPNB_CHAN_DEBUG; + } break; } case DIV_SYSTEM_GB: { diff --git a/src/gui/debug.h b/src/gui/debug.h index 1f22b4855..e3c911a84 100644 --- a/src/gui/debug.h +++ b/src/gui/debug.h @@ -21,5 +21,6 @@ #define _GUI_DEBUG_H #include "../engine/song.h" +void putDispatchChip(void* data, int type); void putDispatchChan(void* data, int chanNum, int type); #endif \ No newline at end of file diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index eec6fefb2..8033add4d 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -66,6 +66,22 @@ void FurnaceGUI::drawDebug() { ImGui::Checkbox("Enable",&bpOn); ImGui::TreePop(); } + if (ImGui::TreeNode("Chip Status")) { + ImGui::Text("for best results set latency to minimum or use the Frame Advance button."); + ImGui::Columns(e->song.systemLen); + for (int i=0; isong.systemLen; i++) { + void* ch=e->getDispatch(i); + ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Chip %d: %s",i,getSystemName(e->song.system[i])); + if (e->song.system[i]==NULL) { + ImGui::Text("NULL"); + } else { + putDispatchChip(ch,e->song.system[i]); + } + ImGui::NextColumn(); + } + ImGui::Columns(); + ImGui::TreePop(); + } if (ImGui::TreeNode("Dispatch Status")) { ImGui::Text("for best results set latency to minimum or use the Frame Advance button."); ImGui::Columns(e->getTotalChannelCount()); From 62ce5ae3cedefd3f2869a55360ddd85ede19ecf7 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 23:41:55 +0900 Subject: [PATCH 480/515] Add compatible flag for PCE DAC volume (always enabled for now) Fix furnacePCM detection for MSM6295 --- src/engine/fileOps.cpp | 2 ++ src/engine/platform/msm6295.cpp | 2 +- src/engine/platform/pce.cpp | 14 ++++++++------ src/engine/song.h | 2 ++ src/gui/compatFlags.cpp | 4 ++++ 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index abfd7395b..2757ac274 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -178,6 +178,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; ds.snNoLowPeriods=true; + ds.ignorePCEDACVolume=true; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1100,6 +1101,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<115) { ds.autoSystem=false; } + ds.ignorePCEDACVolume=true; ds.isDMF=false; reader.readS(); // reserved diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index bd9bce01c..5cfec125a 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -126,7 +126,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_MSM6295 || ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index ea6f0e56e..74667c870 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -69,7 +69,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; chan[i].dacOut=CLAMP(dacData,-16,15); if (!isMuted[i]) { - chWrite(i,0x04,0xc0|chan[i].outVol); + chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].outVol)); chWrite(i,0x06,chan[i].dacOut&0x1f); } else { chWrite(i,0x04,0xc0); @@ -208,7 +208,7 @@ void DivPlatformPCE::tick(bool sysTick) { if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { chan[i].dacPos=0; chan[i].dacPeriod=0; - chWrite(i,0x04,0xc0|chan[i].vol); + chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].vol)); addWrite(0xffff0000+(i<<8),chan[i].dacSample); chan[i].keyOn=true; } @@ -275,7 +275,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } else { if (dumpWrites) { - chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); + chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); } } @@ -310,7 +310,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPeriod=0; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; if (dumpWrites) { - chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); + chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); } } @@ -362,7 +362,9 @@ int DivPlatformPCE::dispatch(DivCommand c) { 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,0x04,0x80|chan[c.chan].outVol); + if (chan[c.chan].active && !chan[c.chan].pcm) { + chWrite(c.chan,0x04,0x80|chan[c.chan].outVol); + } } } break; @@ -464,7 +466,7 @@ void DivPlatformPCE::muteChannel(int ch, bool mute) { isMuted[ch]=mute; chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) { - chWrite(ch,0x04,0xc0|chan[ch].outVol); + chWrite(ch,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[ch].outVol)); chWrite(ch,0x06,chan[ch].dacOut&0x1f); } } diff --git a/src/engine/song.h b/src/engine/song.h index 09a89378c..28a31c759 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -511,6 +511,7 @@ struct DivSong { bool e1e2StopOnSameNote; bool brokenPortaArp; bool snNoLowPeriods; + bool ignorePCEDACVolume; bool autoSystem; std::vector ins; @@ -616,6 +617,7 @@ struct DivSong { e1e2StopOnSameNote(false), brokenPortaArp(false), snNoLowPeriods(false), + ignorePCEDACVolume(true), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 63571dcac..c3627efad 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -143,6 +143,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, any SN period under 8 will be written as 1 instead.\nthis replicates DefleMask behavior, but reduces available period range."); } + ImGui::Checkbox("Ignore PC Engine DAC Volume",&e->song.ignorePCEDACVolume); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); + } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { From b41d306cb3a47af14685bbadeea8697205fd916d Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 23:42:56 +0900 Subject: [PATCH 481/515] Fix compile --- src/gui/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index aff827718..23d0df10e 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -51,7 +51,7 @@ #define COMMON_CHIP_DEBUG \ ImGui::Text("- rate: %d",ch->rate); \ - ImGui::Text("- chipClock: %.f",ch->chipClock); + ImGui::Text("- chipClock: %d",ch->chipClock); #define FM_CHIP_DEBUG \ COMMON_CHIP_DEBUG; \ From a44d696f092c12c4b7af23173fe6e2c75398656d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:11:34 +0900 Subject: [PATCH 482/515] Fix compile (again) --- src/gui/debug.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 23d0df10e..602b7fb0d 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %d",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %.8x",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -108,7 +108,7 @@ DivPlatformSMS* sms=(DivPlatformSMS*)data; \ ImGui::Text("> SMS"); \ ImGui::Text("- rate: %d",sms->rate); \ - ImGui::Text("- chipClock: %.f",sms->chipClock); \ + ImGui::Text("- chipClock: %d",sms->chipClock); \ ImGui::Text("- lastPan: %d",sms->lastPan); \ ImGui::Text("- oldValue: %d",sms->oldValue); \ ImGui::Text("- snNoiseMode: %d",sms->snNoiseMode); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %d",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %.8x",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From b05dafe297795b8839c31670f9cdd413c1247754 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:24:30 +0900 Subject: [PATCH 483/515] Add compatible flag for Y8950 ADPCM Frequency --- src/engine/fileOps.cpp | 2 ++ src/engine/platform/opl.cpp | 6 ++++-- src/engine/song.h | 2 ++ src/gui/compatFlags.cpp | 4 ++++ src/gui/debug.cpp | 12 ++++++------ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 2757ac274..7eb148eae 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -179,6 +179,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenPortaArp=false; ds.snNoLowPeriods=true; ds.ignorePCEDACVolume=true; + ds.newY8950PCMFreq=false; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1102,6 +1103,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.autoSystem=false; } ds.ignorePCEDACVolume=true; + ds.newY8950PCMFreq=false; ds.isDMF=false; reader.readS(); // reserved diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index d3437240b..148ce2799 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -28,6 +28,8 @@ #define KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1) +#define OPLPCMDiv (parent->song.newY8950PCMFreq?((oplType==3)?288:72):144) + #define CHIP_FREQBASE chipFreqBase // N = invalid @@ -274,7 +276,7 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) { if (adpcmChan<0) return 0; if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/((oplType==3)?288:72),off,note,false); + return parent->calcBaseFreq((double)chipClock/OPLPCMDiv,off,note,false); } return 0; } @@ -504,7 +506,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/((oplType==3)?288:72),off); + chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/OPLPCMDiv,off); } else { chan[adpcmChan].freq=0; } diff --git a/src/engine/song.h b/src/engine/song.h index 28a31c759..9f5ca1544 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -512,6 +512,7 @@ struct DivSong { bool brokenPortaArp; bool snNoLowPeriods; bool ignorePCEDACVolume; + bool newY8950PCMFreq; bool autoSystem; std::vector ins; @@ -618,6 +619,7 @@ struct DivSong { brokenPortaArp(false), snNoLowPeriods(false), ignorePCEDACVolume(true), + newY8950PCMFreq(false), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index c3627efad..80e9b0f57 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -147,6 +147,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); } + ImGui::Checkbox("New Y8950 Frequency calculation",&e->song.newY8950PCMFreq); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, use corrected Y8950 frequency calculation"); + } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 602b7fb0d..652150abb 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %.8x",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %lld",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %.8x",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %lld",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From 53c3efc9c1a173ec8301f2273208a36193d965f4 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:32:05 +0900 Subject: [PATCH 484/515] Fix compile (once again) --- src/gui/debug.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 652150abb..e56828d65 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %lld",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %llu",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %lld",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %llu",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From 8d80c5f743876ccea4b5f5b0286f1595cab3b8bf Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:37:37 +0900 Subject: [PATCH 485/515] Actually compile fix --- src/gui/debug.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index e56828d65..5bccb6de0 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %llu",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %lu",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %llu",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %lu",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From 8f0966378ff9f5accb8a8aad3c1425dd22e5d8f1 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:45:24 +0900 Subject: [PATCH 486/515] Remove these for fix compile --- src/gui/debug.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 5bccb6de0..c769f2f39 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,6 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %lu",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +333,6 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +394,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %lu",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +500,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +507,6 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From ef9fedb0b8942a71954d0be06f31d87bc3d325a3 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 01:04:09 +0900 Subject: [PATCH 487/515] Fix Lynx clamping --- src/engine/platform/lynx.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index c67f35234..4db41bcfb 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -34,7 +34,7 @@ #define WRITE_STEREO(v) rWrite(0x50,(v)) #define CHIP_DIVIDER 64 -#define CHIP_FREQBASE 4000000 +#define CHIP_FREQBASE 16000000 #if defined( _MSC_VER ) @@ -141,10 +141,10 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len if (s!=NULL) { if (isMuted[i]) { WRITE_OUTPUT(i,0); - chan[i].samplePos++; } else { - WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127)); + WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos]*chan[i].outVol)>>7,-128,127)); } + chan[i].samplePos++; if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) { chan[i].samplePos=s->loopStart; From 6b684d655a9926c7fff45bbcdc52b115b766cf09 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 12:37:03 -0500 Subject: [PATCH 488/515] fix build --- src/gui/debugWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 8033add4d..d3ecbc98e 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -72,7 +72,7 @@ void FurnaceGUI::drawDebug() { for (int i=0; isong.systemLen; i++) { void* ch=e->getDispatch(i); ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Chip %d: %s",i,getSystemName(e->song.system[i])); - if (e->song.system[i]==NULL) { + if (e->song.system[i]==DIV_SYSTEM_NULL) { ImGui::Text("NULL"); } else { putDispatchChip(ch,e->song.system[i]); From b9a4b568b69c47ad0622d81225b9fd176a5d30e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 13:28:57 -0500 Subject: [PATCH 489/515] i honestly don't agree with this compat flag --- src/engine/fileOps.cpp | 2 -- src/engine/platform/opl.cpp | 6 ++---- src/engine/song.h | 2 -- src/gui/compatFlags.cpp | 4 ---- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 7eb148eae..2757ac274 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -179,7 +179,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenPortaArp=false; ds.snNoLowPeriods=true; ds.ignorePCEDACVolume=true; - ds.newY8950PCMFreq=false; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1103,7 +1102,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.autoSystem=false; } ds.ignorePCEDACVolume=true; - ds.newY8950PCMFreq=false; ds.isDMF=false; reader.readS(); // reserved diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 148ce2799..d44d62712 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -28,8 +28,6 @@ #define KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1) -#define OPLPCMDiv (parent->song.newY8950PCMFreq?((oplType==3)?288:72):144) - #define CHIP_FREQBASE chipFreqBase // N = invalid @@ -276,7 +274,7 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) { if (adpcmChan<0) return 0; if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/OPLPCMDiv,off,note,false); + return parent->calcBaseFreq((double)chipClock/144,off,note,false); } return 0; } @@ -506,7 +504,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/OPLPCMDiv,off); + chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/144,off); } else { chan[adpcmChan].freq=0; } diff --git a/src/engine/song.h b/src/engine/song.h index 9f5ca1544..28a31c759 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -512,7 +512,6 @@ struct DivSong { bool brokenPortaArp; bool snNoLowPeriods; bool ignorePCEDACVolume; - bool newY8950PCMFreq; bool autoSystem; std::vector ins; @@ -619,7 +618,6 @@ struct DivSong { brokenPortaArp(false), snNoLowPeriods(false), ignorePCEDACVolume(true), - newY8950PCMFreq(false), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 80e9b0f57..c3627efad 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -147,10 +147,6 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); } - ImGui::Checkbox("New Y8950 Frequency calculation",&e->song.newY8950PCMFreq); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("when enabled, use corrected Y8950 frequency calculation"); - } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { From 5e2cefff9422a021c728f82fe30364e72a507dbc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 13:36:23 -0500 Subject: [PATCH 490/515] dev117 - save the flag also serves as marker version for this huge change --- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 14 +++++++++++--- src/gui/compatFlags.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 42d29f120..0438e09ce 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1.5" -#define DIV_ENGINE_VERSION 116 +#define DIV_VERSION "dev117" +#define DIV_ENGINE_VERSION 117 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 2757ac274..4f4c6539e 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1101,7 +1101,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<115) { ds.autoSystem=false; } - ds.ignorePCEDACVolume=true; + if (ds.version<117) { + ds.ignorePCEDACVolume=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1534,7 +1536,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<3; i++) { + if (ds.version>=117) { + ds.ignorePCEDACVolume=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<2; i++) { reader.readC(); } } @@ -3779,7 +3786,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.delayBehavior); w->writeC(song.jumpTreatment); w->writeC(song.autoSystem); - for (int i=0; i<3; i++) { + w->writeC(song.ignorePCEDACVolume); + for (int i=0; i<2; i++) { w->writeC(0); } diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index c3627efad..ac7209d63 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -143,10 +143,6 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, any SN period under 8 will be written as 1 instead.\nthis replicates DefleMask behavior, but reduces available period range."); } - ImGui::Checkbox("Ignore PC Engine DAC Volume",&e->song.ignorePCEDACVolume); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); - } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { @@ -285,6 +281,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre1.5"); } + ImGui::Checkbox("Ignore PC Engine DAC volume",&e->song.ignorePCEDACVolume); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6pre2"); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; ImGui::End(); From d5a6d136e51d8470e9f5ba634a054ba404390631 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 18:48:47 -0500 Subject: [PATCH 491/515] update test suite files --- test/assert_delta.c | 2 +- test/furnace-test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/assert_delta.c b/test/assert_delta.c index 6dad6992b..6ef11feae 100644 --- a/test/assert_delta.c +++ b/test/assert_delta.c @@ -34,7 +34,7 @@ int main(int argc, char** argv) { while ((totalRead=sf_readf_float(sf,buf,BUF_SIZE))!=0) { for (int i=0; i Date: Fri, 23 Sep 2022 19:01:01 -0500 Subject: [PATCH 492/515] latency fix --- src/engine/platform/ym2608.cpp | 91 ++++++++++++++--------------- src/engine/platform/ym2610.cpp | 92 +++++++++++++++--------------- src/engine/platform/ym2610b.cpp | 91 ++++++++++++++--------------- src/engine/platform/ym2610shared.h | 4 +- 4 files changed, 140 insertions(+), 138 deletions(-) diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index b27f81ea3..82a130ac0 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -358,14 +358,6 @@ void DivPlatformYM2608::acquire(short* bufL, short* bufR, size_t start, size_t l } void DivPlatformYM2608::tick(bool sysTick) { - // PSG - ay->tick(sysTick); - ay->flushWrites(); - for (DivRegWrite& i: ay->getRegisterWrites()) { - immWrite(i.addr&15,i.val); - } - ay->getRegisterWrites().clear(); - // FM for (int i=0; i<6; i++) { if (i==2 && extMode) continue; @@ -522,6 +514,44 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].keyOff=false; } } + + for (int i=16; i<512; i++) { + if (pendingWrites[i]!=oldWrites[i]) { + immWrite(i,pendingWrites[i]&0xff); + oldWrites[i]=pendingWrites[i]; + } + } + + for (int i=0; i<6; i++) { + if (i==2 && extMode) continue; + if (chan[i].freqChanged) { + if (parent->song.linearPitch==2) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + } else { + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); + int block=(chan[i].baseFreq&0xf800)>>11; + if (fNum<0) fNum=0; + if (fNum>2047) { + while (block<7) { + fNum>>=1; + block++; + } + if (fNum>2047) fNum=2047; + } + chan[i].freq=(block<<11)|fNum; + } + if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; + immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); + immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].opMaskChanged) { + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; + chan[i].keyOn=false; + } + } + // RSS for (int i=9; i<15; i++) { if (chan[i].furnacePCM) { @@ -615,47 +645,18 @@ void DivPlatformYM2608::tick(bool sysTick) { writeRSSOff=0; } - for (int i=16; i<512; i++) { - if (pendingWrites[i]!=oldWrites[i]) { - immWrite(i,pendingWrites[i]&0xff); - oldWrites[i]=pendingWrites[i]; - } - } - - for (int i=0; i<6; i++) { - if (i==2 && extMode) continue; - if (chan[i].freqChanged) { - if (parent->song.linearPitch==2) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - } else { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); - int block=(chan[i].baseFreq&0xf800)>>11; - if (fNum<0) fNum=0; - if (fNum>2047) { - while (block<7) { - fNum>>=1; - block++; - } - if (fNum>2047) fNum=2047; - } - chan[i].freq=(block<<11)|fNum; - } - if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; - immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); - immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); - chan[i].freqChanged=false; - } - if (chan[i].keyOn || chan[i].opMaskChanged) { - immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); - chan[i].opMaskChanged=false; - chan[i].keyOn=false; - } - } - if (writeRSSOn) { immWrite(0x10,writeRSSOn); writeRSSOn=0; } + + // PSG + ay->tick(sysTick); + ay->flushWrites(); + for (DivRegWrite& i: ay->getRegisterWrites()) { + immWrite(i.addr&15,i.val); + } + ay->getRegisterWrites().clear(); } int DivPlatformYM2608::dispatch(DivCommand c) { diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index b8882304c..0adab3ba5 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -294,15 +294,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l } } -void DivPlatformYM2610::tick(bool sysTick) { - // PSG - ay->tick(sysTick); - ay->flushWrites(); - for (DivRegWrite& i: ay->getRegisterWrites()) { - immWrite(i.addr&15,i.val); - } - ay->getRegisterWrites().clear(); - +void DivPlatformYM2610::tick(bool sysTick) { // FM for (int i=0; isong.linearPitch==2) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + } else { + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + int block=(chan[i].baseFreq&0xf800)>>11; + if (fNum<0) fNum=0; + if (fNum>2047) { + while (block<7) { + fNum>>=1; + block++; + } + if (fNum>2047) fNum=2047; + } + chan[i].freq=(block<<11)|fNum; + } + if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; + immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); + immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].opMaskChanged) { + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; + chan[i].keyOn=false; + } + } + // ADPCM-A for (int i=adpcmAChanOffs; isong.linearPitch==2) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - } else { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - int block=(chan[i].baseFreq&0xf800)>>11; - if (fNum<0) fNum=0; - if (fNum>2047) { - while (block<7) { - fNum>>=1; - block++; - } - if (fNum>2047) fNum=2047; - } - chan[i].freq=(block<<11)|fNum; - } - if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; - immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); - immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); - chan[i].freqChanged=false; - } - if (chan[i].keyOn || chan[i].opMaskChanged) { - immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); - chan[i].opMaskChanged=false; - chan[i].keyOn=false; - } - } - if (writeADPCMAOn) { immWrite(0x100,writeADPCMAOn); writeADPCMAOn=0; } + + // PSG + ay->tick(sysTick); + ay->flushWrites(); + for (DivRegWrite& i: ay->getRegisterWrites()) { + immWrite(i.addr&15,i.val); + } + ay->getRegisterWrites().clear(); } int DivPlatformYM2610::dispatch(DivCommand c) { diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 9bcc45741..59913b147 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -358,14 +358,6 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformYM2610B::tick(bool sysTick) { - // PSG - ay->tick(sysTick); - ay->flushWrites(); - for (DivRegWrite& i: ay->getRegisterWrites()) { - immWrite(i.addr&15,i.val); - } - ay->getRegisterWrites().clear(); - // FM for (int i=0; isong.linearPitch==2) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + } else { + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); + int block=(chan[i].baseFreq&0xf800)>>11; + if (fNum<0) fNum=0; + if (fNum>2047) { + while (block<7) { + fNum>>=1; + block++; + } + if (fNum>2047) fNum=2047; + } + chan[i].freq=(block<<11)|fNum; + } + if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; + immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); + immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].opMaskChanged) { + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; + chan[i].keyOn=false; + } + } + // ADPCM-A for (int i=adpcmAChanOffs; isong.linearPitch==2) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - } else { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); - int block=(chan[i].baseFreq&0xf800)>>11; - if (fNum<0) fNum=0; - if (fNum>2047) { - while (block<7) { - fNum>>=1; - block++; - } - if (fNum>2047) fNum=2047; - } - chan[i].freq=(block<<11)|fNum; - } - if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; - immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); - immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); - chan[i].freqChanged=false; - } - if (chan[i].keyOn || chan[i].opMaskChanged) { - immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); - chan[i].opMaskChanged=false; - chan[i].keyOn=false; - } - } - if (writeADPCMAOn) { immWrite(0x100,writeADPCMAOn); writeADPCMAOn=0; } + + // PSG + ay->tick(sysTick); + ay->flushWrites(); + for (DivRegWrite& i: ay->getRegisterWrites()) { + immWrite(i.addr&15,i.val); + } + ay->getRegisterWrites().clear(); } int DivPlatformYM2610B::dispatch(DivCommand c) { diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 6c06eb068..e8bbd16f9 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -265,7 +265,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { chipClock=24167829/3; break; } - rate=fm->sample_rate(chipClock); + rate=chipClock/16; for (int i=0; irate=rate; } @@ -287,7 +287,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { iface.adpcmBMem=adpcmBMem; iface.sampleBank=0; fm=new ymfm::ym2610b(iface); - fm->set_fidelity(ymfm::OPN_FIDELITY_MIN); + fm->set_fidelity(ymfm::OPN_FIDELITY_MAX); setFlags(flags); // YM2149, 2MHz ay=new DivPlatformAY8910(true,chipClock,32); From eb8849ce631ccb99a4bc35d8cc378f6520e04ada Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 19:18:32 -0500 Subject: [PATCH 493/515] add disableSampleMacro flag for compatibility --- src/engine/fileOps.cpp | 8 ++++---- src/engine/platform/ay.cpp | 4 ++-- src/engine/platform/msm6295.cpp | 1 + src/engine/platform/pce.cpp | 10 +++++----- src/engine/song.h | 4 ++-- src/gui/compatFlags.cpp | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 4f4c6539e..47a837899 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -178,7 +178,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; ds.snNoLowPeriods=true; - ds.ignorePCEDACVolume=true; + ds.disableSampleMacro=true; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1102,7 +1102,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.autoSystem=false; } if (ds.version<117) { - ds.ignorePCEDACVolume=true; + ds.disableSampleMacro=true; } ds.isDMF=false; @@ -1537,7 +1537,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { reader.readC(); } if (ds.version>=117) { - ds.ignorePCEDACVolume=reader.readC(); + ds.disableSampleMacro=reader.readC(); } else { reader.readC(); } @@ -3786,7 +3786,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.delayBehavior); w->writeC(song.jumpTreatment); w->writeC(song.autoSystem); - w->writeC(song.ignorePCEDACVolume); + w->writeC(song.disableSampleMacro); for (int i=0; i<2; i++) { w->writeC(0); } diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5ce075ce0..ad2bbc650 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -348,14 +348,14 @@ int DivPlatformAY8910::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { chan[c.chan].psgMode.dac=true; } else if (chan[c.chan].dac.furnaceDAC) { chan[c.chan].psgMode.dac=false; } if (chan[c.chan].psgMode.dac) { if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { chan[c.chan].dac.sample=ins->amiga.getSample(c.value); if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { chan[c.chan].dac.sample=-1; diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 5cfec125a..b85bc1a58 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -88,6 +88,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6295::tick(bool sysTick) { + if (parent->song.disableSampleMacro) return; for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 74667c870..19b71a1be 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -69,7 +69,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; chan[i].dacOut=CLAMP(dacData,-16,15); if (!isMuted[i]) { - chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].outVol)); + chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].outVol)); chWrite(i,0x06,chan[i].dacOut&0x1f); } else { chWrite(i,0x04,0xc0); @@ -208,7 +208,7 @@ void DivPlatformPCE::tick(bool sysTick) { if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { chan[i].dacPos=0; chan[i].dacPeriod=0; - chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].vol)); + chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol)); addWrite(0xffff0000+(i<<8),chan[i].dacSample); chan[i].keyOn=true; } @@ -275,7 +275,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } else { if (dumpWrites) { - chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); + chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); } } @@ -310,7 +310,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPeriod=0; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; if (dumpWrites) { - chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); + chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); } } @@ -466,7 +466,7 @@ void DivPlatformPCE::muteChannel(int ch, bool mute) { isMuted[ch]=mute; chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) { - chWrite(ch,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[ch].outVol)); + chWrite(ch,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[ch].outVol)); chWrite(ch,0x06,chan[ch].dacOut&0x1f); } } diff --git a/src/engine/song.h b/src/engine/song.h index 28a31c759..a9a16263a 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -511,7 +511,7 @@ struct DivSong { bool e1e2StopOnSameNote; bool brokenPortaArp; bool snNoLowPeriods; - bool ignorePCEDACVolume; + bool disableSampleMacro; bool autoSystem; std::vector ins; @@ -617,7 +617,7 @@ struct DivSong { e1e2StopOnSameNote(false), brokenPortaArp(false), snNoLowPeriods(false), - ignorePCEDACVolume(true), + disableSampleMacro(true), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index ac7209d63..fcea0fa06 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -281,7 +281,7 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre1.5"); } - ImGui::Checkbox("Ignore PC Engine DAC volume",&e->song.ignorePCEDACVolume); + ImGui::Checkbox("Disable new sample features",&e->song.disableSampleMacro); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre2"); } From f620782919c3b95e15db37bef565fdc9f75e8e0b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 09:27:33 +0900 Subject: [PATCH 494/515] Fix playback issue --- src/engine/platform/msm6295.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index b85bc1a58..925fefed7 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -88,21 +88,22 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6295::tick(bool sysTick) { - if (parent->song.disableSampleMacro) return; for (int i=0; i<4; i++) { - chan[i].std.next(); - if (chan[i].std.vol.had) { - chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); - } - if (chan[i].std.duty.had) { - if (rateSel!=(chan[i].std.duty.val&1)) { - rateSel=chan[i].std.duty.val&1; - rWrite(12,!rateSel); + if (parent->song.disableSampleMacro) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); } - } - if (chan[i].std.phaseReset.had) { - if (chan[i].std.phaseReset.val && chan[i].active) { - chan[i].keyOn=true; + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&1)) { + rateSel=chan[i].std.duty.val&1; + rWrite(12,!rateSel); + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } } } if (chan[i].keyOn || chan[i].keyOff) { From 4bf46f9315836eeafccb869f790ec09ad7b7d482 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 09:27:46 +0900 Subject: [PATCH 495/515] Oops --- src/engine/platform/msm6295.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 925fefed7..a898ba150 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -89,7 +89,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t void DivPlatformMSM6295::tick(bool sysTick) { for (int i=0; i<4; i++) { - if (parent->song.disableSampleMacro) { + if (!parent->song.disableSampleMacro) { chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); From a5fb9b766e8d51dbdf55926c58ad6cef138075bb Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 09:28:30 +0900 Subject: [PATCH 496/515] disableSampleMacro for MSM6258 --- src/engine/platform/msm6258.cpp | 40 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 119366186..ded3899ef 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -91,28 +91,30 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t void DivPlatformMSM6258::tick(bool sysTick) { for (int i=0; i<1; i++) { - chan[i].std.next(); - if (chan[i].std.duty.had) { - if (rateSel!=(chan[i].std.duty.val&3)) { - rateSel=chan[i].std.duty.val&3; - rWrite(12,rateSel); + if (!parent->song.disableSampleMacro) { + chan[i].std.next(); + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&3)) { + rateSel=chan[i].std.duty.val&3; + rWrite(12,rateSel); + } } - } - if (chan[i].std.panL.had) { - if (chan[i].pan!=(chan[i].std.panL.val&3)) { - chan[i].pan=chan[i].std.panL.val&3; - rWrite(2,chan[i].pan); + if (chan[i].std.panL.had) { + if (chan[i].pan!=(chan[i].std.panL.val&3)) { + chan[i].pan=chan[i].std.panL.val&3; + rWrite(2,chan[i].pan); + } } - } - if (chan[i].std.ex1.had) { - if (clockSel!=(chan[i].std.ex1.val&1)) { - clockSel=chan[i].std.ex1.val&1; - rWrite(8,clockSel); + if (chan[i].std.ex1.had) { + if (clockSel!=(chan[i].std.ex1.val&1)) { + clockSel=chan[i].std.ex1.val&1; + rWrite(8,clockSel); + } } - } - if (chan[i].std.phaseReset.had) { - if (chan[i].std.phaseReset.val && chan[i].active) { - chan[i].keyOn=true; + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } } } if (chan[i].keyOn || chan[i].keyOff) { From bc4c8acd87fcc69814d14ec90e05205870612c4e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 19:34:44 -0500 Subject: [PATCH 497/515] AY PCM still doesn't work so I am leaving a note --- src/engine/platform/ay.cpp | 13 +++++++------ src/engine/platform/ay8930.cpp | 7 ++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index ad2bbc650..851ef46b4 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -89,26 +89,27 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // TODO: try to fit this into the actual loop // PCM part for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; bool end=false; bool changed=false; - int prev_out = chan[i].dac.out; + int prevOut=chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); if (s->samples<=0) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } // Partially unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4); chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15)); - if (prev_out!=chan[i].dac.out) { - prev_out=chan[i].dac.out; + if (prevOut!=chan[i].dac.out) { + prevOut=chan[i].dac.out; changed=true; } chan[i].dac.pos++; @@ -116,7 +117,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } @@ -124,7 +125,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l } if (changed && !end) { if (!isMuted[i]) { - rWrite(0x08+i,chan[i].dac.out); + immWrite(0x08+i,chan[i].dac.out); } } } diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 913be11b0..fbc9b3275 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -85,6 +85,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // TODO: try to fit this into the actual loop // PCM part for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { @@ -96,7 +97,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l DivSample* s=parent->getSample(chan[i].dac.sample); if (s->samples<=0) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } @@ -112,7 +113,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } @@ -120,7 +121,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } if (changed && !end) { if (!isMuted[i]) { - rWrite(0x08+i,chan[i].dac.out); + immWrite(0x08+i,chan[i].dac.out); } } } From b72b5bf0e6d6357da305cd39142d09cda2f04bc9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 20:15:20 -0500 Subject: [PATCH 498/515] A Y P C M --- src/engine/platform/ay.cpp | 92 +++++++++++++++++++++++---------- src/engine/platform/ay.h | 2 + src/engine/platform/ay8930.cpp | 94 +++++++++++++++++++++++----------- src/engine/platform/ay8930.h | 2 + 4 files changed, 133 insertions(+), 57 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 851ef46b4..9526e591d 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -81,16 +81,39 @@ const char** DivPlatformAY8910::getRegisterSheet() { return intellivision?regCheatSheetAY8914:regCheatSheetAY; } -void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) { - if (ayBufLen +#include + +int main(int argc, char** argv) { + for (int i=0; i<256; i++) { + if ((i&15)==0) printf("\n "); + printf(" %d,",(int)round(pow((double)i/255.0,0.36)*15.0)); } - // TODO: try to fit this into the actual loop - // PCM part +} +*/ + +const unsigned char dacLogTableAY[256]={ + 0, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 +}; + +void DivPlatformAY8910::runDAC() { for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; @@ -105,9 +128,8 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l end=true; break; } - // Partially - unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4); - chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15)); + unsigned char dacData=dacLogTableAY[(unsigned char)s->data8[chan[i].dac.pos]^0x80]; + chan[i].dac.out=MAX(0,dacData-(15-chan[i].outVol)); if (prevOut!=chan[i].dac.out) { prevOut=chan[i].dac.out; changed=true; @@ -130,7 +152,9 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l } } } +} +void DivPlatformAY8910::checkWrites() { while (!writes.empty()) { QueuedWrite w=writes.front(); if (intellivision) { @@ -143,8 +167,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l regPool[w.addr&0x0f]=w.val; writes.pop(); } +} + +void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) { + if (ayBufLensound_stream_update(ayBuf,1); bufL[i+start]=ayBuf[0][0]; bufR[i+start]=bufL[i+start]; @@ -154,22 +192,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]>>3; } } else { - ay->sound_stream_update(ayBuf,len); - if (stereo) { - for (size_t i=0; i>8); - bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; - } - } else { - for (size_t i=0; isound_stream_update(ayBuf,1); + if (stereo) { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+((ayBuf[2][0]*stereoSep)>>8); + bufR[i+start]=((ayBuf[0][0]*stereoSep)>>8)+ayBuf[1][0]+ayBuf[2][0]; + } else { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+ayBuf[2][0]; bufR[i+start]=bufL[i+start]; } - } - for (int ch=0; ch<3; ch++) { - for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; - } + + oscBuf[0]->data[oscBuf[0]->needle++]=ayBuf[0][0]<<2; + oscBuf[1]->data[oscBuf[1]->needle++]=ayBuf[1][0]<<2; + oscBuf[2]->data[oscBuf[2]->needle++]=ayBuf[2][0]<<2; } } } @@ -291,7 +329,7 @@ void DivPlatformAY8910::tick(bool sysTick) { off=8363.0/(double)s->centerRate; } } - chan[i].dac.rate=((double)chipClock*4096.0)/(double)(MAX(1,off*chan[i].freq)); + chan[i].dac.rate=((double)rate*16.0)/(double)(MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); } if (chan[i].freq>4095) chan[i].freq=4095; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 4f77281de..ec9a14fe5 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -145,6 +145,8 @@ class DivPlatformAY8910: public DivDispatch { short* ayBuf[3]; size_t ayBufLen; + void runDAC(); + void checkWrites(); void updateOutSel(bool immediate=false); friend void putDispatchChip(void*,int); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index fbc9b3275..b6c59452f 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -77,22 +77,45 @@ const char** DivPlatformAY8930::getRegisterSheet() { return regCheatSheetAY8930; } -void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) { - if (ayBufLen +#include + +int main(int argc, char** argv) { + for (int i=0; i<256; i++) { + if ((i&15)==0) printf("\n "); + printf(" %d,",(int)round(pow((double)i/255.0,0.3)*31.0)); } - // TODO: try to fit this into the actual loop - // PCM part - for (int i=0; i<3; i++) { +} +*/ + +const unsigned char dacLogTableAY8930[256]={ + 0, 6, 7, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 +}; + +void DivPlatformAY8930::runDAC() { + for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; bool end=false; bool changed=false; - int prev_out = chan[i].dac.out; + int prevOut=chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); if (s->samples<=0) { @@ -101,11 +124,10 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l end=true; break; } - // Partially - unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>3); - chan[i].dac.out=MAX(0,MIN(31,(dacData*chan[i].outVol)/31)); - if (prev_out!=chan[i].dac.out) { - prev_out=chan[i].dac.out; + unsigned char dacData=dacLogTableAY8930[(unsigned char)s->data8[chan[i].dac.pos]^0x80]; + chan[i].dac.out=MAX(0,dacData-(31-chan[i].outVol)); + if (prevOut!=chan[i].dac.out) { + prevOut=chan[i].dac.out; changed=true; } chan[i].dac.pos++; @@ -126,7 +148,9 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } } } +} +void DivPlatformAY8930::checkWrites() { while (!writes.empty()) { QueuedWrite w=writes.front(); ay->address_w(w.addr); @@ -138,23 +162,33 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } writes.pop(); } - ay->sound_stream_update(ayBuf,len); - if (stereo) { - for (size_t i=0; i>8); - bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; - } - } else { - for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; + for (size_t i=0; isound_stream_update(ayBuf,1); + if (stereo) { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+((ayBuf[2][0]*stereoSep)>>8); + bufR[i+start]=((ayBuf[0][0]*stereoSep)>>8)+ayBuf[1][0]+ayBuf[2][0]; + } else { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+ayBuf[2][0]; + bufR[i+start]=bufL[i+start]; } + + oscBuf[0]->data[oscBuf[0]->needle++]=ayBuf[0][0]<<2; + oscBuf[1]->data[oscBuf[1]->needle++]=ayBuf[1][0]<<2; + oscBuf[2]->data[oscBuf[2]->needle++]=ayBuf[2][0]<<2; } } @@ -294,7 +328,7 @@ void DivPlatformAY8930::tick(bool sysTick) { off=8363.0/(double)s->centerRate; } } - chan[i].dac.rate=((double)chipClock*16384.0)/(double)(MAX(1,off*chan[i].freq)); + chan[i].dac.rate=((double)chipClock*4.0)/(double)(MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); } if (chan[i].freq>65535) chan[i].freq=65535; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index c1a50e7a5..441e82148 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -148,6 +148,8 @@ class DivPlatformAY8930: public DivDispatch { short* ayBuf[3]; size_t ayBufLen; + void runDAC(); + void checkWrites(); void updateOutSel(bool immediate=false); void immWrite(unsigned char a, unsigned char v); From 593aeeb2437deab7ce618f79284400ce3b716e5f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 10:20:09 +0900 Subject: [PATCH 499/515] Unnecessary space --- src/engine/platform/genesisext.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 352ebc293..ffc83d46c 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -51,7 +51,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { pan(3) {} }; OpChannel opChan[4]; - bool isOpMuted[4]; + bool isOpMuted[4]; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: From 95562afb166c4d635f668490203b644fd1b6a94d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 22:45:47 -0500 Subject: [PATCH 500/515] one more compatibility fix --- src/engine/platform/ym2610.cpp | 2 +- src/engine/platform/ym2610b.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 0adab3ba5..9e8f1847c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -680,7 +680,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (c.chan>=adpcmAChanOffs) { // ADPCM-A DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 59913b147..bf854f36f 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -743,7 +743,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (c.chan>=adpcmAChanOffs) { // ADPCM-A DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; From e8ca6bd4837ac418c7652a8590c32bac51c4882e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 22:48:55 -0500 Subject: [PATCH 501/515] one more fix --- src/engine/platform/qsound.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 18216f03f..4f7d2545f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -308,14 +308,14 @@ void DivPlatformQSound::tick(bool sysTick) { } chan[i].freqChanged=true; } - if (chan[i].std.duty.had) { + if (chan[i].isNewQSound && chan[i].std.duty.had) { chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767); immWrite(Q1_ECHO+i,chan[i].echo&0x7fff); } - if (chan[i].std.ex1.had) { + if (chan[i].isNewQSound && chan[i].std.ex1.had) { immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff); } - if (chan[i].std.ex2.had) { + if (chan[i].isNewQSound && chan[i].std.ex2.had) { immWrite(Q1_ECHO_LENGTH,0xfff-(2725-CLAMP(chan[i].std.ex2.val&0xfff,0,2725))); } if (chan[i].std.pitch.had) { From 67fc945992f3d7c7f3cc9a540278cee71b865d83 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 23:03:07 -0500 Subject: [PATCH 502/515] Y8950 regression fix --- src/engine/platform/opl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index d44d62712..5d81f0834 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -508,6 +508,14 @@ void DivPlatformOPL::tick(bool sysTick) { } else { chan[adpcmChan].freq=0; } + if (chan[adpcmChan].fixedFreq>0) chan[adpcmChan].freq=chan[adpcmChan].fixedFreq; + if (pretendYMU) { // YMU759 only does 4KHz or 8KHz + if (chan[adpcmChan].freq>7500) { + chan[adpcmChan].freq=10922; // 8KHz + } else { + chan[adpcmChan].freq=5461; // 4KHz + } + } immWrite(16,chan[adpcmChan].freq&0xff); immWrite(17,(chan[adpcmChan].freq>>8)&0xff); if (chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { @@ -673,6 +681,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { chan[c.chan].macroInit(ins); + chan[c.chan].fixedFreq=0; if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(18,chan[c.chan].outVol); @@ -718,6 +727,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); int freq=(65536.0*(double)s->rate)/(double)chipRateBase; + chan[c.chan].fixedFreq=freq; immWrite(16,freq&0xff); immWrite(17,(freq>>8)&0xff); chan[c.chan].active=true; From 70825dc45a872d0bea78d9c645a9bbfcdf4e339e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 23:12:39 -0500 Subject: [PATCH 503/515] AY: reduce PCM clicking --- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 9526e591d..5d9823715 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -139,7 +139,7 @@ void DivPlatformAY8910::runDAC() { chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - immWrite(0x08+i,0); + //immWrite(0x08+i,0); end=true; break; } diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index b6c59452f..a1182a809 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -135,7 +135,7 @@ void DivPlatformAY8930::runDAC() { chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - immWrite(0x08+i,0); + //immWrite(0x08+i,0); end=true; break; } From d7900c2390f5f8408bd001ac552d6c93e3a42233 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Fri, 23 Sep 2022 23:23:03 -0500 Subject: [PATCH 504/515] Implemented changes requested by Tildearrow --- src/engine/safeWriter.cpp | 2 ++ src/engine/safeWriter.h | 2 +- src/engine/zsm.cpp | 48 +++++++++++++++++++-------------------- src/engine/zsm.h | 6 ++--- src/engine/zsmOps.cpp | 2 +- src/gui/gui.cpp | 2 +- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index 83fe48902..49f7d9949 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -77,9 +77,11 @@ int SafeWriter::writeC(signed char val) { return write(&val,1); } +/* int SafeWriter::writeUC(unsigned char val) { return write(&val,1); } +*/ #ifdef TA_BIG_ENDIAN int SafeWriter::writeS_BE(short val) { diff --git a/src/engine/safeWriter.h b/src/engine/safeWriter.h index 43f3c67dd..c77726209 100644 --- a/src/engine/safeWriter.h +++ b/src/engine/safeWriter.h @@ -45,7 +45,7 @@ class SafeWriter { int write(const void* what, size_t count); int writeC(signed char val); - int writeUC(unsigned char val); + //int writeUC(unsigned char val); int writeS(short val); int writeS_BE(short val); int writeI(int val); diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index fc8b471e7..6b358802e 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -22,21 +22,21 @@ #include "../utfutils.h" #include "song.h" -ZSM::ZSM() { +DivZSM::DivZSM() { w = NULL; init(); } -ZSM::~ZSM() { +DivZSM::~DivZSM() { } -void ZSM::init(unsigned int rate) { +void DivZSM::init(unsigned int rate) { if (w != NULL) delete w; w = new SafeWriter; w->init(); // write default ZSM data header w->write("zm",2); // magic header - w->writeUC(ZSM_VERSION); + w->writeC(ZSM_VERSION); // no loop offset w->writeS(0); w->writeC(0); @@ -58,11 +58,11 @@ void ZSM::init(unsigned int rate) { ticks=0; } -int ZSM::getoffset() { +int DivZSM::getoffset() { return w->tell(); } -void ZSM::writeYM(unsigned char a, unsigned char v) { +void DivZSM::writeYM(unsigned char a, unsigned char v) { int lastMask = ymMask; if (a==0x19 && v>=0x80) a=0x1a; // AMD/PSD use same reg addr. store PMD as 0x1a if (a==0x08 && (v&0xf8)) ymMask |= (1 << (v & 0x07)); // mark chan as in-use if keyDN @@ -107,7 +107,7 @@ void ZSM::writeYM(unsigned char a, unsigned char v) { } } -void ZSM::writePSG(unsigned char a, unsigned char v) { +void DivZSM::writePSG(unsigned char a, unsigned char v) { // TODO: suppress writes to PSG voice that is not audible (volume=0) if (a >= 64) { logD ("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); @@ -129,16 +129,16 @@ void ZSM::writePSG(unsigned char a, unsigned char v) { if ((a % 4 == 2) && (v & 0x3f)) psgMask |= (1 << (a>>2)); } -void ZSM::writePCM(unsigned char a, unsigned char v) { +void DivZSM::writePCM(unsigned char a, unsigned char v) { // ZSM standard for PCM playback has not been established yet. } -void ZSM::tick(int numticks) { +void DivZSM::tick(int numticks) { flushWrites(); ticks += numticks; } -void ZSM::setLoopPoint() { +void DivZSM::setLoopPoint() { tick(0); // flush any ticks+writes flushTicks(); // flush ticks incase no writes were pending logI("ZSM: loop at file offset %d bytes",w->tell()); @@ -146,7 +146,7 @@ void ZSM::setLoopPoint() { //update the ZSM header's loop offset value w->seek(0x03,SEEK_SET); w->writeS((short)(loopOffset&0xffff)); - w->writeUC((short)((loopOffset>>16)&0xff)); + w->writeC((unsigned char)((loopOffset>>16)&0xff)); w->seek(loopOffset,SEEK_SET); // reset the PSG shadow and write cache memset(&psgState,-1,sizeof(psgState)); @@ -163,56 +163,56 @@ void ZSM::setLoopPoint() { } } -SafeWriter* ZSM::finish() { +SafeWriter* DivZSM::finish() { tick(0); // flush any pending writes / ticks flushTicks(); // flush ticks in case there were no writes pending - w->writeUC(ZSM_EOF); + w->writeC(ZSM_EOF); // update channel use masks. w->seek(0x09,SEEK_SET); - w->writeUC((unsigned char)(ymMask & 0xff)); + w->writeC((unsigned char)(ymMask & 0xff)); w->writeS((short)(psgMask & 0xffff)); // todo: put PCM offset/data writes here once defined in ZSM standard. return w; } -void ZSM::flushWrites() { +void DivZSM::flushWrites() { logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d",numWrites,ticks,ymwrites.size()); if (numWrites==0) return; flushTicks(); // only flush ticks if there are writes pending. for (unsigned char i=0;i<64;i++) { if (psgState[psg_NEW][i] == psgState[psg_PREV][i]) continue; psgState[psg_PREV][i]=psgState[psg_NEW][i]; - w->writeUC(i); - w->writeUC(psgState[psg_NEW][i]); + w->writeC(i); + w->writeC(psgState[psg_NEW][i]); } int n=0; // n = completed YM writes. used to determine when to write the CMD byte... for (DivRegWrite& write: ymwrites) { if (n%ZSM_YM_MAX_WRITES == 0) { if(ymwrites.size()-n > ZSM_YM_MAX_WRITES) { - w->writeUC((unsigned char)(ZSM_YM_CMD+ZSM_YM_MAX_WRITES)); + w->writeC((unsigned char)(ZSM_YM_CMD+ZSM_YM_MAX_WRITES)); logD("ZSM: YM-write: %d (%02x) [max]",ZSM_YM_MAX_WRITES,ZSM_YM_MAX_WRITES+ZSM_YM_CMD); } else { - w->writeUC((unsigned char)(ZSM_YM_CMD+ymwrites.size()-n)); + w->writeC((unsigned char)(ZSM_YM_CMD+ymwrites.size()-n)); logD("ZSM: YM-write: %d (%02x)",ymwrites.size()-n,ZSM_YM_CMD+ymwrites.size()-n); } } n++; - w->writeUC(write.addr); - w->writeUC(write.val); + w->writeC(write.addr); + w->writeC(write.val); } ymwrites.clear(); numWrites=0; } -void ZSM::flushTicks() { +void DivZSM::flushTicks() { while (ticks > ZSM_DELAY_MAX) { logD("ZSM: write delay %d (max)",ZSM_DELAY_MAX); - w->writeUC((unsigned char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); + w->writeC((unsigned char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); ticks -= ZSM_DELAY_MAX; } if (ticks>0) { logD("ZSM: write delay %d",ticks); - w->writeUC(ZSM_DELAY_CMD+ticks); + w->writeC(ZSM_DELAY_CMD+ticks); } ticks=0; } diff --git a/src/engine/zsm.h b/src/engine/zsm.h index 281e19bb4..b6c6a8cc1 100644 --- a/src/engine/zsm.h +++ b/src/engine/zsm.h @@ -36,7 +36,7 @@ enum YM_STATE { ym_PREV, ym_NEW, ym_STATES }; enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; -class ZSM { +class DivZSM { private: SafeWriter* w; int ymState[ym_STATES][256]; @@ -49,8 +49,8 @@ class ZSM { int ymMask = 0; int psgMask = 0; public: - ZSM(); - ~ZSM(); + DivZSM(); + ~DivZSM(); void init(unsigned int rate = 60); int getoffset(); void writeYM(unsigned char a, unsigned char v); diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp index b115876a6..e722ec541 100644 --- a/src/engine/zsmOps.cpp +++ b/src/engine/zsmOps.cpp @@ -74,7 +74,7 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { logI("loop point: %d %d",loopOrder,loopRow); warnings=""; - ZSM zsm; + DivZSM zsm; zsm.init(zsmrate); // reset the playback state diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 739e87a87..190fdec05 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3400,7 +3400,7 @@ bool FurnaceGUI::loop() { } ImGui::Checkbox("loop",&zsmExportLoop); ImGui::SameLine(); - if (ImGui::Button(" Go ")) { + if (ImGui::Button("Begin Export")) { openFileDialog(GUI_FILE_EXPORT_ZSM); ImGui::CloseCurrentPopup(); } From ebb6668e3293d420d53a4a59d9e4408455b63fa2 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Fri, 23 Sep 2022 23:24:25 -0500 Subject: [PATCH 505/515] Removed commented-out function writeUC from safewriter --- src/engine/safeWriter.cpp | 6 ------ src/engine/safeWriter.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index 49f7d9949..5af7fa09d 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -77,12 +77,6 @@ int SafeWriter::writeC(signed char val) { return write(&val,1); } -/* -int SafeWriter::writeUC(unsigned char val) { - return write(&val,1); -} -*/ - #ifdef TA_BIG_ENDIAN int SafeWriter::writeS_BE(short val) { return write(&val,2); diff --git a/src/engine/safeWriter.h b/src/engine/safeWriter.h index c77726209..414417fd2 100644 --- a/src/engine/safeWriter.h +++ b/src/engine/safeWriter.h @@ -45,7 +45,6 @@ class SafeWriter { int write(const void* what, size_t count); int writeC(signed char val); - //int writeUC(unsigned char val); int writeS(short val); int writeS_BE(short val); int writeI(int val); From 3992a1c677e49fb0d0e9a04338c5e8c1d422c166 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 23:29:19 -0500 Subject: [PATCH 506/515] AY: clockSel PCM fix --- src/engine/platform/ay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5d9823715..9f4e0dc28 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -329,7 +329,7 @@ void DivPlatformAY8910::tick(bool sysTick) { off=8363.0/(double)s->centerRate; } } - chan[i].dac.rate=((double)rate*16.0)/(double)(MAX(1,off*chan[i].freq)); + chan[i].dac.rate=((double)rate*((sunsoft||clockSel)?8.0:16.0))/(double)(MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); } if (chan[i].freq>4095) chan[i].freq=4095; From 5dfa089c4928c6b47c791004d2c642f46a831f52 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 00:57:53 -0500 Subject: [PATCH 507/515] GUI: some UI corrections and prepare for OPM/NES split --- src/gui/guiConst.cpp | 16 +++---- src/gui/insEdit.cpp | 101 ++++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 1ce78b5fa..16261e2a4 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -790,14 +790,14 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), D(GUI_COLOR_INSTR_OPM,"",ImVec4(0.2f,0.6f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NES,"",ImVec4(0.4f,1.0f,0.3f,1.0f)), - D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.7f,1.0f)), + D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.6f,0.9f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,1.0f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.75f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.9f,0.6f,1.0f)), + 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_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9d61fff6b..97be4a713 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1786,12 +1786,12 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTabBar("insEditTab")) { std::vector macroList; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPM) { char label[32]; int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; - bool opsAreMutable=(ins->type==DIV_INS_FM); + bool opsAreMutable=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM); if (ImGui::BeginTabItem("FM")) { if (ImGui::BeginTable("fmDetails",3,ImGuiTableFlags_SizingStretchSame)) { @@ -1801,6 +1801,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); switch (ins->type) { case DIV_INS_FM: + case DIV_INS_OPM: ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable @@ -1995,7 +1996,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.05f); // ar ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.05f); // dr ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.05f); // sl - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.05f); // d2r } ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch,0.05f); // rr @@ -2012,7 +2013,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableSetupColumn("c9z",ImGuiTableColumnFlags_WidthStretch,0.05f); // fine } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c10",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt ImGui::TableSetupColumn("c11",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt2 } @@ -2039,7 +2040,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_D2R)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); @@ -2057,7 +2058,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT(FM_SHORT_NAME(FM_TL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_TL)); ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_RS)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RS)); } else { @@ -2081,7 +2082,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TextUnformatted(FM_SHORT_NAME(FM_FINE)); } ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_DT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT)); ImGui::TableNextColumn(); @@ -2089,7 +2090,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT2)); ImGui::TableNextColumn(); } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); } else { @@ -2188,7 +2189,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; bool vibOn=op.vib; @@ -2212,7 +2213,7 @@ void FurnaceGUI::drawInsEdit() { P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); op.d2r&=31; CENTER_VSLIDER; @@ -2241,7 +2242,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); CENTER_VSLIDER; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); } else { P(CWVSliderScalar("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); @@ -2267,7 +2268,7 @@ void FurnaceGUI::drawInsEdit() { P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { int detune=(op.dt&7)-(settings.unsignedDetune?0:3); ImGui::TableNextColumn(); CENTER_VSLIDER; @@ -2275,12 +2276,10 @@ void FurnaceGUI::drawInsEdit() { op.dt=detune+(settings.unsignedDetune?0:3); } + // TODO: separate OPN/OPM ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - if (ImGui::IsItemHovered() && ins->type==DIV_INS_FM) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } ImGui::TableNextColumn(); bool amOn=op.am; @@ -2329,11 +2328,6 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ins->type==DIV_INS_FM) { - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } - } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -2489,7 +2483,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; @@ -2511,7 +2505,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { ImGui::Text("SSG-EG"); } else { ImGui::Text("Waveform"); @@ -2542,7 +2536,7 @@ void FurnaceGUI::drawInsEdit() { } float textX_D2R=0.0f; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::SameLine(); op.d2r&=31; textX_D2R=ImGui::GetCursorPosX(); @@ -2576,7 +2570,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT_20(FM_SHORT_NAME(FM_RR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR)); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::SetCursorPos(ImVec2(textX_D2R,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_D2R)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); @@ -2586,7 +2580,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); switch (ins->type) { - case DIV_INS_FM: { + case DIV_INS_FM: + case DIV_INS_OPM: { // SSG ImGui::BeginDisabled(!ssgOn); drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); @@ -2827,9 +2822,9 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.tl&=maxTl; - P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); + P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-((ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM)?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); bool amOn=op.am; @@ -2947,7 +2942,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; @@ -2959,7 +2954,7 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Only for OPN family chips"); } @@ -3013,7 +3008,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_SL)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -3055,7 +3050,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_RS)); @@ -3132,7 +3127,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_MULT)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { if (!(ins->type==DIV_INS_OPZ && op.egt)) { int detune=(op.dt&7)-(settings.unsignedDetune?0:3); ImGui::TableNextRow(); @@ -3149,13 +3144,10 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - if (ImGui::IsItemHovered() && ins->type==DIV_INS_FM) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_DT2)); - if (ins->type==DIV_INS_FM) { // OPN only + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { // OPN only ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -3225,13 +3217,13 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,fmOperatorBits)); } else if (ins->type==DIV_INS_OPZ) { macroList.push_back(FurnaceGUIMacroDesc("AM Depth 2",&ins->std.ex5Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3263,7 +3255,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3305,7 +3297,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } @@ -4271,7 +4263,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { volMax=64; } - 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) { + 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) { volMax=127; } if (ins->type==DIV_INS_GB) { @@ -4318,13 +4310,13 @@ void FurnaceGUI::drawInsEdit() { dutyMax=96; } } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { dutyMax=32; } if (ins->type==DIV_INS_AY) { dutyMax=ins->amiga.useSample?0:31; } - if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { dutyLabel="Noise Freq"; } if (ins->type==DIV_INS_MIKEY) { @@ -4338,18 +4330,20 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AY8930) { dutyMax=ins->amiga.useSample?0:255; } - if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { + if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || + ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { dutyMax=0; } - if ((ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_NAMCO) { + if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) { dutyLabel="Noise"; - dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?0:1; + dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?1:0; } if (ins->type==DIV_INS_SWAN) { dutyLabel="Noise"; dutyMax=ins->amiga.useSample?0:8; } - if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { + if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || + ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { dutyMax=0; } if (ins->type==DIV_INS_VERA) { @@ -4401,9 +4395,16 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15; if (ins->type==DIV_INS_C64) waveMax=4; if (ins->type==DIV_INS_SAA1099) waveMax=2; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) waveMax=0; + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) waveMax=0; if (ins->type==DIV_INS_MIKEY) waveMax=0; if (ins->type==DIV_INS_MULTIPCM) waveMax=0; + if (ins->type==DIV_INS_ADPCMA) waveMax=0; + 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_MSM6258) waveMax=0; + if (ins->type==DIV_INS_MSM6295) waveMax=0; + if (ins->type==DIV_INS_SEGAPCM) waveMax=0; if (ins->type==DIV_INS_SU) waveMax=7; if (ins->type==DIV_INS_PET) { waveMax=8; @@ -4418,7 +4419,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { - waveMax=ins->amiga.useSample?(MAX(1,e->song.waveLen-1)):3; + waveMax=ins->amiga.useSample?0:3; waveBitMode=ins->amiga.useSample?false:true; } @@ -4471,6 +4472,7 @@ void FurnaceGUI::drawInsEdit() { bool panSingleNoBit=false; if (ins->type==DIV_INS_STD ||//Game Gear ins->type==DIV_INS_FM || + ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_GB || @@ -4555,6 +4557,7 @@ 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_FM || + ins->type==DIV_INS_OPM || ins->type==DIV_INS_STD || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || From 3d5125e792036dd820be00d5ee1ddaa4fb06efdf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 01:33:36 -0500 Subject: [PATCH 508/515] OPM/NES ins type split, part 1 --- src/gui/insEdit.cpp | 99 +++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 97be4a713..bbf7fd5e3 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1214,7 +1214,7 @@ inline bool enBit30(const int val) { void FurnaceGUI::kvsConfig(DivInstrument* ins) { if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("(click to configure KVS)"); + ImGui::SetTooltip("(click to configure TL scaling)"); } int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; @@ -1986,7 +1986,7 @@ void FurnaceGUI::drawInsEdit() { } if (willDisplayOps) { if (settings.fmLayout==0) { - int numCols=16; + int numCols=15; if (ins->type==DIV_INS_OPL ||ins->type==DIV_INS_OPL_DRUMS) numCols=13; if (ins->type==DIV_INS_OPLL) numCols=12; if (ins->type==DIV_INS_OPZ) numCols=19; @@ -2015,12 +2015,14 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c10",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt + } + if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c11",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt2 } ImGui::TableSetupColumn("c15",ImGuiTableColumnFlags_WidthFixed); // am ImGui::TableSetupColumn("c12",ImGuiTableColumnFlags_WidthFixed); // -separator- - if (ins->type!=DIV_INS_OPLL) { + if (ins->type!=DIV_INS_OPLL && ins->type!=DIV_INS_OPM) { ImGui::TableSetupColumn("c13",ImGuiTableColumnFlags_WidthStretch,0.2f); // ssg/waveform } ImGui::TableSetupColumn("c14",ImGuiTableColumnFlags_WidthStretch,0.3f); // env @@ -2086,6 +2088,8 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT(FM_SHORT_NAME(FM_DT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT)); ImGui::TableNextColumn(); + } + if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_DT2)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT2)); ImGui::TableNextColumn(); @@ -2102,7 +2106,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_WS)); ImGui::TextUnformatted(FM_NAME(FM_WS)); - } else if (ins->type!=DIV_INS_OPLL) { + } else if (ins->type!=DIV_INS_OPLL && ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_SSG)); ImGui::TextUnformatted(FM_NAME(FM_SSG)); @@ -2276,10 +2280,11 @@ void FurnaceGUI::drawInsEdit() { op.dt=detune+(settings.unsignedDetune?0:3); } - // TODO: separate OPN/OPM - ImGui::TableNextColumn(); - CENTER_VSLIDER; - P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + if (ins->type!=DIV_INS_FM) { + ImGui::TableNextColumn(); + CENTER_VSLIDER; + P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + } ImGui::TableNextColumn(); bool amOn=op.am; @@ -2318,7 +2323,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ && ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); @@ -2335,7 +2340,7 @@ void FurnaceGUI::drawInsEdit() { op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); } } - } else { + } else if (ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); bool amOn=op.am; ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight()*4.0-ImGui::GetStyle().ItemSpacing.y*3.0)); @@ -2370,7 +2375,7 @@ void FurnaceGUI::drawInsEdit() { if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); } - } else if (ins->type==DIV_INS_OPLL) { + } else if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); } @@ -2470,7 +2475,7 @@ void FurnaceGUI::drawInsEdit() { float sliderHeight=200.0f*dpiScale; float waveWidth=140.0*dpiScale; - float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*(ins->type==DIV_INS_OPLL?4.5f:5.5f); + float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*((ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL)?5.0f:4.5f); int maxTl=127; if (ins->type==DIV_INS_OPLL) { @@ -2505,7 +2510,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_FM) { ImGui::Text("SSG-EG"); } else { ImGui::Text("Waveform"); @@ -2580,8 +2585,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); switch (ins->type) { - case DIV_INS_FM: - case DIV_INS_OPM: { + case DIV_INS_FM: { // SSG ImGui::BeginDisabled(!ssgOn); drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); @@ -2589,9 +2593,6 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -2612,17 +2613,35 @@ void FurnaceGUI::drawInsEdit() { op.dt=detune+(settings.unsignedDetune?0:3); } rightClickable + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + + break; + } + case DIV_INS_OPM: { + drawWaveform(0,true,ImVec2(waveWidth,waveHeight)); + + // params + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-(settings.unsignedDetune?0:3); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+(settings.unsignedDetune?0:3); + } rightClickable + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable - break; } case DIV_INS_OPLL: @@ -2949,16 +2968,11 @@ void FurnaceGUI::drawInsEdit() { bool vibOn=op.vib; bool susOn=op.sus; // don't you make fun of this one unsigned char ssgEnv=op.ssgEnv&7; - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ && ins->type!=DIV_INS_OPM) { ImGui::SameLine(); if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } - } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { @@ -3140,14 +3154,16 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_DT)); } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DT2)); + if (ins->type!=DIV_INS_FM) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DT2)); + } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { // OPN only + if (ins->type==DIV_INS_FM) { // OPN only ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -3217,7 +3233,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3294,10 +3310,12 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_RS),&ins->std.opMacros[ordi].rsMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT),&ins->std.opMacros[ordi].dtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); + if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); + } macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_FM) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } @@ -4310,7 +4328,7 @@ void FurnaceGUI::drawInsEdit() { dutyMax=96; } } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { dutyMax=32; } if (ins->type==DIV_INS_AY) { @@ -4331,7 +4349,8 @@ void FurnaceGUI::drawInsEdit() { dutyMax=ins->amiga.useSample?0:255; } if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || - ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { + ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_FM) { dutyMax=0; } if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) { From d0e581e4cdc591fccb761a4411adb758d946ac18 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 01:37:29 -0500 Subject: [PATCH 509/515] OPM/NES ins type split, part 2 --- src/gui/insEdit.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index bbf7fd5e3..4cb03bf05 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4328,6 +4328,9 @@ void FurnaceGUI::drawInsEdit() { dutyMax=96; } } + if (ins->type==DIV_INS_STD) { + dutyLabel="Duty"; + } if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { dutyMax=32; } @@ -4410,7 +4413,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_SAA1099) { waveBitMode=true; } - if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW) waveMax=0; + if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_NES) waveMax=0; if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15; if (ins->type==DIV_INS_C64) waveMax=4; if (ins->type==DIV_INS_SAA1099) waveMax=2; @@ -4578,6 +4581,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM || ins->type==DIV_INS_STD || + ins->type==DIV_INS_NES || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || From d2a417e1d59605baa9166b341d79a52b0be980aa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 01:46:44 -0500 Subject: [PATCH 510/515] OPM/NES ins type split, part 3 --- src/engine/sysDef.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 1f3f8e07b..624b6a721 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -666,7 +666,7 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "Triangle", "Noise", "PCM"}, {"S1", "S2", "TR", "NO", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, + {DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA}, {}, { {0x11, {DIV_CMD_NES_DMC, "11xx: Write to delta modulation counter (0 to 7F)"}}, @@ -777,7 +777,7 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, + {DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM}, {}, fmEffectHandlerMap, fmOPMPostEffectHandlerMap @@ -916,7 +916,7 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "PCM"}, {"S1", "S2", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, + {DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA}, {}, { {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}}, @@ -1106,7 +1106,7 @@ void DivEngine::registerSystems() { {"Square"}, {"SQ"}, {DIV_CH_PULSE}, - {DIV_INS_STD} + {DIV_INS_BEEPER} ); sysDefs[DIV_SYSTEM_SEGAPCM]=new DivSysDef( From 3eb4f997da0f76d0f45b4afe3d507367cb89e171 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 02:14:26 -0500 Subject: [PATCH 511/515] OPM/NES ins type split, part 4 --- src/engine/fileOps.cpp | 82 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 47a837899..0d8817ebf 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -337,7 +337,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } logD("%d name: %s",i,ins->name.c_str()); if (ds.version<0x0b) { - // instruments in ancient versions were all FM or STD. + // instruments in ancient versions were all FM. mode=1; } else { mode=reader.readC(); @@ -366,6 +366,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (ds.system[0]==DIV_SYSTEM_YMU759) { ins->type=DIV_INS_OPL; } + if (ds.system[0]==DIV_SYSTEM_ARCADE) { + ins->type=DIV_INS_OPM; + } + if ((ds.system[0]==DIV_SYSTEM_NES || ds.system[0]==DIV_SYSTEM_NES_VRC7 || ds.system[0]==DIV_SYSTEM_NES_FDS) && ins->type==DIV_INS_STD) { + ins->type=DIV_INS_NES; + } if (mode) { // FM if (ds.version>0x05) { @@ -1919,6 +1925,57 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } } + // convert OPM/NES instrument types + if (ds.version<117) { + int opnCount=0; + int opmCount=0; + int snCount=0; + int nesCount=0; + for (int i=0; iopnCount) { + for (DivInstrument* i: ds.ins) { + if (i->type==DIV_INS_FM) i->type=DIV_INS_OPM; + } + } + if (nesCount>snCount) { + for (DivInstrument* i: ds.ins) { + if (i->type==DIV_INS_STD) i->type=DIV_INS_NES; + } + } + } + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); @@ -3237,7 +3294,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { unsigned char insType=reader.readC(); switch (insType) { case 1: - ins->type=DIV_INS_STD; + ins->type=DIV_INS_NES; break; case 2: // TODO: tell VRC6 and VRC6 saw instruments apart ins->type=DIV_INS_VRC6; @@ -3264,7 +3321,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { // instrument data switch (ins->type) { - case DIV_INS_STD: { + case DIV_INS_NES: { unsigned int totalSeqs=reader.readI(); if (totalSeqs>5) { logE("%d: too many sequences!",insIndex); @@ -4183,7 +4240,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } for (DivInstrument* i: song.ins) { - if (i->type==DIV_INS_FM) { + if (i->type==DIV_INS_FM || i->type==DIV_INS_OPM) { addWarning("no FM macros in .dmf format"); break; } @@ -4194,11 +4251,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeString(i->name,true); // safety check - if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_FDS) { + if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_NES && i->type!=DIV_INS_FDS) { switch (song.system[0]) { case DIV_SYSTEM_GB: i->type=DIV_INS_GB; break; + case DIV_SYSTEM_NES: + i->type=DIV_INS_NES; + break; case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: i->type=DIV_INS_C64; @@ -4215,12 +4275,16 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { break; } } - if (!isSTDSystem(sys) && i->type!=DIV_INS_FM) { - i->type=DIV_INS_FM; + if (!isSTDSystem(sys) && i->type!=DIV_INS_FM && i->type!=DIV_INS_OPM) { + if (sys==DIV_SYSTEM_ARCADE) { + i->type=DIV_INS_OPM; + } else { + i->type=DIV_INS_FM; + } } - w->writeC((i->type==DIV_INS_FM || i->type==DIV_INS_OPLL)?1:0); - if (i->type==DIV_INS_FM || i->type==DIV_INS_OPLL) { // FM + w->writeC((i->type==DIV_INS_FM || i->type==DIV_INS_OPM || i->type==DIV_INS_OPLL)?1:0); + if (i->type==DIV_INS_FM || i->type==DIV_INS_OPM || i->type==DIV_INS_OPLL) { // FM w->writeC(i->fm.alg); w->writeC(i->fm.fb); w->writeC(i->fm.fms); From 5e2a247b77e47f63120d55716c2f5ccbf8ed7ab2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 02:31:10 -0500 Subject: [PATCH 512/515] tabs to spaces --- src/engine/zsm.cpp | 28 ++++++++++---------- src/engine/zsm.h | 36 +++++++++++++------------- src/engine/zsmOps.cpp | 60 +++++++++++++++++++++---------------------- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index 6b358802e..89eb01496 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -110,14 +110,14 @@ void DivZSM::writeYM(unsigned char a, unsigned char v) { void DivZSM::writePSG(unsigned char a, unsigned char v) { // TODO: suppress writes to PSG voice that is not audible (volume=0) if (a >= 64) { - logD ("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); - return; + logD ("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); + return; } if(psgState[psg_PREV][a] == v) { if (psgState[psg_NEW][a] != v) // NEW value is being reset to the same as PREV value // so it is no longer a new write. - numWrites--; + numWrites--; } else { if (psgState[psg_PREV][a] == psgState[psg_NEW][a]) // if this write changes the NEW cached value to something other @@ -143,7 +143,7 @@ void DivZSM::setLoopPoint() { flushTicks(); // flush ticks incase no writes were pending logI("ZSM: loop at file offset %d bytes",w->tell()); loopOffset=w->tell(); - //update the ZSM header's loop offset value + // update the ZSM header's loop offset value w->seek(0x03,SEEK_SET); w->writeS((short)(loopOffset&0xffff)); w->writeC((unsigned char)((loopOffset>>16)&0xff)); @@ -155,7 +155,7 @@ void DivZSM::setLoopPoint() { // ... and cache (except for unused channels) memset(&ymState[ym_NEW],-1,0x20); for (int chan=0; chan<8 ; chan++) { - //do not clear state for as-yet-unused channels + // do not clear state for as-yet-unused channels if (!(ymMask & (1< ZSM_YM_MAX_WRITES) { - w->writeC((unsigned char)(ZSM_YM_CMD+ZSM_YM_MAX_WRITES)); - logD("ZSM: YM-write: %d (%02x) [max]",ZSM_YM_MAX_WRITES,ZSM_YM_MAX_WRITES+ZSM_YM_CMD); + w->writeC((unsigned char)(ZSM_YM_CMD+ZSM_YM_MAX_WRITES)); + logD("ZSM: YM-write: %d (%02x) [max]",ZSM_YM_MAX_WRITES,ZSM_YM_MAX_WRITES+ZSM_YM_CMD); } else { - w->writeC((unsigned char)(ZSM_YM_CMD+ymwrites.size()-n)); - logD("ZSM: YM-write: %d (%02x)",ymwrites.size()-n,ZSM_YM_CMD+ymwrites.size()-n); + w->writeC((unsigned char)(ZSM_YM_CMD+ymwrites.size()-n)); + logD("ZSM: YM-write: %d (%02x)",ymwrites.size()-n,ZSM_YM_CMD+ymwrites.size()-n); } } n++; @@ -206,13 +206,13 @@ void DivZSM::flushWrites() { void DivZSM::flushTicks() { while (ticks > ZSM_DELAY_MAX) { - logD("ZSM: write delay %d (max)",ZSM_DELAY_MAX); - w->writeC((unsigned char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); - ticks -= ZSM_DELAY_MAX; + logD("ZSM: write delay %d (max)",ZSM_DELAY_MAX); + w->writeC((unsigned char)(ZSM_DELAY_CMD+ZSM_DELAY_MAX)); + ticks -= ZSM_DELAY_MAX; } if (ticks>0) { - logD("ZSM: write delay %d",ticks); - w->writeC(ZSM_DELAY_CMD+ticks); + logD("ZSM: write delay %d",ticks); + w->writeC(ZSM_DELAY_CMD+ticks); } ticks=0; } diff --git a/src/engine/zsm.h b/src/engine/zsm.h index b6c6a8cc1..af0979e7c 100644 --- a/src/engine/zsm.h +++ b/src/engine/zsm.h @@ -38,27 +38,27 @@ enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; class DivZSM { private: - SafeWriter* w; - int ymState[ym_STATES][256]; - int psgState[psg_STATES][64]; - std::vector ymwrites; - int loopOffset; - int numWrites; - int ticks; - int tickRate; + SafeWriter* w; + int ymState[ym_STATES][256]; + int psgState[psg_STATES][64]; + std::vector ymwrites; + int loopOffset; + int numWrites; + int ticks; + int tickRate; int ymMask = 0; int psgMask = 0; public: - DivZSM(); - ~DivZSM(); - void init(unsigned int rate = 60); - int getoffset(); - void writeYM(unsigned char a, unsigned char v); - void writePSG(unsigned char a, unsigned char v); - void writePCM(unsigned char a, unsigned char v); - void tick(int numticks = 1); - void setLoopPoint(); - SafeWriter* finish(); + DivZSM(); + ~DivZSM(); + void init(unsigned int rate = 60); + int getoffset(); + void writeYM(unsigned char a, unsigned char v); + void writePSG(unsigned char a, unsigned char v); + void writePCM(unsigned char a, unsigned char v); + void tick(int numticks = 1); + void setLoopPoint(); + SafeWriter* finish(); private: void flushWrites(); void flushTicks(); diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp index e722ec541..47e819329 100644 --- a/src/engine/zsmOps.cpp +++ b/src/engine/zsmOps.cpp @@ -35,25 +35,25 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { //loop = false; // find indexes for YM and VERA. Ignore other systems. for (int i=0; i= 0) { IGNORED++;break; } - VERA = i; - logD("VERA detected as chip id %d",i); - break; - case DIV_SYSTEM_YM2151: - if (YM >= 0) { IGNORED++;break; } - YM = i; - logD("YM detected as chip id %d",i); - break; - default: - IGNORED++; - logD("Ignoring chip %d systemID %d",i,song.system[i]); - } + switch (song.system[i]) { + case DIV_SYSTEM_VERA: + if (VERA >= 0) { IGNORED++;break; } + VERA = i; + logD("VERA detected as chip id %d",i); + break; + case DIV_SYSTEM_YM2151: + if (YM >= 0) { IGNORED++;break; } + YM = i; + logD("YM detected as chip id %d",i); + break; + default: + IGNORED++; + logD("Ignoring chip %d systemID %d",i,song.system[i]); + } } if (VERA < 0 && YM < 0) { - logE("No supported systems for ZSM"); - return NULL; + logE("No supported systems for ZSM"); + return NULL; } if (IGNORED > 0) logW("ZSM export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); @@ -121,22 +121,22 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { } // get register dumps for (int j=0; j<2; j++) { - int i=0; + int i=0; // dump YM writes first - if (j==0) { - if (YM < 0) - continue; - else - i=YM; - } + if (j==0) { + if (YM < 0) + continue; + else + i=YM; + } // dump VERA writes second - if (j==1) { - if (VERA < 0) - continue; - else { + if (j==1) { + if (VERA < 0) + continue; + else { i=VERA; - } - } + } + } std::vector& writes=disCont[i].dispatch->getRegisterWrites(); if (writes.size() > 0) logD("zsmOps: Writing %d messages to chip %d",writes.size(), i); From 04117c50980bf58605fe1274e64a0c8cd3847687 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 02:41:29 -0500 Subject: [PATCH 513/515] Purposeful Conflict --- src/engine/instrument.h | 20 ++++----- src/gui/insEdit.cpp | 90 ++++++++++++++++++++--------------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 01323d90f..614b8d294 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -520,21 +520,21 @@ struct DivInstrumentES5506 { }; struct DivInstrumentSNES { - enum GainMode: unsigned char { - GAIN_MODE_DIRECT=0, - GAIN_MODE_DEC_LINEAR=4, - GAIN_MODE_DEC_LOG=5, - GAIN_MODE_INC_LINEAR=6, - GAIN_MODE_INC_INVLOG=7 + enum GainMode: unsigned char { // Purposeful Conflict + GAIN_MODE_DIRECT=0, // Purposeful Conflict + GAIN_MODE_DEC_LINEAR=4, // Purposeful Conflict + GAIN_MODE_DEC_LOG=5, // Purposeful Conflict + GAIN_MODE_INC_LINEAR=6, // Purposeful Conflict + GAIN_MODE_INC_INVLOG=7 // Purposeful Conflict }; bool useEnv; - GainMode gainMode; - unsigned char gain; + GainMode gainMode; // Purposeful Conflict + unsigned char gain; // Purposeful Conflict unsigned char a, d, s, r; DivInstrumentSNES(): useEnv(true), - gainMode(GAIN_MODE_DIRECT), - gain(127), + gainMode(GAIN_MODE_DIRECT), // Purposeful Conflict + gain(127), // Purposeful Conflict a(15), d(7), s(7), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 4cb03bf05..c72e8d200 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4006,9 +4006,9 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } } - if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { - P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv)); - ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); + if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { // Purposeful Conflict + P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv)); // Purposeful Conflict + ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); // Purposeful Conflict if (ins->snes.useEnv) { if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); @@ -4049,52 +4049,52 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } } else { - if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { // Purposeful Conflict + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); // Purposeful Conflict + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); // Purposeful Conflict + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); // Purposeful Conflict - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - CENTER_TEXT("Gain Mode"); - ImGui::TextUnformatted("Gain Mode"); - ImGui::TableNextColumn(); - CENTER_TEXT("Gain"); - ImGui::TextUnformatted("Gain"); - ImGui::TableNextColumn(); - CENTER_TEXT("Envelope"); - ImGui::TextUnformatted("Envelope"); + ImGui::TableNextRow(); // Purposeful Conflict + ImGui::TableNextColumn(); // Purposeful Conflict + CENTER_TEXT("Gain Mode"); // Purposeful Conflict + ImGui::TextUnformatted("Gain Mode"); // Purposeful Conflict + ImGui::TableNextColumn(); // Purposeful Conflict + CENTER_TEXT("Gain"); // Purposeful Conflict + ImGui::TextUnformatted("Gain"); // Purposeful Conflict + ImGui::TableNextColumn(); // Purposeful Conflict + CENTER_TEXT("Envelope"); // Purposeful Conflict + ImGui::TextUnformatted("Envelope"); // Purposeful Conflict - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; - PARAMETER; - } - if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; - PARAMETER; - } - if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; - PARAMETER; - } - if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; - PARAMETER; - } - if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { - ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; - PARAMETER; - } + ImGui::TableNextRow(); // Purposeful Conflict + ImGui::TableNextColumn(); // Purposeful Conflict + if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { // Purposeful Conflict + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; // Purposeful Conflict + PARAMETER; // Purposeful Conflict + } // Purposeful Conflict + if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { // Purposeful Conflict + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; // Purposeful Conflict + PARAMETER; // Purposeful Conflict + } // Purposeful Conflict + if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { // Purposeful Conflict + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; // Purposeful Conflict + PARAMETER; // Purposeful Conflict + } // Purposeful Conflict + if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { // Purposeful Conflict + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; // Purposeful Conflict + PARAMETER; // Purposeful Conflict + } // Purposeful Conflict + if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { // Purposeful Conflict + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; // Purposeful Conflict + PARAMETER; // Purposeful Conflict + } // Purposeful Conflict - ImGui::TableNextColumn(); - unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; - if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; - P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); + ImGui::TableNextColumn(); // Purposeful Conflict + unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; // Purposeful Conflict + if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; // Purposeful Conflict + P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); // Purposeful Conflict - ImGui::TableNextColumn(); - ImGui::Text("Envelope goes here..."); + ImGui::TableNextColumn(); // Purposeful Conflict + ImGui::Text("Envelope goes here..."); // Purposeful Conflict ImGui::EndTable(); } From 8eaddcf0705aca3d4b212291ef9668b402d6b169 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 04:27:53 -0500 Subject: [PATCH 514/515] prepare BRR encoding/decoding --- CMakeLists.txt | 1 + src/engine/brrUtils.c | 82 ++++++++++++++++++++++++++++++++++++ src/engine/brrUtils.h | 50 ++++++++++++++++++++++ src/engine/platform/snes.cpp | 14 +++++- src/engine/platform/snes.h | 7 +++ src/engine/sample.cpp | 8 +++- 6 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 src/engine/brrUtils.c create mode 100644 src/engine/brrUtils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fec191a6e..2aae13d9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,6 +444,7 @@ src/engine/platform/ym2608Interface.cpp src/engine/platform/ym2610Interface.cpp src/engine/blip_buf.c +src/engine/brrUtils.c src/engine/safeReader.cpp src/engine/safeWriter.cpp src/engine/config.cpp diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c new file mode 100644 index 000000000..9f0c20bc7 --- /dev/null +++ b/src/engine/brrUtils.c @@ -0,0 +1,82 @@ +/* brrUtils - BRR audio codec utilities + * Copyright (C) 2022 tildearrow + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "brrUtils.h" + +void brrEncode(short* buf, unsigned char* out, long len) { + if (len==0) return; + // TODO +} + +#define DO_ONE_SAMPLE \ + if (next&8) next|=0xfff8; \ +\ + next<<=(buf[0]>>4); /* range */ \ +\ + switch (control&0xc) { /* filter */ \ + case 0: \ + break; \ + case 4: \ + next+=(last1*15)/16; \ + break; \ + case 8: \ + next+=(last1*61)/32-(last2*15)/16; \ + break; \ + case 12: \ + next+=(last1*115)/64-(last2*13)/16; \ + break; \ + } \ +\ + if (next>32767) next=32767; \ + if (next<-32768) next=-32768; \ +\ + last2=last1; \ + last1=next; \ + *out=next; \ + out++; + +void brrDecode(unsigned char* buf, short* out, long len) { + if (len==0) return; + + int last1=0; + int last2=0; + int next=0; + + // don't read out of bounds + len-=8; + + for (long i=0; i>4; + DO_ONE_SAMPLE; + } + + // end bit + if (control&1) break; + buf+=9; + } +} \ No newline at end of file diff --git a/src/engine/brrUtils.h b/src/engine/brrUtils.h new file mode 100644 index 000000000..85192e45a --- /dev/null +++ b/src/engine/brrUtils.h @@ -0,0 +1,50 @@ +/* brrUtils - BRR audio codec utilities + * Copyright (C) 2022 tildearrow + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _BRR_UTILS_H +#define _BRR_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * read len samples from buf, encode in BRR and output to out. + * @param buf input data. + * @param out output buffer. shall be at least 9*(len/16) shorts in size. + * @param len input length (should be a multiple of 16. if it isn't, the output will be padded). + */ +void brrEncode(short* buf, unsigned char* out, long len); + +/** + * read len bytes from buf, decode BRR and output to out. + * @param buf input data. + * @param out output buffer. shall be at least 16*(len/9) shorts in size. + * @param len input length (shall be a multiple of 9). + */ +void brrDecode(unsigned char* buf, short* out, long len); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 2f3e972f9..ca722a419 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -24,7 +24,7 @@ #define CHIP_FREQBASE 131072 -#define rWrite(a,v) {dsp.write(a,v); regPool[(a)&0x7f]=v; } +#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } #define chWrite(c,a,v) {rWrite((a)+(c)*16,v)} #define sampleTableAddr(c) (sampleTableBase+(c)*4) #define waveTableAddr(c) (sampleTableBase+8*4+(c)*9*16) @@ -69,6 +69,14 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len short out[2]; short chOut[16]; for (size_t h=start; h>8); rWrite(0x0c,127); // global volume left rWrite(0x1c,127); // global volume right diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 65c8a6656..5deb30c59 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -73,6 +73,13 @@ class DivPlatformSNES: public DivDispatch { signed char gblVolL, gblVolR; size_t sampleTableBase; + struct QueuedWrite { + unsigned char addr; + unsigned char val; + QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {} + }; + std::queue writes; + signed char sampleMem[65536]; size_t sampleMemLen; unsigned char regPool[0x80]; diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 5697176cd..cc24b9110 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -33,6 +33,7 @@ extern "C" { #include "../../extern/adpcm/ymb_codec.h" #include "../../extern/adpcm/ymz_codec.h" } +#include "brrUtils.h" DivSampleHistory::~DivSampleHistory() { if (data!=NULL) delete[] data; @@ -851,7 +852,7 @@ void DivSample::render() { } break; case DIV_SAMPLE_DEPTH_BRR: // BRR - // TODO! + brrDecode(dataBRR,data16,samples); break; case DIV_SAMPLE_DEPTH_VOX: // VOX oki_decode(dataVOX,data16,samples); @@ -908,7 +909,10 @@ void DivSample::render() { data8[i]=data16[i]>>8; } } - // TODO: BRR! + if (depth!=DIV_SAMPLE_DEPTH_VOX) { // BRR + if (!initInternal(DIV_SAMPLE_DEPTH_BRR,samples)) return; + brrEncode(data16,dataBRR,samples); + } if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return; oki_encode(data16,dataVOX,samples); From 78baff55e844470302d3620ee91824ab773cbf9e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 05:43:33 -0500 Subject: [PATCH 515/515] update brrUtils --- src/engine/brrUtils.c | 26 ++++++++++++++++---------- src/engine/brrUtils.h | 8 +++++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index 9f0c20bc7..123ec165d 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -22,13 +22,14 @@ #include "brrUtils.h" -void brrEncode(short* buf, unsigned char* out, long len) { - if (len==0) return; +long brrEncode(short* buf, unsigned char* out, long len) { + if (len==0) return 0; // TODO + return 0; } #define DO_ONE_SAMPLE \ - if (next&8) next|=0xfff8; \ + if (next&8) next|=0xfffffff8; \ \ next<<=(buf[0]>>4); /* range */ \ \ @@ -39,10 +40,10 @@ void brrEncode(short* buf, unsigned char* out, long len) { next+=(last1*15)/16; \ break; \ case 8: \ - next+=(last1*61)/32-(last2*15)/16; \ + next+=((last1*61)/32)-((last2*15)/16); \ break; \ case 12: \ - next+=(last1*115)/64-(last2*13)/16; \ + next+=((last1*115)/64)-((last2*13)/16); \ break; \ } \ \ @@ -54,8 +55,10 @@ void brrEncode(short* buf, unsigned char* out, long len) { *out=next; \ out++; -void brrDecode(unsigned char* buf, short* out, long len) { - if (len==0) return; +long brrDecode(unsigned char* buf, short* out, long len) { + if (len==0) return 0; + + long total=0; int last1=0; int last2=0; @@ -68,15 +71,18 @@ void brrDecode(unsigned char* buf, short* out, long len) { unsigned char control=buf[0]; for (unsigned char j=1; j<9; j++) { - next=buf[j]&15; + next=buf[j]>>4; DO_ONE_SAMPLE; - next=buf[j]>>4; + next=buf[j]&15; DO_ONE_SAMPLE; } // end bit + total+=16; if (control&1) break; buf+=9; } -} \ No newline at end of file + + return total; +} diff --git a/src/engine/brrUtils.h b/src/engine/brrUtils.h index 85192e45a..ba3a6f534 100644 --- a/src/engine/brrUtils.h +++ b/src/engine/brrUtils.h @@ -32,19 +32,21 @@ extern "C" { * @param buf input data. * @param out output buffer. shall be at least 9*(len/16) shorts in size. * @param len input length (should be a multiple of 16. if it isn't, the output will be padded). + * @return number of written samples. */ -void brrEncode(short* buf, unsigned char* out, long len); +long brrEncode(short* buf, unsigned char* out, long len); /** * read len bytes from buf, decode BRR and output to out. * @param buf input data. * @param out output buffer. shall be at least 16*(len/9) shorts in size. * @param len input length (shall be a multiple of 9). + * @return number of written bytes. */ -void brrDecode(unsigned char* buf, short* out, long len); +long brrDecode(unsigned char* buf, short* out, long len); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif

  • 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 Date: Mon, 15 Aug 2022 21:18:27 +0200 Subject: [PATCH 214/515] Use Amiga 1200 (AGA) instead for this module --- ...government funding breakcore-ish remix.fur | Bin 417084 -> 417079 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/government funding breakcore-ish remix.fur b/demos/government funding breakcore-ish remix.fur index 5659ca1a1a930c347249e700da26b6bf5be42bfe..5c3a47ce2df99d6c61cfe83503540c45567c0dbc 100644 GIT binary patch delta 386179 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�(-fXxl{z2X?42? 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%0A$7ug4*A=9RALzN6Cw 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