From 98a95e83c6494267851d08685761c29a06078b34 Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Thu, 24 Aug 2023 23:14:06 -0700 Subject: [PATCH 1/8] Assorted documentation upkeep. --- doc/1-intro/concepts.md | 14 +++++++------- doc/2-interface/asset-list.md | 14 ++++++++++++-- doc/2-interface/menu-bar.md | 18 ++++++++++-------- doc/6-sample/README.md | 5 +++-- doc/8-advanced/comments.md | 2 +- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/doc/1-intro/concepts.md b/doc/1-intro/concepts.md index 130e2ae8..b9179717 100644 --- a/doc/1-intro/concepts.md +++ b/doc/1-intro/concepts.md @@ -15,22 +15,22 @@ The **[pattern view](../3-pattern/README.md)** is like a spreadsheet that displa ## structure The **order list** is a smaller spreadsheet showing the overall song structure. -- A song is made up of a list of **orders**. -- An **order** is a set of numbered **patterns** used for each channel. +- A song is made up of a list of orders. +- An **order** is a set of numbered patterns used for each channel. - Each channel has its own unique list of patterns. -- Each pattern contains note and effect data for that channel only. +- Each **pattern** contains note and effect data for that channel only. - Patterns may be used multiple times in the order list. Changing a pattern's data in one order will affect the same pattern used in other orders. ## time -- Each pattern is made of the same number of **rows** as seen in the tracker view. -- During playback, Each row lasts a number of **ticks** determined by its **speed** value. -- A tick is the smallest measure of time to which all note, effect, and macro times are quantized. +- Each pattern is made of the same number of rows as seen in the tracker view. +- During playback, each **row** lasts a number of ticks determined by its **speed** value. +- A **tick** is the smallest measure of time to which all note, effect, and macro times are quantized. ## sound Different chips have different capabilities. Even within the same chip, each channel may have its own ways of making sound. - Some channels use one or more waveform **generators** (sine, square, noise...) to build up a sound. - Of special note are **[FM (frequency modulation)](../4-instrument/fm.md)** channels, which use a number of generators called **operators** that can interact to make very complex sounds. -- Some channels use **[samples](../6-sample/README.md)** - recordings of sounds, often with defined loop points to allow a note to sustain. +- Some channels use **[samples](../6-sample/README.md)** which are recordings of sounds, often with defined loop points to allow a note to sustain. - Some channels use **[wavetables](../5-wave/README.md)**, which are like very short samples of fixed length that automatically loop. \ No newline at end of file diff --git a/doc/2-interface/asset-list.md b/doc/2-interface/asset-list.md index 836d9b69..157c934d 100644 --- a/doc/2-interface/asset-list.md +++ b/doc/2-interface/asset-list.md @@ -3,10 +3,20 @@ ![instruments window](instruments.png) Buttons from left to right: -- **Add**: Creates a new, default instrument. +- **Add**: pops up a menu to select which type of instrument to add. + - If the "Display instrument type menu when adding instrument" setting is disabled, this skips the menu and creates an instrument according to the chip under the cursor. + - Right-clicking always brings up the menu. - **Duplicate**: Duplicates the currently selected instrument. - **Open**: Brings up a file dialog to load a file as a new instrument at the end of the list. -- **Save**: Brings up a file dialog to save the currently selected instrument. +- **Save**: Brings up a file dialog to save the currently selected asset. + - Instruments are saved as Furnace instrument (.fui) files. + - Wavetables are saved as Furnace wavetable (.fuw) files. + - Samples are saved as standard wave (.wav) files. + - Right-clicking brings up a menu with the applicable items from this list: + - **save instrument as .dmp...**: saves the selected instrument in DefleMask format. + - **save wavetable as .dmw...**: saves the selected wavetable in DefleMask format. + - **save raw wavetable...**: saves the selected wavetable as raw data. + - **save raw sample...**: saves the selected sample as raw data. - **Toggle folders/standard view**: Enables (and disables) folder view, explained below. - **Move up**: Moves the currently selected instrument up in the list. Pattern data will automatically be adjusted to match. - **Move down**: Same, but downward. diff --git a/doc/2-interface/menu-bar.md b/doc/2-interface/menu-bar.md index fee8f7c5..1ef63fb9 100644 --- a/doc/2-interface/menu-bar.md +++ b/doc/2-interface/menu-bar.md @@ -6,10 +6,10 @@ items in _italics_ don't appear in basic mode and are only available in advanced # file -- **new...**: create a new song. +- **new...**: creates a new song. - **open...**: opens the file picker, allowing you to select a song to open. - **open recent**: contains a list of the songs you've opened before. - - **clear history**: this option erases the file history. + - **clear history**: erases the file history. - **save**: saves the current song. - opens the file picker if this is a new song, or a backup. @@ -33,9 +33,9 @@ items in _italics_ don't appear in basic mode and are only available in advanced - Neo Geo CD (DefleMask 1.0+) - only use this option if you really need it. there are features which DefleMask does not support, like some effects and FM macros, so these will be lost. -- **export audio...**: export your song to a .wav file. see next section for more details. -- **export VGM...**: export your song to a .vgm file. see next section for more details. -- **export ZSM...**: export your song to a .zsm file. see next section for more details. +- **export audio...**: opens the file picker, allowing you to export your song to a .wav file. see next section for more details. +- **export VGM...**: opens the file picker, allowing you to export your song to a .vgm file. see next section for more details. +- **export ZSM...**: opens the file picker, allowing you to export your song to a .zsm file. see next section for more details. - only available when there's a YM2151 and/or VERA. - **export command stream...**: export song data to a command stream file. see next section for more details. - this option is for developers. @@ -48,7 +48,7 @@ items in _italics_ don't appear in basic mode and are only available in advanced - _**remove chip...**_: remove a chip. - **Preserve channel positions**: same thing as above. -- **restore backup**: restore a previously saved backup. +- **restore backup**: restores a previously saved backup. - Furnace keeps up to 5 backups of a song. - the backup directory is located in: - Windows: `%USERPROFILE%\AppData\Roaming\furnace\backups` @@ -87,8 +87,8 @@ the following settings exist: - other versions may not support all chips. - use this option if you need to export for a quirky player or parser. - for example, RYMCast is picky with format versions. if you're going to use this player, select 1.60. -- **loop**: writes loop. if disabled, the resulting file won't loop. -- **loop trail**: this option allows you to set how much of the song is written after it loops. +- **loop**: includes loop information. if disabled, the resulting file won't loop. +- **loop trail**: sets how much of the song is written after it loops. - the reason this exists is to work around a VGM format limitation in where post-loop state isn't recorded at all. - this may change the song length as it appears on a player. - **auto-detect**: detect how much to write automatically. @@ -137,6 +137,8 @@ it's not really useful, unless you're a developer and want to use a command stre # edit +- **...**: does nothing except prevent accidental clicks on later menu items. + - **undo**: reverts the last action. - **redo**: repeats what you undid previously. diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index 9f5a6cf8..bd5767fc 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -46,7 +46,7 @@ if you need to use more samples, you may change the sample bank using effect `EB due to limitations in some of those sound chips, some restrictions exist: -- Amiga: maximum frequency is 31,469Hz, but anything over 28,867 will sound glitchy on hardware. sample lengths and loop will be set to an even number, and your sample can't be longer than 131070. +- Amiga: maximum frequency is 31469Hz, but anything over 28867 will sound glitchy on hardware. 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. @@ -79,7 +79,8 @@ in there, you can modify certain data pertaining to your sample, such as the: - **Name**: name in sample list. - button to left of **Info**: collapses and expands the info bar. - **Type**: sample format. only 8-bit and 16-bit PCM samples are editable. selecting a format converts the sample data. -- **BRR emphasis**: boosts higher frequencies to compensate for the SNES low-pass filter. should not be enabled for BRR-type samples. +- **BRR emphasis**: boosts higher frequencies to compensate for the SNES low-pass filter. should not be enabled for BRR-type samples. only appears when applicable. +- **8-bit dither**: applies dithering to samples meant to play back at 8-bit resolution. only appears when applicable. - **Rate**: switches to normal rate values. - **Compat Rate**: switches to DefleMask-compatible rate values for sample mapping. diff --git a/doc/8-advanced/comments.md b/doc/8-advanced/comments.md index b36d65ab..3fc14d59 100644 --- a/doc/8-advanced/comments.md +++ b/doc/8-advanced/comments.md @@ -2,7 +2,7 @@ ![comments dialog](comments.png) -Comments, credits, or any arbitrary text may be entered here. +Comments, credits, or any arbitrary text may be entered here.\ It has no effect on the song. There is no word wrap; long lines must be broken manually with the Enter key. \ No newline at end of file From f4c778d90ec857755fa145e579c21e6a716b0379 Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Thu, 24 Aug 2023 23:33:32 -0700 Subject: [PATCH 2/8] A few more small edits. Right-clicking every widget to see what happens.... --- doc/5-wave/README.md | 7 +++++-- doc/6-sample/README.md | 4 ++++ doc/8-advanced/piano.md | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/5-wave/README.md b/doc/5-wave/README.md index 7c586ef7..8b0db521 100644 --- a/doc/5-wave/README.md +++ b/doc/5-wave/README.md @@ -27,8 +27,11 @@ Amiga | ≤256 | 256 | controls across the top line: - waveform number. the `-` and `+` buttons step through the list. -- open. -- save. +- open. opens a file selector to choose the file to open. +- save. opens a file selector to choose the file to save to. + - right-clicking brings up a menu: + - **save as .dmw...**: saves the selected wavetable in DefleMask format. + - **save raw...**: saves the selected wavetable as raw data. - **Steps**: view waveform as discrete blocks. - **Lines**: view waveform as a continuous line. - **Width**: length of the waveform data. maximum is 256. diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index bd5767fc..ccd663c1 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -75,7 +75,11 @@ in there, you can modify certain data pertaining to your sample, such as the: - top-left drop-down box: sample slot. - **Open**: replaces current sample. + - Right-clicking brings up a menu: + - **import raw...**: brings up a file selector, then presents a dialog to choose the format of the selected file. - **Save**: saves current sample to disk. + - Right-clicking brings up a menu: + - **save raw...**: brings up a file selector, then saves the sample as raw data. - **Name**: name in sample list. - button to left of **Info**: collapses and expands the info bar. - **Type**: sample format. only 8-bit and 16-bit PCM samples are editable. selecting a format converts the sample data. diff --git a/doc/8-advanced/piano.md b/doc/8-advanced/piano.md index 6217f847..8a135f6f 100644 --- a/doc/8-advanced/piano.md +++ b/doc/8-advanced/piano.md @@ -29,10 +29,11 @@ Key layout: - **Standard**: Black keys are 2/3 length. - **Continuous**: Black keys are full length. -Value input pad: (document this) +Value input pad: applies to mobile UI only. - **Disabled** - **Replace piano** - **Split (automatic)** - **Split (always visible)** -**Share play/edit offset/range**: (document this) +**Share play/edit offset/range**: If disabled, the piano will keep different octave and range values for playback and non-playback states. +**Read-only (can't input notes): Prevents note entry. \ No newline at end of file From ba25910d482d5b924bed26f946ab6e72a7c14865 Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Sun, 27 Aug 2023 08:55:06 -0700 Subject: [PATCH 3/8] Requested fixes. --- doc/2-interface/asset-list.md | 2 +- doc/2-interface/menu-bar.md | 2 +- doc/8-advanced/piano.md | 6 ------ 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/doc/2-interface/asset-list.md b/doc/2-interface/asset-list.md index 157c934d..7c8340f5 100644 --- a/doc/2-interface/asset-list.md +++ b/doc/2-interface/asset-list.md @@ -3,7 +3,7 @@ ![instruments window](instruments.png) Buttons from left to right: -- **Add**: pops up a menu to select which type of instrument to add. +- **Add**: pops up a menu to select which type of instrument to add. if only one instrument type is available, the menu is skipped. - If the "Display instrument type menu when adding instrument" setting is disabled, this skips the menu and creates an instrument according to the chip under the cursor. - Right-clicking always brings up the menu. - **Duplicate**: Duplicates the currently selected instrument. diff --git a/doc/2-interface/menu-bar.md b/doc/2-interface/menu-bar.md index 1ef63fb9..9b4268cf 100644 --- a/doc/2-interface/menu-bar.md +++ b/doc/2-interface/menu-bar.md @@ -137,7 +137,7 @@ it's not really useful, unless you're a developer and want to use a command stre # edit -- **...**: does nothing except prevent accidental clicks on later menu items. +- **...**: does nothing except prevent accidental clicks on later menu items if the menu is too tall to fit on the program window. - **undo**: reverts the last action. - **redo**: repeats what you undid previously. diff --git a/doc/8-advanced/piano.md b/doc/8-advanced/piano.md index 8a135f6f..4218ef08 100644 --- a/doc/8-advanced/piano.md +++ b/doc/8-advanced/piano.md @@ -29,11 +29,5 @@ Key layout: - **Standard**: Black keys are 2/3 length. - **Continuous**: Black keys are full length. -Value input pad: applies to mobile UI only. -- **Disabled** -- **Replace piano** -- **Split (automatic)** -- **Split (always visible)** - **Share play/edit offset/range**: If disabled, the piano will keep different octave and range values for playback and non-playback states. **Read-only (can't input notes): Prevents note entry. \ No newline at end of file From 17a88fda703ef67c336426f109360ce9d9c32fe3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 27 Aug 2023 15:52:54 -0500 Subject: [PATCH 4/8] C140: update emulator with the one from C219 branch --- CMakeLists.txt | 2 +- src/engine/platform/c140.h | 2 +- .../platform/sound/{c140.c => c140_c219.c} | 210 +++++++++++++++++- .../platform/sound/{c140.h => c140_c219.h} | 41 +++- src/gui/about.cpp | 2 +- src/main.cpp | 2 +- 6 files changed, 245 insertions(+), 14 deletions(-) rename src/engine/platform/sound/{c140.c => c140_c219.c} (53%) rename src/engine/platform/sound/{c140.h => c140_c219.h} (71%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47d7b3f9..63053c78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -507,7 +507,7 @@ src/engine/platform/sound/d65modified.c src/engine/platform/sound/ted-sound.c -src/engine/platform/sound/c140.c +src/engine/platform/sound/c140_c219.c src/engine/platform/oplAInterface.cpp src/engine/platform/ym2608Interface.cpp diff --git a/src/engine/platform/c140.h b/src/engine/platform/c140.h index 1c8ed907..6239c8f5 100644 --- a/src/engine/platform/c140.h +++ b/src/engine/platform/c140.h @@ -21,7 +21,7 @@ #define _C140_H #include "../dispatch.h" -#include "sound/c140.h" +#include "sound/c140_c219.h" #include "../fixedQueue.h" class DivPlatformC140: public DivDispatch { diff --git a/src/engine/platform/sound/c140.c b/src/engine/platform/sound/c140_c219.c similarity index 53% rename from src/engine/platform/sound/c140.c rename to src/engine/platform/sound/c140_c219.c index 9cdc4ecb..4855bd78 100644 --- a/src/engine/platform/sound/c140.c +++ b/src/engine/platform/sound/c140_c219.c @@ -2,7 +2,7 @@ ============================================================================ -MODIFIED Namco C140 sound emulator - MODIFIED VERSION +MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION by cam900 MODIFICATION by tildearrow - adds muting function and fixes overflow @@ -41,7 +41,7 @@ TODO: */ -#include "c140.h" +#include "c140_c219.h" static int c140_max(int a, int b) { return (a > b) ? a : b; } static int c140_min(int a, int b) { return (a < b) ? a : b; } @@ -61,6 +61,18 @@ void c140_tick(struct c140_t *c140, const int cycle) } } +void c219_tick(struct c219_t *c219, const int cycle) +{ + c219->lout = 0; + c219->rout = 0; + for (int i = 0; i < 16; i++) + { + c219_voice_tick(c219, i, cycle); + c219->lout += c219->voice[i].lout; + c219->rout += c219->voice[i].rout; + } +} + void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle) { struct c140_voice_t *voice = &c140->voice[v]; @@ -117,6 +129,84 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle } } +void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle) +{ + struct c140_voice_t *voice = &c219->voice[v]; + if (voice->busy && voice->keyon) + { + for (int c = 0; c < cycle; c++) + { + voice->frac += voice->freq; + if (voice->frac > 0xffff) + { + voice->addr += voice->frac >> 16; + if ((voice->addr >> 1) > voice->end_addr) + { + if (voice->loop) + { + voice->addr = (voice->addr + (voice->loop_addr << 1)) - (voice->end_addr << 1); + } + else + { + voice->keyon = false; + voice->lout = 0; + voice->rout = 0; + return; + } + } + if (voice->noise) + { + c219->lfsr = (c219->lfsr >> 1) ^ ((-(c219->lfsr & 1)) & 0xfff6); + } + voice->frac &= 0xffff; + } + } + if (!voice->muted) + { + signed int sample = 0; + if (voice->noise) + { + sample = (signed int)((signed short)(c219->lfsr)); + } + else + { + // fetch 8 bit sample + signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | voice->addr]; + signed short s2 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | ((voice->addr + 1) & 0x1ffff)]; + if (voice->compressed) + { + s1 = c219->mulaw[s1]; + s2 = c219->mulaw[s2]; + } + else + { + s1 = (signed short)((signed char)(s1) << 8); + s2 = (signed short)((signed char)(s2) << 8); + } + if (voice->inv_sign) + { + s1 = -s1; + s2 = -s2; + } + // interpolate (originally was >>16, but I had to reduce it to 15 to prevent overflow) + sample = s1 + (((voice->frac >> 1) * (s2 - s1)) >> 15); + } + voice->lout = (voice->inv_lout ? (-sample) : sample) * voice->lvol; + voice->rout = sample * voice->rvol; + } + else + { + voice->lout = 0; + voice->rout = 0; + } + } + else + { + voice->lout = 0; + voice->rout = 0; + } +} + void c140_keyon(struct c140_voice_t *c140_voice) { c140_voice->busy = true; @@ -125,6 +215,14 @@ void c140_keyon(struct c140_voice_t *c140_voice) c140_voice->addr = c140_voice->start_addr; } +void c219_keyon(struct c140_voice_t *c140_voice) +{ + c140_voice->busy = true; + c140_voice->keyon = true; + c140_voice->frac = 0; + c140_voice->addr = c140_voice->start_addr << 1; +} + void c140_init(struct c140_t *c140) { // u-law table verified from Wii Virtual Console Arcade Starblade @@ -149,6 +247,41 @@ void c140_init(struct c140_t *c140) } } +void c219_init(struct c219_t *c219) +{ + // u-law table verified from Wii Virtual Console Arcade Knuckle Heads + for (int i = 0; i < 128; i++) + { + signed int compressed_sample = 0; + if (i < 16) + { + compressed_sample = 0x20 * i; + } + else if (i < 24) + { + compressed_sample = (0x200 + (0x40 * i)) - 0x400; + } + else if (i < 48) + { + compressed_sample = (0x400 + (0x80 * i)) - 0xc00; + } + else if (i < 100) + { + compressed_sample = (0x1000 + (0x100 * i)) - 0x3000; + } + else + { + compressed_sample = (0x4400 + (0x200 * i)) - 0xc800; + } + c219->mulaw[i] = compressed_sample; + c219->mulaw[i + 128] = (~compressed_sample) & 0xffe0; + } + for (int i = 0; i < 16; i++) + { + c219->voice[i].muted = false; + } +} + void c140_reset(struct c140_t *c140) { for (int i = 0; i < 24; i++) @@ -171,6 +304,35 @@ void c140_reset(struct c140_t *c140) } } +void c219_reset(struct c219_t *c219) +{ + for (int i = 0; i < 16; i++) + { + c219->voice[i].busy = false; + c219->voice[i].keyon = false; + c219->voice[i].freq = 0; + c219->voice[i].start_addr = 0; + c219->voice[i].loop_addr = 0; + c219->voice[i].end_addr = 0; + c219->voice[i].lvol = 0; + c219->voice[i].rvol = 0; + c219->voice[i].noise = false; + c219->voice[i].inv_lout = false; + c219->voice[i].inv_sign = false; + c219->voice[i].compressed = false; + c219->voice[i].loop = false; + c219->voice[i].addr = 0; + c219->voice[i].frac = 0; + c219->voice[i].lout = 0; + c219->voice[i].rout = 0; + } + c219->lfsr = 0x1234; + for (int i = 0; i < 4; i++) + { + c219->bank[i] = 0; + } +} + void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data) { // voice register @@ -203,3 +365,47 @@ void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned c } // Timer } + +void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data) +{ + // voice register + if (addr < 0x180) + { + struct c140_voice_t *voice = &c219->voice[addr >> 4]; + switch (addr & 0xf) + { + case 0x0: voice->rvol = data; break; + case 0x1: voice->lvol = data; break; + case 0x2: voice->freq = (voice->freq & ~0xff00) | (unsigned int)(data << 8); break; + case 0x3: voice->freq = (voice->freq & ~0x00ff) | data; break; + //case 0x4: break; // Unknown + case 0x5: + voice->compressed = c140_bit(data, 0); + voice->noise = c140_bit(data, 2); + voice->inv_lout = c140_bit(data, 3); + voice->loop = c140_bit(data, 4); + voice->inv_sign = c140_bit(data, 6); + if (data & 0x80) + c219_keyon(voice); + else + voice->busy = false; + break; + case 0x6: voice->start_addr = (voice->start_addr & ~0xff00) | (unsigned int)(data << 8); break; + case 0x7: voice->start_addr = (voice->start_addr & ~0x00ff) | data; break; + case 0x8: voice->end_addr = (voice->end_addr & ~0xff00) | (unsigned int)(data << 8); break; + case 0x9: voice->end_addr = (voice->end_addr & ~0x00ff) | data; break; + case 0xa: voice->loop_addr = (voice->loop_addr & ~0xff00) | (unsigned int)(data << 8); break; + case 0xb: voice->loop_addr = (voice->loop_addr & ~0x00ff) | data; break; + default: break; + } + } + // bank + else if (addr >= 0x1f0) + { + if (addr & 1) + { + const unsigned short bankaddr = (addr >> 1) & 3; + c219->bank[(bankaddr + 1) & 3] = (data & 3); + } + } +} diff --git a/src/engine/platform/sound/c140.h b/src/engine/platform/sound/c140_c219.h similarity index 71% rename from src/engine/platform/sound/c140.h rename to src/engine/platform/sound/c140_c219.h index 21a8b8a4..fb19125a 100644 --- a/src/engine/platform/sound/c140.h +++ b/src/engine/platform/sound/c140_c219.h @@ -2,7 +2,7 @@ ============================================================================ -MODIFIED Namco C140 sound emulator - MODIFIED VERSION +MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION by cam900 MODIFICATION by tildearrow - adds muting function @@ -41,8 +41,8 @@ TODO: */ -#ifndef _C140_EMU_H -#define _C140_EMU_H +#ifndef _C140_C219_EMU_H +#define _C140_C219_EMU_H #include @@ -58,13 +58,16 @@ struct c140_voice_t bool keyon; // key on flag unsigned short freq; // sample frequency unsigned char bank; // sample bank - unsigned short start_addr; // sample start address - unsigned short loop_addr; // sample loop address - unsigned short end_addr; // sample end address + unsigned int start_addr; // sample start address + unsigned int loop_addr; // sample loop address + unsigned int end_addr; // sample end address int lvol, rvol; // left/right volume + bool noise; // noise flag + bool inv_lout; // invert left output flag + bool inv_sign; // invert sign bit flag bool compressed; // compressed sample flag bool loop; // loop flag - unsigned short addr; // sample address + unsigned int addr; // sample address int frac; // frequency counter (.16 fixed point) int lout, rout; // left/right output }; @@ -77,20 +80,42 @@ struct c140_t signed short *sample_mem; }; +struct c219_t +{ + struct c140_voice_t voice[16]; + signed int lout, rout; + signed short mulaw[256]; + unsigned short lfsr; + unsigned char bank[4]; + signed char *sample_mem; +}; + void c140_tick(struct c140_t *c140, const int cycle); +void c219_tick(struct c219_t *c219, const int cycle); + void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle); +void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle); + void c140_keyon(struct c140_voice_t *c140_voice); +void c219_keyon(struct c140_voice_t *c140_voice); + void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data); +void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data); + void c140_init(struct c140_t *c140); +void c219_init(struct c219_t *c219); + void c140_reset(struct c140_t *c140); +void c219_reset(struct c219_t *c219); + #ifdef __cplusplus } // extern "C" #endif -#endif // _C140_EMU_H +#endif // _C140_C219_EMU_H diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 2151f5c6..e1ce1b64 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -199,7 +199,7 @@ const char* aboutLine[]={ "vgsound_emu (second version, modified version) by cam900", "SM8521 emulator (modified version) by cam900", "D65010G031 emulator (modified version) by cam900", - "Namco C140 (modified version) emulator by cam900", + "Namco C140/C219 emulator (modified version) by cam900", "", "greetings to:", "NEOART Costa Rica", diff --git a/src/main.cpp b/src/main.cpp index 2c12678a..dd0cc2bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -210,7 +210,7 @@ TAParamResult pVersion(String) { printf("- ASAP POKEY emulator by Piotr Fusik ported to C++ by laoo (GPLv2)\n"); printf("- SM8521 emulator (modified version) by cam900 (zlib license)\n"); printf("- D65010G031 emulator (modified version) by cam900 (zlib license)\n"); - printf("- C140 emulator (modified version) by cam900 (zlib license)\n"); + printf("- C140/C219 emulator (modified version) by cam900 (zlib license)\n"); return TA_PARAM_QUIT; } From 80961354f7670e8b09b008a0974726127087d72e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 27 Aug 2023 16:20:16 -0500 Subject: [PATCH 5/8] prepare for C219 --- src/engine/platform/c140.cpp | 5 +++++ src/engine/platform/c140.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index ba80284a..d95a3216 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -483,6 +483,11 @@ void DivPlatformC140::renderSamples(int sysID) { sampleMemLen=memPos+256; } +void DivPlatformC219::set219(bool is_219) { + is219=is_219; + totalChans=is219?16:24; +} + void DivPlatformC140::setFlags(const DivConfig& flags) { chipClock=32000*256; // 8.192MHz and 12.288MHz input, verified from Assault Schematics CHECK_CUSTOM_CLOCK; diff --git a/src/engine/platform/c140.h b/src/engine/platform/c140.h index 6239c8f5..bb596ecf 100644 --- a/src/engine/platform/c140.h +++ b/src/engine/platform/c140.h @@ -53,6 +53,8 @@ class DivPlatformC140: public DivDispatch { bool isMuted[24]; unsigned int sampleOff[256]; bool sampleLoaded[256]; + bool is219; + int totalChans; signed short* sampleMem; size_t sampleMemLen; @@ -95,6 +97,7 @@ class DivPlatformC140: public DivDispatch { size_t getSampleMemUsage(int index = 0); bool isSampleLoaded(int index, int sample); void renderSamples(int chipID); + void set219(bool is_219); void setFlags(const DivConfig& flags); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); From 859182bb089a53b0f3e48bc2dfa72a70203e52ab Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 27 Aug 2023 18:46:10 -0500 Subject: [PATCH 6/8] C219: initial work --- papers/format.md | 2 +- papers/newIns.md | 1 + src/engine/dispatchContainer.cpp | 5 + src/engine/engine.h | 4 +- src/engine/instrument.cpp | 4 + src/engine/instrument.h | 1 + src/engine/platform/c140.cpp | 224 ++++++++++++++++++++++--------- src/engine/platform/c140.h | 6 +- src/engine/song.h | 3 +- src/engine/sysDef.cpp | 14 ++ src/gui/furIcons.h | 5 +- src/gui/gui.h | 1 + src/gui/guiConst.cpp | 6 +- 13 files changed, 207 insertions(+), 69 deletions(-) diff --git a/papers/format.md b/papers/format.md index a09579bd..66bec724 100644 --- a/papers/format.md +++ b/papers/format.md @@ -222,7 +222,7 @@ size | description | - 0xcc: K053260 - 4 channels | - 0xcd: TED - 2 channels | - 0xce: Namco C140 - 24 channels - | - 0xcf: Namco C219 - 16 channels (UNAVAILABLE) + | - 0xcf: Namco C219 - 16 channels | - 0xd0: Namco C352 - 32 channels (UNAVAILABLE) | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels diff --git a/papers/newIns.md b/papers/newIns.md index 4ef3be31..27a505c1 100644 --- a/papers/newIns.md +++ b/papers/newIns.md @@ -120,6 +120,7 @@ the following instrument types are available: - 50: K053260 - 52: TED - 53: C140 +- 54: C219 the following feature codes are recognized: diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 49222c39..8ff1a33c 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -587,6 +587,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_C140: dispatch=new DivPlatformC140; + ((DivPlatformC140*)dispatch)->set219(false); + break; + case DIV_SYSTEM_C219: + dispatch=new DivPlatformC140; + ((DivPlatformC140*)dispatch)->set219(true); break; case DIV_SYSTEM_PCM_DAC: dispatch=new DivPlatformPCMDAC; diff --git a/src/engine/engine.h b/src/engine/engine.h index 7fb6b511..8df2652d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -54,9 +54,9 @@ #define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; -//#define DIV_UNSTABLE +#define DIV_UNSTABLE -#define DIV_VERSION "0.6pre9" +#define DIV_VERSION "dev169" #define DIV_ENGINE_VERSION 169 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 842b88fc..28cb99bc 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -967,6 +967,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { featureSM=true; featureSL=true; break; + case DIV_INS_C219: + featureSM=true; + featureSL=true; + break; case DIV_INS_MAX: break; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index cd8c5652..a019198f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -84,6 +84,7 @@ enum DivInstrumentType: unsigned short { // DIV_INS_YMF292=51, DIV_INS_TED=52, DIV_INS_C140=53, + DIV_INS_C219=54, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index d95a3216..05aa963c 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -49,11 +49,40 @@ const char** DivPlatformC140::getRegisterSheet() { return regCheatSheetC140; } -void DivPlatformC140::acquire(short** buf, size_t len) { +void DivPlatformC140::acquire_219(short** buf, size_t len) { for (size_t h=0; h>= 10; + c219.rout >>= 10; + + if (c219.lout<-32768) c219.lout=-32768; + if (c219.lout>32767) c219.lout=32767; + + if (c219.rout<-32768) c219.rout=-32768; + if (c219.rout>32767) c219.rout=32767; + + buf[0][h]=c219.lout; + buf[1][h]=c219.rout; + + for (int i=0; idata[oscBuf[i]->needle++]=(c219.voice[i].lout+c219.voice[i].rout)>>10; + } + } +} + +void DivPlatformC140::acquire_140(short** buf, size_t len) { + for (size_t h=0; hdata[oscBuf[i]->needle++]=(c140.voice[i].lout+c140.voice[i].rout)>>10; } } } +void DivPlatformC140::acquire(short** buf, size_t len) { + if (is219) { + acquire_219(buf,len); + } else { + acquire_140(buf,len); + } +} + void DivPlatformC140::tick(bool sysTick) { - for (int i=0; i<24; i++) { + for (int i=0; icalcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE)); if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; - ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); + if (is219) { + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?1:0); + } else { + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); + } if (chan[i].keyOn) { unsigned int bank=0; unsigned int start=0; unsigned int loop=0; unsigned int end=0; if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - bank=(sampleOff[chan[i].sample]>>16)&0xff; - start=sampleOff[chan[i].sample]&0xffff; - end=MIN(start+s->length8-1,65535); + if (is219) { + bank=(sampleOff[chan[i].sample]>>16)&0xff; + start=sampleOff[chan[i].sample]&0xffff; + end=MIN(start+(s->length8>>1)-1,65535); + logV("sampleOff[%d]=%d",chan[i].sample,sampleOff[chan[i].sample]); + } else { + bank=(sampleOff[chan[i].sample]>>16)&0xff; + start=sampleOff[chan[i].sample]&0xffff; + end=MIN(start+s->length8-1,65535); + } } if (chan[i].audPos>0) { - start=MIN(start+MIN(chan[i].audPos,s->length8),65535); + start=MIN(start+(MIN(chan[i].audPos,s->length8)>>1),65535); } if (s->isLoopable()) { - loop=MIN(start+s->loopStart,65535); - end=MIN(start+s->loopEnd-1,65535); + if (is219) { + loop=MIN(start+(s->loopStart>>1),65535); + end=MIN(start+(s->loopEnd>>1)-1,65535); + } else { + loop=MIN(start+s->loopStart,65535); + end=MIN(start+s->loopEnd-1,65535); + } } rWrite(0x05+(i<<4),0); // force keyoff first - rWrite(0x04+(i<<4),bank); + if (is219) { + // TODO; group banking + + } else { + rWrite(0x04+(i<<4),bank); + } rWrite(0x06+(i<<4),(start>>8)&0xff); rWrite(0x07+(i<<4),start&0xff); rWrite(0x08+(i<<4),(end>>8)&0xff); @@ -323,11 +381,15 @@ int DivPlatformC140::dispatch(DivCommand c) { void DivPlatformC140::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - c140.voice[ch].muted=mute; + if (is219) { + c219.voice[ch].muted=mute; + } else { + c140.voice[ch].muted=mute; + } } void DivPlatformC140::forceIns() { - for (int i=0; i<24; i++) { + for (int i=0; ilength16; - // fit sample size to single bank size - if (length>(131072)) { - length=131072; - } - if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) { - memPos=((memPos+0x1ffff)&0xfe0000); - } - if (memPos>=(getSampleMemCapacity())) { - logW("out of C140 memory for sample %d!",i); - break; - } - // why is C140 not G.711-compliant? this weird bit mangling had me puzzled for 3 hours... - if (memPos+length>=(getSampleMemCapacity())) { - if (s->depth==DIV_SAMPLE_DEPTH_MULAW) { - for (unsigned int i=0; i<(getSampleMemCapacity())-memPos; i++) { - if (i>=s->lengthMuLaw) break; - unsigned char x=s->dataMuLaw[i]^0xff; - if (x&0x80) x^=15; - unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4); - sampleMem[i+(memPos/sizeof(short))]=((c140Mu)<<8); - } - } else { - memcpy(sampleMem+(memPos/sizeof(short)),s->data16,(getSampleMemCapacity())-memPos); + if (is219) { // C219 (8-bit) + unsigned int length=s->length8; + // fit sample size to single bank size + if (length>131072) { + length=131072; + } + if (length&1) length++; + if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) { + memPos=((memPos+0x1ffff)&0xfe0000); + } + if (memPos>=(getSampleMemCapacity())) { + logW("out of C219 memory for sample %d!",i); + break; + } + if (memPos+length>=(getSampleMemCapacity())) { + length=getSampleMemCapacity()-memPos; + logW("out of C219 memory for sample %d!",i); } - logW("out of C140 memory for sample %d!",i); - } else { if (s->depth==DIV_SAMPLE_DEPTH_MULAW) { for (unsigned int i=0; i=s->lengthMuLaw) break; - unsigned char x=s->dataMuLaw[i]^0xff; - if (x&0x80) x^=15; - unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4); - sampleMem[i+(memPos/sizeof(short))]=((c140Mu)<<8); + if (i>=s->lengthMuLaw) { + sampleMem[i+memPos]=0; + } else { + unsigned char x=s->dataMuLaw[i]^0xff; + sampleMem[i+memPos]=x; + } } } else { - memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length); + for (unsigned int i=0; i=s->length8) { + sampleMem[memPos+i]=0; + } else { + sampleMem[memPos+i]=s->data8[i]; + } + } } + sampleOff[i]=memPos>>1; + sampleLoaded[i]=true; + memPos+=length; + } else { // C140 (16-bit) + unsigned int length=s->length16; + // fit sample size to single bank size + if (length>(131072)) { + length=131072; + } + if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) { + memPos=((memPos+0x1ffff)&0xfe0000); + } + if (memPos>=(getSampleMemCapacity())) { + logW("out of C140 memory for sample %d!",i); + break; + } + // why is C140 not G.711-compliant? this weird bit mangling had me puzzled for 3 hours... + if (memPos+length>=(getSampleMemCapacity())) { + length=getSampleMemCapacity()-memPos; + logW("out of C140 memory for sample %d!",i); + } + if (s->depth==DIV_SAMPLE_DEPTH_MULAW) { + for (unsigned int i=0; i>1)>=s->lengthMuLaw) break; + unsigned char x=s->dataMuLaw[i>>1]^0xff; + if (x&0x80) x^=15; + unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4); + sampleMem[i+memPos]=0; + sampleMem[1+i+memPos]=c140Mu; + } + } else { + memcpy(sampleMem+memPos,s->data16,length); + } + sampleOff[i]=memPos>>1; + sampleLoaded[i]=true; + memPos+=length; } - sampleOff[i]=memPos>>1; - sampleLoaded[i]=true; - memPos+=length; } sampleMemLen=memPos+256; } -void DivPlatformC219::set219(bool is_219) { +void DivPlatformC140::set219(bool is_219) { is219=is_219; totalChans=is219?16:24; } @@ -492,7 +589,7 @@ void DivPlatformC140::setFlags(const DivConfig& flags) { chipClock=32000*256; // 8.192MHz and 12.288MHz input, verified from Assault Schematics CHECK_CUSTOM_CLOCK; rate=chipClock/192; - for (int i=0; i<24; i++) { + for (int i=0; irate=rate; } } @@ -502,23 +599,28 @@ int DivPlatformC140::init(DivEngine* p, int channels, int sugRate, const DivConf dumpWrites=false; skipRegisterWrites=false; - for (int i=0; i<24; i++) { + for (int i=0; i>1]; + sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; - c140_init(&c140); - c140.sample_mem=sampleMem; + if (is219) { + c219_init(&c219); + c219.sample_mem=(signed char*)sampleMem; + } else { + c140_init(&c140); + c140.sample_mem=(short*)sampleMem; + } setFlags(flags); reset(); - return 24; + return totalChans; } void DivPlatformC140::quit() { delete[] sampleMem; - for (int i=0; i<24; i++) { + for (int i=0; i writes; struct c140_t c140; + struct c219_t c219; unsigned char regPool[512]; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); + void acquire_219(short** buf, size_t len); + void acquire_140(short** buf, size_t len); + public: void acquire(short** buf, size_t len); int dispatch(DivCommand c); diff --git a/src/engine/song.h b/src/engine/song.h index f0510079..78c49b4e 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -130,7 +130,8 @@ enum DivSystem { DIV_SYSTEM_PV1000, DIV_SYSTEM_K053260, DIV_SYSTEM_TED, - DIV_SYSTEM_C140 + DIV_SYSTEM_C140, + DIV_SYSTEM_C219 }; enum DivEffectType: unsigned short { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 9fc6ab9d..f4273195 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1887,6 +1887,20 @@ void DivEngine::registerSystems() { {} ); + sysDefs[DIV_SYSTEM_C219]=new DivSysDef( + "Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U< Date: Sun, 27 Aug 2023 20:05:08 -0500 Subject: [PATCH 7/8] C219: more updates to-do: - VGM export - presets - noise/invert toggles --- src/engine/platform/c140.cpp | 12 ++++++++---- src/engine/platform/c140.h | 1 + src/engine/sysDef.cpp | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index 05aa963c..34457eee 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -193,10 +193,9 @@ void DivPlatformC140::tick(bool sysTick) { unsigned int end=0; if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { if (is219) { - bank=(sampleOff[chan[i].sample]>>16)&0xff; + bank=(sampleOff[chan[i].sample]>>16)&3; start=sampleOff[chan[i].sample]&0xffff; end=MIN(start+(s->length8>>1)-1,65535); - logV("sampleOff[%d]=%d",chan[i].sample,sampleOff[chan[i].sample]); } else { bank=(sampleOff[chan[i].sample]>>16)&0xff; start=sampleOff[chan[i].sample]&0xffff; @@ -217,8 +216,10 @@ void DivPlatformC140::tick(bool sysTick) { } rWrite(0x05+(i<<4),0); // force keyoff first if (is219) { - // TODO; group banking - + if (groupBank[i>>2]!=bank) { + groupBank[i>>2]=bank; + } + rWrite(0x1f1+(((3+(i>>2))&3)<<1),groupBank[i>>2]); } else { rWrite(0x04+(i<<4),bank); } @@ -427,6 +428,9 @@ void DivPlatformC140::reset() { chan[i].std.setEngine(parent); rWrite(0x05+(i<<4),0); } + for (int i=0; i<4; i++) { + groupBank[i]=0; + } } int DivPlatformC140::getOutputCount() { diff --git a/src/engine/platform/c140.h b/src/engine/platform/c140.h index 3fcb881f..d5c29fea 100644 --- a/src/engine/platform/c140.h +++ b/src/engine/platform/c140.h @@ -55,6 +55,7 @@ class DivPlatformC140: public DivDispatch { bool sampleLoaded[256]; bool is219; int totalChans; + unsigned char groupBank[4]; unsigned char* sampleMem; size_t sampleMemLen; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index f4273195..e0631177 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1891,7 +1891,7 @@ void DivEngine::registerSystems() { "Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U< Date: Sun, 27 Aug 2023 23:04:32 -0500 Subject: [PATCH 8/8] C219: more updates --- src/engine/platform/c140.cpp | 25 ++++++++++++++++++++++--- src/engine/platform/c140.h | 5 ++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index 34457eee..ba2b5d33 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -45,8 +45,27 @@ const char* regCheatSheetC140[]={ NULL }; +const char* regCheatSheetC219[]={ + "CHx_RVol", "00+x*10", + "CHx_LVol", "01+x*10", + "CHx_FreqH", "02+x*10", + "CHx_FreqL", "03+x*10", + "CHx_Ctrl", "05+x*10", + "CHx_StartH", "06+x*10", + "CHx_StartL", "07+x*10", + "CHx_EndH", "08+x*10", + "CHx_EndL", "09+x*10", + "CHx_LoopH", "0A+x*10", + "CHx_LoopL", "0B+x*10", + "BankA", "1F7", + "BankB", "1F1", + "BankC", "1F3", + "BankD", "1F5", + NULL +}; + const char** DivPlatformC140::getRegisterSheet() { - return regCheatSheetC140; + return is219?regCheatSheetC219:regCheatSheetC140; } void DivPlatformC140::acquire_219(short** buf, size_t len) { @@ -182,7 +201,7 @@ void DivPlatformC140::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; if (is219) { - ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?1:0); + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?1:0)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4:0); } else { ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); } @@ -481,7 +500,7 @@ const void* DivPlatformC140::getSampleMem(int index) { } size_t DivPlatformC140::getSampleMemCapacity(int index) { - return index == 0 ? 16777216 : 0; + return index == 0 ? (is219?524288:16777216) : 0; } size_t DivPlatformC140::getSampleMemUsage(int index) { diff --git a/src/engine/platform/c140.h b/src/engine/platform/c140.h index d5c29fea..01802de8 100644 --- a/src/engine/platform/c140.h +++ b/src/engine/platform/c140.h @@ -28,7 +28,7 @@ class DivPlatformC140: public DivDispatch { struct Channel: public SharedChannel { unsigned int audPos; int sample, wave; - bool setPos, volChangedL, volChangedR; + bool setPos, invert, surround, noise, volChangedL, volChangedR; int chPanL, chPanR; int chVolL, chVolR; int macroVolMul; @@ -39,6 +39,9 @@ class DivPlatformC140: public DivDispatch { sample(-1), wave(-1), setPos(false), + invert(false), + surround(false), + noise(false), volChangedL(false), volChangedR(false), chPanL(255),