Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5504704
Nes init
paator Jun 17, 2026
4ae68e5
Instrument editor
paator Jun 17, 2026
75d7612
Some nes sounds
paator Jun 17, 2026
d451cc0
Remove rand() usage from nes_dmc
akumanatt Jun 17, 2026
2971b34
Fix NES audio driver
akumanatt Jun 18, 2026
67041e1
Merge pull request #28 from akumanatt/nes
paator Jun 18, 2026
b4c3148
A4 table for NES
paator Jun 18, 2026
b887090
Fix loading different chip type .btp
paator Jun 18, 2026
4b60c92
Reset NES channels properly
paator Jun 18, 2026
d3b1675
Fix multichip issues
paator Jun 18, 2026
6c84eff
Add tone offset and accumulation features to NES audio driver and ins…
paator Jun 18, 2026
a875650
NES renderer
paator Jun 18, 2026
042021e
Refactor module imports in PSG and TMR export services to use updated…
paator Jun 18, 2026
acfb0fb
Enhance instrument reconstruction to support NES chip type, preservin…
paator Jun 18, 2026
c10b111
Fix 6 command for NES
paator Jun 19, 2026
3424255
Add NES hw sweep
paator Jun 20, 2026
0557e34
Add 60hz option for NES
paator Jun 20, 2026
fbca3ad
NES env
paator Jun 20, 2026
c8e675b
Remove envelope types
paator Jun 20, 2026
0cfb533
Change NES duty cycle labels
paator Jun 20, 2026
8df1dc1
Add instrument tabs
paator Jun 21, 2026
059e8dd
Update noise channel
paator Jun 21, 2026
7e6cb0c
Reverse noise
paator Jun 21, 2026
d7576a8
Refactor instrument selection and handling for AY chip type. Update e…
paator Jun 21, 2026
5dacc3b
Fix windows build
paator Jun 21, 2026
3a70789
Oscilloscope fix
paator Jun 22, 2026
50997ce
Allow NES envelope 0 and triangle volume 0
akumanatt Jun 22, 2026
dcf8e6e
Enable NES noise mode setting through the pulse width row
akumanatt Jun 22, 2026
ae0a737
Fix NES sound length lookup
akumanatt Jun 22, 2026
aab5bac
Merge pull request #30 from akumanatt/nes
paator Jun 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions build-wasm.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ if ($env:EMSDK) {
if (Test-Path $envScript) { & $envScript }
}

$emccArgs = "-O3",
$emccArgs = "-O3", "-DNDEBUG",
"-s", "WASM=1",
"-s", "ALLOW_MEMORY_GROWTH=1", "-s", "INITIAL_MEMORY=16777216", "-s", "MAXIMUM_MEMORY=16777216",
"-s", "ENVIRONMENT=web", "-s", "STANDALONE_WASM=1", "--no-entry"

$ayumiArgs = "external/ayumi/ayumi.c", "-o", "public/ayumi.wasm",
"-s", "EXPORTED_FUNCTIONS=`"[\`"_ayumi_configure\`", \`"_ayumi_set_pan\`", \`"_ayumi_set_tone\`", \`"_ayumi_set_noise\`", \`"_ayumi_set_mixer\`", \`"_ayumi_set_volume\`", \`"_ayumi_set_timer_effect\`", \`"_ayumi_set_timer_effect_slot\`", \`"_ayumi_set_timer_effect_waveform\`", \`"_ayumi_timer_effect_reset\`", \`"_ayumi_get_timer_effect_active_period\`", \`"_ayumi_get_registers\`", \`"_ayumi_struct_size\`", \`"_ayumi_set_envelope\`", \`"_ayumi_set_envelope_shape\`", \`"_ayumi_process\`", \`"_ayumi_remove_dc\`", \`"_malloc\`", \`"_free\`"]`"",
$ayumiArgs = "external/ayumi/ayumi.c", "-o", "public/ay/ayumi.wasm",
"-s", "EXPORTED_FUNCTIONS=`"[\`"_ayumi_configure\`", \`"_ayumi_set_pan\`", \`"_ayumi_set_tone\`", \`"_ayumi_set_noise\`", \`"_ayumi_set_mixer\`", \`"_ayumi_set_volume\`", \`"_ayumi_set_timer_effect\`", \`"_ayumi_set_timer_effect_slot\`", \`"_ayumi_set_timer_effect_waveform\`", \`"_ayumi_timer_effect_reset\`", \`"_ayumi_get_timer_effect_active_period\`", \`"_ayumi_get_registers\`", \`"_ayumi_struct_size\`", \`"_ayumi_set_envelope\`", \`"_ayumi_set_envelope_shape\`", \`"_ayumi_process\`", \`"_ayumi_remove_dc\`", \`"_malloc\`", \`"_free\`"]`""

$nesApuArgs = "external/nsfplug/nes_apu.c", "external/nsfplug/nes_dmc.c", "-o", "public/nes_apu.wasm",
"-s", "EXPORTED_FUNCTIONS=`"[\`"_nes_apu_Init\`", \`"_nes_apu_Reset\`", \`"_nes_apu_Tick\`", \`"_nes_apu_Render\`", \`"_nes_apu_Write\`", \`"_nes_apu_SetMask\`", \`"_nes_apu_SetStereoMix\`", \`"_nes_dmc_Init\`", \`"_nes_dmc_Reset\`", \`"_nes_dmc_Tick\`", \`"_nes_dmc_Render\`", \`"_nes_dmc_Write\`", \`"_nes_dmc_SetMask\`", \`"_nes_dmc_SetStereoMix\`", \`"_nes_dmc_SetPal\`", \`"_nes_dmc_SetAPU\`", \`"_nes_dmc_SetMemory_Read\`", \`"_nes_dmc_TickFrameSequence\`"]`""
$nesApuArgs = "external/nsfplug/nes_apu.c", "external/nsfplug/nes_dmc.c", "-o", "public/nes/nes_apu.wasm",
"-s", "EXPORTED_FUNCTIONS=`"[\`"_nes_apu_Init\`", \`"_nes_apu_Reset\`", \`"_nes_apu_Tick\`", \`"_nes_apu_Render\`", \`"_nes_apu_Write\`", \`"_nes_apu_SetMask\`", \`"_nes_apu_SetStereoMix\`", \`"_nes_apu_GetOut\`", \`"_nes_dmc_Init\`", \`"_nes_dmc_Reset\`", \`"_nes_dmc_Tick\`", \`"_nes_dmc_Render\`", \`"_nes_dmc_Write\`", \`"_nes_dmc_SetMask\`", \`"_nes_dmc_SetStereoMix\`", \`"_nes_dmc_SetPal\`", \`"_nes_dmc_SetAPU\`", \`"_nes_dmc_SetMemory_Read\`", \`"_nes_dmc_TickFrameSequence\`", \`"_nes_dmc_GetOut\`", \`"_malloc\`", \`"_free\`"]`""

$nesMmc5Args = "external/nsfplug/nes_mmc5.c", "-o", "public/nes_mmc5.wasm",
$nesMmc5Args = "external/nsfplug/nes_mmc5.c", "-o", "public/nes/nes_mmc5.wasm",
"-s", "EXPORTED_FUNCTIONS=`"[\`"_nes_mmc5_Init\`", \`"_nes_mmc5_Reset\`", \`"_nes_mmc5_Tick\`", \`"_nes_mmc5_Render\`", \`"_nes_mmc5_Write\`", \`"_nes_mmc5_SetMask\`", \`"_nes_mmc5_SetStereoMix\`", \`"_nes_mmc5_TickFrameSequence\`"]`""

$python = $null
Expand Down
9 changes: 5 additions & 4 deletions build-wasm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fi

EMCC_ARGS="\
-O3 \
-DNDEBUG \
-s WASM=1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s INITIAL_MEMORY=16777216 \
Expand All @@ -23,15 +24,15 @@ EMCC_ARGS="\

emcc ${EMCC_ARGS} \
external/ayumi/ayumi.c \
-o public/ayumi.wasm \
-o public/ay/ayumi.wasm \
-s EXPORTED_FUNCTIONS='["_ayumi_configure", "_ayumi_set_pan", "_ayumi_set_tone", "_ayumi_set_noise", "_ayumi_set_mixer", "_ayumi_set_volume", "_ayumi_set_timer_effect", "_ayumi_set_timer_effect_slot", "_ayumi_set_timer_effect_waveform", "_ayumi_timer_effect_reset", "_ayumi_get_timer_effect_active_period", "_ayumi_get_registers", "_ayumi_struct_size", "_ayumi_set_envelope", "_ayumi_set_envelope_shape", "_ayumi_process", "_ayumi_remove_dc", "_malloc", "_free"]'

emcc ${EMCC_ARGS} \
external/nsfplug/nes_apu.c external/nsfplug/nes_dmc.c \
-o public/nes_apu.wasm \
-s EXPORTED_FUNCTIONS='["_nes_apu_Init", "_nes_apu_Reset", "_nes_apu_Tick", "_nes_apu_Render", "_nes_apu_Write", "_nes_apu_SetMask", "_nes_apu_SetStereoMix", "_nes_dmc_Init", "_nes_dmc_Reset", "_nes_dmc_Tick", "_nes_dmc_Render", "_nes_dmc_Write", "_nes_dmc_SetMask", "_nes_dmc_SetStereoMix", "_nes_dmc_SetPal", "_nes_dmc_SetAPU", "_nes_dmc_SetMemory_Read", "_nes_dmc_TickFrameSequence"]'
-o public/nes/nes_apu.wasm \
-s EXPORTED_FUNCTIONS='["_nes_apu_Init", "_nes_apu_Reset", "_nes_apu_Tick", "_nes_apu_Render", "_nes_apu_Write", "_nes_apu_SetMask", "_nes_apu_SetStereoMix", "_nes_apu_GetOut", "_nes_dmc_Init", "_nes_dmc_Reset", "_nes_dmc_Tick", "_nes_dmc_Render", "_nes_dmc_Write", "_nes_dmc_SetMask", "_nes_dmc_SetStereoMix", "_nes_dmc_SetPal", "_nes_dmc_SetAPU", "_nes_dmc_SetMemory_Read", "_nes_dmc_TickFrameSequence", "_nes_dmc_GetOut", "_malloc", "_free"]'

emcc ${EMCC_ARGS} \
external/nsfplug/nes_mmc5.c \
-o public/nes_mmc5.wasm \
-o public/nes/nes_mmc5.wasm \
-s EXPORTED_FUNCTIONS='["_nes_mmc5_Init", "_nes_mmc5_Reset", "_nes_mmc5_Tick", "_nes_mmc5_Render", "_nes_mmc5_Write", "_nes_mmc5_SetMask", "_nes_mmc5_SetStereoMix", "_nes_mmc5_TickFrameSequence"]'
7 changes: 7 additions & 0 deletions external/nsfplug/nes_apu.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ uint32_t nes_apu_Render (nes_apu_t *s, int32_t b[2])
return 2;
}

int32_t nes_apu_GetOut (nes_apu_t *s, int channel)
{
if (channel < 0 || channel > 1)
return 0;
return s->out[channel];
}

void nes_apu_Init (nes_apu_t *s)
{
s->option[NES_APU_OPT_UNMUTE_ON_RESET] = true;
Expand Down
2 changes: 2 additions & 0 deletions external/nsfplug/nes_apu.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ void nes_apu_SetOption (nes_apu_t *s, int id, int b);
void nes_apu_SetMask(nes_apu_t *s, int m);
void nes_apu_SetStereoMix (nes_apu_t *s, int trk, int32_t mixl, int32_t mixr);

int32_t nes_apu_GetOut (nes_apu_t *s, int channel);

#endif
27 changes: 17 additions & 10 deletions external/nsfplug/nes_dmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,13 @@ uint32_t nes_dmc_Render (nes_dmc_t* s, int32_t b[2])
return 2;
}

int32_t nes_dmc_GetOut (nes_dmc_t* s, int channel)
{
if (channel < 0 || channel > 2)
return 0;
return (int32_t)s->out[channel];
}

void nes_dmc_SetPal (nes_dmc_t* s, bool is_pal)
{
s->pal = (is_pal ? 1 : 0);
Expand Down Expand Up @@ -484,16 +491,16 @@ void nes_dmc_Reset (nes_dmc_t* s)
s->noise = 1;
s->noise_tap = (1<<1);

if (s->option[NES_DMC_OPT_RANDOMIZE_NOISE])
{
s->noise |= rand();
s->counter[1] = -(rand() & 511);
}
if (s->option[NES_DMC_OPT_RANDOMIZE_TRI])
{
s->tphase = rand() & 31;
s->counter[0] = -(rand() & 2047);
}
// if (s->option[NES_DMC_OPT_RANDOMIZE_NOISE])
// {
// s->noise |= rand();
// s->counter[1] = -(rand() & 511);
// }
// if (s->option[NES_DMC_OPT_RANDOMIZE_TRI])
// {
// s->tphase = rand() & 31;
// s->counter[0] = -(rand() & 2047);
// }
}

void nes_dmc_SetMemory_Read (nes_dmc_t* s, read_func * r)
Expand Down
2 changes: 2 additions & 0 deletions external/nsfplug/nes_dmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ bool nes_dmc_Read (nes_dmc_t* s, uint32_t adr, uint32_t* val);
void nes_dmc_SetOption (nes_dmc_t* s, int id, int b);
void nes_dmc_SetStereoMix (nes_dmc_t* s, int trk, int32_t mixl, int32_t mixr);

int32_t nes_dmc_GetOut (nes_dmc_t* s, int channel);

// void nes_dmc_SetCPU(nes_dmc_t* s, NES_CPU* cpu_);

#endif
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import SongTimeline from './song-timeline.js';
import SongTimeline from '../tracker/song-timeline.js';
import { createAudioSlot } from './audio-slot-registry.js';
import './builtin-audio-slots.js';

function sortPlaySlotsForQuantum(playSlots) {
return [...playSlots].sort((a, b) => (b.chipIndex ?? 0) - (a.chipIndex ?? 0));
}

class BitphaseAudioProcessor extends AudioWorkletProcessor {
constructor() {
super();
Expand Down Expand Up @@ -78,14 +82,19 @@ class BitphaseAudioProcessor extends AudioWorkletProcessor {
return true;
}

const active = slots.filter((s) => s && s.canRender());
const anyPreview = active.some((s) => s.isPreviewActive());
const playSlots = anyPreview ? [] : active.filter((s) => s.shouldRunPlaybackAccumulation());
const outputSlots = anyPreview
? []
: active.filter((s) => s.shouldAccumulateStereoOutput());
const quantumSlots = sortPlaySlotsForQuantum(playSlots);
const leaderLen = this.leaderPatternLength();

for (let i = 0; i < numSamples; i++) {
tl.tickAccumulator += tl.tickStep;
const mix = { l: 0, r: 0 };

const active = slots.filter((s) => s && s.canRender());
const anyPreview = active.some((s) => s.isPreviewActive());
const playSlots = active.filter((s) => s.shouldRunPlaybackAccumulation());

if (anyPreview) {
for (const s of active) {
if (s.isPreviewActive()) {
Expand All @@ -94,21 +103,19 @@ class BitphaseAudioProcessor extends AudioWorkletProcessor {
}
}
} else if (playSlots.length > 0 && tl.tickAccumulator >= 1.0) {
for (const s of playSlots) {
for (const s of quantumSlots) {
s.runSharedPlaybackQuantum();
}
const leaderLen = this.leaderPatternLength();
const needsOrderWrap = tl.advancePosition(leaderLen);
for (let j = 0; j < slots.length; j++) {
const s = slots[j];
if (s) s.onPatternOrderAdvanced(needsOrderWrap);
}
tl.tickAccumulator -= 1.0;
for (const s of playSlots) {
s.accumulateStereoOutput(i, mix);
}
} else {
for (const s of playSlots) {
}

if (!anyPreview) {
for (const s of outputSlots) {
s.accumulateStereoOutput(i, mix);
}
}
Expand Down
15 changes: 15 additions & 0 deletions public/audio/builtin-audio-slots.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { registerAudioSlotKind } from './audio-slot-registry.js';
import { AyumiSlot } from '../ay/ayumi-slot.js';
import { NesWorkletSlot } from '../nes/nes-worklet-slot.js';

registerAudioSlotKind('ayumi', (port, chipIndex, sharedTimeline, initData) => {
const slot = new AyumiSlot(port, chipIndex, sharedTimeline);
void slot.handleMessage({ type: 'init', wasmBuffer: initData.wasmBuffer });
return slot;
});

registerAudioSlotKind('nes', (port, chipIndex, sharedTimeline, initData) => {
const slot = new NesWorkletSlot(port, chipIndex, sharedTimeline);
void slot.handleMessage({ type: 'init', wasmBuffer: initData.wasmBuffer });
return slot;
});
104 changes: 54 additions & 50 deletions public/ay-audio-driver.js → public/ay/ay-audio-driver.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,40 @@
import AYChipRegisterState from './ay-chip-register-state.js';
import EffectAlgorithms from './effect-algorithms.js';
import { PT3VolumeTable } from './pt3-volume-table.js';
import { normalizeAyInstrumentFields, getAySidBaseVolume, computeTimerEffectPeriod, computeTimerPwmPeriods, effectiveRowTimerWaveform, effectiveRowFmWaveform, effectiveRowFmWaveformLoop, effectiveRowEnvFmWaveform, effectiveRowEnvFmWaveformLoop, resolveAyFmOffsetMode, effectiveRowTimerWaveformLoop, effectiveRowTimerPwmDuty, effectiveRowTimerPwmSweep, effectiveRowTimerPwmSweepMin, rowSupportsSidTimerPwm, rowSupportsSyncbuzzerTimerPwm, rowSupportsFmTimerPwm, rowSupportsEnvFmTimerPwm, rowSupportsTimerPwm, rowUsesSyncbuzzerPwmDuty, resolveSyncbuzzerWaveform, isPatternEnvelopeShapeSet, advanceTimerPwmSweep, DEFAULT_AY_TIMER_PWM_DUTY } from './ay-instrument-utils.js';
import EffectAlgorithms from '../tracker/effect-algorithms.js';
import { PT3VolumeTable } from '../tracker/pt3-volume-table.js';
import { advanceInstrumentRowPosition } from '../tracker/tracker-audio-utils.js';
import {
assignPatternRowInstrument,
channelHasAssignedInstrument,
getChannelInstrument,
isChannelOnOffHalted,
processChannelOnOffCounters
} from '../tracker/tracker-instrument-channel.js';
import {
normalizeAyInstrumentFields,
getAySidBaseVolume,
computeTimerEffectPeriod,
computeTimerPwmPeriods,
effectiveRowTimerWaveform,
effectiveRowFmWaveform,
effectiveRowFmWaveformLoop,
effectiveRowEnvFmWaveform,
effectiveRowEnvFmWaveformLoop,
resolveAyFmOffsetMode,
effectiveRowTimerWaveformLoop,
effectiveRowTimerPwmDuty,
effectiveRowTimerPwmSweep,
effectiveRowTimerPwmSweepMin,
rowSupportsSidTimerPwm,
rowSupportsSyncbuzzerTimerPwm,
rowSupportsFmTimerPwm,
rowSupportsEnvFmTimerPwm,
rowSupportsTimerPwm,
rowUsesSyncbuzzerPwmDuty,
resolveSyncbuzzerWaveform,
isPatternEnvelopeShapeSet,
advanceTimerPwmSweep,
DEFAULT_AY_TIMER_PWM_DUTY
} from './ay-instrument-utils.js';
import {
instrumentHasSample,
computeSampleSidPeriod,
Expand All @@ -23,15 +56,6 @@ import {
disableTimerEffect
} from './ay-timer-effect-constants.js';

function advanceInstrumentRowPosition(position, rowsLength, loop) {
const length = rowsLength > 0 ? rowsLength : 1;
let next = position + 1;
if (next >= length) {
next = loop > 0 && loop < length ? loop : 0;
}
return next;
}

class AYAudioDriver {
constructor(channelCount = 3) {
this.channelMixerState = [];
Expand Down Expand Up @@ -290,30 +314,23 @@ class AYAudioDriver {
}

_processInstrument(state, channelIndex, row) {
if (!state.channelInstruments || !state.instruments) return;
if (state.channelMuted[channelIndex]) return;
const assignment = assignPatternRowInstrument(state, channelIndex, row);
if (!assignment.changed) return;
if (!assignment.assigned) return;

if (row.instrument > 0) {
const instrumentIndex = state.instrumentIdToIndex.get(row.instrument);
if (instrumentIndex !== undefined && state.instruments[instrumentIndex]) {
const instrument = state.instruments[instrumentIndex];
state.channelInstruments[channelIndex] = instrumentIndex;
const preserveSamplePlayback = this.shouldPreserveSamplePlayback(state, channelIndex, row);
if (!(preserveSamplePlayback && instrumentHasSample(instrument))) {
state.instrumentPositions[channelIndex] = 0;
if (state.channelTimerPositions) {
state.channelTimerPositions[channelIndex] = 0;
}
}
if (instrumentHasSample(instrument) && !preserveSamplePlayback) {
resetChannelSamplePlayback(state, channelIndex, instrument);
}
const preserveTimerPwmSweep = this.shouldPreserveTimerPwmSweep(state, channelIndex, row);
this.resetInstrumentAccumulators(state, channelIndex, { preserveTimerPwmSweep });
} else {
state.channelInstruments[channelIndex] = -1;
const instrument = assignment.instrument;
const preserveSamplePlayback = this.shouldPreserveSamplePlayback(state, channelIndex, row);
if (!(preserveSamplePlayback && instrumentHasSample(instrument))) {
state.instrumentPositions[channelIndex] = 0;
if (state.channelTimerPositions) {
state.channelTimerPositions[channelIndex] = 0;
}
}
if (instrumentHasSample(instrument) && !preserveSamplePlayback) {
resetChannelSamplePlayback(state, channelIndex, instrument);
}
const preserveTimerPwmSweep = this.shouldPreserveTimerPwmSweep(state, channelIndex, row);
this.resetInstrumentAccumulators(state, channelIndex, { preserveTimerPwmSweep });
}

rowHasPortamentoCommand(row) {
Expand Down Expand Up @@ -871,8 +888,7 @@ class AYAudioDriver {
for (let channelIndex = 0; channelIndex < state.channelInstruments.length; channelIndex++) {
const isMuted = state.channelMuted[channelIndex];
const isSoundEnabled = state.channelSoundEnabled[channelIndex];
const onOffHalted =
state.channelOnOffCounter[channelIndex] > 0 && !state.channelSoundEnabled[channelIndex];
const onOffHalted = isChannelOnOffHalted(state, channelIndex);

if (isMuted) {
registerState.channels[channelIndex].volume = 0;
Expand All @@ -886,8 +902,7 @@ class AYAudioDriver {
continue;
}

const instrumentIndex = state.channelInstruments[channelIndex];
const instrument = state.instruments[instrumentIndex];
const { instrumentIndex, instrument } = getChannelInstrument(state, channelIndex);

if (instrumentHasSample(instrument)) {
this.processSampleInstrument(
Expand All @@ -901,7 +916,7 @@ class AYAudioDriver {
continue;
}

if (instrumentIndex < 0 || !instrument) {
if (!channelHasAssignedInstrument(state, channelIndex)) {
registerState.channels[channelIndex].volume = 0;
registerState.channels[channelIndex].mixer.tone = false;
registerState.channels[channelIndex].mixer.noise = false;
Expand Down Expand Up @@ -1196,18 +1211,7 @@ class AYAudioDriver {
);
}

for (let channelIndex = 0; channelIndex < state.channelInstruments.length; channelIndex++) {
if (state.channelOnOffCounter[channelIndex] > 0) {
const result = EffectAlgorithms.processOnOffCounter(
state.channelOnOffCounter[channelIndex],
state.channelOnDuration[channelIndex],
state.channelOffDuration[channelIndex],
state.channelSoundEnabled[channelIndex]
);
state.channelOnOffCounter[channelIndex] = result.counter;
state.channelSoundEnabled[channelIndex] = result.enabled;
}
}
processChannelOnOffCounters(state, state.channelInstruments.length);

this.processEnvelopeOnOff(state);

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Loading