Skip to content

Commit

Permalink
Enumerate and document all MA-3 wave shapes
Browse files Browse the repository at this point in the history
This is a breaking change because of a rename.
PULSE_MA3_WAVE is now PULSE_MA3_SINE.
The rest of the values are new, although they
they only add definitions for values which
were allowed previously anyway. So that part
is not breaking.

Also some minor cleanup related to MA-3
and wave shapes.
  • Loading branch information
YuriSizov committed Oct 22, 2024
1 parent 14aea53 commit ab5139a
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 89 deletions.
107 changes: 100 additions & 7 deletions doc_classes/SiONDriver.xml
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@
OPX sound chip type.
</constant>
<constant name="CHIP_MA3" value="5" enum="SiONChipType">
MA3 sound chip type.
MA-3 sound chip type.
</constant>
<constant name="CHIP_PMS_GUITAR" value="6" enum="SiONChipType">
PMS guitar sound chip type.
Expand All @@ -525,7 +525,7 @@
Noise wave module type.
</constant>
<constant name="MODULE_MA3" value="3" enum="SiONModuleType">
MA3 module type.
MA-3 module type.
</constant>
<constant name="MODULE_SCC" value="4" enum="SiONModuleType">
SCC-like wave table module type.
Expand Down Expand Up @@ -615,7 +615,7 @@
Downwards saw wave pulse generator.
</constant>
<constant name="PULSE_TRIANGLE_FC" value="3" enum="SiONPulseGeneratorType">
Triangle wave pulse generator quantized by 4 bit.
Triangle wave pulse generator quantized by 4 bits.
</constant>
<constant name="PULSE_TRIANGLE" value="4" enum="SiONPulseGeneratorType">
Triangle wave pulse generator.
Expand All @@ -639,7 +639,7 @@
Offset pulse generator.
</constant>
<constant name="PULSE_SAW_VC6" value="11" enum="SiONPulseGeneratorType">
VC6 saw pulse generator (32 samples saw).
VC6 saw pulse generator (32-sample saw).
</constant>
<constant name="PULSE_NOISE_WHITE" value="16" enum="SiONPulseGeneratorType">
16k white noise pulse generator.
Expand Down Expand Up @@ -668,8 +668,101 @@
<constant name="PULSE_PC_NZ_OPM" value="26" enum="SiONPulseGeneratorType">
Pitch-controllable pulse noise with OPM noise table pulse generator.
</constant>
<constant name="PULSE_MA3_WAVE" value="32" enum="SiONPulseGeneratorType">
This and the next [code]32[/code] values are MA3 waveform pulse generators.
<constant name="PULSE_MA3_SINE" value="32" enum="SiONPulseGeneratorType">
MA-3 sine wave pulse generator.
</constant>
<constant name="PULSE_MA3_SINE_HALF" value="33" enum="SiONPulseGeneratorType">
MA-3 half sine wave pulse generator.
</constant>
<constant name="PULSE_MA3_SINE_HALF_DOUBLE" value="34" enum="SiONPulseGeneratorType">
MA-3 half sine doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_SINE_QUART_DOUBLE" value="35" enum="SiONPulseGeneratorType">
MA-3 quarter sine doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_SINE_X2" value="36" enum="SiONPulseGeneratorType">
MA-3 sine sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_SINE_HALF_DOUBLE_X2" value="37" enum="SiONPulseGeneratorType">
MA-3 half sine doubled sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_SQUARE" value="38" enum="SiONPulseGeneratorType">
MA-3 square wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW_SINE" value="39" enum="SiONPulseGeneratorType">
MA-3 downwards saw wave with sine flattening pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_SINE" value="40" enum="SiONPulseGeneratorType">
MA-3 triangle modulated sine wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_SINE_HALF" value="41" enum="SiONPulseGeneratorType">
MA-3 half triangle modulated sine wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_SINE_HALF_DOUBLE" value="42" enum="SiONPulseGeneratorType">
MA-3 half triangle modulated sine doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_SINE_QUART_DOUBLE" value="43" enum="SiONPulseGeneratorType">
MA-3 quarter triangle modulated sine doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_SINE_X2" value="44" enum="SiONPulseGeneratorType">
MA-3 triangle modulated sine sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_SINE_HALF_DOUBLE_X2" value="45" enum="SiONPulseGeneratorType">
MA-3 half triangle modulated sine doubled sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_SQUARE_HALF" value="46" enum="SiONPulseGeneratorType">
MA-3 half square wave pulse generator.
</constant>
<constant name="PULSE_MA3_USER1" value="47" enum="SiONPulseGeneratorType">
MA-3 user defined wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI" value="48" enum="SiONPulseGeneratorType">
MA-3 triangle wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_HALF" value="49" enum="SiONPulseGeneratorType">
MA-3 half triangle wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_HALF_DOUBLE" value="50" enum="SiONPulseGeneratorType">
MA-3 half triangle doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_QUART_DOUBLE" value="51" enum="SiONPulseGeneratorType">
MA-3 quarter triangle doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_X2" value="52" enum="SiONPulseGeneratorType">
MA-3 triangle sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_TRI_HALF_DOUBLE_X2" value="53" enum="SiONPulseGeneratorType">
MA-3 half triangle doubled sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_SQUARE_QUART_DOUBLE" value="54" enum="SiONPulseGeneratorType">
MA-3 quarter square doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_USER2" value="55" enum="SiONPulseGeneratorType">
MA-3 user defined wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW" value="56" enum="SiONPulseGeneratorType">
MA-3 upwards saw wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW_HALF" value="57" enum="SiONPulseGeneratorType">
MA-3 half upwards saw wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW_HALF_DOUBLE" value="58" enum="SiONPulseGeneratorType">
MA-3 half upwards saw doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW_QUART_DOUBLE" value="59" enum="SiONPulseGeneratorType">
MA-3 quarter upwards saw doubled wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW_X2" value="60" enum="SiONPulseGeneratorType">
MA-3 upwards saw sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_SAW_HALF_DOUBLE_X2" value="61" enum="SiONPulseGeneratorType">
MA-3 half upwards saw doubled sped up (half phase) wave pulse generator.
</constant>
<constant name="PULSE_MA3_SQUARE_QUART" value="62" enum="SiONPulseGeneratorType">
MA-3 quarter square wave pulse generator.
</constant>
<constant name="PULSE_MA3_USER3" value="63" enum="SiONPulseGeneratorType">
MA-3 user defined wave pulse generator.
</constant>
<constant name="PULSE_PULSE" value="64" enum="SiONPulseGeneratorType">
This and the next [code]16[/code] values are square pulse wave pulse generators.
Expand All @@ -678,7 +771,7 @@
This and the next [code]16[/code] values are square pulse wave with spike pulse generators.
</constant>
<constant name="PULSE_RAMP" value="128" enum="SiONPulseGeneratorType">
This and the next [code]128[/code] values are ramp wave pulse generators.
This and the next [code]128[/code] values are ramp wave pulse generators. Values [code]0-4[/code] are equivalent to an upwards saw wave. Values [code]124-127[/code] are equivalent to a downwards saw wave. Value [code]64[/code] is equivalent to a triangle wave.
</constant>
<constant name="PULSE_CUSTOM" value="256" enum="SiONPulseGeneratorType">
This and the next [code]128[/code] values are custom wave table pulse generators.
Expand Down
4 changes: 2 additions & 2 deletions doc_classes/SiONVoice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<method name="get_params_ma3" qualifiers="const">
<return type="int[]" />
<description>
Returns a configuration of this voice as an array of integers. The voice is treated as an MA3 voice.
Returns a configuration of this voice as an array of integers. The voice is treated as an MA-3 voice.
</description>
</method>
<method name="get_params_opl" qualifiers="const">
Expand Down Expand Up @@ -160,7 +160,7 @@
<return type="void" />
<param index="0" name="args" type="int[]" />
<description>
Sets the configuration of this voice as an array of integers. The voice is treated as an MA3 voice.
Sets the configuration of this voice as an array of integers. The voice is treated as an MA-3 voice.
</description>
</method>
<method name="set_params_opl">
Expand Down
4 changes: 2 additions & 2 deletions doc_classes/SiOPMChannelFM.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
</brief_description>
<description>
This implementation is based on OPM emulation, referenced from sources of mame, fmgen, and x68sound.
It also introduces a few extensions to simulate several other FM sound modules (OPNA, OPLL, OPL2, OPL3, OPX, MA3, MA5, MA7, TSS, and DX7), including:
- stereo output (from TSS, DX7)[br]- key scale level (from OPL3, OPX, MAx)[br]- phase selection (from TSS)[br]- fixed frequency (from MAx)[br]- SSG envelope control (from OPNA)[br]- wave shape selection (from OPX, MAx, TSS)[br]- custom wave shapes (from MAx)[br]- more supported algorithms (from OPLx, OPX, MAx, DX7)[br]- decimal multiple (from p-TSS)[br]- feedback from operators 1-3 (from DX7)[br]- channel independent LFO (from TSS)[br]- low-pass filter envelope (from MAx)[br]- flexible FM connections (from TSS)[br]- ring modulation (from C64?)
It also introduces a few extensions to simulate several other FM sound modules (OPNA, OPLL, OPL2, OPL3, OPX, MA-3, MA-5, MA-7, TSS, and DX7), including:
- stereo output (from TSS, DX7)[br]- key scale level (from OPL3, OPX, MA-x)[br]- phase selection (from TSS)[br]- fixed frequency (from MA-x)[br]- SSG envelope control (from OPNA)[br]- wave shape selection (from OPX, MA-x, TSS)[br]- custom wave shapes (from MA-x)[br]- more supported algorithms (from OPLx, OPX, MA-x, DX7)[br]- decimal multiple (from p-TSS)[br]- feedback from operators 1-3 (from DX7)[br]- channel independent LFO (from TSS)[br]- low-pass filter envelope (from MA-x)[br]- flexible FM connections (from TSS)[br]- ring modulation (from C64?)
[b]Warning:[/b] This class currently has no intended use in the API. If you need this class and its unexposed methods in your project, please [b][url=https://github.com/YuriSizov/gdsion/issues]create a feature request with your use case[/url][/b]!
</description>
<tutorials>
Expand Down
2 changes: 1 addition & 1 deletion example/globals/VoiceManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func _register_voices() -> void:
_register_voice("CHIPTUNE", "Konami Wave", "konami", 4, 3)
_register_voice("CHIPTUNE", "Ramp Wave", "ramp", 4, 18)
_register_voice("CHIPTUNE", "Pulse Wave", "beep", 4, 29)
_register_voice("CHIPTUNE", "MA3 Wave", "ma1", 4, 25)
_register_voice("CHIPTUNE", "MA-3 Wave", "ma1", 4, 25)
_register_voice("CHIPTUNE", "Noise (Bass)", "bassdrumm", 20, 115)
_register_voice("CHIPTUNE", "Noise (Snare)", "snare", 20, 118)
_register_voice("CHIPTUNE", "Noise (Hi-Hat)", "closedhh", 20, 126)
Expand Down
85 changes: 43 additions & 42 deletions src/chip/siopm_ref_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,11 @@ void SiOPMRefTable::register_wave_table(int p_index, const Ref<SiOPMWaveTable> &
int index = p_index & (WAVE_TABLE_MAX - 1);
_custom_wave_tables.write[index] = p_table;

// Update PULSE_MA3_WAVE waveform 15,23,31.
// MA-3 waveforms support up to 3 user defined values. If this table is one of the first
// 3 custom tables, use it.
if (index < 3) {
// index=0,1,2 are same as PULSE_MA3 waveform 15,23,31.
wave_tables.write[15 + index * 8 + SiONPulseGeneratorType::PULSE_MA3_WAVE] = p_table;
// User defined waves are at offsets 15,23,31.
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_SINE + 15 + index * 8] = p_table;
}
}

Expand Down Expand Up @@ -1028,14 +1029,13 @@ void SiOPMRefTable::_create_wave_samples() {

// MA3 wave tables.
{
// Waveforms 0-5 = sine wave
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE] = wave_tables[SiONPulseGeneratorType::PULSE_SINE];
_expand_ma3_waves(0);
// 0-5 - sine waves.
_create_ma3_waveset(SiONPulseGeneratorType::PULSE_MA3_SINE, wave_tables[SiONPulseGeneratorType::PULSE_SINE]);

// Waveform 6 = square
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE+6] = wave_tables[SiONPulseGeneratorType::PULSE_SQUARE];
// 6 - square wave.
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_SQUARE] = wave_tables[SiONPulseGeneratorType::PULSE_SQUARE];

// Waveform 7 ???
// 7 - downwards saw wave with sine flattening. Best name I can come up with, not sure if there is a more common description.
{
Vector<int> table1;
table1.resize_zeroed(SAMPLING_TABLE_SIZE);
Expand All @@ -1058,10 +1058,10 @@ void SiOPMRefTable::_create_wave_samples() {
value_base += value_delta;
}

wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 7] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table1)));
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_SAW_SINE] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table1)));
}

// Waveforms 8-13 = bi-triangle modulated sine ?
// 8-13 - triangle modulated sine
{
Vector<int> base_table = wave_tables[SiONPulseGeneratorType::PULSE_SINE]->get_wavelet();
Vector<int> table;
Expand All @@ -1073,54 +1073,55 @@ void SiOPMRefTable::_create_wave_samples() {
j += 1 - (((i >> (SAMPLING_TABLE_BITS - 3)) + 1) & 2); // triangle wave
}

wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 8] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
_expand_ma3_waves(8);
_create_ma3_waveset(SiONPulseGeneratorType::PULSE_MA3_TRI_SINE, Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table))));
}

// Waveform 14 = half square
// 14 - half square
{
int value = calculate_log_table_index(1);
Vector<int> table = { value, LOG_TABLE_BOTTOM };

wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 14] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_SQUARE_HALF] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveforms 16-21 = triangle wave
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 16] = wave_tables[SiONPulseGeneratorType::PULSE_TRIANGLE];
_expand_ma3_waves(16);
// 16-21 - triangle waves
_create_ma3_waveset(SiONPulseGeneratorType::PULSE_MA3_TRI, wave_tables[SiONPulseGeneratorType::PULSE_TRIANGLE]);

// Waveform 22 = twice of half square
// 22 - quarter square doubled.
{
int value = calculate_log_table_index(1);
Vector<int> table = { value, LOG_TABLE_BOTTOM, value, LOG_TABLE_BOTTOM };

wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 22] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_SQUARE_QUART_DOUBLE] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveforms 24-29 = saw wave
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 24] = wave_tables[SiONPulseGeneratorType::PULSE_SAW_UP];
_expand_ma3_waves(24);
// 24-29 - upwards saw waves.
_create_ma3_waveset(SiONPulseGeneratorType::PULSE_MA3_SAW, wave_tables[SiONPulseGeneratorType::PULSE_SAW_UP]);

// Waveform 30 = quarter square
// 30 - quarter square wave.
{
int value = calculate_log_table_index(1);
Vector<int> table = { value, LOG_TABLE_BOTTOM, LOG_TABLE_BOTTOM, LOG_TABLE_BOTTOM };

wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE+30] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_SQUARE_QUART] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveforms 15,23,31 = custom waveform 0-2 (not available)
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 15] = no_wave_table;
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 23] = no_wave_table;
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_WAVE + 31] = no_wave_table;
// 15,23,31 - user defined waves.
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_USER1] = no_wave_table;
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_USER2] = no_wave_table;
wave_tables.write[SiONPulseGeneratorType::PULSE_MA3_USER3] = no_wave_table;
}
}

void SiOPMRefTable::_expand_ma3_waves(int p_index) {
int wave_index = SiONPulseGeneratorType::PULSE_MA3_WAVE + p_index;
Vector<int> basic_waveform = wave_tables[wave_index]->get_wavelet();
void SiOPMRefTable::_create_ma3_waveset(int p_index, const Ref<SiOPMWaveTable> &p_table) {
// MA-3 waveforms contain 4 sets with the same basic premise. We take the base one,
// then modify it via the same transforms to get 5 variations.

// Waveform 1
// 0 - Full wave.
wave_tables.write[p_index] = p_table;
Vector<int> basic_waveform = p_table->get_wavelet();

// 1 - Half wave.
{
Vector<int> table;
table.resize_zeroed(SAMPLING_TABLE_SIZE);
Expand All @@ -1129,10 +1130,10 @@ void SiOPMRefTable::_expand_ma3_waves(int p_index) {
table.write[i] = basic_waveform[i];
table.write[i + table_offset] = LOG_TABLE_BOTTOM;
}
wave_tables.write[wave_index + 1] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[p_index + 1] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveform 2
// 2 - Half wave doubled.
{
Vector<int> table;
table.resize_zeroed(SAMPLING_TABLE_SIZE);
Expand All @@ -1141,10 +1142,10 @@ void SiOPMRefTable::_expand_ma3_waves(int p_index) {
table.write[i] = basic_waveform[i];
table.write[i + table_offset] = basic_waveform[i];
}
wave_tables.write[wave_index + 2] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[p_index + 2] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveform 3
// 3 - Quarter wave doubled.
{
Vector<int> table;
table.resize_zeroed(SAMPLING_TABLE_SIZE);
Expand All @@ -1155,10 +1156,10 @@ void SiOPMRefTable::_expand_ma3_waves(int p_index) {
table.write[i + table_offset * 2] = basic_waveform[i];
table.write[i + table_offset * 3] = LOG_TABLE_BOTTOM;
}
wave_tables.write[wave_index + 3] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[p_index + 3] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveform 4
// 4 - Sped up wave.
{
Vector<int> table;
table.resize_zeroed(SAMPLING_TABLE_SIZE);
Expand All @@ -1167,10 +1168,10 @@ void SiOPMRefTable::_expand_ma3_waves(int p_index) {
table.write[i] = basic_waveform[i << 1];
table.write[i + table_offset] = LOG_TABLE_BOTTOM;
}
wave_tables.write[wave_index + 4] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[p_index + 4] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}

// Waveform 5
// 5 - Sped up half wave doubled.
{
Vector<int> table;
table.resize_zeroed(SAMPLING_TABLE_SIZE);
Expand All @@ -1181,7 +1182,7 @@ void SiOPMRefTable::_expand_ma3_waves(int p_index) {
table.write[i + table_offset * 2] = LOG_TABLE_BOTTOM;
table.write[i + table_offset * 3] = LOG_TABLE_BOTTOM;
}
wave_tables.write[wave_index + 5] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
wave_tables.write[p_index + 5] = Ref<SiOPMWaveTable>(memnew(SiOPMWaveTable(table)));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/chip/siopm_ref_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class SiOPMRefTable {
void _create_eg_tables();
void _create_pg_tables();
void _create_wave_samples();
void _expand_ma3_waves(int p_index);
void _create_ma3_waveset(int p_index, const Ref<SiOPMWaveTable> &p_table);
void _create_lfo_tables();
void _create_filter_tables();

Expand Down
Loading

0 comments on commit ab5139a

Please sign in to comment.