Merge branch 'master' of https://github.com/tildearrow/furnace into k053260

This commit is contained in:
cam900 2023-07-06 20:00:20 +09:00
commit ac8db58cbf
127 changed files with 2967 additions and 1338 deletions

View file

@ -455,6 +455,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/c64_d/dsid.c
src/engine/platform/sound/tia/AudioChannel.cpp
src/engine/platform/sound/tia/Audio.cpp
@ -861,7 +863,7 @@ endif()
string(REPLACE ";" " " WARNING_FLAGS_STRING "${WARNING_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_STRING}")
if (WARNINGS_ARE_ERRORS)
message(WARNING
message(STATUS
"Treating all warnings in furnace's C++ code as errors! "
"Please report any errors you encounter on the bug tracker."
)

Binary file not shown.

Binary file not shown.

BIN
demos/gameboy/finger.fur Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
demos/x16/keygen19.fur Normal file

Binary file not shown.

View file

@ -12,7 +12,7 @@ Furnace uses hexadecimal (abbreviated as "hex") numbers frequently. see [this gu
## interface
Furnace uses a music tracker interface. think of a table with music notes written on it. then that table scrolls up and plays the notes.
Furnace uses a music tracker interface. think of a table with music notes written on it. then that table scrolls up and plays the notes. even experienced tracker musicians might benefit from a quick review of [tracker concepts and terms](concepts.md) before using Furnace.
due to its nature of being feature-packed, it may be technical and somewhat difficult to get around. therefore we added a basic mode, which hides several advanced features.

36
doc/1-intro/concepts.md Normal file
View file

@ -0,0 +1,36 @@
# concepts and terms
- A **module** is a file for a tracker that contains at least one **song**.
- Each Furnace module involves at least one **[chip](../7-systems/README.md)**, an emulation of a specific audio processor.
## tracking
The **[pattern view](../3-pattern/README.md)** is like a spreadsheet that displays the following:
- Each labeled column represents a **channel** of sound provided by the chips in use.
- Each **note** starts a sound playing. Within a channel, only one note can play at a time.
- Each note is assigned an **[instrument](../4-instrument/README.md)** which describes what it will sound like.
- An **effect** is a command that changes some aspect of playback. It can alter note pitch, volume, timing, and more.
- An instrument **macro** is an automated sequence of effects that applies to every note of that instrument.
## 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.
- Each channel has its own unique list of patterns.
- 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.
## 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 **[wavetables](../5-wave/README.md)**, which are like very short samples of fixed length that automatically loop.

View file

@ -1,6 +1,6 @@
# basic mode
Furnace comes with a "basic mode" that can be toggled through the "settings" menu. it disables certain features in Furnace that may look intimidating or confusing for newcomers. if you find that a certain feature of furnace is missing, see if this setting is enabled or not.
Furnace comes with a "basic mode" that can be toggled through the "settings" menu. it disables certain features in Furnace that may look intimidating or confusing for newcomers. if you find that a certain feature of Furnace is missing, see if this setting is enabled or not.
among the features that cannot be accessed in this mode are:
* file menu:

View file

@ -11,7 +11,7 @@ All of this metadata will be included in a VGM export. This isn't the case for a
# subsongs
This window allows one to create **subsongs** multiple individual songs within a single file. Each song has its own order list and patterns, but all songs within a file share the same chips, samples, and so forth.
This window allows one to create **subsongs** - multiple individual songs within a single file. Each song has its own order list and patterns, but all songs within a file share the same chips, samples, and so forth.
- The drop-down box selects the current subsong.
- The **`+`** button adds a new subsong.

View file

@ -1,78 +1,98 @@
# effect list
most of the effect numbers are from ProTracker / FastTracker 2.
however, effects are continuous, which means you only need to type it once and then stop it with an effect value of `00`.
- **`00xy`**: arpeggio. after using this effect the channel will rapidly switch between `note`, `note+x` and `note+y`.
- **`01xx`**: slide up.
- **`02xx`**: slide down.
- **`03xx`**: note portamento.
- a note must be present for this effect to work.
- **`04xy`**: vibrato. `x` is the speed, while `y` is the depth.
- maximum vibrato depth is ±1 semitone.
- **`07xy`**: tremolo. `x` is the speed, while `y` is the depth.
- maximum tremolo depth is -60 volume steps.
- **`08xy`**: set panning. `x` is the left channel and `y` is the right one.
- not all chips support this effect.
- **`80xx`**: set panning (linear). this effect behaves more like other trackers:
however, effects are continuous, which means you only need to type it once and then stop it with an effect value of `00` or no effect value at all.
## volume
- `0Axy`: **Volume slide.**
- If `x` is 0 then this is a slide down.
- If `y` is 0 then this is a slide up.
- `F8xx`: **Single tick volume slide up.**
- `F9xx`: **Single tick volume slide down.**
- `F3xx`: **Fine volume slide up.** 64× slower than `0Axy`.
- `F4xx`: **Fine volume slide down.** 64× slower than `0Axy`.
- `FAxy`: **Fast volume slide.** 4× faster than `0Axy`.
- If `x` is 0 then this is a slide down.
- If `y` is 0 then this is a slide up.
- `07xy`: **Tremolo.** changes volume to be "wavy" with a sine LFO. `x` is the speed, while `y` is the depth.
- Tremolo is downward only.
- Maximum tremolo depth is -60 volume steps.
## pitch
- `E5xx`: **Set pitch.** `00` is -1 semitone, `80` is base pitch, `FF` is nearly +1 semitone.
- `01xx`: **Pitch slide up.**
- `02xx`: **Pitch slide down.**
- `F1xx`: **Single tick pitch slide up.**
- `F2xx`: **Single tick pitch slide down.**
- `03xx`: **Portamento.** slides the current note's pitch to the specified note.
- A note _must_ be present for this effect to work.
- `E1xy`: **Note slide up.** `x` is the speed, while `y` is how many semitones to slide up.
- `E2xy`: **Note slide down.** `x` is the speed, while `y` is how many semitones to slide down.
- `EAxx`: **Toggle legato.** while on, notes instantly change the pitch of the currrently playing sound instead of starting it over.
- `00xy`: **Arpeggio.** after using this effect the channel will rapidly switch between semitone values of `note`, `note + x` and `note + y`.
- `E0xx`: **Set arpeggio speed.** this sets the number of ticks between arpeggio values.
- `04xy`: **Vibrato.** changes pitch to be "wavy" with a sine LFO. `x` is the speed, while `y` is the depth.
- Maximum vibrato depth is ±1 semitone.
- `E3xx`: **Set vibrato direction.** `xx` may be one of the following:
- `00`: Up and down.
- `01`: Up only.
- `02`: Down only.
- `E4xx`: **Set vibrato range** in 1/16th of a semitone.
## panning
not all chips support these effects.
- `08xy`: **Set panning.** changes stereo volumes independently. `x` is the left channel and `y` is the right one.
- `88xy`: **Set rear panning.** changes rear channel volumes independently. `x` is the rear left channel and `y` is the rear right one.
- `80xx`: **Set panning (linear).** this effect behaves more like other trackers:
- `00` is left.
- `80` is center.
- `FF` is right.
- not all chips support this effect.
- **`81xx`**: set volume of left channel (from `00` to `FF`).
- not all chips support this effect.
- **`82xx`**: set volume of right channel (from `00` to `FF`).
- not all chips support this effect.
- **`09xx`**: set speed 1.
- **`0Axy`**: volume slide.
- if `x` is 0 then this is a slide down.
- if `y` is 0 then this is a slide up.
- **`0Bxx`**: jump to pattern.
- **`0Cxx`**: retrigger note every `xx` ticks.
- this effect is not continuous.
- **`0Dxx`**: jump to next pattern.
- **`0Fxx`**: set speed 2.
- `81xx`: **Set volume of left channel** (from `00` to `FF`).
- `82xx`: **Set volume of right channel** (from `00` to `FF`).
- `89xx`: **Set volume of rear left channel** (from `00` to `FF`).
- `8Axx`: **Set volume of rear right channel** (from `00` to `FF`).
- **`9xxx`**: set sample position to `xxx`\*0x100.
- not all chips support this effect.
## time
- **`Cxxx`**: change song Hz.
- `09xx`: **Set speed/groove.** if no grooves are defined, this sets speed. If alternating speeds are active, this sets the first speed.
- `0Fxx`: **Set speed 2.** during alternating speeds or a groove, this sets the second speed.
- `Cxxx`: **Set tick rate.** changes tick rate to `xxx` Hz (ticks per second).
- `xxx` may be from `000` to `3ff`.
- `F0xx`: **Set BPM.** changes tick rate according to beats per minute.
- **`E0xx`**: set arpeggio tick.
- this sets the number of ticks between arpeggio values.
- **`E1xy`**: note slide up. `x` is the speed, while `y` is how many semitones to slide up.
- **`E2xy`**: note slide down. `x` is the speed, while `y` is how many semitones to slide down.
- **`E3xx`**: set vibrato direction. `xx` may be one of the following:
- `00`: up and down.
- `01`: up only.
- `02`: down only.
- **`E4xx`**: set vibrato range in 1/16th of a semitone.
- **`E5xx`**: set pitch. `80` is 0 cents.
- range is ±1 semitone.
- **`EAxx`**: toggle legato.
- **`EBxx`**: set sample bank.
- does not apply on Amiga.
- **`ECxx`**: note off after `xx` ticks.
- **`EDxx`**: delay note by `xx` ticks.
- **`EExx`**: send external command.
- this effect is currently incomplete.
- **`F0xx`**: change song Hz by BPM value.
- **`F1xx`**: single tick slide up.
- **`F2xx`**: single tick slide down.
- **`F3xx`**: fine volume slide up (64x slower than `0Axy`).
- **`F4xx`**: fine volume slide down (64x slower than `0Axy`).
- **`F5xx`**: disable macro.
- see macro table at the end of this document for possible values.
- **`F6xx`**: enable macro.
- **`F8xx`**: single tick volume slide up.
- **`F9xx`**: single tick volume slide down.
- **`FAxy`**: fast volume slide (4x faster than `0Axy`).
- if `x` is 0 then this is a slide down.
- if `y` is 0 then this is a slide up.
- **`FFxx`**: end of song/stop playback.
- `0Bxx`: **Jump to order.** this can be used to loop a song.
- `0Dxx`: **Jump to next pattern.** this can be used to shorten the current order.
- `FFxx`: **Stop song.** stops playback and ends the song.
additionally each chip has its own effects. [click here for more details](../7-systems/README.md).
## note
- `0Cxx`: **Retrigger.** repeats current note every `xx` ticks.
- This effect is not continuous; it must be entered on every row.
- `ECxx`: **Note cut.** ends current note after `xx` ticks. For FM instruments, it's equivalent to a "key off".
- `EDxx`: **Note delay.** delays note by `x` ticks.
## other
- `9xxx`: **Set sample position.** jumps current sample to position `xxx \* 0x100`.
- Not all chips support this effect.
- `EBxx`: **Set sample bank.**
- Does not apply on Amiga.
- `EExx`: **Send external command.**
- This effect is currently incomplete.
- `F5xx`: **Disable macro.** see macro table at the end of this document for possible values.
- `F6xx`: **Enable macro.**
additionally, [each chip has its own effects](../7-systems/README.md).
## macro table
@ -98,8 +118,8 @@ ID | macro
11 | extra 6
12 | extra 7
13 | extra 8
---|-----------------------------
20 | **operator 1 macros** - AM
| | **operator 1 macros**
20 | AM
21 | AR
22 | DR
23 | MULT
@ -119,10 +139,9 @@ ID | macro
31 | VIB
32 | WS
33 | KSR
---|-----------------------------
40 | operator 2 macros
60 | operator 3 macros
80 | operator 4 macros
40 | **operator 2 macros**
60 | **operator 3 macros**
80 | **operator 4 macros**
the interpretation of duty, wave and extra macros depends on chip/instrument type:

View file

@ -10,7 +10,7 @@ double-click to open the instrument editor.
every instrument can be renamed and have its type changed.
depending on the instrument type, there are currently 13 different types of an instrument editor:
depending on the instrument type, there are many different types of instrument editor:
- [FM synthesis](fm.md) - for use with YM2612, YM2151 and FM block portion of YM2610.
- [Standard](standard.md) - for use with NES and Sega Master System's PSG sound source and its derivatives.
@ -29,7 +29,8 @@ depending on the instrument type, there are currently 13 different types of an i
- [Konami SCC / Bubble System WSG](scc.md) - for use with Konami SCC and Wavetable portion in Bubble System's sound hardware.
- [Namco 163](n163.md) - for use with Namco 163.
- [Konami VRC6](vrc6.md) - for use with VRC6's PSG sound source.
- [SNES](snes.md) - for use with SNES S-APU.
- [Casio PV-1000](pv1000.md) - for use with Casio PV-1000.
# macros
@ -52,9 +53,9 @@ Each macro has two buttons on the left.
Every macro can be defined though one of three methods, selectable with the leftmost button under the macro type label:
- ![](macro-button-seq.png) **Sequence:** Displayed as a bar graph, this is a sequence of numeric values.
- ![](macro-button-ADSR.png) **ADSR:** This is a traditional ADSR envelope, defined by the rate of increase and decrease of value over time.
- ![](macro-button-LFO.png) **LFO:** The Low Frequency Oscillator generates a repeating wave of values.
- ![](macro-button-seq.png) **Sequence:** displayed as a bar graph, this is a sequence of numeric values.
- ![](macro-button-ADSR.png) **ADSR:** this is a traditional ADSR envelope, defined by the rate of increase and decrease of value over time.
- ![](macro-button-LFO.png) **LFO:** the Low Frequency Oscillator generates a repeating wave of values.
Some macros are "bitmap" style. They represent a number of "bits" that can be toggled individually, and the values listed represent the sum of which bits are turned on.
@ -94,6 +95,19 @@ Finally, the sequence of values can be directly edited in the text box at the bo
![LFO macro editor](macro-LFO.png)
- **Bottom** and **Top** determine the range of values generated by the macro. (Bottom can be larger than Top to invert the waveform!)
- **Speed** is how quickly the values change the frequency of the oscillator.
- **Speed** is how quickly the values change - the frequency of the oscillator.
- **Phase** is which part of the waveform the macro will start at, measured in 1/1024 increments.
- **Shape** is the waveform used. Triangle is the default, and Saw and Square are exactly as they say.
# samples
This tab appears for Generic PCM, SNES, Amiga, and other sample-based instruments.
![](sample-map.png)
- **Initial Sample**: the sample that the instrument will use.
- **Use wavetable**: instead of samples, use wavetables. this causes the [Wavetables](../5-wave/README.md) tab to appear next to Sample.
- depending on the system and use of the wavetable synthesizer, this may or may not be reproducible on hardware.
- **Use sample map**: assigns a sample to each note.
- samples will be played at their default pitch.
- to set a note's sample, click the list entry in the `#` column then type the number of the sample.

View file

@ -8,7 +8,7 @@ The PCM instrument editor consists of a sample selector and several macros:
# Macros
- **Volume**: volume sequence WARNING: it works only on Amiga system, as of version 0.5.5!!
- **Volume**: volume sequence. _warning:_ it works only on Amiga system, as of version 0.5.5!
- **Arpeggio**: pitch sequence
- **Waveform**: sample sequence
- **Panning (left)**: output level for left channel

View file

@ -0,0 +1,7 @@
# PV-1000 instrument editor
The instrument editor for the Casio PV-1000 consists of these macros:
- **Volume**: volume
- **Arpeggio**: pitch in half-steps
- **Pitch**: fine pitch

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

46
doc/4-instrument/snes.md Normal file
View file

@ -0,0 +1,46 @@
# SNES instrument editor
these tabs are unique to the editor for SNES instruments.
# SNES
**Use envelope** enables the ADSR volume envelope. if it's on:
- **A**: attack rate.
- **D**: decay rate.
- **S**: sustain level.
- **D2**: decay rate during sustain.
- **R**: release rate.
- **Sustain/release mode**:
- **Direct**: note release acts as note cut.
- **Effective (linear decrease)**: after release, volume lowers by subtractions of 1/64 steps.
- **Effective (exponential decrease)**: after release, volume decays exponentially. see [gain chart](../7-systems/snes.md).
- **Delayed (write R on release)**: after release, waits until A and D have completed before starting exponential decrease.
if envelope is off, select gain mode as described below.
# Macros
- **Volume**: volume.
- **Arpeggio**: pitch in half-steps.
- **Noise Freq**: preset frequency of noise generator.
- **Waveform**: waveform.
- **Panning (left)**: output level of left channel.
- **Panning (right)**: output level of right channel.
- **Pitch**: fine pitch.
- **Special**: bitmap of flags.
- invert left: inverts output of left channel.
- invert right: inverts output of right channel.
- pitch mod: modulates pitch using previous channel's output.
- echo: enables echo.
- noise: enables noise generator.
- **Gain**: sets mode and value of gain.
- 0 - 127: direct gain from 0 to 127
- 128 - 159: linear gain from -0 to -31
- 160 - 191: exponential gain from -0 to -31
- 192 - 223: linear gain from +0 to +31
- 224 - 255: exponential gain from +0 to +31

View file

@ -1,11 +1,11 @@
# X1-010 instrument editor
X1-010 instrument editor consists of 7 macros.
X1-010 instrument editor consists of these macros.
- **Volume**: volume levels sequence
- **Arpeggio**: pitch sequence
- **Waveform**: spicifies wavetables sequence
- **Waveform**: specifies wavetables sequence
- **Envelope Mode**: allows shaping an envelope
- **Envelope**: spicifies envelope shape sequence, it's also wavetable.
- **Envelope**: specifies envelope shape sequence, it's also wavetable.
- **Auto envelope numerator**: sets the envelope to the channel's frequency multiplied by numerator
- **Auto envelope denominator**: sets the envelope to the channel's frequency divided by denominator

View file

@ -11,7 +11,7 @@ Furnace's wavetable editor features multiple ways of creating desired waveform s
- **Exponent**: Powers the waveform in the mathematical sense of the word (^2, ^3 and so on)
- **XOR Point**: Determines the point where the waveform gets negated.
- _TODO:_ amplitude/phase part
- **FM** For creating the waveform with frequency modulation synthesis principles: One can set carrier/modulation levels, frquency multiplier, connection between operators and FM waveforms of these operators.
- **FM** for creating the waveform with frequency modulation synthesis principles: One can set carrier/modulation levels, frquency multiplier, connection between operators and FM waveforms of these operators.
- **WaveTools**: Allows user to fine-tune the waveform: scale said waveform in both X and Y axes, smoothen, amplify, normalize, convert to signed/unisgned, invert or even randomize the wavetable.
## wavetable synthesizer

View file

@ -6,7 +6,7 @@ In Furnace, these samples can be generated by importing a .wav (think of it as a
## supported chips
as of Furnace 0.6, the following sound chips have sample support:
the following sound chips have sample support:
- NES/Ricoh 2A03 (with DPCM support and only on channel 5)
- Sega Genesis/YM2612 (channel 6 only)
@ -32,6 +32,7 @@ as of Furnace 0.6, the following sound chips have sample support:
- Ensoniq OTTO/ES5506
- Yamaha PCMD8/YMZ280B
- MMC5 (last channel only)
- SNES/S-DSP
## compatible sample mode
@ -61,12 +62,77 @@ furthermore, many of these chips have a limited amount of sample memory. check m
# the sample editor
You can actually tweak your samples in Furnace's sample editor, which can be accessed by clicking on `window` (at the top of the screen) then clicking on `sample editor`.
you can actually tweak your samples in Furnace's sample editor, which can be accessed by clicking on `window` (at the top of the screen) then clicking on `sample editor`.
In there, you can modify certain data pertaining to your sample, such as the:
the changes you make will be applied as soon as you've committed them to your sample, but they can be undone and redone, just like text.
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.
- 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 undone and redoed, just like text.
![sample editor](sample-editor.png)
- top-left drop-down box: sample slot.
- **Open**: replaces current sample.
- **Save**: saves current sample to disk.
- **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.
- **Rate**: switches to normal rate values.
- **Compat Rate**: switches to DefleMask-compatible rate values for sample mapping.
- **Hz**: base frequency of sample played at `C-4`.
- **Note**: note corresponding to Hz.
- **Fine**: fine tuning. ranges from -64 to 63, which maps to -1 to almost +1 semitone.
- **Loop**: enable or disable sample loop. only on supported chips.
- **Mode**: direction of loop. backward and ping pong loops are only natively available on some chips; on others, loop will be automatically unrolled as needed.
- **Start**: start of loop.
- **End**: end of loop.
- **Chips:** set assignment to chips and sample banks.
- sample will only be uploaded to selected chips.
- columns correspond to chips in use.
- rows correspond to sample banks.
![sample editor button bar](sample-editor-buttons.png)
- **Edit mode: Select**: cursor selects portion of sample.
- **Edit mode: Draw**: cursor draws over wave.
- **Resize**: stretches sample. pops up a dialog to type new length.
- **Resample**: stretches sample. pops up a dialog box:
- **Rate**: new sample rate.
- **0.5x**: halves sample rate.
- **==**: returns to original sample rate.
- **2.0x**: doubles sample rate.
- **Factor**: multiplier of original sample rate.
- **Filter**: selects interpolation filter for resampling.
- **Undo**: undoes previous edit.
- **Redo**: redoes undone edit.
- **Amplify**: changes amplitude of selection. pops up a dialog to type amount.
- **Normalize**: adjusts amplitude of selection to maximum without clipping.
- **Fade in**: ramp amplitude of selection from 0 to original.
- **Fade in**: ramp amplitude of selection from original to 0.
- **Insert silence**: inserts silence. pops up a dialog to type length.
- **Apply silence**: reduces amplitude of selection to 0.
- **Delete**: removes selection.
- **Trim**: removes all but selection.
- **Reverse**: reverses direction of selection.
- **Invert**: flips selection "vertically".
- **Signed/unsigned exchange**: reinterprets selection data as being of the opposite sign. if a sample sounds fine elsewhere but is distorted on import, it may have been interpreted as signed when it should be unsigned, or vice versa; this will correct that.
- **Apply filter**: filters the selection. pops up a dialog box:
- **From**: filter cutoff frequency at start of selection.
- **To**: filter cutoff frequency at end of selection.
- **Resonance**: emphasizes frequencies around filter cutoff.
- **Power**: number of times resonance is applied.
- **Low-pass**: amount to attenuate everything above cutoff.
- **Band-pass**: amount to attenuate everything outside cutoff.
- **High-pass**: amount to attenuate everything below cutoff.
- **Preview sample**: plays sample at base frequency.
- **Stop sample preview**: stops preview.
- **Create instrument from sample**: creates a new instrument with its initial sample set to the current sample.
- **Zoom**: shows and sets sample view zoom level.
- **Zoom mode**: switches between "Auto" (entire sample fits in window) and "100%" (each horizontal pixel represents one sample point).

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View file

@ -6,6 +6,7 @@ this is a list of sound chips that Furnace supports, including effects.
- [AY-3-8910](ay8910.md)
- [Microchip AY8930](ay8930.md)
- [Bubble System WSG](bubblesystem.md)
- [Casio PV-1000](pv1000.md)
- [Commodore 64](c64.md)
- [Commodore PET](pet.md)
- [Commodore VIC-20](vic20.md)

View file

@ -4,12 +4,14 @@ a computer with a desktop OS, lifelike graphics and 4 channels of PCM sound in 1
in this very computer music trackers were born...
imported MOD files use this chip, and will set A-4 tuning to 436.
# effects
- **`10xx`**: toggle low-pass filter. `0` turns it off and `1` turns it on.
- **`11xx`**: toggle amplitude modulation with the next channel.
- `10xx`: **toggle low-pass filter.** `0` turns it off and `1` turns it on.
- `11xx`: **toggle amplitude modulation with the next channel.**
- does not work on the last channel.
- **`12xx`**: toggle period (frequency) modulation with the next channel.
- `12xx`: **toggle period (frequency) modulation with the next channel.**
- does not work on the last channel.
- **`13xx`**: change wave.
- `13xx`: **change wave.**
- only works when "Mode" is set to "Wavetable" in the instrument.

View file

@ -8,39 +8,39 @@ the AY-3-8914 variant was used in Intellivision, which is pretty much an AY with
# effects
- **`20xx`**: set channel mode. `xx` may be one of the following:
- `00`: square
- `01`: noise
- `02`: square and noise
- `03`: envelope
- `04`: envelope and square
- `05`: envelope and noise
- `06`: envelope and square and noise
- `07`: nothing
- **`21xx`**: set noise frequency. `xx` is a value between 00 and 1F.
- **`22xy`**: set envelope mode.
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- `20xx`: **set channel mode.**
- `0`: square
- `1`: noise
- `2`: square and noise
- `3`: envelope
- `4`: envelope and square
- `5`: envelope and noise
- `6`: envelope and square and noise
- `7`: nothing
- `21xx`: **set noise frequency.** range is `0` to `1F`.
- `22xy`: **set envelope mode.**
- `x` sets the envelope shape:
- `0`: `\___` decay
- `4`: `/___` attack once
- `8`: `\\\\` saw
- `9`: `\___` decay
- `A`: `\/\/` inverse obelisco
- `B`: `\¯¯¯` decay once
- `C`: `////` inverse saw
- `D`: `/¯¯¯` attack
- `E`: `/\/\` obelisco
- `F`: `/___` attack once
- if `y` is 1 then the envelope will affect this channel.
- **`23xx`**: set envelope period low byte.
- **`24xx`**: set envelope period high byte.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`29xy`**: enable auto-envelope mode.
- `23xx`: **set envelope period low byte.**
- `24xx`: **set envelope period high byte.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `29xy`: **enable auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.
- **`2Exx`**: write to I/O port A.
- `2Exx`: **write to I/O port A.**
- this changes the port's mode to "write". make sure you have connected something to it.
- **`2Fxx`**: write to I/O port B.
- `2Fxx`: **write to I/O port B.**
- this changes the port's mode to "write". make sure you have connected something to it.

View file

@ -3,52 +3,52 @@
a backwards-compatible successor to the AY-3-8910, with increased volume resolution, duty cycle control, three envelopes and highly configurable noise generator.
sadly, this soundchip has only ever observed minimal success, and has remained rather obscure since.
it is best known for being used in the Covox Sound Master, which didn't sell well either. It also observed very minimal success in Merit's CRT-250 machines, but only as a replacement for the AY-3-8910.
it is best known for being used in the Covox Sound Master, which didn't sell well either. it also observed very minimal success in Merit's CRT-250 machines, but only as a replacement for the AY-3-8910.
emulation of this chip in Furnace is now complete thanks to community efforts and hardware testing, which an MSX board called Darky has permitted.
# effects
- **`12xx`**: set channel duty cycle. `xx` is a value between 00 and 08.
- `00`: 3.125%
- `01`: 6.25%
- `02`: 12.5%
- `03`: 25%
- `04`: 50%
- `05`: 75%
- `06`: 87.5%
- `07`: 93.75%
- `08`: 96.875%
- **`20xx`**: set channel mode. `xx` may be one of the following:
- `00`: square
- `01`: noise
- `02`: square and noise
- `03`: envelope
- `04`: envelope and square
- `05`: envelope and noise
- `06`: envelope and square and noise
- `07`: nothing
- **`21xx`**: set noise frequency. `xx` is a value between 00 and FF.
- **`22xy`**: set envelope mode.
- `12xx`: **set channel duty cycle.**
- `0`: 3.125%
- `1`: 6.25%
- `2`: 12.5%
- `3`: 25%
- `4`: 50%
- `5`: 75%
- `6`: 87.5%
- `7`: 93.75%
- `8`: 96.875%
- `20xx`: **set channel mode.** `xx` may be one of the following:
- `0`: square
- `1`: noise
- `2`: square and noise
- `3`: envelope
- `4`: envelope and square
- `5`: envelope and noise
- `6`: envelope and square and noise
- `7`: nothing
- `21xx`: **set noise frequency.** `xx` is a value between `00` and `FF`.
- `22xy`: **set envelope mode.**
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- `0`: `\___` decay
- `4`: `/___` attack once
- `8`: `\\\\` saw
- `9`: `\___` decay
- `A`: `\/\/` inverse obelisco
- `B`: `\¯¯¯` decay once
- `C`: `////` inverse saw
- `D`: `/¯¯¯` attack
- `E`: `/\/\` obelisco
- `F`: `/___` attack once
- if `y` is 1 then the envelope will affect this channel.
- **`23xx`**: set envelope period low byte.
- **`24xx`**: set envelope period high byte.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`27xx`**: set noise AND mask.
- **`28xx`**: set noise OR mask.
- **`29xy`**: enable auto-envelope mode.
- `23xx`: **set envelope period low byte.**
- `24xx`: **set envelope period high byte.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `27xx`: **set noise AND mask.**
- `28xx`: **set noise OR mask.**
- `29xy`: **enable auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.

View file

@ -6,8 +6,8 @@ however, the K005289 is just part of the logic used for pitch and wavetable ROM
waveform select and volume control are tied with single AY-3-8910 IO for both channels.
another AY-3-8910 IO is used for reading sound hardware status.
Furnace emulates this configuration as a "chip" with 32x16 wavetables.
Furnace emulates this configuration as a "chip" with 32×16 wavetables.
# effects
- **`10xx`**: change wave.
- `10xx`: **change wave.**

View file

@ -8,7 +8,7 @@ two versions of aforementioned chip exist - 6581 (original chip) and 8580 (impro
# effects
- **`10xx`**: change wave. the following values are accepted:
- `10xx`: **change wave.** the following values are accepted:
- `00`: nothing
- `01`: triangle
- `02`: saw
@ -18,14 +18,14 @@ two versions of aforementioned chip exist - 6581 (original chip) and 8580 (impro
- `06`: pulse and saw
- `07`: pulse and triangle and saw
- `08`: noise
- **`11xx`**: set coarse cutoff. `xx` may be a value between 00 to 64.
- **this effect only exists for compatibility reasons, and its use is discouraged.**
- `11xx`: **set coarse cutoff.** `xx` may be a value between `00` and `64`.
- _this effect only exists for compatibility reasons, and its use is discouraged._
- use effect `4xxx` instead.
- **`12xx`**: set coarse duty cycle. `xx` may be a value between 00 to 64.
- **this effect only exists for compatibility reasons, and its use is discouraged.**
- `12xx`: **set coarse duty cycle.** `xx` may be a value between `00` and `64`.
- _this effect only exists for compatibility reasons, and its use is discouraged._
- use effect `3xxx` instead.
- **`13xx`**: set resonance. `xx` may be a value between 00 and 0F.
- **`14xx`**: set filter mode. the following values are accepted:
- `13xx`: **set resonance.** `xx` may be a value between `00` and `0F`.
- `14xx`: **set filter mode.** the following values are accepted:
- `00`: filter off
- `01`: low pass
- `02`: band pass
@ -34,26 +34,26 @@ two versions of aforementioned chip exist - 6581 (original chip) and 8580 (impro
- `05`: band reject/stop/notch
- `06`: high+band pass
- `07`: all pass
- **`15xx`**: set envelope reset time.
- `15xx`: **set envelope reset time.**
- this is the amount of ticks the channel turns off before a note occurs in order to reset the envelope safely.
- if `xx` is 0 or higher than the song speed, the envelope will not reset.
- **`1Axx`**: disable envelope reset for this channel.
- **`1Bxy`**: reset cutoff:
- `1Axx`: **disable envelope reset for this channel.**
- `1Bxy`: **reset cutoff**:
- if `x` is not 0: on new note
- if `y` is not 0: now
- this effect is not necessary if the instrument's cutoff macro is absolute.
- **`1Cxy`**: reset duty cycle:
- `1Cxy`: **reset duty cycle**:
- if `x` is not 0: on new note
- if `y` is not 0: now
- this effect is not necessary if the instrument's duty macro is absolute.
- **`1Exy`**: change additional parameters.
- `1Exy`: **change additional parameters.**
- `x` may be one of the following:
- `0`: attack (`y` from 0 to F)
- `1`: decay (`y` from 0 to F)
- `2`: sustain (`y` from 0 to F)
- `3`: release (`y` from 0 to F)
- `4`: ring modulation (`y` is 0 or 1)
- `5`: oscillator sync (`y` is 0 or 1)
- `6`: disable channel 3 (`y` is 0 or 1)
- **`3xxx`**: set duty cycle. `xxx` range is 000-FFF
- **`4xxx`**: set cutoff. `xxx` range is 000-7FF.
- `0`: attack (`y` from `0` to `F`)
- `1`: decay (`y` from `0` to `F`)
- `2`: sustain (`y` from `0` to `F`)
- `3`: release (`y` from `0` to `F`)
- `4`: ring modulation (`y` is `0` or `1`)
- `5`: oscillator sync (`y` is `0` or `1`)
- `6`: disable channel 3 (`y` is `0` or `1`)
- `3xxx`: **set duty cycle.** `xxx` range is `000` to `FFF`.
- `4xxx`: **set cutoff.** `xxx` range is `000` to `7FF`.

View file

@ -1,41 +1,41 @@
# Ensoniq ES5506 (OTTO)
Sample-based synthesis chip used in a bunch of Taito arcade machines and PC sound cards like Soundscape Elite. A variant of it was the heart of the well-known Gravis Ultrasound.
sample-based synthesis chip used in a bunch of Taito arcade machines and PC sound cards like Soundscape Elite. a variant of it was the heart of the well-known Gravis Ultrasound.
it supports a whooping 32 channels of 16-bit PCM and:
it supports a whopping 32 channels of 16-bit PCM and:
- Real time digital filters
- Frequency interpolation
- Loop start and stop positions for each voice (bidirectional and reverse looping)
- Internal volume multiplication and stereo panning
- Hardware support for envelopes
- real time digital filters
- frequency interpolation
- loop start and stop positions for each voice (bidirectional and reverse looping)
- internal volume multiplication and stereo panning
- hardware support for envelopes
# effects
- **`10xx`**: set waveform.
- **`11xx`**: set filter mode (0-3)
- **`120x`**: set pause (bit 0). Pauses the sample until the bit is unset, where it will then resume where it left off.
- **`14xx`**: set filter coefficient K1 low byte.
- **`15xx`**: set filter coefficient K1 high byte.
- **`16xx`**: set filter coefficient K2 low byte.
- **`17xx`**: set filter coefficient K2 high byte.
- **`18xx`**: set filter coefficient K1 slide up.
- **`19xx`**: set filter coefficient K1 slide down.
- **`1Axx`**: set filter coefficient K2 slide up.
- **`1Bxx`**: set filter coefficient K2 slide down.
- **`20xx`**: set envelope count.
- **`22xx`**: set envelope left volume ramp.
- **`23xx`**: set envelope right volume ramp.
- **`24xx`**: set envelope filter coefficient K1 ramp.
- **`25xx`**: set envelope filter coefficient K1 ramp (slower).
- **`26xx`**: set envelope filter coefficient K2 ramp.
- **`27xx`**: set envelope filter coefficient K2 ramp (slower).
- **`3xxx`**: set coarse filter coefficient K1.
- **`4xxx`**: set coarse filter coefficient K2.
- **`81xx`**: set panning (left channel).
- **`82xx`**: set panning (right channel).
- **`88xx`**: set panning (rear channels).
- **`89xx`**: set panning (rear left channel).
- **`8Axx`**: set panning (rear right channel).
- **`9xxx`**: set sample offset (x256).
- **`DFxx`**: set sample playback direction.
- `10xx`: **set waveform.**
- `11xx`: **set filter mode.** values are `0` through `3`.
- `120x`: **set pause (bit 0).** pauses the sample until the bit is unset; it will then resume where it left off.
- `14xx`: **set filter coefficient K1 low byte.**
- `15xx`: **set filter coefficient K1 high byte.**
- `16xx`: **set filter coefficient K2 low byte.**
- `17xx`: **set filter coefficient K2 high byte.**
- `18xx`: **set filter coefficient K1 slide up.**
- `19xx`: **set filter coefficient K1 slide down.**
- `1Axx`: **set filter coefficient K2 slide up.**
- `1Bxx`: **set filter coefficient K2 slide down.**
- `20xx`: **set envelope count.**
- `22xx`: **set envelope left volume ramp.**
- `23xx`: **set envelope right volume ramp.**
- `24xx`: **set envelope filter coefficient K1 ramp.**
- `25xx`: **set envelope filter coefficient K1 ramp (slower).**
- `26xx`: **set envelope filter coefficient K2 ramp.**
- `27xx`: **set envelope filter coefficient K2 ramp (slower).**
- `3xxx`: **set coarse filter coefficient K1.**
- `4xxx`: **set coarse filter coefficient K2.**
- `81xx`: **set panning (left channel).**
- `82xx`: **set panning (right channel).**
- `88xx`: **set panning (rear channels).**
- `89xx`: **set panning (rear left channel).**
- `8Axx`: **set panning (rear right channel).**
- `9xxx`: **set sample offset.** resets sample position to `xxx * 0x100`.
- `DFxx`: **set sample playback direction.**

View file

@ -1,20 +1,20 @@
# Famicom Disk System
the Famicom Disk System is an expansion device for the Famicom (known as NES outside Japan), a popular console from the '80's.
the Famicom Disk System is an expansion device for the Famicom (known as NES outside Japan), a popular console from the '80s.
as it name implies, it allowed people to play games on specialized floppy disks that could be rewritten on vending machines, therefore reducing the cost of ownership and manufacturing.
it also offers an additional 6-bit, 64-byte wavetable sound channel with (somewhat limited) FM capabilities, which is what Furnace supports.
# effects
- **`10xx`**: change wave.
- **`11xx`**: set modulation depth.
- **`12xy`**: set modulation speed high byte and toggle on/off.
- `x` is the toggle. a value of 1 turns on the modulator.
- `10xx`: **change wave.**
- `11xx`: **set modulation depth.**
- `12xy`: **set modulation speed high byte and toggle on/off.**
- `x` is the toggle. a value of `1` turns on the modulator.
- `y` is the speed.
- **`13xx`**: set modulation speed low byte.
- **`14xx`**: set modulator position.
- **`15xx`**: set modulator wave.
- `13xx`: **set modulation speed low byte.**
- `14xx`: **set modulator position.**
- `15xx`: **set modulator wave.**
- `xx` points to a wavetable. it should (preferably) have a height of 7 with the values mapping to:
- 0: +0
- 1: +1

View file

@ -6,13 +6,17 @@ with stereo sound, two pulse channels, a wave channel and a noise one it packed
# effects
- **`10xx`**: change wave.
- **`11xx`**: set noise length. `xx` may be one of:
- 0: long
- 1: short
- **`12xx`**: set duty cycle (from 0 to 3).
- **`13xy`**: setup sweep (pulse channels only).
- `10xx`: **change wave.**
- `11xx`: **set noise length.**
- `0`: long
- `1`: short
- `12xx`: **set duty cycle.**
- `0`: 12.5%
- `1`: 25%
- `2`: 50%
- `3`: 75%
- `13xy`: **setup sweep.** pulse channels only.
- `x` is the time.
- `y` is the shift.
- set to 0 to disable it.
- **`14xx`**: set sweep direction. 0 is up and 1 is down.
- set to `0` to disable it.
- `14xx`: **set sweep direction.** `0` is up and `1` is down.

View file

@ -6,32 +6,56 @@ this console is powered by two sound chips: the [Yamaha YM2612](ym2612.md) and [
# effects
- **`10xy`**: set LFO parameters.
- `10xy`: **set LFO parameters.**
- `x` toggles the LFO.
- `y` sets its speed.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`17xx`**: enable PCM channel.
- `17xx`: **enable PCM channel.**
- this only works on channel 6.
- **this effect is there for compatibility reasons** - it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used).
- **`18xx`**: toggle extended channel 3 mode.
- 0 disables it and 1 enables it.
- _this effect is here for compatibility reasons!_ it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used).
- `18xx`: **toggle extended channel 3 mode.**
- `0` disables it and `1` enables it.
- only in extended channel 3 chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`20xy`**: set PSG noise mode.
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `20xy`: **set PSG noise mode.**
- `x` controls whether to inherit frequency from PSG channel 3.
- 0: use one of 3 preset frequencies (C: A-2; C#: A-3; D: A-4).
- 1: use frequency of PSG channel 3.
- `0`: use one of 3 preset frequencies (`C`: A-2; `C#`: A-3; `D`: A-4).
- `1`: use frequency of PSG channel 3.
- `y` controls whether to select noise or thin pulse.
- 0: thin pulse.
- 1: noise.
- `0`: thin pulse.
- `1`: noise.
# system modes
## extended channel 3
in ExtCh mode, channel 3 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds.
all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone.
## CSM
CSM is short for "Composite Sinusoidal Modeling". CSM works by sending key-on and key-off commands to channel 3 at a specific frequency, controlled by the added "CSM Timer" channel. this can be used to create vocal formants (speech synthesis!) or other complex effects.
CSM is beyond the scope of this documentation. for more information, see this [brief SSG-EG and CSM video tutorial](https://www.youtube.com/watch?v=IKOR0TUlnWU).
## DualPCM
DualPCM splits channel 6 into two individual PCM channels. using the console's Z80 processor, these are mixed together in software and streamed to channel 6 in PCM mode. because this generates a stream of data, exported VGM files will be very large.
## Sega CD
this isn't a mode so much as a chip configuration. it adds the [Ricoh RF5C68](ricoh.md) found in the Sega CD add-on, providing 8 channels of PCM.

View file

@ -2,10 +2,10 @@
a 2-channel PCM sound chip from Konami which was used in some of their 1986-1990 arcade boards.
Its sample format is unique; the topmost bit is the end marker, and the low 7 bits are used for generating sound (unsigned format).
its sample format is unique; the topmost bit is the end marker, and the low 7 bits are used for generating sound (unsigned format).
It has 7 bit digital output per each channel and no volume register on chip, so it needs external logic to control channel volume.
it has 7 bit digital output per each channel and no volume register on chip, so it needs external logic to control channel volume.
# effects
- Nothing for now
- nothing for now.

View file

@ -15,6 +15,5 @@ the Atari Lynx has a 6502-based CPU with a sound part (this chip is known as MIK
# effects
- **`3xxx`**: Load LFSR (0 to FFF).
- this is a bitmask.
- `3xxx`: **load LFSR.** this is a bitmask with values ranging from `000` to `FFF`.
- for it to work, duty macro in instrument editor must be set to some value. without it LFSR will not be fed with any bits.

View file

@ -8,5 +8,5 @@ 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.
- `12xx`: **set duty cycle or noise mode of channel.**
- may be `0` through `3` for the pulse channels.

View file

@ -16,11 +16,11 @@ Furnace implements this chip in a way that allows the following features:
# effects
- **`10xy`**: set group control.
- `10xy`: **set group control.**
- `x` sets sustain mode.
- `y` is a 4-bit mask which toggles overtones.
- **`11xx`**: set noise mode.
- **`12xx`**: set group attack (0 to 5).
- `11xx`: **set noise mode.**
- `12xx`: **set group attack.** range is `0` to `5`.
- only in internal (capacitor-based) envelope mode.
- **`13xx`**: set group decay (0 to 11).
- `13xx`: **set group decay.** range is `0` to `11`.
- only in internal (capacitor-based) envelope mode.

View file

@ -1,7 +1,7 @@
# OKI MSM6295
an upgrade from 6258 - it provides 4 ADPCM channels, at max 32 KHz (still no variable pitch though). between late 80s and late 90s, it was one of the most common, if not THE most common soundchip used in arcade machines (Capcom, Toaplan, Kaneko, Atari, Tecmo, the list can go on and on...)
an upgrade from 6258 - it provides 4 ADPCM channels, at max 32 KHz (still no variable pitch though). between late '80s and late '90s, it was one of the most common, if not _the_ most common soundchip used in arcade machines (Capcom, Toaplan, Kaneko, Atari, Tecmo, the list can go on and on...)
# effects
- **`20xx`**: set chip output rate.
- `20xx`: **set chip output rate.**

View file

@ -13,20 +13,29 @@ Furnace supports loading waveforms into RAM and waveform playback simultaneously
you must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes.
both waveform playback and load command work independently per each channel columns.
(Global) commands don't care about the channel columns for work commands and its load behavior is independent with per-channel column load commands.
global commands don't care about the channel columns for work commands and its load behavior is independent with per-channel column load commands.
# effects
- **`10xx`**: set waveform for playback.
- **`11xx`**: set waveform position in RAM for playback (single nibble unit).
- **`12xx`**: set waveform length in RAM for playback (04 to FC, 4 nibble unit).
- **`130x`**: set playback waveform update behavior (0: off, bit 0: update now, bit 1: update when every waveform is changed).
- **`14xx`**: set waveform for load to RAM.
- **`15xx`**: set waveform position for load to RAM (single nibble unit).
- **`16xx`**: set waveform length for load to RAM (04 to FC, 4 nibble unit).
- **`170x`**: set waveform load behavior (0: off, bit 0: load now, bit 1: load when every waveform is changed).
- **`180x`**: set channel limit (0 to 7, x + 1).
- **`20xx`**: (Global) set waveform for load to RAM.
- **`21xx`**: (Global) set waveform position for load to RAM (single nibble unit).
- **`22xx`**: (Global) set waveform length for load to RAM (04 to FC, 4 nibble unit).
- **`230x`**: (Global) set waveform load behavior (0: off, bit 0: load now, bit 1: load when every waveform is changed).
- `10xx`: **set waveform for playback.**
- `11xx`: **set waveform position in RAM for playback.** single nibble unit.
- `12xx`: **set waveform length in RAM for playback.** `04` to `FC`, 4 nibble unit.
- `130x`: **set playback waveform update behavior.**
- `0`: off.
- bit 0: update now.
- bit 1: update when every waveform is changed.
- `14xx`: **set waveform for load to RAM.**
- `15xx`: **set waveform position for load to RAM.** single nibble unit.
- `16xx`: **set waveform length for load to RAM.** `04` to `FC`, 4 nibble unit.
- `170x`: **set waveform load behavior.**
- `0`: off.
- bit 0: load now.
- bit 1: load when every waveform is changed.
- `180x`: **set channel limit.** range is `0` to `7`; 1 is added to get results of 1 through 8.
- `20xx`: **globally set waveform for load to RAM.**
- `21xx`: **globally set waveform position for load to RAM.** single nibble unit.
- `22xx`: **globally set waveform length for load to RAM.** `04` to `FC`, 4 nibble unit.
- `230x`: **globally set waveform load behavior.**
- `0`: off.
- bit 0: load now.
- bit 1: load when every waveform is changed.

View file

@ -6,5 +6,5 @@ everything starts with Namco WSG, which is a simple 3-channel wavetable with no
# effects
- **`10xx`**: change waveform.
- **`11xx`**: toggle noise mode (WARNING: only on C30).
- `10xx`: **change waveform.**
- `11xx`: **toggle noise mode.** _warning:_ only on C30.

View file

@ -6,30 +6,37 @@ also known as Famicom. it is a five-channel sound generator: first two channels
# effects
- **`11xx`**: write to delta modulation counter.
- this may be used to attenuate the triangle and noise channels.
- `11xx`: **write to delta modulation counter.** range is `00` to `7F`.
- this may be used to attenuate the triangle and noise channels; at `7F`, they will be at about 57% volume.
- will not work if a sample is playing.
- **`12xx`**: set duty cycle or noise mode of channel.
- may be 0-3 for the pulse channels and 0-1 for the noise channel.
- **`13xy`**: setup sweep up.
- `12xx`: **set duty cycle or noise mode of channel.**
- may be `0` to `3` for the pulse channels:
- `0`: 12.5%
- `1`: 25%
- `2`: 50%
- `3`: 75%
- may be `0` or `1` for the noise channel:
- `0`: long (15-bit LFSR, 32767-step)
- `1`: short (9-bit LFSR, 93-step)
- `13xy`: **setup sweep up.**
- `x` is the time.
- `y` is the shift.
- set to 0 to disable it.
- **`14xy`**: setup sweep down.
- set to `0` to disable it.
- `14xy`: **setup sweep down.**
- `x` is the time.
- `y` is the shift.
- set to 0 to disable it.
- **`15xx`**: set envelope mode.
- `0`: envelope + length counter (volume represents envelope duration).
- `1`: length counter (volume represents output volume).
- `2`: looping envelope (volume represents envelope duration).
- `3`: constant volume (default; volume represents output volume).
- pulse and noise channels only.
- set to `0` to disable it.
- `15xx`: **set envelope mode.**
- `0`: envelope + length counter. volume represents envelope duration.
- `1`: length counter. volume represents output volume.
- `2`: looping envelope. volume represents envelope duration.
- `3`: constant volume. default value. volume represents output volume.
- Pulse and noise channels only.
- you may need to apply a phase reset (using the macro) to make the envelope effective.
- **`16xx`**: set length counter.
- `16xx`: **set length counter.**
- see table below for possible values.
- this will trigger phase reset.
- **`17xx`**: set frame counter mode.
- `17xx`: **set frame counter mode.**
- `0`: 4-step.
- NTSC: 120Hz sweeps and lengths; 240Hz envelope.
- PAL: 100Hz sweeps and lengths; 200Hz envelope.
@ -38,73 +45,137 @@ also known as Famicom. it is a five-channel sound generator: first two channels
- NTSC: 96Hz sweeps and lengths; 192Hz envelope.
- PAL: 80Hz sweeps and lengths; 160Hz envelope.
- Dendy: 95.1Hz sweeps and lengths; 190.2Hz envelope.
- **`18xx`**: set PCM channel mode.
- `18xx`: **set PCM channel mode.**
- `00`: PCM (software).
- `01`: DPCM (hardware).
- when in DPCM mode, samples will sound muffled (due to its nature), availables pitches are limited and loop point is ignored.
- **`19xx`**: set triangle linear counter.
- when in DPCM mode, samples will sound muffled (due to its nature), availables pitches are limited, and loop point is ignored.
- `19xx`: **set triangle linear counter.**
- `00` to `7F` set the counter.
- `80` and higher halt it.
- **`20xx`**: set DPCM frequency.
- `20xx`: **set DPCM frequency.**
- only works in DPCM mode.
- see table below for possible values.
# DPCM frequency table
# tables
val | NTSC | PAL
----|-----------|-----------
00 | 4181.7Hz | 4177.4Hz
01 | 4709.9Hz | 4696.6Hz
02 | 5264.0Hz | 5261.4Hz
03 | 5593.0Hz | 5579.2Hz
04 | 6257.9Hz | 6023.9Hz
05 | 7046.3Hz | 7044.9Hz
06 | 7919.3Hz | 7917.2Hz
07 | 8363.4Hz | 8397.0Hz
08 | 9419.9Hz | 9446.6Hz
09 | 11186.1Hz | 11233.8Hz
0A | 12604.0Hz | 12595.5Hz
0B | 13982.6Hz | 14089.9Hz
0C | 16884.6Hz | 16965.4Hz
0D | 21306.8Hz | 21315.5Hz
0E | 24858.0Hz | 25191.0Hz
0F | 33143.9Hz | 33252.1Hz
## short noise frequencies (NTSC)
# length counter table
note | arpeggio | fundamental | MIDI note | pitch
:---- | -------: | ----------: | --------: | :----------
`C-0` | @0 | 4.7 Hz | -9.47 | `d_1` + 53¢
`C#0` | @1 | 9.5 Hz | 2.53 | `D-0` + 53¢
`D-0` | @2 | 18.9 Hz | 14.55 | `D-1` + 55¢
`D#0` | @3 | 25.3 Hz | 19.53 | `G-1` + 53¢
`E-0` | @4 | 37.9 Hz | 26.55 | `D-2` + 55¢
`F-0` | @5 | 50.6 Hz | 31.57 | `G-2` + 57¢
`F#0` | @6 | 75.8 Hz | 38.55 | `D-3` + 55¢
`G-0` | @7 | 95.3 Hz | 42.51 | `F#3` + 51¢
`G#0` | @8 | 120.3 Hz | 46.55 | `A#3` + 55¢
`A-0` | @9 | 150.4 Hz | 50.41 | `D-4` + 41¢
`A#0` | @10 | 200.5 Hz | 55.39 | `G-4` + 39¢
`B-0` | @11 | 300.7 Hz | 62.41 | `D-5` + 41¢
`C-1` | @12 | 601.4 Hz | 74.41 | `D-6` + 41¢
`C#1` | @13 | 1202.8 Hz | 86.41 | `D-7` + 41¢
`D-1` | @14 | 2405.6 Hz | 98.41 | `D-8` + 41¢
`D#1` | @15 | 4811.2 Hz | 110.41 | `D-9` + 41¢
val | raw | NTSC | PAL | Dendy | NTSC 5-step | PAL 5-step | Dendy 5-step
----|-----|-------|-------|-------|-------------|------------|--------------
00 | 10 | 83ms | 100ms | 84ms | 104ms | 125ms | 105ms
01 | 254 | 2.1s | 2.5s | 2.1s | 2.6s | 3.2s | 2.7s
02 | 20 | 166ms | 200ms | 168ms | 208ms | 250ms | 210ms
03 | 2 | 17ms | 20ms | 17ms | 21ms | 25ms | 21ms
04 | 40 | 333ms | 400ms | 336ms | 417ms | 500ms | 421ms
05 | 4 | 33ms | 40ms | 34ms | 42ms | 50ms | 42ms
06 | 80 | 667ms | 800ms | 673ms | 833ms | 1.0s | 841ms
07 | 6 | 50ms | 60ms | 50ms | 63ms | 75ms | 63ms
08 | 160 | 1.3s | 1.6s | 1.3s | 1.7s | 2.0s | 1.7s
09 | 8 | 67ms | 80ms | 67ms | 83ms | 100ms | 84ms
0A | 60 | 500ms | 600ms | 505ms | 625ms | 750ms | 631ms
0B | 10 | 83ms | 100ms | 84ms | 104ms | 125ms | 105ms
0C | 14 | 117ms | 140ms | 118ms | 146ms | 175ms | 147ms
0D | 12 | 100ms | 120ms | 101ms | 125ms | 150ms | 126ms
0E | 26 | 217ms | 260ms | 219ms | 271ms | 325ms | 273ms
0F | 14 | 117ms | 140ms | 118ms | 145ms | 175ms | 147ms
10 | 12 | 100ms | 120ms | 101ms | 125ms | 150ms | 126ms
11 | 16 | 133ms | 160ms | 135ms | 167ms | 200ms | 168ms
12 | 24 | 200ms | 240ms | 202ms | 250ms | 300ms | 252ms
13 | 18 | 150ms | 180ms | 151ms | 188ms | 225ms | 189ms
14 | 48 | 400ms | 480ms | 404ms | 500ms | 600ms | 505ms
15 | 20 | 167ms | 200ms | 168ms | 208ms | 250ms | 210ms
16 | 96 | 800ms | 960ms | 807ms | 1.0s | 1.2s | 1.0s
17 | 22 | 183ms | 220ms | 185ms | 229ms | 275ms | 231ms
18 | 192 | 1.6s | 1.9s | 1.6s | 2.0s | 2.4s | 2.0s
19 | 24 | 200ms | 240ms | 202ms | 250ms | 300ms | 252ms
1A | 72 | 600ms | 720ms | 606ms | 750ms | 900ms | 757ms
1B | 26 | 217ms | 260ms | 219ms | 271ms | 325ms | 273ms
1C | 16 | 133ms | 160ms | 135ms | 167ms | 200ms | 168ms
1D | 28 | 233ms | 280ms | 235ms | 292ms | 350ms | 294ms
1E | 32 | 267ms | 320ms | 269ms | 333ms | 400ms | 336ms
1F | 30 | 250ms | 300ms | 252ms | 313ms | 375ms | 315ms
reference: [NESdev](https://www.nesdev.org/wiki/APU_Noise)
## length counter table
<!-- organized by input value... of little use -->
<!--
value | raw | NTSC | PAL | Dendy | NTSC 5-step | PAL 5-step | Dendy 5-step
-----:|----:|------:|------:|------:|------------:|-----------:|-------------:
`00` | 10 | 83ms | 100ms | 84ms | 104ms | 125ms | 105ms
`01` | 254 | 2.1s | 2.5s | 2.1s | 2.6s | 3.2s | 2.7s
`02` | 20 | 166ms | 200ms | 168ms | 208ms | 250ms | 210ms
`03` | 2 | 17ms | 20ms | 17ms | 21ms | 25ms | 21ms
`04` | 40 | 333ms | 400ms | 336ms | 417ms | 500ms | 421ms
`05` | 4 | 33ms | 40ms | 34ms | 42ms | 50ms | 42ms
`06` | 80 | 667ms | 800ms | 673ms | 833ms | 1.0s | 841ms
`07` | 6 | 50ms | 60ms | 50ms | 63ms | 75ms | 63ms
`08` | 160 | 1.3s | 1.6s | 1.3s | 1.7s | 2.0s | 1.7s
`09` | 8 | 67ms | 80ms | 67ms | 83ms | 100ms | 84ms
`0A` | 60 | 500ms | 600ms | 505ms | 625ms | 750ms | 631ms
`0B` | 10 | 83ms | 100ms | 84ms | 104ms | 125ms | 105ms
`0C` | 14 | 117ms | 140ms | 118ms | 146ms | 175ms | 147ms
`0D` | 12 | 100ms | 120ms | 101ms | 125ms | 150ms | 126ms
`0E` | 26 | 217ms | 260ms | 219ms | 271ms | 325ms | 273ms
`0F` | 14 | 117ms | 140ms | 118ms | 145ms | 175ms | 147ms
`10` | 12 | 100ms | 120ms | 101ms | 125ms | 150ms | 126ms
`11` | 16 | 133ms | 160ms | 135ms | 167ms | 200ms | 168ms
`12` | 24 | 200ms | 240ms | 202ms | 250ms | 300ms | 252ms
`13` | 18 | 150ms | 180ms | 151ms | 188ms | 225ms | 189ms
`14` | 48 | 400ms | 480ms | 404ms | 500ms | 600ms | 505ms
`15` | 20 | 167ms | 200ms | 168ms | 208ms | 250ms | 210ms
`16` | 96 | 800ms | 960ms | 807ms | 1.0s | 1.2s | 1.0s
`17` | 22 | 183ms | 220ms | 185ms | 229ms | 275ms | 231ms
`18` | 192 | 1.6s | 1.9s | 1.6s | 2.0s | 2.4s | 2.0s
`19` | 24 | 200ms | 240ms | 202ms | 250ms | 300ms | 252ms
`1A` | 72 | 600ms | 720ms | 606ms | 750ms | 900ms | 757ms
`1B` | 26 | 217ms | 260ms | 219ms | 271ms | 325ms | 273ms
`1C` | 16 | 133ms | 160ms | 135ms | 167ms | 200ms | 168ms
`1D` | 28 | 233ms | 280ms | 235ms | 292ms | 350ms | 294ms
`1E` | 32 | 267ms | 320ms | 269ms | 333ms | 400ms | 336ms
`1F` | 30 | 250ms | 300ms | 252ms | 313ms | 375ms | 315ms
-->
<!-- organized by resulting times... more useful! -->
value | raw | NTSC | PAL | Dendy | NTSC 5-step | PAL 5-step | Dendy 5-step
-----:|----:|------:|------:|------:|------------:|-----------:|-------------:
`03` | 2 | 17ms | 20ms | 17ms | 21ms | 25ms | 21ms
`05` | 4 | 33ms | 40ms | 34ms | 42ms | 50ms | 42ms
`07` | 6 | 50ms | 60ms | 50ms | 63ms | 75ms | 63ms
`09` | 8 | 67ms | 80ms | 67ms | 83ms | 100ms | 84ms
`00` | 10 | 83ms | 100ms | 84ms | 104ms | 125ms | 105ms
`0B` | 10 | 83ms | 100ms | 84ms | 104ms | 125ms | 105ms
`0D` | 12 | 100ms | 120ms | 101ms | 125ms | 150ms | 126ms
`10` | 12 | 100ms | 120ms | 101ms | 125ms | 150ms | 126ms
`0C` | 14 | 117ms | 140ms | 118ms | 146ms | 175ms | 147ms
`0F` | 14 | 117ms | 140ms | 118ms | 145ms | 175ms | 147ms
`1C` | 16 | 133ms | 160ms | 135ms | 167ms | 200ms | 168ms
`11` | 16 | 133ms | 160ms | 135ms | 167ms | 200ms | 168ms
`13` | 18 | 150ms | 180ms | 151ms | 188ms | 225ms | 189ms
`02` | 20 | 166ms | 200ms | 168ms | 208ms | 250ms | 210ms
`15` | 20 | 167ms | 200ms | 168ms | 208ms | 250ms | 210ms
`17` | 22 | 183ms | 220ms | 185ms | 229ms | 275ms | 231ms
`12` | 24 | 200ms | 240ms | 202ms | 250ms | 300ms | 252ms
`19` | 24 | 200ms | 240ms | 202ms | 250ms | 300ms | 252ms
`0E` | 26 | 217ms | 260ms | 219ms | 271ms | 325ms | 273ms
`1B` | 26 | 217ms | 260ms | 219ms | 271ms | 325ms | 273ms
`1D` | 28 | 233ms | 280ms | 235ms | 292ms | 350ms | 294ms
`1F` | 30 | 250ms | 300ms | 252ms | 313ms | 375ms | 315ms
`1E` | 32 | 267ms | 320ms | 269ms | 333ms | 400ms | 336ms
`04` | 40 | 333ms | 400ms | 336ms | 417ms | 500ms | 421ms
`14` | 48 | 400ms | 480ms | 404ms | 500ms | 600ms | 505ms
`0A` | 60 | 500ms | 600ms | 505ms | 625ms | 750ms | 631ms
`1A` | 72 | 600ms | 720ms | 606ms | 750ms | 900ms | 757ms
`06` | 80 | 667ms | 800ms | 673ms | 833ms | 1.0s | 841ms
`16` | 96 | 800ms | 960ms | 807ms | 1.0s | 1.2s | 1.0s
`08` | 160 | 1.3s | 1.6s | 1.3s | 1.7s | 2.0s | 1.7s
`18` | 192 | 1.6s | 1.9s | 1.6s | 2.0s | 2.4s | 2.0s
`01` | 254 | 2.1s | 2.5s | 2.1s | 2.6s | 3.2s | 2.7s
reference: [NESdev](https://www.nesdev.org/wiki/APU_Length_Counter)
## DPCM frequency table
value | NTSC | PAL
------|----------:|----------:
`00` | 4181.7Hz | 4177.4Hz
`01` | 4709.9Hz | 4696.6Hz
`02` | 5264.0Hz | 5261.4Hz
`03` | 5593.0Hz | 5579.2Hz
`04` | 6257.9Hz | 6023.9Hz
`05` | 7046.3Hz | 7044.9Hz
`06` | 7919.3Hz | 7917.2Hz
`07` | 8363.4Hz | 8397.0Hz
`08` | 9419.9Hz | 9446.6Hz
`09` | 11186.1Hz | 11233.8Hz
`0A` | 12604.0Hz | 12595.5Hz
`0B` | 13982.6Hz | 14089.9Hz
`0C` | 16884.6Hz | 16965.4Hz
`0D` | 21306.8Hz | 21315.5Hz
`0E` | 24858.0Hz | 25191.0Hz
`0F` | 33143.9Hz | 33252.1Hz

View file

@ -16,65 +16,65 @@ afterwards everyone moved to Windows and software mixed PCM streaming...
# effects
- 10xx: set AM depth. the following values are accepted:
- 0: 1dB (shallow)
- 1: 4.8dB (deep)
- `10xx`: **set AM depth.** the following values are accepted:
- `0`: 1dB (shallow)
- `1`: 4.8dB (deep)
- this effect applies to all channels.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- only in 4-op mode (OPL3).
- **`15xx`**: set operator 4 level.
- `15xx`: **set operator 4 level.**
- only in 4-op mode (OPL3).
- **`16xy`**: set multiplier of operator.
- `16xy`: **sSet multiplier of operator.**
- `x` is the operator (1-4; last 2 operators only in 4-op mode).
- `y` is the multiplier.
- 17xx: set vibrato depth. the following values are accepted:
- 0: normal
- 1: double
- `17xx`: **set vibrato depth.**
- `0`: normal
- `1`: double
- this effect applies to all channels.
- **`18xx`**: toggle drums mode.
- 0 disables it and 1 enables it.
- `18xx`: **toggle drums mode.**
- `0` disables it and `1` enables it.
- only in drums chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- only in 4-op mode (OPL3).
- **`1Dxx`**: set attack of operator 4.
- `1Dxx`: **set attack of operator 4.**
- only in 4-op mode (OPL3).
- **`2Axy`**: set waveform of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `2Axy`: **set waveform of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` is the value.
- only in OPL2 or higher.
- **`30xx`**: enable envelope hard reset.
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `50xy`: **set AM of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `51xy`: **set SL of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `52xy`: **set RR of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` is the value.
- **`53xy`**: set VIB of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `53xy`: **set VIB of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` determines whether VIB is on.
- **`54xy`**: set KSL of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `54xy`: **set KSL of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` is the value.
- **`55xy`**: set SUS of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `55xy`: **set SUS of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` determines whether SUS is on.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- only in 4-op mode (OPL3).
- **`5Axx`**: set DR of operator 4.
- `5Axx`: **set DR of operator 4.**
- only in 4-op mode (OPL3).
- **`5Bxy`**: set KSR of operator.
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
- `5Bxy`: **set KSR of operator.**
- `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators".
- `y` determines whether KSR is on.

View file

@ -12,56 +12,56 @@ OPLL also spawned a few derivative chips, the best known of these is:
the YM2413 is equipped with the following features:
- 9 channels of 2 operator FM synthesis
- A drum/percussion mode, replacing the last 3 voices with 5 rhythm channels, with drum mode tones hard-defined in the chip itself, like FM instruments. Only pitch might be altered.
- a drum/percussion mode, replacing the last 3 voices with 5 rhythm channels, with drum mode tones hard-defined in the chip itself, like FM instruments. only pitch might be altered.
- Drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mxier twice for 2x volume, like all drum sounds. FM channel 8 splits to Snare Drum and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. CH9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave.
- Special syntheis mentioned already is: 5 square waves are gathered from 4x, 64x and 128x the pitch of channel 8 and 16x and 64x the pitch of channel 9 and they go through a process where 2 HH bits OR'd together, then 1 HH and 1 TC bit OR'd, then the two TC bits OR'd together, and those 3 results get XOR'd.
- drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mixer twice for 2× volume, like all drum sounds. FM channel 8 splits to Snare, Drum, and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. CH9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave.
- special synthesis mentioned already is: 5 square waves are gathered from 4×, 64× and 128× the pitch of channel 8 and 16× and 64× the pitch of channel 9 and they go through a process where 2 HH bits OR'd together, then 1 HH and 1 TC bit OR'd, then the two TC bits OR'd together, and those 3 results get XOR'd.
- 1 user-definable patch (this patch can be changed throughout the course of the song)
- 15 pre-defined patches which can all be used at the same time
- Support for ADSR on both the modulator and the carrier
- Sine and half-sine based FM synthesis
- support for ADSR on both the modulator and the carrier
- sine and half-sine based FM synthesis
- 9 octave note control
- 4096 different frequencies for channels
- 16 unique volume levels (NOTE: Volume 0 is NOT silent.)
- Modulator and carrier key scaling
- Built-in hardware vibrato support
- 16 unique volume levels (NOTE: volume 0 is NOT silent.)
- modulator and carrier key scaling
- built-in hardware vibrato support
# effects
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`16xy`**: set multiplier of operator.
- `x` is the operator (1 or 2).
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator, either 1 or 2.
- `y` is the multiplier.
- **`18xx`**: toggle drums mode.
- 0 disables it and 1 enables it.
- `18xx`: **toggle drums mode.**
- `0` disables it and `1` enables it.
- only in drums chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`50xy`**: set AM of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `50xy`: **set AM of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `51xy`: **set SL of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `52xy`: **set RR of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` is the value.
- **`53xy`**: set VIB of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `53xy`: **set VIB of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` determines whether VIB is on.
- **`54xy`**: set KSL of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `54xy`: **set KSL of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` is the value.
- **`55xy`**: set EGT of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `55xy`: **set EGT of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` determines whether EGT is on.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`5Bxy`**: set KSR of operator.
- `x` is the operator (1-2). a value of 0 means "all operators".
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `5Bxy`: **set KSR of operator.**
- `x` is the operator, either 1 or 2. a value of `0` means "all operators".
- `y` determines whether KSR is on.

View file

@ -25,91 +25,91 @@ no plans have been made for TX81Z MIDI passthrough, because:
# effects
- **`10xx`**: set noise frequency of channel 8 operator 4. 00 disables noise while 01 to 20 enables it.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `10xx`: **set noise frequency of channel 8 operator 4.** `00` disables noise while `01` to `20` enable it.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`17xx`**: set LFO speed.
- **`18xx`**: set LFO waveform. `xx` may be one of the following:
- `17xx`: **set LFO speed.**
- `18xx`: **set LFO waveform.** `xx` may be one of the following:
- `00`: saw
- `01`: square
- `02`: triangle
- `03`: noise
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`1Exx`**: set LFO AM depth.
- **`1Fxx`**: set LFO PM depth.
- **`24xx`**: set LFO 2 speed.
- **`25xx`**: set LFO 2 waveform. `xx` may be one of the following:
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `1Exx`: **set LFO AM depth.**
- `1Fxx`: **set LFO PM depth.**
- `24xx`: **set LFO 2 speed.**
- `25xx`: **set LFO 2 waveform.** `xx` may be one of the following:
- `00`: saw
- `01`: square
- `02`: triangle
- `03`: noise
- **`26xx`**: set LFO 2 AM depth.
- **`27xx`**: set LFO 2 PM depth.
- **`28xy`**: set reverb of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `26xx`: **set LFO 2 AM depth.**
- `27xx`: **set LFO 2 PM depth.**
- `28xy`: **set reverb of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`2Axy`**: set waveform of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `2Axy`: **set waveform of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`2Bxy`**: set EG shift of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `2Bxy`: **set EG shift of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`2Cxy`**: set fine multiplier of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `2Cxy`: **set fine multiplier of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`2Fxx`**: enable envelope hard reset.
- `2Fxx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`3xyy`**: set fixed frequency of operator 1/2.
- `x` is the block (0-7 for operator 1; 8-F for operator 2).
- `3xyy`: **set fixed frequency of operator 1/2.**
- `x` is the block (`0-7` for operator 1; `8-F` for operator 2).
- `y` is the frequency. fixed frequency mode will be disabled if this is less than 8.
- the actual frequency is: `y*(2^x)`.
- **`4xyy`**: set fixed frequency of operator 3/4.
- `x` is the block (0-7 for operator 3; 8-F for operator 4).
- `4xyy`: **set fixed frequency of operator 3/4.**
- `x` is the block (`0-7` for operator 3; `8-F` for operator 4).
- `y` is the frequency. fixed frequency mode will be disabled if this is less than 8.
- the actual frequency is: `y*(2^x)`.
- **`50xy`**: set AM of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value:
- 0: +0
- 1: +1
- 2: +2
- 3: +3
- 4: -0
- 5: -3
- 6: -2
- 7: -1
- **`54xy`**: set RS of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `0`: +0
- `1`: +1
- `2`: +2
- `3`: +3
- `4`: -0
- `5`: -3
- `6`: -2
- `7`: -1
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`55xy`**: set DT2 of operator.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `55xy`: **set DT2 of operator.**
- `x` is the operator (1-4). a value of `0` means "all operators".
- `y` is the value.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -1,22 +1,22 @@
# PC Engine/TurboGrafx-16
a console from NEC that, depending on a region:
attempted to enter the fierce battle between Nintendo and Sega, but because its capabilities are a mix of third and fourth generation, it failed to last long. (US and Europe)
was Nintendo's most fearsome rival, completely defeating Sega Mega Drive and defending itself against Super Famicom (Japan)
- attempted to enter the fierce battle between Nintendo and Sega, but because its capabilities are a mix of third and fourth generation, it failed to last long. (US and Europe)
- was Nintendo's most fearsome rival, completely defeating Sega Mega Drive and defending itself against Super Famicom (Japan)
it has 6 wavetable channels and the last two ones also double as noise channels.
furthermore, it has some PCM and LFO!
# effects
- **`10xx`**: change wave.
- **`11xx`**: toggle noise mode. only available in the last two channels.
- **`12xx`**: setup LFO. the following values are accepted:
- `10xx`: **change wave.**
- `11xx`: **toggle noise mode.** only available in the last two channels.
- `12xx`: **setup LFO.** the following values are accepted:
- `00`: LFO disabled.
- `01`: LFO enabled, shift 0.
- `02`: LFO enabled, shift 4.
- `03`: LFO enabled, shift 8.
- when LFO is enabled, channel 2 is muted and its output is passed to channel 1's frequency.
- **`13xx`**: set LFO speed.
- **`17xx`**: toggle PCM mode.
- **this effect is there for compatibility reasons** - it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used).
- `13xx`: **set LFO speed.**
- `17xx`: **toggle PCM mode.**
- _this effect is here for compatibility reasons_; it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used).

View file

@ -8,4 +8,4 @@ some of these didn't even have sound...
# effects
- **`10xx`**: set waveform. `xx` is a bitmask.
- `10xx`: **set waveform.** `xx` is a bitmask.

View file

@ -4,7 +4,7 @@ a sound and input chip developed by Atari for their 8-bit computers (Atari 400,
# effects
- **`10xx`**: set waveform.
- `10xx`: **set waveform.**
- 0: harsh noise (poly5+17)
- 1: square buzz (poly5)
- 2: weird noise (poly4+5)
@ -13,7 +13,7 @@ a sound and input chip developed by Atari for their 8-bit computers (Atari 400,
- 5: square
- 6: bass (poly4)
- 7: buzz (poly4)
- **`11xx`**: set AUDCTL. `xx` is a bitmask.
- `11xx`: **set AUDCTL.** `xx` is a bitmask.
- bit 7: 9-bit poly mode. shortens noise.
- bit 6: high channel 1 clock (~1.79MHz on NTSC).
- overrides 15KHz mode.
@ -32,6 +32,6 @@ a sound and input chip developed by Atari for their 8-bit computers (Atari 400,
- filtered output on channel 2 (I suggest you to set channel 4 volume to 0).
- use for PWM effects (not automatic!).
- bit 0: 15KHz mode.
- **`12xx`**: toggle two-tone mode.
- `12xx`: **toggle two-tone mode.**
- when enabled, channel 2 modulates channel 1. I don't know how, but it does.
- only on ASAP core.

7
doc/7-systems/pv1000.md Normal file
View file

@ -0,0 +1,7 @@
# Casio PV-1000
released only in Japan, this console was pulled after only a few weeks on the market. it has only 3 square waves with 6-bit pitch resolution and no bass.
# effects
- `10xx`: **set ring modulation.** amplitude modulation by the previous channel's output. `0` turns it off and `1` turns it on.

View file

@ -12,8 +12,8 @@ there are also 3 ADPCM channels. ADPCM samples are fixed to 8012 Hz.
# effects
- **`10xx`**: set echo feedback level.
- `10xx`: **set echo feedback level.**
- this effect will apply to all channels.
- **`11xx`**: set echo level.
- **`12xx`**: toggle QSound algorithm (on by default).
- **`3xxx`**: set the length of the echo delay buffer.
- `11xx`: **set echo level.**
- `12xx`: **toggle QSound algorithm.** on by default.
- `3xxx`: **set echo delay buffer length.**

View file

@ -1,18 +1,18 @@
# Philips SAA1099
this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY-3-8910, but has stereo sound, twice the channels and two envelopes, both of which are highly flexible. The envelopes work like this:
this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY-3-8910, but has stereo sound, twice the channels and two envelopes, both of which are highly flexible. the envelopes work like this:
- an instrument with envelope settings is placed on channel 2 or channel 5
- an instrument that is used as an "envelope output" is placed on channel 3 or channel 6 (you may want to disable wave output on the output channel)
# effects
- **`10xy`**: set channel mode.
- `10xy`: **set channel mode.**
- `x` toggles noise.
- `y` toggles square.
- this effect affects either the first 3 or last 3 channels, depending on where it is placed.
- **`11xx`**: set noise frequency.
- `11xx`: **set noise frequency.**
- this effect affects either the first 3 or last 3 channels, depending on where it is placed.
- **`12xx`**: setup envelope. this is a bitmask.
- `12xx`: **setup envelope.** this is a bitmask.
- bit 7 toggles the envelope.
- bit 5 toggles whether to use a fixed frequency or lock to the frequency of channel 2 or 5.
- bit 4 sets the envelope resolution.

View file

@ -8,4 +8,4 @@ the SCC+ fixes this issue though (while being compatible with SCC games).
# effects
- **`10xx`**: change wave.
- `10xx`: **change wave.**

View file

@ -12,6 +12,6 @@ Furnace also has a five channel version of this chip, but it only exists for Def
# effects
- **`20xx`**: set PCM frequency.
- `20xx`: **set PCM frequency.**
- `xx` is a 256th fraction of 31250Hz.
- this effect exists for mostly DefleMask compatibility - it is otherwise recommended to use Sample type instruments.
- this effect exists mostly for DefleMask compatibility; it is otherwise recommended to use Sample type instruments.

View file

@ -1,23 +1,23 @@
# Sharp SM8521
The SM8521 is the CPU and sound chip of the Game.com, a handheld console released in 1997 as a competitor to the infamous Nintendo Virtual Boy.
the SM8521 is the CPU and sound chip of the Game.com, a handheld console released in 1997 as a competitor to the infamous Nintendo Virtual Boy.
Ultimately, most of the games for the Game.com ended up being failures in the eyes of reviewers, thus giving the Game.com a pretty bad reputation. This was one of the reasons that the Game.com only ended up selling at least 300,000 units. For these reasons and more, the Game.com ended up being discontinued in 2000.
ultimately, most of the games for the Game.com ended up being failures in the eyes of reviewers, thus giving the Game.com a pretty bad reputation. this was one of the reasons that the Game.com only ended up selling at least 300,000 units. for these reasons and more, the Game.com ended up being discontinued in 2000.
However, for its time, it was a pretty competitively priced system. The Gameboy Color was to be released in a year for $79.95, while the Game.com was released for $69.99, and its later model, the Pocket Pro, was released in mid-1999 for $29.99 due to the Game.com's apparent significant decrease in value.
however, for its time, it was a pretty competitively priced system. the Gameboy Color was to be released in a year for $79.95, while the Game.com was released for $69.99, and its later model, the Pocket Pro, was released in mid-1999 for $29.99 due to the Game.com's apparent significant decrease in value.
In fact, most games never used the wavetable/noise mode of the chip. Sonic Jam, for example, uses a sine wave with a software-controlled volume envelope on the DAC channel (see below for more information on the DAC channel).
in fact, most games never used the wavetable/noise mode of the chip. sonic Jam, for example, uses a sine wave with a software-controlled volume envelope on the DAC channel (see below for more information on the DAC channel).
The sound-related features and quirks of the SM8521 are as follows:
the sound-related features and quirks of the SM8521 are as follows:
- 2 4-bit wavetable channels
- a noise channel (which can go up to a very high pitch, creating an almost periodic noise sound)
- 5-bit volume
- A low bit-depth output (which means it distorts a lot).
- It phase resets when you switch waves
- a low bit-depth output (which means it distorts a lot).
- it phase resets when you switch waves
- 12-bit pitch with a wide frequency range
- A software-controlled D/A register that (potentially) requires all other registers to be stopped to play. Due to this, it is currently, it is not implemented in Furnace as of version 0.6pre4.
- a software-controlled D/A register that (potentially) requires all other registers to be stopped to play. due to this, it is currently, it is not implemented in Furnace as of version 0.6pre4.
## effect commands
- **`10xx`**: Set waveform
- `xx` is a value between 0 and 255, that sets the waveform of the channel you place it on.
- `10xx`: **set waveform.**
- `xx` is a value between 0 and 255 that sets the waveform of the channel you place it on.

View file

@ -1,17 +1,15 @@
# TI SN76489 (e.g. Sega Master System)
# TI SN76489 (e.g. sega Master System)
a relatively simple sound chip made by Texas Instruments. a derivative of it is used in Sega's Master System, the predecessor to Genesis.
the original iteration of the SN76489 used in the TI-99/4A computers was clocked at 447 KHz, being able to play as low as 13.670 Hz (A -1). consequently, pitch accuracy for higher notes is compromised.
on the other hand, the chip was clocked at a much higher speed on Master System and Genesis, which makes it rather poor in the bass range.
the original iteration of the SN76489 used in the TI-99/4A computer, the SN94624, could only produce tones as low as 100Hz, and was clocked at 447 KHz. all later versions (such as the one in the Master System and Genesis) had a clock divider but ran on a faster clock... except for the SN76494, which can play notes as low as 13.670 Hz (A -1). consequently, its pitch accuracy for higher notes is compromised.
# effects
- **`20xy`**: set noise mode.
- `20xy`: **set noise mode.**
- `x` controls whether to inherit frequency from channel 3.
- 0: use one of 3 preset frequencies (C: A-2; C#: A-3; D: A-4).
- 1: use frequency of channel 3.
- `0`: use one of 3 preset frequencies (C: A-2; C#: A-3; D: A-4).
- `1`: use frequency of channel 3.
- `y` controls whether to select noise or thin pulse.
- 0: thin pulse.
- 1: noise.
- `0`: thin pulse.
- `1`: noise.

View file

@ -2,7 +2,7 @@
the successor to NES to compete with Genesis, packing superior graphics and sample-based audio.
its audio system, developed by Sony, features a DSP chip, SPC700 CPU and 64KB of dedicated SRAM used by both.
its Sony-developed audio system features a DSP chip, SPC700 CPU, 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.
Furnace communicates with the DSP directly and provides a full 64KB of memory. this memory might be reduced excessively on ROM export to make up for playback engine and pattern data. you can go to window > statistics to see how much memory your samples are using.
@ -22,60 +22,156 @@ Furnace also allows the SNES to use wavetables (and the wavetable synthesizer) i
# effects
- **`10xx`**: set waveform.
- **`11xx`**: toggle noise mode.
- **`12xx`**: toggle echo on this channel.
- **`13xx`**: toggle pitch modulation.
- **`14xy`**: toggle inverting the left or right channels (x: left, y: right).
- **`15xx`**: set envelope mode.
- 0: ADSR.
- 1: gain (direct).
- 2: linear decrement.
- 3: exponential decrement.
- 4: linear increment.
- 5: bent line (inverse log) increment.
- **`16xx`**: set gain (00 to 7F if direct, 00 to 1F otherwise).
- **`18xx`**: enable echo buffer.
- **`19xx`**: set echo delay
- goes from 0 to F.
- **`1Axx`**: set left echo channel volume.
- this is a signed number.
- 00 to 7F for 0 to 127.
- 80 to FF for -128 to -1.
- setting this to -128 is not recommended as it may cause echo output to overflow and therefore click.
- **`1Bxx`**: set right echo channel volume.
- this is a signed number.
- 00 to 7F for 0 to 127.
- 80 to FF for -128 to -1.
- setting this to -128 is not recommended as it may cause echo output to overflow and therefore click.
- **`1Cxx`**: set echo feedback.
- this is a signed number.
- 00 to 7F for 0 to 127.
- 80 to FF for -128 to -1.
- setting this to -128 is not recommended as it may cause echo output to overflow and therefore click.
- **`1Dxx`**: set noise generator frequency (00 to 1F).
- **`1Exx`**: set left dry/global volume.
- this does not affect echo.
- **`1Fxx`**: set right dry/global volume.
- this does not affect echo.
- **`20xx`**: set attack (0 to F).
- only in ADSR envelope mode.
- **`21xx`**: set decay (0 to 7).
- only in ADSR envelope mode.
- **`22xx`**: set sustain (0 to 7).
- only in ADSR envelope mode.
- **`23xx`**: set release (00 to 1F).
- only in ADSR envelope mode.
- **`30xx`**: set echo filter coefficient 0.
- **`31xx`**: set echo filter coefficient 1.
- **`32xx`**: set echo filter coefficient 2.
- **`33xx`**: set echo filter coefficient 3.
- **`34xx`**: set echo filter coefficient 4.
- **`35xx`**: set echo filter coefficient 5.
- **`36xx`**: set echo filter coefficient 6.
- **`37xx`**: set echo filter coefficient 7.
- `10xx`: **set waveform.**
- `11xx`: **toggle noise mode.**
- `12xx`: **toggle echo on this channel.**
- `13xx`: **toggle pitch modulation.** frequency modulation by the previous channel's output. no effect on channel 1.
- `14xy`: **toggle inverting the left or right channels.** `x` is left, `y` is right.
- `15xx`: **set envelope mode.** see gain chart below for `1` through `5`.
- `0`: ADSR mode.
- `1`: gain (direct). volume holds at one level.
- `2`: linear decrement. volume lowers by subtractions of 1/64.
- `3`: exponential decrement. volume lowers by multiplications of 255/256.
- `4`: linear increment. volume rises by additions of 1/64.
- `5`: bent line (inverse log) increment. volume rises by additions of 1/64 until 3/4, then additions of 1/256.
- `16xx`: **set gain.** `00` to `7F` if direct, `00` to `1F` otherwise.
- `18xx`: **enable echo buffer.**
- `19xx`: **set echo delay.** range is `0` to `F`.
- `1Axx`: **set left echo channel volume.**\
`1Bxx`: **set right echo channel volume.**\
`1Cxx`: **set echo feedback.**
- all of these are signed numbers.
- 00 to 7F for 0 to 127.
- 80 to FF for -128 to -1.
- make sure the sum of these is between -128 or 127.
- failure to comply may result in overflow and therefore clicking.
- `00` to `7F` for 0 to 127.
- `80` to `FF` for -128 to -1.
- setting these to -128 is not recommended as it may cause echo output to overflow and therefore click.
- `1Dxx`: **set noise generator frequency.** range is `00` to `1F`. see noise frequencies chart below.
- `1Exx`: **set left dry / global volume.**\
`1Fxx`: **set right dry / global volume.**
- these do not affect echo.
- `20xx`: **set attack.** range is `0` to `F`.\
`21xx`: **set decay.** range is `0` to `7`.\
`22xx`: **set sustain.** range is `0` to `7`.\
`23xx`: **set release.** range is `00` to `1F`.
- these four are only used in ADSR envelope mode. see ADSR chart below.
- `30xx`: **set echo filter coefficient 0.**\
`31xx`: **set echo filter coefficient 1.**\
`32xx`: **set echo filter coefficient 2.**\
`33xx`: **set echo filter coefficient 3.**\
`34xx`: **set echo filter coefficient 4.**\
`35xx`: **set echo filter coefficient 5.**\
`36xx`: **set echo filter coefficient 6.**\
`37xx`: **set echo filter coefficient 7.**
- all of these are signed numbers.
- `00` to `7F` for 0 to 127.
- `80` to `FF` for -128 to -1.
- _Note:_ Be sure the sum of all coefficients is between -128 and 127. sums outside that may result in overflow and therefore clicking.
- see [SnesLab](https://sneslab.net/wiki/FIR_Filter) for a full explanation and examples.
# tables
## ADSR
| attack | 0→1 time | decay | 1→S time | sustain | ratio | release | S→0 time
| -----: | -------: | ----: | -------: | ------: | :---: | ------: | -------:
| `00` | 4.1s | `00` | 1.2s | `00` | 1/8 | `00` | ∞
| `01` | 2.5s | `01` | 740ms | `01` | 2/8 | `01` | 38s
| `02` | 1.5s | `02` | 440ms | `02` | 3/8 | `02` | 28s
| `03` | 1.0s | `03` | 290ms | `03` | 4/8 | `03` | 24s
| `04` | 640ms | `04` | 180ms | `04` | 5/8 | `04` | 19s
| `05` | 380ms | `05` | 110ms | `05` | 6/8 | `05` | 14s
| `06` | 260ms | `06` | 74ms | `06` | 7/8 | `06` | 12s
| `07` | 160ms | `07` | 37ms | `07` | 1 | `07` | 9.4s
| `08` | 96ms | | | | | `08` | 7.1s
| `09` | 64ms | | | | | `09` | 5.9s
| `0A` | 40ms | | | | | `0A` | 4.7s
| `0B` | 24ms | | | | | `0B` | 3.5s
| `0C` | 16ms | | | | | `0C` | 2.9s
| `0D` | 10ms | | | | | `0D` | 2.4s
| `0E` | 6ms | | | | | `0E` | 1.8s
| `0F` | 0ms | | | | | `0F` | 1.5s
| | | | | | | `10` | 1.2s
| | | | | | | `11` | 880ms
| | | | | | | `12` | 740ms
| | | | | | | `13` | 590ms
| | | | | | | `14` | 440ms
| | | | | | | `15` | 370ms
| | | | | | | `16` | 290ms
| | | | | | | `17` | 220ms
| | | | | | | `18` | 180ms
| | | | | | | `19` | 150ms
| | | | | | | `1A` | 110ms
| | | | | | | `1B` | 92ms
| | | | | | | `1C` | 74ms
| | | | | | | `1D` | 55ms
| | | | | | | `1E` | 37ms
| | | | | | | `1F` | 18ms
reference: [Super Famicom Development Wiki](https://wiki.superfamicom.org/spc700-reference#dsp-voice-register:-adsr-1097)
## gain
value | linear inc. | bent line inc. | linear dec. | exponent dec.
----: | ----------: | -------------: | ----------: | ------------:
`00` | ∞ | ∞ | ∞ | ∞
`01` | 4.1s | 7.2s | 4.1s | 38s
`02` | 3.1s | 5.4s | 3.1s | 28s
`03` | 2.6s | 4.6s | 2.6s | 24s
`04` | 2.0s | 3.5s | 2.0s | 19s
`05` | 1.5s | 2.6s | 1.5s | 14s
`06` | 1.3s | 2.3s | 1.3s | 12s
`07` | 1.0s | 1.8s | 1.0s | 9.4s
`08` | 770ms | 1.3s | 770ms | 7.1s
`09` | 640ms | 1.1s | 640ms | 5.9s
`0A` | 510ms | 900ms | 510ms | 4.7s
`0B` | 380ms | 670ms | 380ms | 3.5s
`0C` | 320ms | 560ms | 320ms | 2.9s
`0D` | 260ms | 450ms | 260ms | 2.4s
`0E` | 190ms | 340ms | 190ms | 1.8s
`0F` | 160ms | 280ms | 160ms | 1.5s
`10` | 130ms | 220ms | 130ms | 1.2s
`11` | 96ms | 170ms | 96ms | 880ms
`12` | 80ms | 140ms | 80ms | 740ms
`13` | 64ms | 110ms | 64ms | 590ms
`14` | 48ms | 84ms | 48ms | 440ms
`15` | 40ms | 70ms | 40ms | 370ms
`16` | 32ms | 56ms | 32ms | 290ms
`17` | 24ms | 42ms | 24ms | 220ms
`18` | 20ms | 35ms | 20ms | 180ms
`19` | 16ms | 28ms | 16ms | 150ms
`1A` | 12ms | 21ms | 12ms | 110ms
`1B` | 10ms | 18ms | 10ms | 92ms
`1C` | 8ms | 14ms | 8ms | 74ms
`1D` | 6ms | 11ms | 6ms | 55ms
`1E` | 4ms | 7ms | 4ms | 37ms
`1F` | 2ms | 3.5ms | 2ms | 18ms
reference: [Super Famicom Development Wiki](https://wiki.superfamicom.org/spc700-reference#dsp-voice-register:-gain-1156)
## noise frequencies
value | freq. | value | freq.
----: | -----: | ----: | -------:
`00` | 0 Hz | `10` | 500 Hz
`01` | 16 Hz | `11` | 667 Hz
`02` | 21 Hz | `12` | 800 Hz
`03` | 25 Hz | `13` | 1.0 KHz
`04` | 31 Hz | `14` | 1.3 KHz
`05` | 42 Hz | `15` | 1.6 KHz
`06` | 50 Hz | `16` | 2.0 KHz
`07` | 63 Hz | `17` | 2.7 KHz
`08` | 83 Hz | `18` | 3.2 KHz
`09` | 100 Hz | `19` | 4.0 KHz
`0A` | 125 Hz | `1A` | 5.3 KHz
`0B` | 167 Hz | `1B` | 6.4 KHz
`0C` | 200 Hz | `1C` | 8.0 KHz
`0D` | 250 Hz | `1D` | 10.7 KHz
`0E` | 333 Hz | `1E` | 16 KHz
`0F` | 400 Hz | `1F` | 32 KHz
reference: [Super Famicom Development Wiki](https://wiki.superfamicom.org/spc700-reference#dsp-register:-flg-1318)
# resources
- [SNES-format BRR samples](https://www.smwcentral.net/?p=stion&s=brrsamples) at SMW Central

View file

@ -14,43 +14,43 @@ it has the following capabilities:
# effects
- **`10xx`**: set waveform
- 0: pulse wave
- 1: sawtooth
- 2: sine wave
- 3: triangle wave
- 4: noise
- 5: periodic noise
- 6: XOR sine
- 7: XOR triangle
- **`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
- `10xx`: **set waveform.**
- `0`: pulse wave
- `1`: sawtooth
- `2`: sine wave
- `3`: triangle wave
- `4`: noise
- `5`: periodic noise
- `6`: XOR sine
- `7`: XOR triangle
- `12xx`: **set pulse width.** range is `0` to `7F`.
- `13xx`: **set resonance of filter.** range is `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.**
- bit 0: ring mod
- bit 1: low pass
- bit 2: high pass
- bit 3: band pass
- **`15xx`**: set frequency sweep period low byte
- **`16xx`**: set frequency sweep period high byte
- **`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 high byte
- **`1Bxx`**: set frequency sweep boundary
- **`1Cxx`**: set volume sweep boundary
- **`1Dxx`**: set cutoff sweep boundary
- **`1Exx`**: set phase reset period low byte
- **`1Fxx`**: set phase reset period high byte
- **`20xx`**: toggle frequency sweep
- `15xx`: **set frequency sweep period low byte.**
- `16xx`: **set frequency sweep period high byte.**
- `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 high byte.**
- `1Bxx`: **set frequency sweep boundary.**
- `1Cxx`: **set volume sweep boundary.**
- `1Dxx`: **set cutoff sweep boundary.**
- `1Exx`: **set phase reset period low byte.**
- `1Fxx`: **set phase reset period high byte.**
- `20xx`: **toggle frequency sweep.**
- bit 0-6: speed
- bit 7: up direction
- **`21xx`**: toggle volume sweep
- `21xx`: **toggle volume sweep.**
- bit 0-4: speed
- bit 5: up direction
- bit 6: loop
- bit 7: alternate
- **`22xx`**: toggle cutoff sweep
- `22xx`: **toggle cutoff sweep.**
- bit 0-6: speed
- bit 7: up direction
- **`4xxx`**: set cutoff (0 to FFF)
- `4xxx`: **set cutoff.** range is `0` to `FFF`.

View file

@ -6,6 +6,6 @@ this chip was used in Neo Geo Pocket.
# effects
- **`20xx`**: set noise mode.
- 0: thin pulse.
- 1: noise.
- `20xx`: **set noise mode.**
- `0`: thin pulse.
- `1`: noise.

View file

@ -9,20 +9,20 @@ Furnace isn't complete without this one...
# effects
- **`10xx`**: select shape. `xx` may be one of:
- 0: nothing
- 1: buzzy
- 2: low buzzy
- 3: flangy
- 4: square
- 5: square
- 6: pure buzzy
- 7: reedy
- 8: noise
- 9: reedy
- 10: pure buzzy
- 11: nothing
- 12: low square
- 13: low square
- 14: low pure buzzy
- 15: low reedy
- `10xx`: **select shape.**
- `0`: nothing
- `1`: buzzy
- `2`: low buzzy
- `3`: flangy
- `4`: square
- `5`: square
- `6`: pure buzzy
- `7`: reedy
- `8`: noise
- `9`: reedy
- `A`: pure buzzy
- `B`: nothing
- `C`: low square
- `D`: low square
- `E`: low pure buzzy
- `F`: low reedy

View file

@ -7,9 +7,11 @@ currently Furnace does not support the PCM channel's stereo mode, though (except
# effects
- **`20xx`**: set waveform. the following values are accepted:
- 0: pulse
- 1: saw
- 2: triangle
- 3: noise
- **`22xx`**: set duty cycle. `xx` may go from 0 to 3F.
- `20xx`: **set waveform.**
- `0`: pulse
- `1`: saw
- `2`: triangle
- `3`: noise
- `22xx`: **set duty cycle.** range is `0` to `3F`.
- `EExx`: **ZSM synchronization event.**
- Where `xx` is the event payload. This has no effect in how the music is played in Furnace, but the ZSMKit library for the Commander X16 interprets these events inside ZSM files and optionally triggers a callback routine. This can be used, for instance, to cause game code to respond to beats or at certain points in the music.

View file

@ -15,4 +15,4 @@ these channels are not referred as "square" wave channels since a technique to p
## effect commands
- **`10xx`**: Switch waveform (`xx` from `00` to `0F`)
- `10xx`: **switch waveform.** range is `00` to `0F`.

View file

@ -10,34 +10,34 @@ additionally, channel 5 offers a modulation/sweep unit. the former is similar to
# effects
- **`10xx`**: set waveform.
- **`11xx`**: set noise length (0 to 7).
- `10xx`: **set waveform.**
- `11xx`: **set noise length.** range is `0` to `7`.
- only in the noise channel.
- **`12xy`**: setup envelope.
- `12xy`: **setup envelope.**
- `x` determines whether envelope is enabled or not.
- 0: disabled
- 1: enabled
- 3: enabled and loop
- yeah, the value 2 isn't useful.
- `0`: disabled
- `1`: enabled
- `3`: enabled and loop
- yeah, the value `2` isn't useful.
- `y` sets the speed and direction.
- 0-7: down
- 8-F: up
- **`13xy`**: setup sweep.
- `0-7`: down
- `8-F`: up
- `13xy`: **setup sweep.**
- `x` sets the speed.
- 0 and 8 are "speed 0" - sweep is ineffective.
- `y` sets the shift (0 to 7).
- 8 and higher will mute the channel.
- `0` and `8` are "speed 0" - sweep is ineffective.
- `y` sets the shift (`0` to `7`).
- `8` and higher will mute the channel.
- only in channel 5.
- **`14xy`**: setup modulation.
- `14xy`: **setup modulation.**
- `x` determines whether it's enabled or not.
- 0: disabled
- 1: enabled
- 3: enabled and loop
- 2 isn't useful here either.
- `y` sets the speed.
- 0 and 8 are "speed 0" - modulation is ineffective.
- `0` and `8` are "speed 0" - modulation is ineffective.
- no, you can't really do Yamaha FM using this.
- only in channel 5.
- **`15xx`**: set modulation wave.
- `xx` points to a wavetable. it should have a height of 255.
- `15xx`: **set modulation wave.**
- `xx` points to a wavetable. range is `0` to `FF`.
- this is an alternative to setting the modulation wave through the instrument.

View file

@ -14,5 +14,5 @@ Furnace supports this routine for PCM playback, but it consumes a lot of CPU tim
these effects only are effective in the pulse channels.
- **`12xx`**: set duty cycle (0 to 7).
- **`17xx`**: toggle PCM mode.
- `12xx`: **set duty cycle.** range is `0` to `7`.
- `17xx`: **toggle PCM mode.**

View file

@ -10,12 +10,12 @@ it has 4 wavetable channels. some of them have additional capabilities:
# effects
- **`10xx`**: change wave.
- **`11xx`**: setup noise mode (channel 4 only).
- `10xx`: **change wave**.
- `11xx`: **setup noise mode.** channel 4 only.
- 0: disable.
- 1-8: enable and set tap preset.
- **`12xx`**: setup sweep period (channel 3 only).
- `12xx`: **setup sweep period.** channel 3 only.
- 0: disable.
- 1-32: enable and set period.
- **`13xx`**: setup sweep amount (channel 3 only).
- **`17xx`**: toggle PCM mode (channel 2 only).
- `13xx`: **setup sweep amount.** channel 3 only.
- `17xx`: **toggle PCM mode.** channel 2 only.

View file

@ -1,47 +1,47 @@
# Seta/Allumer X1-010
A sound chip designed by Seta, mainly used in their own arcade hardware from the late 80s to the early 2000s.
It has 2 output channels, but there is no known hardware taking advantage of stereo sound capabilities.
Later hardware paired this with external bankswitching logic, but this isn't emulated yet.
a sound chip designed by Seta, mainly used in their own arcade hardware from the late 80s to the early 2000s.
it has 2 output channels, but there is no known hardware taking advantage of stereo sound capabilities.
later hardware paired this with external bankswitching logic, but this isn't emulated yet.
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.
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:
this chip supports 2 types of waveforms, needs to be paired to external 8 KB RAM to access these features:
One is a signed 8 bit mono waveform, operated like other wavetable based sound systems.
These are stored at the lower half of RAM at common case.
one is a signed 8 bit mono waveform, operated like other wavetable based sound systems.
these are stored at the lower half of RAM at common case.
The other one ("Envelope") is a 4 bit stereo waveform, multiplied with the above and calculates final output, each nibble is used for each output channel.
These are stored at the upper half of RAM at common case.
the other one ("Envelope") is a 4 bit stereo waveform, multiplied with the above and calculates final output, each nibble is used for each output channel.
these are stored at the upper half of RAM at common case.
Both waveforms are 128 bytes (fixed size), freely allocated at each half of RAM except the channel register area: each half can store total 32/31 waveforms at once.
In furnace, you can enable the envelope shape split mode. When it is set, its waveform will be split to the left and right halves for each output. Each max size is 128 bytes, total 256 bytes.
both waveforms are 128 bytes (fixed size), freely allocated at each half of RAM except the channel register area: each half can store total 32/31 waveforms at once.
in Furnace, you can enable the envelope shape split mode. when it is set, its waveform will be split to the left and right halves for each output. each max size is 128 bytes, total 256 bytes.
# effects
- **`10xx`**: change wave.
- **`11xx`**: change envelope shape (also wavetable).
- **`17xx`**: toggle PCM mode.
- **`20xx`**: set PCM frequency (1 to FF).
- **`22xx`**: set envelope mode.
- `10xx`: **change wave.**
- `11xx`: **change envelope shape.** also wavetable.
- `17xx`: **toggle PCM mode.**
- `20xx`: **set PCM frequency.** range is `1` to `FF`.
- PCM frequency formula: `step * (clock / 8192)`.
- range is 1.95KHz to 498KHz if the chip clock is 16MHz.
- `22xx`: **set envelope mode.**
- bit 0 sets whether envelope will affect this channel.
- bit 1 toggles the envelope one-shot mode. when it is set, channel is halted after envelope cycle is finished.
- bit 2 toggles the envelope shape split mode. when it is set, envelope shape will be split to left half and right half.
- bit 3/5 sets whether the right/left shape will mirror the original one.
- bit 4/6 sets whether the right/left output will mirror the original one.
- **`23xx`**: set envelope period.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`29xy`**: enable auto-envelope mode.
- `23xx`: **set envelope period.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `29xy`: **enable auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.
* PCM frequency: 255 step, formula: `step * (Chip clock / 8192)`; 1.95KHz to 498KHz if Chip clock is 16MHz.

View file

@ -1,6 +1,6 @@
# Yamaha YM2151
the sound chip powering several arcade boards, the Sharp X1/X68000 and the Commander X16. Eight 4-op FM channels, with overpowered LFO and almost unused noise generator.
the sound chip powering several arcade boards, the Sharp X1/X68000 and the Commander X16. eight 4-op FM channels, with overpowered LFO and almost unused noise generator.
it also was present on several pinball machines and synthesizers of the era, and later surpassed by the YM2414 (OPZ) present in the world-famous TX81Z.
@ -8,63 +8,63 @@ in most arcade boards the chip was used in combination with a PCM chip, like [Se
# effects
- **`10xx`**: set noise frequency of channel 8 operator 4. 00 disables noise while 01 to 20 enables it.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `10xx`: **set noise frequency of channel 8 operator 4.** `00` disables noise while `01` to `20` enables it.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`17xx`**: set LFO speed.
- **`18xx`**: set LFO waveform. `xx` may be one of the following:
- `17xx`: **set LFO speed.**
- `18xx`: **set LFO waveform.**
- `00`: saw
- `01`: square
- `02`: triangle
- `03`: noise
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`1Exx`**: set LFO AM depth.
- **`1Fxx`**: set LFO PM depth.
- **`30xx`**: enable envelope hard reset.
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `1Exx`: **set LFO AM depth.**
- `1Fxx`: **set LFO PM depth.**
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value:
- 0: +0
- 1: +1
- 2: +2
- 3: +3
- 4: -0
- 5: -3
- 6: -2
- 7: -1
- **`54xy`**: set RS of operator.
- `0`: +0
- `1`: +1
- `2`: +2
- `3`: +3
- `4`: -0
- `5`: -3
- `6`: -2
- `7`: -1
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`55xy`**: set DT2 of operator.
- `55xy`: **set DT2 of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -11,91 +11,91 @@ several variants of this chip were released as well, with more features.
# effects
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `x` is the operator (1-4).
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator from 1 to 4.
- `y` is the multiplier.
- **`18xx`**: toggle extended channel 3 mode.
- 0 disables it and 1 enables it.
- `18xx`: **toggle extended channel 3 mode.**
- `0` disables it and `1` enables it.
- only in extended channel 3 chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`20xx`**: set SSG channel mode. `xx` may be one of the following:
- `00`: square
- `01`: noise
- `02`: square and noise
- `03`: nothing (apparently)
- `04`: envelope and square
- `05`: envelope and noise
- `06`: envelope and square and noise
- `07`: nothing
- **`21xx`**: set noise frequency. `xx` is a value between 00 and 1F.
- **`22xy`**: set envelope mode.
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `20xx`: **set SSG channel mode.** `xx` may be one of the following:
- `0`: square
- `1`: noise
- `2`: square and noise
- `3`: nothing (apparently)
- `4`: envelope and square
- `5`: envelope and noise
- `6`: envelope and square and noise
- `7`: nothing
- `21xx`: **set noise frequency.** `xx` is a value between 00 and 1F.
- `22xy`: **set envelope mode.**
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- `0`: `\___` decay
- `4`: `/___` attack once
- `8`: `\\\\` saw
- `9`: `\___` decay
- `A`: `\/\/` inverse obelisco
- `B`: `\¯¯¯` decay once
- `C`: `////` inverse saw
- `D`: `/¯¯¯` attack
- `E`: `/\/\` obelisco
- `F`: `/___` attack once
- if `y` is 1 then the envelope will affect this channel.
- **`23xx`**: set envelope period low byte.
- **`24xx`**: set envelope period high byte.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`29xy`**: enable SSG auto-envelope mode.
- `23xx`: **set envelope period low byte.**
- `24xx`: **set envelope period high byte.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `29xy`: **enable SSG auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.
- **`30xx`**: enable envelope hard reset.
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value:
- 0: +0
- 1: +1
- 2: +2
- 3: +3
- 4: -0
- 5: -3
- 6: -2
- 7: -1
- **`54xy`**: set RS of operator.
- `0`: +0
- `1`: +1
- `2`: +2
- `3`: +3
- `4`: -0
- `5`: -3
- `6`: -2
- `7`: -1
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`55xy`**: set SSG-EG of operator.
- `55xy`: **set SSG-EG of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value (0-8).
- values between 0 and 7 set SSG-EG.
- value 8 disables it.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -8,26 +8,26 @@ the YM2610 (OPNB) and YM2610B chips are very similar to this one, but the built-
# effects
- **`10xy`**: set LFO parameters.
- `10xy`: **set LFO parameters.**
- `x` toggles the LFO.
- `y` sets its speed.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`18xx`**: toggle extended channel 3 mode.
- 0 disables it and 1 enables it.
- `18xx`: **toggle extended channel 3 mode.**
- `0` disables it and `1` enables it.
- only in extended channel 3 chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`20xx`**: set SSG channel mode. `xx` may be one of the following:
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `20xx`: **set SSG channel mode.**
- `00`: square
- `01`: noise
- `02`: square and noise
@ -36,66 +36,66 @@ the YM2610 (OPNB) and YM2610B chips are very similar to this one, but the built-
- `05`: envelope and noise
- `06`: envelope and square and noise
- `07`: nothing
- **`21xx`**: set noise frequency. `xx` is a value between 00 and 1F.
- **`22xy`**: set envelope mode.
- `21xx`: **set noise frequency.** range is `0` to `1F`.
- `22xy`: **set envelope mode.**
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- `0`: `\___` decay
- `4`: `/___` attack once
- `8`: `\\\\` saw
- `9`: `\___` decay
- `A`: `\/\/` inverse obelisco
- `B`: `\¯¯¯` decay once
- `C`: `////` inverse saw
- `D`: `/¯¯¯` attack
- `E`: `/\/\` obelisco
- `F`: `/___` attack once
- if `y` is 1 then the envelope will affect this channel.
- **`23xx`**: set envelope period low byte.
- **`24xx`**: set envelope period high byte.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`29xy`**: enable SSG auto-envelope mode.
- `23xx`: **set envelope period low byte.**
- `24xx`: **set envelope period high byte.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `29xy`: **enable SSG auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.
- **`30xx`**: enable envelope hard reset.
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value:
- 0: +0
- 1: +1
- 2: +2
- 3: +3
- 4: -0
- 5: -3
- 6: -2
- 7: -1
- **`54xy`**: set RS of operator.
- `0`: +0
- `1`: +1
- `2`: +2
- `3`: +3
- `4`: -0
- `5`: -3
- `6`: -2
- `7`: -1
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`55xy`**: set SSG-EG of operator.
- `55xy`: **set SSG-EG of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value (0-8).
- values between 0 and 7 set SSG-EG.
- value 8 disables it.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -6,69 +6,69 @@ its soundchip is a 4-in-1: 4ch 4-op FM, YM2149 (AY-3-8910 clone) and 2 different
# effects
- **`10xy`**: set LFO parameters.
- `10xy`: **set LFO parameters.**
- `x` toggles the LFO.
- `y` sets its speed.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`18xx`**: toggle extended channel 2 mode.
- `18xx`: **toggle extended channel 2 mode.**
- 0 disables it and 1 enables it.
- only in extended channel 2 chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`20xx`**: set SSG channel mode. `xx` may be one of the following:
- `00`: square
- `01`: noise
- `02`: square and noise
- `03`: nothing (apparently)
- `04`: envelope and square
- `05`: envelope and noise
- `06`: envelope and square and noise
- `07`: nothing
- **`21xx`**: set noise frequency. `xx` is a value between 00 and 1F.
- **`22xy`**: set envelope mode.
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `20xx`: **set SSG channel mode.**
- `0`: square
- `1`: noise
- `2`: square and noise
- `3`: nothing (apparently)
- `4`: envelope and square
- `5`: envelope and noise
- `6`: envelope and square and noise
- `7`: nothing
- `21xx`: **set noise frequency.** range is `00` to `1F`.
- `22xy`: **set envelope mode.**
- `x` sets the envelope shape:
- `0`: `\___` decay
- `4`: `/___` attack once
- `8`: `\\\\` saw
- `9`: `\___` decay
- `A`: `\/\/` inverse obelisco
- `B`: `\¯¯¯` decay once
- `C`: `////` inverse saw
- `D`: `/¯¯¯` attack
- `E`: `/\/\` obelisco
- `F`: `/___` attack once
- if `y` is 1 then the envelope will affect this channel.
- **`23xx`**: set envelope period low byte.
- **`24xx`**: set envelope period high byte.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`29xy`**: enable SSG auto-envelope mode.
- `23xx`: **set envelope period low byte.**
- `24xx`: **set envelope period high byte.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `29xy`: **enable SSG auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.
- **`30xx`**: enable envelope hard reset.
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value:
- 0: +0
@ -79,21 +79,21 @@ its soundchip is a 4-in-1: 4ch 4-op FM, YM2149 (AY-3-8910 clone) and 2 different
- 5: -3
- 6: -2
- 7: -1
- **`54xy`**: set RS of operator.
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`55xy`**: set SSG-EG of operator.
- `55xy`: **set SSG-EG of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value (0-8).
- values between 0 and 7 set SSG-EG.
- value 8 disables it.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -5,26 +5,26 @@ it is backward compatible with the original chip.
# effects
- **`10xy`**: set LFO parameters.
- `10xy`: **set LFO parameters.**
- `x` toggles the LFO.
- `y` sets its speed.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`18xx`**: toggle extended channel 3 mode.
- `18xx`: **toggle extended channel 3 mode.**
- 0 disables it and 1 enables it.
- only in extended channel 3 chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`20xx`**: set SSG channel mode. `xx` may be one of the following:
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `20xx`: **set SSG channel mode.**
- `00`: square
- `01`: noise
- `02`: square and noise
@ -33,66 +33,66 @@ it is backward compatible with the original chip.
- `05`: envelope and noise
- `06`: envelope and square and noise
- `07`: nothing
- **`21xx`**: set noise frequency. `xx` is a value between 00 and 1F.
- **`22xy`**: set envelope mode.
- `21xx`: **set noise frequency.** range is `00` to `1F`.
- `22xy`: **set envelope mode.**
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- `0`:` \___` decay
- `4`:` /___` attack once
- `8`:` \\\\` saw
- `9`:` \___` decay
- `A`:` \/\/` inverse obelisco
- `B`:` \¯¯¯` decay once
- `C`:` ////` inverse saw
- `D`:` /¯¯¯` attack
- `E`:` /\/\` obelisco
- `F`:` /___` attack once
- if `y` is 1 then the envelope will affect this channel.
- **`23xx`**: set envelope period low byte.
- **`24xx`**: set envelope period high byte.
- **`25xx`**: slide envelope period up.
- **`26xx`**: slide envelope period down.
- **`29xy`**: enable SSG auto-envelope mode.
- `23xx`: **set envelope period low byte.**
- `24xx`: **set envelope period high byte.**
- `25xx`: **slide envelope period up.**
- `26xx`: **slide envelope period down.**
- `29xy`: **enable SSG auto-envelope mode.**
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
- `x` is the numerator.
- `y` is the denominator.
- if `x` or `y` are 0 this will disable auto-envelope mode.
- **`30xx`**: enable envelope hard reset.
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value:
- 0: +0
- 1: +1
- 2: +2
- 3: +3
- 4: -0
- 5: -3
- 6: -2
- 7: -1
- **`54xy`**: set RS of operator.
- `0`: +0
- `1`: +1
- `2`: +2
- `3`: +3
- `4`: -0
- `5`: -3
- `6`: -2
- `7`: -1
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`55xy`**: set SSG-EG of operator.
- `55xy`: **set SSG-EG of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value (0-8).
- values between 0 and 7 set SSG-EG.
- value 8 disables it.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -1,67 +1,67 @@
# Yamaha YM2612
one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player, that via software mixing, thanks to Z80 sound CPU, can play more than one channel of straight-shot samples at once. As of Furnace 0.6pre5, Furnace offers DualPCM, which allows 2 channels of software-mixed 8-bit PCM samples at 13750 Hz.
one of two chips that powered the Sega Genesis. it is a six-channel, four-operator FM synthesizer. channel #6 can be turned into 8-bit PCM player, that via software mixing, thanks to Z80 sound CPU, can play more than one channel of straight-shot samples at once. as of Furnace 0.6pre5, Furnace offers DualPCM, which allows 2 channels of software-mixed 8-bit PCM samples at 13750 Hz.
# effects
- **`10xy`**: set LFO parameters.
- `10xy`: **set LFO parameters.**
- `x` toggles the LFO.
- `y` sets its speed.
- **`11xx`**: set feedback of channel.
- **`12xx`**: set operator 1 level.
- **`13xx`**: set operator 2 level.
- **`14xx`**: set operator 3 level.
- **`15xx`**: set operator 4 level.
- **`16xy`**: set multiplier of operator.
- `11xx`: **set feedback of channel.**
- `12xx`: **set operator 1 level.**
- `13xx`: **set operator 2 level.**
- `14xx`: **set operator 3 level.**
- `15xx`: **set operator 4 level.**
- `16xy`: **set multiplier of operator.**
- `x` is the operator (1-4).
- `y` is the multiplier.
- **`17xx`**: enable PCM channel.
- `17xx`: **enable PCM channel.**
- this only works on channel 6.
- **`18xx`**: toggle extended channel 3 mode.
- `18xx`: **toggle extended channel 3 mode.**
- 0 disables it and 1 enables it.
- only in extended channel 3 chip.
- **`19xx`**: set attack of all operators.
- **`1Axx`**: set attack of operator 1.
- **`1Bxx`**: set attack of operator 2.
- **`1Cxx`**: set attack of operator 3.
- **`1Dxx`**: set attack of operator 4.
- **`30xx`**: enable envelope hard reset.
- `19xx`: **set attack of all operators.**
- `1Axx`: **set attack of operator 1.**
- `1Bxx`: **set attack of operator 2.**
- `1Cxx`: **set attack of operator 3.**
- `1Dxx`: **set attack of operator 4.**
- `30xx`: **enable envelope hard reset.**
- this works by inserting a quick release and tiny delay before a new note.
- **`50xy`**: set AM of operator.
- `50xy`: **set AM of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` determines whether AM is on.
- **`51xy`**: set SL of operator.
- `51xy`: **set SL of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`52xy`**: set RR of operator.
- `52xy`: **set RR of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`53xy`**: set DT of operator.
- `53xy`: **set DT of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value:
- 0: -3
- 1: -2
- 2: -1
- 3: 0
- 4: 1
- 5: 2
- 6: 3
- 7: -0
- **`54xy`**: set RS of operator.
- `0`: -3
- `1`: -2
- `2`: -1
- `3`: 0
- `4`: 1
- `5`: 2
- `6`: 3
- `7`: -0
- `54xy`: **set RS of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value.
- **`55xy`**: set SSG-EG of operator.
- `55xy`: **set SSG-EG of operator.**
- `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value (0-8).
- values between 0 and 7 set SSG-EG.
- value 8 disables it.
- **`56xx`**: set DR of all operators.
- **`57xx`**: set DR of operator 1.
- **`58xx`**: set DR of operator 2.
- **`59xx`**: set DR of operator 3.
- **`5Axx`**: set DR of operator 4.
- **`5Bxx`**: set D2R/SR of all operators.
- **`5Cxx`**: set D2R/SR of operator 1.
- **`5Dxx`**: set D2R/SR of operator 2.
- **`5Exx`**: set D2R/SR of operator 3.
- **`5Fxx`**: set D2R/SR of operator 4.
- `56xx`: **set DR of all operators.**
- `57xx`: **set DR of operator 1.**
- `58xx`: **set DR of operator 2.**
- `59xx`: **set DR of operator 3.**
- `5Axx`: **set DR of operator 4.**
- `5Bxx`: **set D2R/SR of all operators.**
- `5Cxx`: **set D2R/SR of operator 1.**
- `5Dxx`: **set D2R/SR of operator 2.**
- `5Exx`: **set D2R/SR of operator 3.**
- `5Fxx`: **set D2R/SR of operator 4.**

View file

@ -46,11 +46,11 @@ SOFTWARE.
#include <emscripten.h>
#endif // EMSCRIPTEN
#ifdef WIN32
#define stat _stat
#define stricmp _stricmp
#include <cctype>
#include "dirent/dirent.h" // directly open the dirent file attached to this lib
#define PATH_SEP '\\'
#define PATH_SEP_STR "\\"
#ifndef PATH_MAX
#define PATH_MAX 260
#endif // PATH_MAX
@ -60,6 +60,7 @@ SOFTWARE.
#include <sys/types.h>
#include <dirent.h>
#define PATH_SEP '/'
#define PATH_SEP_STR "/"
#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#include "imgui.h"
@ -1440,10 +1441,14 @@ namespace IGFD
return fileNameExt;
}
void IGFD::FileManager::AddFile(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, const char& vFileType)
void IGFD::FileManager::AddFile(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, const char& vFileType, void* ent)
{
auto infos = std::make_shared<FileInfos>();
#ifdef _WIN32
struct dirent* dent=(struct dirent*)ent;
#endif
infos->filePath = vPath;
infos->fileNameExt = vFileName;
infos->fileNameExt_optimized = prOptimizeFilenameForSearchOperations(infos->fileNameExt);
@ -1473,6 +1478,24 @@ namespace IGFD
}
}
#ifdef _WIN32
SYSTEMTIME systemTime;
SYSTEMTIME localTime;
char timebuf[100];
infos->fileSize=dent->dwin_size;
if (FileTimeToSystemTime(&dent->dwin_mtime,&systemTime)==TRUE) {
if (SystemTimeToTzSpecificLocalTime(NULL,&systemTime,&localTime)==TRUE) {
snprintf(timebuf,99,"%d/%.2d/%.2d %.2d:%.2d",localTime.wYear,localTime.wMonth,localTime.wDay,localTime.wHour,localTime.wMinute);
} else {
snprintf(timebuf,99,"%d/%.2d/%.2d %.2d:%.2d",systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute);
}
infos->fileModifDate=timebuf;
} else {
infos->fileModifDate="???";
}
#endif
vFileDialogInternal.puFilterManager.prFillFileStyle(infos);
prCompleteFileInfos(infos);
@ -1510,9 +1533,9 @@ namespace IGFD
for (i = 0; i < n; i++)
{
struct dirent* ent = files[i];
std::string where = path + std::string("/") + std::string(ent->d_name);
std::string where = path + std::string(PATH_SEP_STR) + std::string(ent->d_name);
char fileType = 0;
#ifdef HAVE_DIRENT_TYPE
#if defined(HAVE_DIRENT_TYPE) || defined(_WIN32)
if (ent->d_type != DT_UNKNOWN)
{
switch (ent->d_type)
@ -1522,6 +1545,9 @@ namespace IGFD
case DT_DIR:
fileType = 'd'; break;
case DT_LNK:
#ifdef _WIN32
fileType = 'f';
#else
DIR* dirTest = opendir(where.c_str());
if (dirTest == NULL)
{
@ -1539,12 +1565,14 @@ namespace IGFD
fileType = 'd';
closedir(dirTest);
}
#endif
break;
}
}
else
#endif // HAVE_DIRENT_TYPE
{
#ifndef _WIN32
struct stat filestat;
if (stat(where.c_str(), &filestat) == 0)
{
@ -1557,11 +1585,12 @@ namespace IGFD
fileType = 'f';
}
}
#endif
}
auto fileNameExt = ent->d_name;
AddFile(vFileDialogInternal, path, fileNameExt, fileType);
AddFile(vFileDialogInternal, path, fileNameExt, fileType, ent);
}
for (i = 0; i < n; i++)
@ -1744,6 +1773,12 @@ namespace IGFD
//time_t st_mtime; /* time of last modification - not sure out of ntfs */
//time_t st_ctime; /* time of last status change - not sure out of ntfs */
#ifdef _WIN32
if (vInfos->fileType != 'd')
{
vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
}
#else
std::string fpn;
if (vInfos->fileType == 'f' || vInfos->fileType == 'l' || vInfos->fileType == 'd') // file
@ -1778,6 +1813,7 @@ namespace IGFD
vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
vInfos->fileModifDate="???";
}
#endif
}
}

View file

@ -883,7 +883,7 @@ namespace IGFD
void prRemoveFileNameInSelection(const std::string& vFileName); // selection : remove a file name
void prAddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName); // selection : add a file name
void AddFile(const FileDialogInternal& vFileDialogInternal,
const std::string& vPath, const std::string& vFileName, const char& vFileType); // add file called by scandir
const std::string& vPath, const std::string& vFileName, const char& vFileType, void* ent); // add file called by scandir
public:
FileManager();

View file

@ -36,8 +36,8 @@
//#define IGFD_KEY_BACKSPACE GLFW_KEY_BACKSPACE
// by ex you can quit the dialog by pressing the key excape
//#define USE_DIALOG_EXIT_WITH_KEY
//#define IGFD_EXIT_KEY GLFW_KEY_ESCAPE
#define USE_DIALOG_EXIT_WITH_KEY
#define IGFD_EXIT_KEY ImGuiKey_Escape
// widget
// filter combobox width

View file

@ -237,6 +237,10 @@ struct _wdirent {
/* File name */
wchar_t d_name[PATH_MAX+1];
/* Windows extensions */
size_t dwin_size;
FILETIME dwin_mtime;
};
typedef struct _wdirent _wdirent;
@ -277,6 +281,10 @@ struct dirent {
/* File name */
char d_name[PATH_MAX+1];
/* Windows extensions */
size_t dwin_size;
FILETIME dwin_mtime;
};
typedef struct dirent dirent;
@ -516,6 +524,9 @@ _wreaddir_r(
entry->d_off = 0;
entry->d_reclen = sizeof (struct _wdirent);
entry->dwin_size = ((size_t)datap->nFileSizeHigh<<32) | datap->nFileSizeLow;
entry->dwin_mtime = datap->ftLastWriteTime;
/* Set result address */
*result = entry;
@ -806,6 +817,9 @@ readdir_r(
entry->d_off = 0;
entry->d_reclen = sizeof (struct dirent);
entry->dwin_size = ((size_t)datap->nFileSizeHigh<<32) | datap->nFileSizeLow;
entry->dwin_mtime = datap->ftLastWriteTime;
} else {
/*
@ -821,6 +835,9 @@ readdir_r(
entry->d_ino = 0;
entry->d_off = -1;
entry->d_reclen = 0;
entry->dwin_size = 0;
entry->dwin_mtime.dwHighDateTime = 0;
entry->dwin_mtime.dwLowDateTime = 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -2,9 +2,11 @@
#### Zsound Repo
ZSM is part of the Zsound suite of Commander X16 audio tools found at:</br>
ZSM is part of the Zsound suite of Commander X16 audio tools found at:
https://github.com/ZeroByteOrg/zsound/
An alternative library with PCM support, ZSMKit, is avalable at:
https://github.com/mooinglemur/ZSMKit
#### Current ZSM Revision: 1
@ -69,14 +71,35 @@ The EXTCMD byte is formatted as `ccnnnnnn` where `c`=channel and `n`=number of b
### 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.
If the PCM header exists in the ZSM file, it will immediately follow the 0x80 end-of-data marker. The PCM header exists only if at least one PCM instrument exists.
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.
Since each instrument defined is 16 bytes, the size of the PCM header can be calculated
as 4+(16*(last_instrument_index+1)).
Offset|Type|Value
--|--|--
0x00-0x02|String|"PCM"
0x03|Byte|The last PCM instrument index
0x04-0x13|Mixed|Instrument definition for instrument 0x00
0x14-0x23|Mixed|(optional) Instrument definition for instrument 0x01
...
### Instrument definition
Offset|Type|Value
--|--|--
0x00|Byte|This instrument's index
0x01|Bitmask|AUDIO_CTRL: 00**DC**0000: D is set for 16-bit, and clear for 8-bit. C is set for stereo and clear for mono
0x02-0x04|24-bit int|Little-endian offset into the PCM data block
0x05-0x07|24-bit int|Little-endian length of PCM data
0x08|Bitmask|Features: **L**xxxxxxx: L is set if the sample is looped
0x09-0x0b|24-bit int|Little-endian loop point offset (relative, 0 is the beginning of this instrument's sample)
0x0c-0x0f|...|Reserved for expansion
Any offset values contained in the PCM data header block are relative to the beginning of the PCM sample data section, not to the PCM header or 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.
This is a blob of PCM data with no internal formatting. Offsets into this blob are provided via the PCM header. The end of this blob will be the end of the ZSM file.
## EXTCMD Channel Scifications
@ -108,7 +131,13 @@ The Custom channel data may take whatever format is desired for any particular p
### EXTCMD Channel:
#### 0: PCM audio
The structure of data within this channel is not yet defined.
This EXTCMD stream can contain one or more command + argument pairs.
command|meaning|argument|description
---|---|---|---
0x00|AUDIO_CTRL byte|byte|This byte sets PCM channel volume and/or clears the FIFO
0x01|AUDIO_RATE byte|byte|A value from 0x00-0x80 to set the sample rate (playback speed)
0x02|Instrument trigger|byte|Triggers the PCM instrument specified by this byte index
#### 1: Expansion Sound Devices
@ -120,7 +149,7 @@ Players implementing this channel should implement detection routines during ini
An expansion HW write will contain the following data:
Chip ID|Nuber of writes (`N`)| `N` tuples of data
Chip ID|Number of writes (`N`)| `N` tuples of data
--|--|--
one byte|one byte|N * tuple_size bytes
@ -133,7 +162,14 @@ There are currently no supported expansion HW IDs assigned.
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.
The synchronization format currently defines this one event type:
Event Type|Description|Message Format
--|--|--
`0x00`|Generic sync message|`xx` (any value from `0x00`-`0xff`)
An example of an EXTCMD containing one sync event might look as follows: `0x40 0x82 0x00 0x05`
#### 3: Custom

View file

@ -236,6 +236,8 @@ enum DivDispatchCmds {
DIV_CMD_NES_LINEAR_LENGTH,
DIV_CMD_EXTERNAL, // (value)
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
DIV_CMD_MAX

View file

@ -173,6 +173,7 @@ void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size)
if (bbIn[i]==NULL) continue;
if (bb[i]==NULL) continue;
for (size_t j=0; j<runtotal; j++) {
if (bbIn[i][j]==temp[i]) continue;
temp[i]=bbIn[i][j];
blip_add_delta_fast(bb[i],j,temp[i]-prevSample[i]);
prevSample[i]=temp[i];
@ -183,6 +184,7 @@ void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size)
if (bbIn[i]==NULL) continue;
if (bb[i]==NULL) continue;
for (size_t j=0; j<runtotal; j++) {
if (bbIn[i][j]==temp[i]) continue;
temp[i]=bbIn[i][j];
blip_add_delta(bb[i],j,temp[i]-prevSample[i]);
prevSample[i]=temp[i];
@ -274,12 +276,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)->setCore(eng->getConfInt("c64Core",0));
((DivPlatformC64*)dispatch)->setChipModel(true);
break;
case DIV_SYSTEM_C64_8580:
dispatch=new DivPlatformC64;
((DivPlatformC64*)dispatch)->setFP(eng->getConfInt("c64Core",1)==1);
((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0));
((DivPlatformC64*)dispatch)->setChipModel(false);
break;
case DIV_SYSTEM_YM2151:

View file

@ -1678,6 +1678,51 @@ int DivEngine::addSubSong() {
return song.subsong.size()-1;
}
int DivEngine::duplicateSubSong(int index) {
if (song.subsong.size()>=127) return -1;
BUSY_BEGIN;
saveLock.lock();
DivSubSong* theCopy=new DivSubSong;
DivSubSong* theOrig=song.subsong[index];
theCopy->name=theOrig->name;
theCopy->notes=theOrig->notes;
theCopy->hilightA=theOrig->hilightA;
theCopy->hilightB=theOrig->hilightB;
theCopy->timeBase=theOrig->timeBase;
theCopy->arpLen=theOrig->arpLen;
theCopy->speeds=theOrig->speeds;
theCopy->virtualTempoN=theOrig->virtualTempoN;
theCopy->virtualTempoD=theOrig->virtualTempoD;
theCopy->hz=theOrig->hz;
theCopy->patLen=theOrig->patLen;
theCopy->ordersLen=theOrig->ordersLen;
theCopy->orders=theOrig->orders;
memcpy(theCopy->chanShow,theOrig->chanShow,DIV_MAX_CHANS*sizeof(bool));
memcpy(theCopy->chanCollapse,theOrig->chanCollapse,DIV_MAX_CHANS);
for (int i=0; i<DIV_MAX_CHANS; i++) {
theCopy->chanName[i]=theOrig->chanName[i];
theCopy->chanShortName[i]=theOrig->chanShortName[i];
theCopy->pat[i].effectCols=theOrig->pat[i].effectCols;
for (int j=0; j<DIV_MAX_PATTERNS; j++) {
if (theOrig->pat[i].data[j]==NULL) continue;
DivPattern* origPat=theOrig->pat[i].getPattern(j,false);
DivPattern* copyPat=theCopy->pat[i].getPattern(j,true);
origPat->copyOn(copyPat);
}
}
song.subsong.push_back(theCopy);
saveLock.unlock();
BUSY_END;
return song.subsong.size()-1;
}
bool DivEngine::removeSubSong(int index) {
if (song.subsong.size()<=1) return false;
stop();

View file

@ -54,8 +54,8 @@
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
#define DIV_VERSION "dev159"
#define DIV_ENGINE_VERSION 159
#define DIV_VERSION "dev160"
#define DIV_ENGINE_VERSION 160
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -1052,6 +1052,9 @@ class DivEngine {
// add subsong
int addSubSong();
// duplicate subsong
int duplicateSubSong(int index);
// remove subsong
bool removeSubSong(int index);

View file

@ -1047,6 +1047,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.systemFlags[0].set("dpcmMode",false);
}
// C64 no key priority
if (ds.system[0]==DIV_SYSTEM_C64_8580 || ds.system[0]==DIV_SYSTEM_C64_6581) {
ds.systemFlags[0].set("keyPriority",false);
}
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
if (active) quitDispatch();
@ -2927,6 +2932,15 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
}
}
// C64 key priority compat
if (ds.version<160) {
for (int i=0; i<ds.systemLen; i++) {
if (ds.system[i]==DIV_SYSTEM_C64_8580 || ds.system[i]==DIV_SYSTEM_C64_6581) {
ds.systemFlags[i].set("keyPriority",false);
}
}
}
if (active) quitDispatch();
BUSY_BEGIN_SOFT;
saveLock.lock();

View file

@ -21,6 +21,7 @@
#include "../engine.h"
#include "sound/c64_fp/siddefs-fp.h"
#include <math.h>
#include "../../ta-log.h"
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
@ -64,34 +65,45 @@ const char** DivPlatformC64::getRegisterSheet() {
}
void DivPlatformC64::acquire(short** buf, size_t len) {
int dcOff=isFP?0:sid.get_dc(0);
int dcOff=(sidCore)?0:sid->get_dc(0);
for (size_t i=0; i<len; i++) {
if (!writes.empty()) {
QueuedWrite w=writes.front();
if (isFP) {
sid_fp.write(w.addr,w.val);
if (sidCore==2) {
dSID_write(sid_d,w.addr,w.val);
} else if (sidCore==1) {
sid_fp->write(w.addr,w.val);
} else {
sid.write(w.addr,w.val);
};
sid->write(w.addr,w.val);
}
regPool[w.addr&0x1f]=w.val;
writes.pop();
}
if (isFP) {
sid_fp.clock(4,&buf[0][i]);
if (sidCore==2) {
double o=dSID_render(sid_d);
buf[0][i]=32767*CLAMP(o,-1.0,1.0);
if (++writeOscBuf>=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;
oscBuf[0]->data[oscBuf[0]->needle++]=sid_d->lastOut[0];
oscBuf[1]->data[oscBuf[1]->needle++]=sid_d->lastOut[1];
oscBuf[2]->data[oscBuf[2]->needle++]=sid_d->lastOut[2];
}
} else if (sidCore==1) {
sid_fp->clock(4,&buf[0][i]);
if (++writeOscBuf>=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();
buf[0][i]=sid.output();
sid->clock();
buf[0][i]=sid->output();
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;
oscBuf[2]->data[oscBuf[2]->needle++]=(sid.last_chan_out[2]-dcOff)>>5;
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;
}
}
}
@ -106,7 +118,9 @@ void DivPlatformC64::updateFilter() {
void DivPlatformC64::tick(bool sysTick) {
bool willUpdateFilter=false;
for (int i=0; i<3; i++) {
for (int _i=0; _i<3; _i++) {
int i=chanOrder[_i];
chan[i].std.next();
if (chan[i].std.vol.had) {
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
@ -179,8 +193,8 @@ void DivPlatformC64::tick(bool sysTick) {
if (--chan[i].testWhen<1) {
if (!chan[i].resetMask && !chan[i].inPorta) {
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
rWrite(i*7+5,0);
rWrite(i*7+6,0);
rWrite(i*7+5,testAD);
rWrite(i*7+6,testSR);
rWrite(i*7+4,(chan[i].wave<<4)|(ins->c64.noTest?0:8)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1));
}
}
@ -212,6 +226,7 @@ void DivPlatformC64::tick(bool sysTick) {
}
int DivPlatformC64::dispatch(DivCommand c) {
if (c.chan>2) return 0;
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
@ -249,6 +264,16 @@ int DivPlatformC64::dispatch(DivCommand c) {
if (chan[c.chan].insChanged) {
chan[c.chan].insChanged=false;
}
if (keyPriority) {
if (chanOrder[1]==c.chan) {
chanOrder[1]=chanOrder[2];
chanOrder[2]=c.chan;
} else if (chanOrder[0]==c.chan) {
chanOrder[0]=chanOrder[1];
chanOrder[1]=chanOrder[2];
chanOrder[2]=c.chan;
}
}
chan[c.chan].macroInit(ins);
break;
}
@ -352,7 +377,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
break;
case DIV_CMD_C64_CUTOFF:
if (c.value>100) c.value=100;
filtCut=c.value*2047/100;
filtCut=(c.value+2)*2047/102;
updateFilter();
break;
case DIV_CMD_C64_FINE_CUTOFF:
@ -438,10 +463,17 @@ int DivPlatformC64::dispatch(DivCommand c) {
void DivPlatformC64::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
if (isFP) {
sid_fp.mute(ch,mute);
if (sidCore==2) {
dSID_setMuteMask(
sid_d,
(isMuted[0]?0:1)|
(isMuted[1]?0:2)|
(isMuted[2]?0:4)
);
} else if (sidCore==1) {
sid_fp->mute(ch,mute);
} else {
sid.set_is_muted(ch,mute);
sid->set_is_muted(ch,mute);
}
}
@ -500,7 +532,7 @@ bool DivPlatformC64::getWantPreNote() {
}
float DivPlatformC64::getPostAmp() {
return isFP?3.0f:1.0f;
return (sidCore==1)?3.0f:1.0f;
}
void DivPlatformC64::reset() {
@ -510,10 +542,20 @@ void DivPlatformC64::reset() {
chan[i].std.setEngine(parent);
}
if (isFP) {
sid_fp.reset();
if (sidCore==2) {
dSID_init(sid_d,chipClock,rate,sidIs6581?6581:8580,needInitTables);
dSID_setMuteMask(
sid_d,
(isMuted[0]?0:1)|
(isMuted[1]?0:2)|
(isMuted[2]?0:4)
);
needInitTables=false;
} else if (sidCore==1) {
sid_fp->reset();
sid_fp->clockSilent(16000);
} else {
sid.reset();
sid->reset();
}
memset(regPool,0,32);
@ -524,6 +566,10 @@ void DivPlatformC64::reset() {
filtCut=2047;
resetTime=1;
vol=15;
chanOrder[0]=0;
chanOrder[1]=1;
chanOrder[2]=2;
}
void DivPlatformC64::poke(unsigned int addr, unsigned short val) {
@ -535,23 +581,11 @@ void DivPlatformC64::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformC64::setChipModel(bool is6581) {
if (is6581) {
if (isFP) {
sid_fp.setChipModel(reSIDfp::MOS6581);
} else {
sid.set_chip_model(MOS6581);
}
} else {
if (isFP) {
sid_fp.setChipModel(reSIDfp::MOS8580);
} else {
sid.set_chip_model(MOS8580);
}
}
sidIs6581=is6581;
}
void DivPlatformC64::setFP(bool fp) {
isFP=fp;
void DivPlatformC64::setCore(unsigned char which) {
sidCore=which;
}
void DivPlatformC64::setFlags(const DivConfig& flags) {
@ -572,21 +606,58 @@ void DivPlatformC64::setFlags(const DivConfig& flags) {
for (int i=0; i<3; i++) {
oscBuf[i]->rate=rate/16;
}
if (isFP) {
if (sidCore>0) {
rate/=4;
sid_fp.setSamplingParameters(chipClock,reSIDfp::DECIMATE,rate,0);
if (sidCore==1) sid_fp->setSamplingParameters(chipClock,reSIDfp::DECIMATE,rate,0);
}
keyPriority=flags.getBool("keyPriority",true);
testAD=((flags.getInt("testAttack",0)&15)<<4)|(flags.getInt("testDecay",0)&15);
testSR=((flags.getInt("testSustain",0)&15)<<4)|(flags.getInt("testRelease",0)&15);
}
int DivPlatformC64::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p;
dumpWrites=false;
skipRegisterWrites=false;
needInitTables=true;
writeOscBuf=0;
for (int i=0; i<3; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
if (sidCore==2) {
sid=NULL;
sid_fp=NULL;
sid_d=new struct SID_chip;
} else if (sidCore==1) {
sid=NULL;
sid_fp=new reSIDfp::SID;
sid_d=NULL;
} else {
sid=new SID;
sid_fp=NULL;
sid_d=NULL;
}
if (sidIs6581) {
if (sidCore==2) {
// do nothing
} else if (sidCore==1) {
sid_fp->setChipModel(reSIDfp::MOS6581);
} else {
sid->set_chip_model(MOS6581);
}
} else {
if (sidCore==2) {
// do nothing
} else if (sidCore==1) {
sid_fp->setChipModel(reSIDfp::MOS8580);
} else {
sid->set_chip_model(MOS8580);
}
}
setFlags(flags);
reset();
@ -598,6 +669,9 @@ void DivPlatformC64::quit() {
for (int i=0; i<3; i++) {
delete oscBuf[i];
}
if (sid!=NULL) delete sid;
if (sid_fp!=NULL) delete sid_fp;
if (sid_d!=NULL) delete sid_d;
}
DivPlatformC64::~DivPlatformC64() {

View file

@ -24,6 +24,7 @@
#include <queue>
#include "sound/c64/sid.h"
#include "sound/c64_fp/SID.h"
#include "sound/c64_d/dsid.h"
class DivPlatformC64: public DivDispatch {
struct Channel: public SharedChannel<signed char> {
@ -64,11 +65,16 @@ class DivPlatformC64: public DivDispatch {
unsigned char filtControl, filtRes, vol;
unsigned char writeOscBuf;
unsigned char sidCore;
int filtCut, resetTime;
bool isFP;
SID sid;
reSIDfp::SID sid_fp;
bool keyPriority, sidIs6581, needInitTables;
unsigned char chanOrder[3];
unsigned char testAD, testSR;
SID* sid;
reSIDfp::SID* sid_fp;
struct SID_chip* sid_d;
unsigned char regPool[32];
friend void putDispatchChip(void*,int);
@ -101,7 +107,7 @@ class DivPlatformC64: public DivDispatch {
const char** getRegisterSheet();
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void setChipModel(bool is6581);
void setFP(bool fp);
void setCore(unsigned char which);
void quit();
~DivPlatformC64();
};

View file

@ -19,6 +19,7 @@
#include "gb.h"
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} }
@ -80,6 +81,7 @@ void DivPlatformGB::acquire(short** buf, size_t len) {
}
void DivPlatformGB::updateWave() {
logV("WAVE UPDATE");
rWrite(0x1a,0);
for (int i=0; i<16; i++) {
int nibble1=ws.output[((i<<1)+antiClickWavePos)&31];
@ -299,6 +301,7 @@ void DivPlatformGB::tick(bool sysTick) {
}
if (chan[i].keyOn) {
if (i==2) { // wave
rWrite(16+i*5,0x00);
rWrite(16+i*5,0x80);
rWrite(16+i*5+2,gbVolMap[chan[i].outVol]);
} else {
@ -664,9 +667,7 @@ void DivPlatformGB::setFlags(const DivConfig& flags) {
}
invertWave=flags.getBool("invertWave",true);
enoughAlready=flags.getBool("enoughAlready",false);
}
int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
chipClock=4194304;
CHECK_CUSTOM_CLOCK;
rate=chipClock/16;
@ -675,6 +676,9 @@ int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, const DivConfig
oscBuf[i]=new DivDispatchOscBuffer;
oscBuf[i]->rate=rate;
}
}
int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p;
dumpWrites=false;
skipRegisterWrites=false;

View file

@ -207,7 +207,7 @@ void DivPlatformN163::tick(bool sysTick) {
}
}
if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val) {
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].waveMode&0x2) {

View file

@ -423,7 +423,7 @@ const void* DivPlatformSegaPCM::getSampleMem(int index) {
}
size_t DivPlatformSegaPCM::getSampleMemCapacity(int index) {
return index == 0 ? 16777216 : 0;
return index == 0 ? 2097152 : 0;
}
size_t DivPlatformSegaPCM::getSampleMemUsage(int index) {
@ -465,7 +465,7 @@ void DivPlatformSegaPCM::reset() {
void DivPlatformSegaPCM::renderSamples(int sysID) {
size_t memPos=0;
memset(sampleMem,0,16777216);
memset(sampleMem,0,2097152);
memset(sampleLoaded,0,256*sizeof(bool));
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
memset(sampleEndSegaPCM,0,256);
@ -482,7 +482,7 @@ void DivPlatformSegaPCM::renderSamples(int sysID) {
}
logV("- sample %d will be at %x with length %x",i,memPos,alignedSize);
sampleLoaded[i]=true;
if (memPos>=16777216) break;
if (memPos>=2097152) break;
sampleOffSegaPCM[i]=memPos;
for (unsigned int j=0; j<alignedSize; j++) {
if (j>=sample->samples) {
@ -491,10 +491,10 @@ void DivPlatformSegaPCM::renderSamples(int sysID) {
sampleMem[memPos++]=((unsigned char)sample->data8[j]+0x80);
}
sampleEndSegaPCM[i]=((memPos+0xff)>>8)-1;
if (memPos>=16777216) break;
if (memPos>=2097152) break;
}
logV(" and it ends in %d",sampleEndSegaPCM[i]);
if (memPos>=16777216) break;
if (memPos>=2097152) break;
}
sampleMemLen=memPos;
}
@ -522,10 +522,10 @@ int DivPlatformSegaPCM::init(DivEngine* p, int channels, int sugRate, const DivC
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
sampleMem=new unsigned char[16777216];
sampleMem=new unsigned char[2097152];
pcm.set_bank(segapcm_device::BANK_12M|segapcm_device::BANK_MASKF8);
pcm.set_read([this](unsigned int addr) -> unsigned char {
return sampleMem[addr&0xffffff];
return sampleMem[addr&0x1fffff];
});
setFlags(flags);
reset();

View file

@ -0,0 +1,19 @@
Copyright (c) 2021 DefleMask Team
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.

View file

@ -0,0 +1,11 @@
dSID
===
This is the SID core used in DefleMask.
The project started as a very careful port from jsSID, comparing the wave
output from both, ensuring they were exactly the same.
## License
MIT License

View file

@ -0,0 +1,367 @@
#include "dsid.h"
#include <stdio.h>
#include <math.h> // INFINITY
#include <stdlib.h>
#include <string.h> // memset, memcpy
#define SID_OUT_SCALE (0x10000 * 3 * 16)
// CONTROL
#define GAT 0x01
#define SYN 0x02
#define RNG 0x04
#define TST 0x08
#define TRI 0x10
#define SAW 0x20
#define PUL 0x40
#define NOI 0x80
#define _HZ 0x10
#define DECSUS 0x40
#define ATK 0x80
// filter mode (high)
#define LP 0x10
#define BP 0x20
#define HP 0x40
#define OFF3 0x80
#define waveforms_add_sample(_id,_s) \
sid->lastOut[_id]=(_s);
const int Aexp[256] = {
1, 30, 30, 30, 30, 30, 30, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
double cmbWF(int chn, int *wfa, int index, int differ6581, struct SID_globals *g) {
if (differ6581 && g->model == 6581)
index &= 0x7FF;
return wfa[index];
}
void cCmbWF(int *wfa, double bitmul, double bstr, double trh) {
for (int i = 0; i < 4096; i++) {
wfa[i] = 0;
for (int j = 0; j < 12; j++) {
double blvl = 0;
for (int k = 0; k < 12; k++) {
blvl += (bitmul / pow(bstr, abs(k - j))) * (((i >> k) & 1) - 0.5);
}
wfa[i] += (blvl >= trh) ? pow(2, j) : 0;
}
wfa[i] *= 12;
}
}
void dSID_init(struct SID_chip* sid, double clockRate, double samplingRate, int model, unsigned char init_wf) {
if (model == 6581) {
sid->g.model = 6581;
} else {
sid->g.model = 8580;
}
memset(sid->M,0,MemLen);
memset(sid->SIDct, 0, sizeof(sid->SIDct));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
sid->SIDct[i].ch[j].Ast = _HZ;
sid->SIDct[i].ch[j].nLFSR = 0x7FFFF8;
sid->SIDct[i].ch[j].prevwfout = 0;
}
sid->SIDct[i].ch[0].FSW = 1;
sid->SIDct[i].ch[1].FSW = 2;
sid->SIDct[i].ch[2].FSW = 4;
}
sid->g.ctfr = -2.0 * 3.14 * (12500.0 / 256.0) / samplingRate,
sid->g.ctf_ratio_6581 = -2.0 * 3.14 * (samplingRate / 44100.0) * (20000.0 / 256.0) / samplingRate;
sid->g.ckr = clockRate / samplingRate;
const double bAprd[16] = {9, 32 * 1, 63 * 1, 95 * 1, 149 * 1, 220 * 1,
267 * 1, 313 * 1, 392 * 1, 977 * 1, 1954 * 1, 3126 * 1,
3907 * 1, 11720 * 1, 19532 * 1, 31251 * 1};
const int bAstp[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
memcpy(&sid->g.Aprd, &bAprd, sizeof(bAprd));
memcpy(&sid->g.Astp, &bAstp, sizeof(bAstp));
if (init_wf) {
cCmbWF(sid->g.trsaw, 0.8, 2.4, 0.64);
cCmbWF(sid->g.pusaw, 1.4, 1.9, 0.68);
cCmbWF(sid->g.Pulsetrsaw, 0.8, 2.5, 0.64);
for (int i = 0; i < 2048; i++) {
double ctf = (double) i / 8.0 + 0.2;
if (model == 8580) {
ctf = 1 - exp(ctf * sid->g.ctfr);
} else {
if (ctf < 24) {
ctf = 2.0 * sin(771.78 / samplingRate);
} else {
ctf = (44100.0 / samplingRate) - 1.263 * (44100.0 / samplingRate) * exp(ctf * sid->g.ctf_ratio_6581);
}
}
sid->g.ctf_table[i] = ctf;
}
}
double prd0 = sid->g.ckr > 9 ? sid->g.ckr : 9;
sid->g.Aprd[0] = prd0;
sid->g.Astp[0] = ceil(prd0 / 9);
}
double dSID_render(struct SID_chip* sid) {
double flin = 0, output = 0;
double wfout = 0;
for (int chn = 0; chn < 3; chn++) {
struct SIDVOICE *voic = &((struct SIDMEM *) (sid->M))->v[chn];
double pgt = (sid->SIDct->ch[chn].Ast & GAT);
uint8_t ctrl = voic->control;
uint8_t wf = ctrl & 0xF0;
uint8_t test = ctrl & TST;
uint8_t SR = voic->susres;
double tmp = 0;
if (pgt != (ctrl & GAT)) {
if (pgt) {
sid->SIDct->ch[chn].Ast &= 0xFF - (GAT | ATK | DECSUS);
} else {
sid->SIDct->ch[chn].Ast = (GAT | ATK | DECSUS);
if ((SR & 0xF) > (sid->SIDct->ch[chn].pSR & 0xF))
tmp = 1;
}
}
sid->SIDct->ch[chn].pSR = SR;
sid->SIDct->ch[chn].rcnt += sid->g.ckr;
if (sid->SIDct->ch[chn].rcnt >= 0x8000)
sid->SIDct->ch[chn].rcnt -= 0x8000;
static double step;
double prd;
if (sid->SIDct->ch[chn].Ast & ATK) {
step = voic->attack;
prd = sid->g.Aprd[(int) step];
} else if (sid->SIDct->ch[chn].Ast & DECSUS) {
step = voic->decay;
prd = sid->g.Aprd[(int) step];
} else {
step = SR & 0xF;
prd = sid->g.Aprd[(int) step];
}
step = sid->g.Astp[(int) step];
if (sid->SIDct->ch[chn].rcnt >= prd && sid->SIDct->ch[chn].rcnt < prd + sid->g.ckr &&
tmp == 0) {
sid->SIDct->ch[chn].rcnt -= prd;
if ((sid->SIDct->ch[chn].Ast & ATK) ||
++sid->SIDct->ch[chn].expcnt == Aexp[(int) sid->SIDct->ch[chn].envcnt]) {
if (!(sid->SIDct->ch[chn].Ast & _HZ)) {
if (sid->SIDct->ch[chn].Ast & ATK) {
sid->SIDct->ch[chn].envcnt += step;
if (sid->SIDct->ch[chn].envcnt >= 0xFF) {
sid->SIDct->ch[chn].envcnt = 0xFF;
sid->SIDct->ch[chn].Ast &= 0xFF - ATK;
}
} else if (!(sid->SIDct->ch[chn].Ast & DECSUS) ||
sid->SIDct->ch[chn].envcnt > (SR >> 4) + (SR & 0xF0)) {
sid->SIDct->ch[chn].envcnt -= step;
if (sid->SIDct->ch[chn].envcnt <= 0 &&
sid->SIDct->ch[chn].envcnt + step != 0) {
sid->SIDct->ch[chn].envcnt = 0;
sid->SIDct->ch[chn].Ast |= _HZ;
}
}
}
sid->SIDct->ch[chn].expcnt = 0;
} else {
}
}
sid->SIDct->ch[chn].envcnt = (int) sid->SIDct->ch[chn].envcnt & 0xFF;
double aAdd = (voic->freq_low + voic->freq_high * 256) * sid->g.ckr;
if (test || ((ctrl & SYN) && sid->SIDct->sMSBrise)) {
sid->SIDct->ch[chn].pacc = 0;
} else {
sid->SIDct->ch[chn].pacc += aAdd;
if (sid->SIDct->ch[chn].pacc > 0xFFFFFF)
sid->SIDct->ch[chn].pacc -= 0x1000000;
}
double MSB = (int) sid->SIDct->ch[chn].pacc & 0x800000;
sid->SIDct->sMSBrise = (MSB > ((int) sid->SIDct->ch[chn].pracc & 0x800000)) ? 1 : 0;
if (wf & NOI) {
tmp = sid->SIDct->ch[chn].nLFSR;
if ((((int) sid->SIDct->ch[chn].pacc & 0x100000) !=
((int) sid->SIDct->ch[chn].pracc & 0x100000)) ||
aAdd >= 0x100000) {
step = ((int) tmp & 0x400000) ^ (((int) tmp & 0x20000) << 5);
tmp = (((int) tmp << 1) + (step > 0 || test)) & 0x7FFFFF;
sid->SIDct->ch[chn].nLFSR = tmp;
}
wfout = (wf & 0x70) ? 0
: (((int) tmp & 0x100000) >> 5) + (((int) tmp & 0x40000) >> 4) +
(((int) tmp & 0x4000) >> 1) + (((int) tmp & 0x800) << 1) +
(((int) tmp & 0x200) << 2) + (((int) tmp & 0x20) << 5) +
(((int) tmp & 0x04) << 7) + (((int) tmp & 0x01) << 8);
} else if (wf & PUL) {
double pw = (voic->pw_low + (voic->pw_high) * 256) * 16;
tmp = (int) aAdd >> 9;
if (0 < pw && pw < tmp)
pw = tmp;
tmp = (int) tmp ^ 0xFFFF;
if (pw > tmp)
pw = tmp;
tmp = (int) sid->SIDct->ch[chn].pacc >> 8;
if (wf == PUL) {
int lel = ((int) aAdd >> 16);
if (lel > 0) {
step = 256.0 / (double) lel;
} else {
step = INFINITY;
}
if (test)
wfout = 0xFFFF;
else if (tmp < pw) {
double lim = (0xFFFF - pw) * step;
if (lim > 0xFFFF)
lim = 0xFFFF;
wfout = lim - (pw - tmp) * step;
if (wfout < 0)
wfout = 0;
} else {
double lim = pw * step;
if (lim > 0xFFFF)
lim = 0xFFFF;
wfout = (0xFFFF - tmp) * step - lim;
if (wfout >= 0)
wfout = 0xFFFF;
wfout = (int) wfout & 0xFFFF;
}
} else {
wfout = (tmp >= pw || test) ? 0xFFFF : 0;
if (wf & TRI) {
if (wf & SAW) {
wfout =
(wfout) ? cmbWF(chn, sid->g.Pulsetrsaw, (int) tmp >> 4, 1, &sid->g) : 0;
} else {
tmp = (int) sid->SIDct->ch[chn].pacc ^ (ctrl & RNG ? sid->SIDct->sMSB : 0);
wfout =
(wfout)
? cmbWF(chn, sid->g.pusaw,
((int) tmp ^ ((int) tmp & 0x800000 ? 0xFFFFFF : 0)) >> 11,
0, &sid->g)
: 0;
}
} else if (wf & SAW)
wfout = (wfout) ? cmbWF(chn, sid->g.pusaw, (int) tmp >> 4, 1, &sid->g) : 0;
}
} else if (wf & SAW) {
wfout = (int) sid->SIDct->ch[chn].pacc >> 8;
if (wf & TRI)
wfout = cmbWF(chn, sid->g.trsaw, (int) wfout >> 4, 1, &sid->g);
else {
step = aAdd / 0x1200000;
wfout += wfout * step;
if (wfout > 0xFFFF)
wfout = 0xFFFF - (wfout - 0x10000) / step;
}
} else if (wf & TRI) {
tmp = (int) sid->SIDct->ch[chn].pacc ^ (ctrl & RNG ? sid->SIDct->sMSB : 0);
wfout = ((int) tmp ^ ((int) tmp & 0x800000 ? 0xFFFFFF : 0)) >> 7;
}
if (wf)
sid->SIDct->ch[chn].prevwfout = wfout;
else {
wfout = sid->SIDct->ch[chn].prevwfout;
}
sid->SIDct->ch[chn].pracc = sid->SIDct->ch[chn].pacc;
sid->SIDct->sMSB = MSB;
// double preflin = flin;
if ((sid->mute_mask & (1 << chn))) {
if (sid->M[0x17] & sid->SIDct->ch[chn].FSW) {
double chnout = (wfout - 0x8000) * (sid->SIDct->ch[chn].envcnt / 256);
flin += chnout;
// fake filter for solo waveform ahead
// mostly copypasted from below
double fakeflin = chnout;
double fakeflout = 0;
static double fakeplp[3] = {0};
static double fakepbp[3] = {0};
double ctf = sid->g.ctf_table[((sid->M[0x15]&7)|(sid->M[0x16]<<3))&0x7ff];
double reso;
if (sid->g.model == 8580) {
reso = pow(2, ((double) (4 - (double) (sid->M[0x17] >> 4)) / 8));
} else {
reso = (sid->M[0x17] > 0x5F) ? 8.0 / (double) (sid->M[0x17] >> 4) : 1.41;
}
double tmp = fakeflin + fakepbp[chn] * reso + fakeplp[chn];
if (sid->M[0x18] & HP)
fakeflout -= tmp;
tmp = fakepbp[chn] - tmp * ctf;
fakepbp[chn] = tmp;
if (sid->M[0x18] & BP)
fakeflout -= tmp;
tmp = fakeplp[chn] + tmp * ctf;
fakeplp[chn] = tmp;
if (sid->M[0x18] & LP)
fakeflout += tmp;
double wf_out = (fakeflout / SID_OUT_SCALE) * (sid->M[0x18] & 0xF) * 65535;
waveforms_add_sample(chn, wf_out);
} else if ((chn % 3) != 2 || !(sid->M[0x18] & OFF3)) {
double chnout = (wfout - 0x8000) * (sid->SIDct->ch[chn].envcnt / 256);
output += chnout;
double wf_out = (chnout / SID_OUT_SCALE) * (sid->M[0x18] & 0xF) * 65535;
waveforms_add_sample(chn, wf_out);
}
} else {
waveforms_add_sample(chn, 0);
}
}
int M1 = 0;
if (M1 & 3)
sid->M[0x1B] = (int) wfout >> 8;
sid->M[0x1C] = sid->SIDct->ch[2].envcnt;
double ctf = sid->g.ctf_table[((sid->M[0x15]&7)|(sid->M[0x16]<<3))&0x7ff];
double reso;
if (sid->g.model == 8580) {
reso = pow(2, ((double) (4 - (double) (sid->M[0x17] >> 4)) / 8));
} else {
reso = (sid->M[0x17] > 0x5F) ? 8.0 / (double) (sid->M[0x17] >> 4) : 1.41;
}
double tmp = flin + sid->SIDct->pbp * reso + sid->SIDct->plp;
if (sid->M[0x18] & HP)
output -= tmp;
tmp = sid->SIDct->pbp - tmp * ctf;
sid->SIDct->pbp = tmp;
if (sid->M[0x18] & BP)
output -= tmp;
tmp = sid->SIDct->plp + tmp * ctf;
sid->SIDct->plp = tmp;
if (sid->M[0x18] & LP)
output += tmp;
return (output / SID_OUT_SCALE) * (sid->M[0x18] & 0xF);
}
void dSID_setMuteMask(struct SID_chip* sid, int mute_mask) {
sid->mute_mask = mute_mask;
}
float dSID_getVolume(struct SID_chip* sid, int channel) {
if ((sid->M[0x18] & 0xF) == 0)
return 0;
return sid->SIDct[0].ch[channel].envcnt / 256.0f;
}
void dSID_write(struct SID_chip* sid, unsigned char addr, unsigned char val) {
sid->M[addr&0x1f]=val;
}

View file

@ -0,0 +1,97 @@
#ifndef DSID_H
#define DSID_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
struct SID_ctx_chan {
double rcnt;
double envcnt;
double expcnt;
double pacc;
double pracc;
int FSW;
int nLFSR;
double prevwfout;
uint8_t pSR;
int Ast;
};
struct SID_ctx {
int sMSBrise;
int sMSB;
double plp;
double pbp;
struct SID_ctx_chan ch[3];
};
struct SIDVOICE {
uint8_t freq_low;
uint8_t freq_high;
uint8_t pw_low;
uint8_t pw_high : 4;
uint8_t UNUSED : 4;
uint8_t control;
uint8_t decay : 4;
uint8_t attack : 4;
uint8_t susres;
// uint8_t release : 4;
// uint8_t sustain : 4;
};
struct SIDMEM {
struct SIDVOICE v[3];
uint8_t UNUSED : 4;
uint8_t cutoff_low : 4;
uint8_t cutoff_high;
uint8_t reso_rt : 4;
uint8_t reso : 4;
uint8_t volume : 4;
uint8_t filter_mode : 4;
uint8_t paddlex;
uint8_t paddley;
uint8_t osc3;
uint8_t env3;
};
struct SID_globals {
double ckr;
double ctfr;
double ctf_ratio_6581;
double ctf_table[2048];
int trsaw[4096];
int pusaw[4096];
int Pulsetrsaw[4096];
double Aprd[16];
int Astp[16];
int model;
};
#define MemLen 65536
struct SID_chip {
struct SID_globals g;
struct SID_ctx SIDct[3];
uint8_t M[MemLen];
int16_t lastOut[3];
int mute_mask;
};
double dSID_render(struct SID_chip* sid);
void dSID_init(struct SID_chip* sid, double clockRate, double samplingRate, int model, unsigned char init_wf);
float dSID_getVolume(struct SID_chip* sid, int channel);
void dSID_setMuteMask(struct SID_chip* sid, int mute_mask);
void dSID_write(struct SID_chip* sid, unsigned char addr, unsigned char val);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -61,7 +61,6 @@ const unsigned int EnvelopeGenerator::adsrtable[16] =
void EnvelopeGenerator::reset()
{
// counter is not changed on reset
envelope_pipeline = 0;
state_pipeline = 0;
@ -73,7 +72,7 @@ void EnvelopeGenerator::reset()
gate = false;
resetLfsr = true;
resetLfsr = false;
exponential_counter = 0;
exponential_counter_period = 1;
@ -81,7 +80,11 @@ void EnvelopeGenerator::reset()
state = RELEASE;
counter_enabled = true;
rate = adsrtable[release];
rate = 0;
envelope_counter = 0;
env3 = 0;
lfsr = 0x7fff;
}
void EnvelopeGenerator::writeCONTROL_REG(unsigned char control)

View file

@ -146,7 +146,7 @@ public:
counter_enabled(true),
gate(false),
resetLfsr(false),
envelope_counter(0xaa),
envelope_counter(0),
attack(0),
decay(0),
sustain(0),

View file

@ -19,6 +19,7 @@
#include "vera.h"
#include "../engine.h"
#include "../../ta-log.h"
#include <string.h>
#include <math.h>
@ -32,10 +33,11 @@ extern "C" {
#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);}
#define rWritePCMRate(d) {regPool[65]=(d); pcm_write_rate(pcm,d);}
#define rWritePCMCtrl(d) {regPool[64]=(d); pcm_write_ctrl(pcm,d);if (dumpWrites) addWrite(64,(d));}
#define rWritePCMRate(d) {regPool[65]=(d); pcm_write_rate(pcm,d);if (dumpWrites) addWrite(65,(d));}
#define rWritePCMData(d) {regPool[66]=(d); pcm_write_fifo(pcm,d);}
#define rWritePCMVol(d) rWritePCMCtrl((regPool[64]&(~0x8f))|((d)&15))
#define rWriteZSMSync(d) {if (dumpWrites) addWrite(68,(d));}
const char* regCheatSheetVERA[]={
"CHxFreq", "00+x*4",
@ -45,6 +47,7 @@ const char* regCheatSheetVERA[]={
"AUDIO_CTRL", "40",
"AUDIO_RATE", "41",
"AUDIO_DATA", "42",
"ZSM_SYNC", "44",
NULL
};
@ -226,6 +229,49 @@ void DivPlatformVERA::tick(bool sysTick) {
rWritePCMRate(chan[16].freq&0xff);
chan[16].freqChanged=false;
}
if (dumpWrites) {
DivSample* s=parent->getSample(chan[16].pcm.sample);
if (s->samples>0) {
while (true) {
short tmp_l=0;
short tmp_r=0;
if (!isMuted[16]) {
if (chan[16].pcm.depth16) {
tmp_l=s->data16[chan[16].pcm.pos];
tmp_r=tmp_l;
} else {
tmp_l=s->data8[chan[16].pcm.pos];
tmp_r=tmp_l;
}
if (!(chan[16].pan&1)) tmp_l=0;
if (!(chan[16].pan&2)) tmp_r=0;
}
if (chan[16].pcm.depth16) {
addWrite(66,tmp_l&0xff);
addWrite(66,(tmp_l>>8)&0xff);
addWrite(66,tmp_r&0xff);
addWrite(66,(tmp_r>>8)&0xff);
} else {
addWrite(66,tmp_l&0xff);
addWrite(66,tmp_r&0xff);
}
chan[16].pcm.pos++;
if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->loopEnd) {
//chan[16].pcm.pos=s->loopStart;
logI("VERA PCM export: treating looped sample as non-looped");
chan[16].pcm.sample=-1;
break;
}
if (chan[16].pcm.pos>=s->samples) {
chan[16].pcm.sample=-1;
break;
}
}
} else {
chan[16].pcm.sample=-1;
}
}
}
int DivPlatformVERA::dispatch(DivCommand c) {
@ -370,6 +416,9 @@ int DivPlatformVERA::dispatch(DivCommand c) {
case DIV_CMD_MACRO_ON:
chan[c.chan].std.mask(c.value,false);
break;
case DIV_CMD_EXTERNAL:
rWriteZSMSync(c.value);
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;
@ -441,6 +490,15 @@ void DivPlatformVERA::poke(std::vector<DivRegWrite>& wlist) {
for (auto &i: wlist) poke(i.addr,i.val);
}
void DivPlatformVERA::setFlags(const DivConfig& flags) {
chipClock=25000000;
CHECK_CUSTOM_CLOCK;
rate=chipClock/512;
for (int i=0; i<17; i++) {
oscBuf[i]->rate=rate;
}
}
int DivPlatformVERA::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
for (int i=0; i<17; i++) {
isMuted[i]=false;
@ -451,12 +509,7 @@ int DivPlatformVERA::init(DivEngine* p, int channels, int sugRate, const DivConf
pcm=new struct VERA_PCM;
dumpWrites=false;
skipRegisterWrites=false;
chipClock=25000000;
CHECK_CUSTOM_CLOCK;
rate=chipClock/512;
for (int i=0; i<17; i++) {
oscBuf[i]->rate=rate;
}
setFlags(flags);
reset();
return 17;
}

View file

@ -51,7 +51,7 @@ class DivPlatformVERA: public DivDispatch {
Channel chan[17];
DivDispatchOscBuffer* oscBuf[17];
bool isMuted[17];
unsigned char regPool[67];
unsigned char regPool[69];
struct VERA_PSG* psg;
struct VERA_PCM* pcm;
@ -70,6 +70,7 @@ class DivPlatformVERA: public DivDispatch {
void reset();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(const DivConfig& flags);
void notifyInsDeletion(void* ins);
float getPostAmp();
int getOutputCount();

View file

@ -236,6 +236,8 @@ const char* cmdName[]={
"NES_LINEAR_LENGTH",
"EXTERNAL",
"ALWAYS_SET_VOLUME"
};
@ -913,6 +915,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
//printf("\x1b[1;36m%d: extern command %d\x1b[m\n",i,effectVal);
extValue=effectVal;
extValuePresent=true;
dispatchCmd(DivCommand(DIV_CMD_EXTERNAL,effectVal));
break;
case 0xef: // global pitch
globalPitch+=(signed char)(effectVal-0x80);
@ -1980,14 +1983,10 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
} else {
// 3. run MIDI clock
int midiTotal=MIN(cycles,runLeftG);
for (int i=0; i<midiTotal; i++) {
runMidiClock();
}
runMidiClock(midiTotal);
// 4. run MIDI timecode
for (int i=0; i<midiTotal; i++) {
runMidiTime();
}
runMidiTime(midiTotal);
// 5. tick the clock and fill buffers as needed
if (cycles<runLeftG) {

Some files were not shown because too many files have changed in this diff Show more