M3: an instrument for each voice
Play loads a patch per channel before a note is played: an oboe for the
melody, strings under it, a square wave for the bass and a kalimba for
the arpeggio. It reads a count and that many parameter and value pairs -
the format SoundPatch writes - and understands nothing else about them,
which keeps SoundPatch the only thing that knows what soundThing's JSON
means.
FOUR PATCHES CAN BE UP AT ONCE, and that is the whole rung. It is the
first use of d361ea1: before it the LFOs belonged to the whole device, so
whichever patch loaded last owned them for every voice. Kalimba has LFO 0
switched off and the other three have it on, so on the old device this
piece would have played all four parts with the arpeggio's setting -
which is exactly the fault that stopped Lunar Porter's low fuel warning
trilling after the first landing of a run.
The eight patches are the user's, brought over from soundThing; four are
used here and the rest are a palette for the next piece.
The test now asks BOTH VOICES FOR NOTE 60 and gets an octave, because
their patches differ in one parameter and the lower is loaded first. A
device where a patch was global would have the second overwrite the first
and the two would answer in unison. Verified with break.sh: loading both
patches onto one channel flips the octave onto the wrong voice and the
ratio inverts to 0.499.
The test patches carry a release, and that was measured rather than
assumed: without one the first voice's note was still fading into the
second voice's window, which read 634 hertz - not a note, not an octave,
and a reminder that a crossing counter given two notes answers with
neither.
Play.sbx went 379 -> 740 bytes, which is four patches of 47 pairs each,
and is why ten recordings moved. makedisks.sh needed the Sounds include
path that Lander's line already had.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
1687422619
commit
ce1c0517aa
@@ -45,19 +45,30 @@
|
|||||||
#Base 0x5000
|
#Base 0x5000
|
||||||
|
|
||||||
start:
|
start:
|
||||||
; ---- A sound to play it with ----
|
; ---- An instrument for each voice ----
|
||||||
;
|
;
|
||||||
; The same on all four channels, which is exactly what M3 replaces: a patch per voice, out
|
; Four patches, designed in soundThing and converted by SoundPatch, which is the only thing
|
||||||
; of the format SoundPatch already writes. Until then they are four of the same instrument,
|
; here that understands what a patch means. This reads a count and that many parameter and
|
||||||
; which is enough to hear four parts and not enough to enjoy them.
|
; value pairs and knows nothing else about them.
|
||||||
|
;
|
||||||
|
; A PATCH BELONGS TO ITS CHANNEL, which is why four of them can be up at once. It did not
|
||||||
|
; used to: the LFOs belonged to the whole device, so whichever patch was loaded last owned
|
||||||
|
; them for every voice. Kalimba has LFO 0 switched off and the other three have it on, so
|
||||||
|
; under the old device this piece would have played with the arpeggio's setting on all four
|
||||||
|
; parts - which is exactly the fault that made Lunar Porter's low fuel warning stop
|
||||||
|
; trilling after the first landing of a run.
|
||||||
|
SETD.0 OboePatch
|
||||||
RSTA
|
RSTA
|
||||||
CALL setUpChannel
|
CALL loadPatch ; The melody sings, so it is the one with a voice.
|
||||||
|
SETD.0 StringsPatch
|
||||||
INIA 0d1
|
INIA 0d1
|
||||||
CALL setUpChannel
|
CALL loadPatch ; A pad underneath it.
|
||||||
|
SETD.0 SquarePatch
|
||||||
INIA 0d2
|
INIA 0d2
|
||||||
CALL setUpChannel
|
CALL loadPatch ; And a square wave for the bass, which is where one belongs.
|
||||||
|
SETD.0 KalimbaPatch
|
||||||
INIA 0d3
|
INIA 0d3
|
||||||
CALL setUpChannel
|
CALL loadPatch ; Plucked, for the arpeggio.
|
||||||
|
|
||||||
INIA 0x60 ; Room over the top for four voices at once.
|
INIA 0x60 ; Room over the top for four voices at once.
|
||||||
OUTA 0x46
|
OUTA 0x46
|
||||||
@@ -175,39 +186,27 @@ stepEnded:
|
|||||||
STA.3
|
STA.3
|
||||||
RET
|
RET
|
||||||
|
|
||||||
; A plucked sound, on the channel named by A.
|
; ---- A patch, onto the channel named by A ----
|
||||||
setUpChannel:
|
;
|
||||||
|
; A count, then that many pairs of parameter and value: the format SoundPatch writes and the
|
||||||
|
; one Lander already plays. B holds what is left, which costs nothing to keep - a CALL saves
|
||||||
|
; B, so a caller's count is not disturbed by a patch being loaded inside its loop.
|
||||||
|
;
|
||||||
|
; The channel is selected FIRST. Every parameter write below lands on whichever channel was
|
||||||
|
; named last, so a patch loaded without one would be quietly rewriting somebody else's voice.
|
||||||
|
loadPatch:
|
||||||
OUTA 0x41
|
OUTA 0x41
|
||||||
RSTA
|
LDB.0
|
||||||
|
INCD.0
|
||||||
|
loadPatchPair:
|
||||||
|
LDA.0
|
||||||
OUTA 0x42
|
OUTA 0x42
|
||||||
INIA 0d2
|
INCD.0
|
||||||
OUTA 0x43 ; A saw, which has harmonics enough to hear a filter on.
|
LDA.0
|
||||||
INIA 0x01
|
OUTA 0x43
|
||||||
OUTA 0x42
|
INCD.0
|
||||||
INIA 0xFF
|
DECB
|
||||||
OUTA 0x43 ; Oscillator 0 at full gain
|
BNB loadPatchPair
|
||||||
INIA 0x05
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0x01
|
|
||||||
OUTA 0x43 ; and switched on, which is a separate write and the one that
|
|
||||||
; matters: a gain on an oscillator that is off does nothing.
|
|
||||||
INIA 0x20
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0d8
|
|
||||||
OUTA 0x43 ; Almost no attack
|
|
||||||
INIA 0x21
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0d140
|
|
||||||
OUTA 0x43 ; a long decay
|
|
||||||
INIA 0x22
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0d60
|
|
||||||
OUTA 0x43 ; held quietly rather than at nothing, so a long note is still
|
|
||||||
; there when the next one starts
|
|
||||||
INIA 0x23
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0d40
|
|
||||||
OUTA 0x43 ; and a short release when the gate drops.
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
; The tick has nothing to do: the loop above is the player and WAIT only needs something to
|
; The tick has nothing to do: the loop above is the player and WAIT only needs something to
|
||||||
@@ -294,6 +293,13 @@ Track3:
|
|||||||
0d00 0d16 ; and out, so the last bar is the other three
|
0d00 0d16 ; and out, so the last bar is the other three
|
||||||
0xFF
|
0xFF
|
||||||
|
|
||||||
|
; The instruments, at the bottom because each brings its own #Data and a base has to come
|
||||||
|
; before anything is in the segment it bases.
|
||||||
|
#Include oboe.asm
|
||||||
|
#Include strings.asm
|
||||||
|
#Include square.asm
|
||||||
|
#Include kalimba.asm
|
||||||
|
|
||||||
#Vectors
|
#Vectors
|
||||||
|
|
||||||
Boot start
|
Boot start
|
||||||
|
|||||||
@@ -720,7 +720,7 @@ from every assembly file in it. Several are old programs written for the bare ma
|
|||||||
| Life | Conway's Game of Life, which had to be taught to stop, since a program that never ends takes the shell with it. Polls the console between generations. |
|
| Life | Conway's Game of Life, which had to be taught to stop, since a program that never ends takes the shell with it. Polls the console between generations. |
|
||||||
| Snake | A game. Draws a whole screen with cursor addressing and steers with single keys, asking the console once a frame and never waiting. |
|
| Snake | A game. Draws a whole screen with cursor addressing and steers with single keys, asking the console once a frame and never waiting. |
|
||||||
| Keys | The console interrupting rather than being asked. The only one that brings a vector of its own, which is what the version two format exists for. |
|
| Keys | The console interrupting rather than being asked. The only one that brings a vector of its own, which is what the version two format exists for. |
|
||||||
| Play | Four voices on one clock, which is what music is and one channel cannot be. The timer keeps a tick and every voice keeps its own place in its own track and its own count of how much longer the note it is holding lasts, so the parts move at four different rates and share nothing but the beat. A track is pairs of bytes, what to play and how many ticks it lasts: 1 to 127 is a MIDI note, zero is a rest, and 255 ends it - MIDI stops at 127, so neither of those had to be invented. A note's duration is its whole life and the gate goes down when the count runs out, which means a gap between two notes is written as a rest rather than invented by the player out of some fraction it decided on. The tune is assembled in for now; reading one from a file is what makes it a player rather than a program with one song in it. It spends over ninety nine per cent of its time asleep, because a beat is something to be woken by rather than counted up to. |
|
| Play | Four voices on one clock, which is what music is and one channel cannot be. The timer keeps a tick and every voice keeps its own place in its own track and its own count of how much longer the note it is holding lasts, so the parts move at four different rates and share nothing but the beat. A track is pairs of bytes, what to play and how many ticks it lasts: 1 to 127 is a MIDI note, zero is a rest, and 255 ends it - MIDI stops at 127, so neither of those had to be invented. A note's duration is its whole life and the gate goes down when the count runs out, which means a gap between two notes is written as a rest rather than invented by the player out of some fraction it decided on. Each voice loads an instrument of its own before a note is played - an oboe for the melody, strings under it, a square wave for the bass and a kalimba for the arpeggio - out of the format SoundPatch writes, which the player reads as a count and that many parameter and value pairs and understands nothing else about. Four patches can be up at once because a patch belongs to its channel; Kalimba has an LFO switched off and the other three have one on, and under a device where the LFOs belonged to the whole machine the last patch loaded would have imposed its setting on every part. The tune is assembled in for now; reading one from a file is what makes it a player rather than a program with one song in it. It spends over ninety nine per cent of its time asleep, because a beat is something to be woken by rather than counted up to. |
|
||||||
| Say | Prints whatever it was told, which is the shortest thing that shows osArgument working. |
|
| Say | Prints whatever it was told, which is the shortest thing that shows osArgument working. |
|
||||||
| Reboot | Starts the machine again, in 45 bytes. Writes a port rather than asking the system, because a reset has to work when the system does not. |
|
| Reboot | Starts the machine again, in 45 bytes. Writes a port rather than asking the system, because a reset has to work when the system does not. |
|
||||||
| Once | Asks the loader to start something else on the next start, and only that one, in 569 bytes. |
|
| Once | Asks the loader to start something else on the next start, and only that one, in 569 bytes. |
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 4,
|
||||||
|
"osc0_dutyCycle": 0.200000,
|
||||||
|
"osc0_detune": 0.000000,
|
||||||
|
"osc0_gain": 3.500000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 0,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.000000,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 5,
|
||||||
|
"osc1_dutyCycle": 0.500000,
|
||||||
|
"osc1_detune": 0.000000,
|
||||||
|
"osc1_gain": 0.000000,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 0,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 2,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 1.500000,
|
||||||
|
"ampEnv_attack": 0.001000,
|
||||||
|
"ampEnv_decay": 0.900000,
|
||||||
|
"ampEnv_sustain": 0.000000,
|
||||||
|
"ampEnv_release": 0.250000,
|
||||||
|
"modEnv_attack": 0.000000,
|
||||||
|
"modEnv_decay": 0.050000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.025000,
|
||||||
|
"lfo0_rate": 1.000000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 0,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"filter_cutoff": 5000.000000,
|
||||||
|
"filter_resonance": 0.150000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 1,
|
||||||
|
"filter_modRouting": 1,
|
||||||
|
"filter_modDepth": 5000.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.750000,
|
||||||
|
"master_pitchBendRange": 1.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 4,
|
||||||
|
"osc0_dutyCycle": 0.250000,
|
||||||
|
"osc0_detune": -4.000000,
|
||||||
|
"osc0_gain": 2.800000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 3,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.100000,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 4,
|
||||||
|
"osc1_dutyCycle": 0.250000,
|
||||||
|
"osc1_detune": 4.000000,
|
||||||
|
"osc1_gain": 2.800000,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 0,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 0,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 0.000000,
|
||||||
|
"ampEnv_attack": 0.120000,
|
||||||
|
"ampEnv_decay": 0.100000,
|
||||||
|
"ampEnv_sustain": 0.800000,
|
||||||
|
"ampEnv_release": 0.200000,
|
||||||
|
"modEnv_attack": 0.001000,
|
||||||
|
"modEnv_decay": 0.500000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.200000,
|
||||||
|
"lfo0_rate": 0.350000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 1,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"filter_cutoff": 20000.000000,
|
||||||
|
"filter_resonance": 0.000000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 0,
|
||||||
|
"filter_modRouting": 0,
|
||||||
|
"filter_modDepth": 0.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.700000,
|
||||||
|
"master_pitchBendRange": 1.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 1,
|
||||||
|
"osc0_dutyCycle": 0.500000,
|
||||||
|
"osc0_detune": 0.000000,
|
||||||
|
"osc0_gain": 2.500000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 0,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.000000,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 0,
|
||||||
|
"osc1_dutyCycle": 0.500000,
|
||||||
|
"osc1_detune": 0.000000,
|
||||||
|
"osc1_gain": 0.300000,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 2,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 2,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 2.000000,
|
||||||
|
"ampEnv_attack": 0.003000,
|
||||||
|
"ampEnv_decay": 0.080000,
|
||||||
|
"ampEnv_sustain": 0.800000,
|
||||||
|
"ampEnv_release": 0.250000,
|
||||||
|
"modEnv_attack": 0.000000,
|
||||||
|
"modEnv_decay": 0.090000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.050000,
|
||||||
|
"lfo0_rate": 1.000000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 0,
|
||||||
|
"lfo0_mode": 0,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"lfo1_mode": 0,
|
||||||
|
"filter_cutoff": 5000.000000,
|
||||||
|
"filter_resonance": 0.150000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 1,
|
||||||
|
"filter_modRouting": 2,
|
||||||
|
"filter_modDepth": 4500.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"voice_levelSource": 1,
|
||||||
|
"voice_gate": 0,
|
||||||
|
"master_volume": 1.000000,
|
||||||
|
"master_pitchBendRange": 1.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 4,
|
||||||
|
"osc0_dutyCycle": 0.700000,
|
||||||
|
"osc0_detune": 0.000000,
|
||||||
|
"osc0_gain": 3.500000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 0,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.000000,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 4,
|
||||||
|
"osc1_dutyCycle": 0.700000,
|
||||||
|
"osc1_detune": 3.000000,
|
||||||
|
"osc1_gain": 1.500000,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 1,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 2,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 1.000000,
|
||||||
|
"ampEnv_attack": 0.001000,
|
||||||
|
"ampEnv_decay": 0.700000,
|
||||||
|
"ampEnv_sustain": 0.000000,
|
||||||
|
"ampEnv_release": 0.060000,
|
||||||
|
"modEnv_attack": 0.000000,
|
||||||
|
"modEnv_decay": 0.060000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.030000,
|
||||||
|
"lfo0_rate": 1.000000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 0,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"filter_cutoff": 9000.000000,
|
||||||
|
"filter_resonance": 0.120000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 1,
|
||||||
|
"filter_modRouting": 2,
|
||||||
|
"filter_modDepth": 5000.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.750000,
|
||||||
|
"master_pitchBendRange": 0.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 0,
|
||||||
|
"osc0_dutyCycle": 0.500000,
|
||||||
|
"osc0_detune": 0.000000,
|
||||||
|
"osc0_gain": 4.000000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 1,
|
||||||
|
"osc0_modRouting0": 0,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.000000,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 0,
|
||||||
|
"osc1_dutyCycle": 0.500000,
|
||||||
|
"osc1_detune": 8.000000,
|
||||||
|
"osc1_gain": 3.423103,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 2,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 0,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 0.000000,
|
||||||
|
"ampEnv_attack": 0.001000,
|
||||||
|
"ampEnv_decay": 0.600000,
|
||||||
|
"ampEnv_sustain": 0.000000,
|
||||||
|
"ampEnv_release": 0.100000,
|
||||||
|
"modEnv_attack": 0.001000,
|
||||||
|
"modEnv_decay": 0.100000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.020000,
|
||||||
|
"lfo0_rate": 1.000000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 0,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"filter_cutoff": 3000.000000,
|
||||||
|
"filter_resonance": 0.080000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 1,
|
||||||
|
"filter_modRouting": 0,
|
||||||
|
"filter_modDepth": 0.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.700000,
|
||||||
|
"master_pitchBendRange": 2.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 4,
|
||||||
|
"osc0_dutyCycle": 0.500000,
|
||||||
|
"osc0_detune": -8.000000,
|
||||||
|
"osc0_gain": 2.500000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 3,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.280000,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 4,
|
||||||
|
"osc1_dutyCycle": 0.500000,
|
||||||
|
"osc1_detune": 8.000000,
|
||||||
|
"osc1_gain": 2.500000,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 0,
|
||||||
|
"osc1_modRouting0": 4,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 0,
|
||||||
|
"osc1_modDepth0": 0.280000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 0.000000,
|
||||||
|
"ampEnv_attack": 0.420000,
|
||||||
|
"ampEnv_decay": 0.100000,
|
||||||
|
"ampEnv_sustain": 0.880000,
|
||||||
|
"ampEnv_release": 1.300000,
|
||||||
|
"modEnv_attack": 0.000000,
|
||||||
|
"modEnv_decay": 0.500000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.400000,
|
||||||
|
"lfo0_rate": 0.290000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 1,
|
||||||
|
"lfo1_rate": 0.370000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 1,
|
||||||
|
"filter_cutoff": 4200.000000,
|
||||||
|
"filter_resonance": 0.080000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 1,
|
||||||
|
"filter_modRouting": 1,
|
||||||
|
"filter_modDepth": 2800.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.720000,
|
||||||
|
"master_pitchBendRange": 2.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 4,
|
||||||
|
"osc0_dutyCycle": 0.250000,
|
||||||
|
"osc0_detune": 0.000000,
|
||||||
|
"osc0_gain": 3.000000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 0,
|
||||||
|
"osc0_modRouting1": 3,
|
||||||
|
"osc0_modRouting2": 0,
|
||||||
|
"osc0_modDepth0": 0.000000,
|
||||||
|
"osc0_modDepth1": 5.000000,
|
||||||
|
"osc0_modDepth2": 0.000000,
|
||||||
|
"osc1_waveform": 4,
|
||||||
|
"osc1_dutyCycle": 0.200000,
|
||||||
|
"osc1_detune": 2.000000,
|
||||||
|
"osc1_gain": 2.000000,
|
||||||
|
"osc1_active": 1,
|
||||||
|
"osc1_octave": 0,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 0,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 0.000000,
|
||||||
|
"ampEnv_attack": 0.055000,
|
||||||
|
"ampEnv_decay": 0.030000,
|
||||||
|
"ampEnv_sustain": 0.920000,
|
||||||
|
"ampEnv_release": 0.150000,
|
||||||
|
"modEnv_attack": 0.000000,
|
||||||
|
"modEnv_decay": 0.500000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.200000,
|
||||||
|
"lfo0_rate": 5.000000,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 1,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"filter_cutoff": 2500.000000,
|
||||||
|
"filter_resonance": 0.400000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 1,
|
||||||
|
"filter_modRouting": 0,
|
||||||
|
"filter_modDepth": 0.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.700000,
|
||||||
|
"master_pitchBendRange": 2.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"osc0_waveform": 4,
|
||||||
|
"osc0_dutyCycle": 0.153236,
|
||||||
|
"osc0_detune": 0.000000,
|
||||||
|
"osc0_gain": 4.000000,
|
||||||
|
"osc0_active": 1,
|
||||||
|
"osc0_octave": 0,
|
||||||
|
"osc0_modRouting0": 1,
|
||||||
|
"osc0_modRouting1": 0,
|
||||||
|
"osc0_modRouting2": 3,
|
||||||
|
"osc0_modDepth0": 0.290788,
|
||||||
|
"osc0_modDepth1": 0.000000,
|
||||||
|
"osc0_modDepth2": -0.833591,
|
||||||
|
"osc1_waveform": 1,
|
||||||
|
"osc1_dutyCycle": 0.500000,
|
||||||
|
"osc1_detune": 0.000000,
|
||||||
|
"osc1_gain": 0.000000,
|
||||||
|
"osc1_active": 0,
|
||||||
|
"osc1_octave": 0,
|
||||||
|
"osc1_modRouting0": 0,
|
||||||
|
"osc1_modRouting1": 0,
|
||||||
|
"osc1_modRouting2": 0,
|
||||||
|
"osc1_modDepth0": 0.000000,
|
||||||
|
"osc1_modDepth1": 0.000000,
|
||||||
|
"osc1_modDepth2": 0.000000,
|
||||||
|
"ampEnv_attack": 0.005000,
|
||||||
|
"ampEnv_decay": 0.100000,
|
||||||
|
"ampEnv_sustain": 0.700000,
|
||||||
|
"ampEnv_release": 0.500000,
|
||||||
|
"modEnv_attack": 0.005000,
|
||||||
|
"modEnv_decay": 0.500000,
|
||||||
|
"modEnv_sustain": 0.000000,
|
||||||
|
"modEnv_release": 0.100000,
|
||||||
|
"lfo0_rate": 2.598532,
|
||||||
|
"lfo0_waveform": 0,
|
||||||
|
"lfo0_active": 1,
|
||||||
|
"lfo1_rate": 1.000000,
|
||||||
|
"lfo1_waveform": 0,
|
||||||
|
"lfo1_active": 0,
|
||||||
|
"filter_cutoff": 8000.000000,
|
||||||
|
"filter_resonance": 0.000000,
|
||||||
|
"filter_type": 0,
|
||||||
|
"filter_active": 0,
|
||||||
|
"filter_modRouting": 0,
|
||||||
|
"filter_modDepth": 0.000000,
|
||||||
|
"filter_resModRouting": 0,
|
||||||
|
"filter_resModDepth": 0.000000,
|
||||||
|
"master_volume": 0.362205,
|
||||||
|
"master_pitchBendRange": 2.000000
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
; KalimbaPatch, converted from Programs/Sounds/Kalimba.json by SoundPatch.
|
||||||
|
; Designed in soundThing, where it can be heard. Do not edit the numbers
|
||||||
|
; here: change the patch and convert it again.
|
||||||
|
|
||||||
|
#Data
|
||||||
|
|
||||||
|
KalimbaPatch:
|
||||||
|
0d47 ; how many pairs follow
|
||||||
|
0x00 0d0 ; oscillator 0, waveform
|
||||||
|
0x01 0d255 ; gain
|
||||||
|
0x02 0d128 ; duty
|
||||||
|
0x03 0d128 ; detune, in cents
|
||||||
|
0x04 0d129 ; octave
|
||||||
|
0x05 0d1 ; on
|
||||||
|
0x06 0d0 ; what moves its width
|
||||||
|
0x07 0d128 ; and how far
|
||||||
|
0x08 0d0 ; what moves its pitch
|
||||||
|
0x09 0d128 ; and how far
|
||||||
|
0x0A 0d0 ; what moves its gain
|
||||||
|
0x0B 0d128 ; and how far
|
||||||
|
0x10 0d0 ; oscillator 1, waveform
|
||||||
|
0x11 0d218 ; gain
|
||||||
|
0x12 0d128 ; duty
|
||||||
|
0x13 0d129 ; detune, in cents
|
||||||
|
0x14 0d130 ; octave
|
||||||
|
0x15 0d1 ; on
|
||||||
|
0x16 0d0 ; what moves its width
|
||||||
|
0x17 0d128 ; and how far
|
||||||
|
0x18 0d0 ; what moves its pitch
|
||||||
|
0x19 0d128 ; and how far
|
||||||
|
0x1A 0d0 ; what moves its gain
|
||||||
|
0x1B 0d128 ; and how far
|
||||||
|
0x20 0d4 ; amplitude envelope, attack
|
||||||
|
0x21 0d99 ; decay
|
||||||
|
0x22 0d0 ; sustain
|
||||||
|
0x23 0d40 ; release
|
||||||
|
0x30 0d4 ; modulation envelope, attack
|
||||||
|
0x31 0d40 ; decay
|
||||||
|
0x32 0d0 ; sustain
|
||||||
|
0x33 0d18 ; release
|
||||||
|
0x40 0d1 ; filter, on
|
||||||
|
0x41 0d0 ; type: 0 low, 1 high, 2 band
|
||||||
|
0x42 0d185 ; cutoff, in hertz
|
||||||
|
0x43 0d21 ; resonance
|
||||||
|
0x44 0d0 ; what moves the cutoff
|
||||||
|
0x45 0d128 ; and how far, in hertz
|
||||||
|
0x46 0d0 ; what moves the resonance
|
||||||
|
0x47 0d128 ; and how far
|
||||||
|
0x60 0d0 ; LFO 0, on
|
||||||
|
0x61 0d0 ; waveform
|
||||||
|
0x62 0d127 ; rate, in hertz
|
||||||
|
0x70 0d0 ; LFO 1, on
|
||||||
|
0x71 0d0 ; waveform
|
||||||
|
0x72 0d127 ; rate, in hertz
|
||||||
|
0x50 0d1 ; what shapes the level, which this patch predates
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
; OboePatch, converted from Programs/Sounds/Oboe.json by SoundPatch.
|
||||||
|
; Designed in soundThing, where it can be heard. Do not edit the numbers
|
||||||
|
; here: change the patch and convert it again.
|
||||||
|
|
||||||
|
#Data
|
||||||
|
|
||||||
|
OboePatch:
|
||||||
|
0d47 ; how many pairs follow
|
||||||
|
0x00 0d4 ; oscillator 0, waveform
|
||||||
|
0x01 0d191 ; gain
|
||||||
|
0x02 0d57 ; duty
|
||||||
|
0x03 0d128 ; detune, in cents
|
||||||
|
0x04 0d128 ; octave
|
||||||
|
0x05 0d1 ; on
|
||||||
|
0x06 0d0 ; what moves its width
|
||||||
|
0x07 0d128 ; and how far
|
||||||
|
0x08 0d3 ; what moves its pitch
|
||||||
|
0x09 0d129 ; and how far
|
||||||
|
0x0A 0d0 ; what moves its gain
|
||||||
|
0x0B 0d128 ; and how far
|
||||||
|
0x10 0d4 ; oscillator 1, waveform
|
||||||
|
0x11 0d128 ; gain
|
||||||
|
0x12 0d43 ; duty
|
||||||
|
0x13 0d128 ; detune, in cents
|
||||||
|
0x14 0d128 ; octave
|
||||||
|
0x15 0d1 ; on
|
||||||
|
0x16 0d0 ; what moves its width
|
||||||
|
0x17 0d128 ; and how far
|
||||||
|
0x18 0d0 ; what moves its pitch
|
||||||
|
0x19 0d128 ; and how far
|
||||||
|
0x1A 0d0 ; what moves its gain
|
||||||
|
0x1B 0d128 ; and how far
|
||||||
|
0x20 0d30 ; amplitude envelope, attack
|
||||||
|
0x21 0d22 ; decay
|
||||||
|
0x22 0d235 ; sustain
|
||||||
|
0x23 0d49 ; release
|
||||||
|
0x30 0d0 ; modulation envelope, attack
|
||||||
|
0x31 0d90 ; decay
|
||||||
|
0x32 0d0 ; sustain
|
||||||
|
0x33 0d57 ; release
|
||||||
|
0x40 0d1 ; filter, on
|
||||||
|
0x41 0d0 ; type: 0 low, 1 high, 2 band
|
||||||
|
0x42 0d178 ; cutoff, in hertz
|
||||||
|
0x43 0d103 ; resonance
|
||||||
|
0x44 0d0 ; what moves the cutoff
|
||||||
|
0x45 0d128 ; and how far, in hertz
|
||||||
|
0x46 0d0 ; what moves the resonance
|
||||||
|
0x47 0d128 ; and how far
|
||||||
|
0x60 0d1 ; LFO 0, on
|
||||||
|
0x61 0d0 ; waveform
|
||||||
|
0x62 0d196 ; rate, in hertz
|
||||||
|
0x70 0d0 ; LFO 1, on
|
||||||
|
0x71 0d0 ; waveform
|
||||||
|
0x72 0d127 ; rate, in hertz
|
||||||
|
0x50 0d1 ; what shapes the level, which this patch predates
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
; SquarePatch, converted from Programs/Sounds/SidSquare.json by SoundPatch.
|
||||||
|
; Designed in soundThing, where it can be heard. Do not edit the numbers
|
||||||
|
; here: change the patch and convert it again.
|
||||||
|
|
||||||
|
#Data
|
||||||
|
|
||||||
|
SquarePatch:
|
||||||
|
0d47 ; how many pairs follow
|
||||||
|
0x00 0d4 ; oscillator 0, waveform
|
||||||
|
0x01 0d255 ; gain
|
||||||
|
0x02 0d29 ; duty
|
||||||
|
0x03 0d128 ; detune, in cents
|
||||||
|
0x04 0d128 ; octave
|
||||||
|
0x05 0d1 ; on
|
||||||
|
0x06 0d1 ; what moves its width
|
||||||
|
0x07 0d202 ; and how far
|
||||||
|
0x08 0d0 ; what moves its pitch
|
||||||
|
0x09 0d128 ; and how far
|
||||||
|
0x0A 0d3 ; what moves its gain
|
||||||
|
0x0B 0d101 ; and how far
|
||||||
|
0x10 0d1 ; oscillator 1, waveform
|
||||||
|
0x11 0d0 ; gain
|
||||||
|
0x12 0d128 ; duty
|
||||||
|
0x13 0d128 ; detune, in cents
|
||||||
|
0x14 0d128 ; octave
|
||||||
|
0x15 0d0 ; on
|
||||||
|
0x16 0d0 ; what moves its width
|
||||||
|
0x17 0d128 ; and how far
|
||||||
|
0x18 0d0 ; what moves its pitch
|
||||||
|
0x19 0d128 ; and how far
|
||||||
|
0x1A 0d0 ; what moves its gain
|
||||||
|
0x1B 0d128 ; and how far
|
||||||
|
0x20 0d9 ; amplitude envelope, attack
|
||||||
|
0x21 0d40 ; decay
|
||||||
|
0x22 0d179 ; sustain
|
||||||
|
0x23 0d90 ; release
|
||||||
|
0x30 0d9 ; modulation envelope, attack
|
||||||
|
0x31 0d90 ; decay
|
||||||
|
0x32 0d0 ; sustain
|
||||||
|
0x33 0d40 ; release
|
||||||
|
0x40 0d0 ; filter, on
|
||||||
|
0x41 0d0 ; type: 0 low, 1 high, 2 band
|
||||||
|
0x42 0d221 ; cutoff, in hertz
|
||||||
|
0x43 0d0 ; resonance
|
||||||
|
0x44 0d0 ; what moves the cutoff
|
||||||
|
0x45 0d128 ; and how far, in hertz
|
||||||
|
0x46 0d0 ; what moves the resonance
|
||||||
|
0x47 0d128 ; and how far
|
||||||
|
0x60 0d1 ; LFO 0, on
|
||||||
|
0x61 0d0 ; waveform
|
||||||
|
0x62 0d168 ; rate, in hertz
|
||||||
|
0x70 0d0 ; LFO 1, on
|
||||||
|
0x71 0d0 ; waveform
|
||||||
|
0x72 0d127 ; rate, in hertz
|
||||||
|
0x50 0d1 ; what shapes the level, which this patch predates
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
; StringsPatch, converted from Programs/Sounds/LushStrings.json by SoundPatch.
|
||||||
|
; Designed in soundThing, where it can be heard. Do not edit the numbers
|
||||||
|
; here: change the patch and convert it again.
|
||||||
|
|
||||||
|
#Data
|
||||||
|
|
||||||
|
StringsPatch:
|
||||||
|
0d47 ; how many pairs follow
|
||||||
|
0x00 0d4 ; oscillator 0, waveform
|
||||||
|
0x01 0d159 ; gain
|
||||||
|
0x02 0d128 ; duty
|
||||||
|
0x03 0d127 ; detune, in cents
|
||||||
|
0x04 0d128 ; octave
|
||||||
|
0x05 0d1 ; on
|
||||||
|
0x06 0d3 ; what moves its width
|
||||||
|
0x07 0d200 ; and how far
|
||||||
|
0x08 0d0 ; what moves its pitch
|
||||||
|
0x09 0d128 ; and how far
|
||||||
|
0x0A 0d0 ; what moves its gain
|
||||||
|
0x0B 0d128 ; and how far
|
||||||
|
0x10 0d4 ; oscillator 1, waveform
|
||||||
|
0x11 0d159 ; gain
|
||||||
|
0x12 0d128 ; duty
|
||||||
|
0x13 0d129 ; detune, in cents
|
||||||
|
0x14 0d128 ; octave
|
||||||
|
0x15 0d1 ; on
|
||||||
|
0x16 0d4 ; what moves its width
|
||||||
|
0x17 0d200 ; and how far
|
||||||
|
0x18 0d0 ; what moves its pitch
|
||||||
|
0x19 0d128 ; and how far
|
||||||
|
0x1A 0d0 ; what moves its gain
|
||||||
|
0x1B 0d128 ; and how far
|
||||||
|
0x20 0d83 ; amplitude envelope, attack
|
||||||
|
0x21 0d40 ; decay
|
||||||
|
0x22 0d224 ; sustain
|
||||||
|
0x23 0d145 ; release
|
||||||
|
0x30 0d0 ; modulation envelope, attack
|
||||||
|
0x31 0d90 ; decay
|
||||||
|
0x32 0d0 ; sustain
|
||||||
|
0x33 0d81 ; release
|
||||||
|
0x40 0d1 ; filter, on
|
||||||
|
0x41 0d0 ; type: 0 low, 1 high, 2 band
|
||||||
|
0x42 0d197 ; cutoff, in hertz
|
||||||
|
0x43 0d21 ; resonance
|
||||||
|
0x44 0d1 ; what moves the cutoff
|
||||||
|
0x45 0d173 ; and how far, in hertz
|
||||||
|
0x46 0d0 ; what moves the resonance
|
||||||
|
0x47 0d128 ; and how far
|
||||||
|
0x60 0d1 ; LFO 0, on
|
||||||
|
0x61 0d0 ; waveform
|
||||||
|
0x62 0d75 ; rate, in hertz
|
||||||
|
0x70 0d1 ; LFO 1, on
|
||||||
|
0x71 0d0 ; waveform
|
||||||
|
0x72 0d85 ; rate, in hertz
|
||||||
|
0x50 0d1 ; what shapes the level, which this patch predates
|
||||||
@@ -10,6 +10,10 @@
|
|||||||
; ticks 4-7 voice 0 rests voice 1 plays the C above it
|
; ticks 4-7 voice 0 rests voice 1 plays the C above it
|
||||||
; ticks 8-11 voice 0 plays middle C voice 1 plays the C above it
|
; ticks 8-11 voice 0 plays middle C voice 1 plays the C above it
|
||||||
;
|
;
|
||||||
|
; BOTH VOICES ARE ASKED FOR NOTE 60. The octave between them is in their patches, which is
|
||||||
|
; M3: a patch belongs to its channel, so four of them can be up at once. Under a device where
|
||||||
|
; it did not, the second patch loaded would own both voices and they would sound in unison.
|
||||||
|
;
|
||||||
; So the first two windows have one voice in them and can be measured for pitch, and the third
|
; So the first two windows have one voice in them and can be measured for pitch, and the third
|
||||||
; has both and can be measured for level. Two voices sounding at once cannot be asked their
|
; has both and can be measured for level. Two voices sounding at once cannot be asked their
|
||||||
; pitch - a crossing counter given two notes answers with neither.
|
; pitch - a crossing counter given two notes answers with neither.
|
||||||
@@ -23,10 +27,16 @@
|
|||||||
|
|
||||||
#Program
|
#Program
|
||||||
start:
|
start:
|
||||||
|
; A patch each, in the format SoundPatch writes: a count and that many pairs. They differ
|
||||||
|
; in ONE parameter - the octave - and the low one is loaded first, so if a patch belonged to
|
||||||
|
; the device rather than to its channel the second would overwrite the first and both voices
|
||||||
|
; would sound the same.
|
||||||
|
SETD.0 PatchLow
|
||||||
RSTA
|
RSTA
|
||||||
CALL setUpChannel
|
CALL loadPatch
|
||||||
|
SETD.0 PatchHigh
|
||||||
INIA 0d1
|
INIA 0d1
|
||||||
CALL setUpChannel
|
CALL loadPatch
|
||||||
|
|
||||||
INIA 0x60
|
INIA 0x60
|
||||||
OUTA 0x46
|
OUTA 0x46
|
||||||
@@ -103,38 +113,23 @@ stepVoice:
|
|||||||
stepDone:
|
stepDone:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
; Held at full and released quickly, so a note lasts exactly its ticks and the boundary
|
; ---- A patch, onto the channel named by A ----
|
||||||
; between two of them is something a counter can find.
|
;
|
||||||
setUpChannel:
|
; The channel is selected first: every parameter write lands on whichever channel was named
|
||||||
|
; last, so a patch loaded without one would be rewriting somebody else's voice.
|
||||||
|
loadPatch:
|
||||||
OUTA 0x41
|
OUTA 0x41
|
||||||
RSTA
|
LDB.0
|
||||||
|
INCD.0
|
||||||
|
loadPatchPair:
|
||||||
|
LDA.0
|
||||||
OUTA 0x42
|
OUTA 0x42
|
||||||
INIA 0d2
|
INCD.0
|
||||||
OUTA 0x43 ; Saw
|
LDA.0
|
||||||
INIA 0x01
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0xFF
|
|
||||||
OUTA 0x43
|
|
||||||
INIA 0x05
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0x01
|
|
||||||
OUTA 0x43 ; Oscillator 0, on and loud.
|
|
||||||
INIA 0x20
|
|
||||||
OUTA 0x42
|
|
||||||
RSTA
|
|
||||||
OUTA 0x43 ; No attack
|
|
||||||
INIA 0x21
|
|
||||||
OUTA 0x42
|
|
||||||
RSTA
|
|
||||||
OUTA 0x43 ; no decay
|
|
||||||
INIA 0x22
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0xFF
|
|
||||||
OUTA 0x43 ; and held at full.
|
|
||||||
INIA 0x23
|
|
||||||
OUTA 0x42
|
|
||||||
INIA 0d5
|
|
||||||
OUTA 0x43
|
OUTA 0x43
|
||||||
|
INCD.0
|
||||||
|
DECB
|
||||||
|
BNB loadPatchPair
|
||||||
RET
|
RET
|
||||||
|
|
||||||
tick:
|
tick:
|
||||||
@@ -160,10 +155,37 @@ Track0:
|
|||||||
0d00 0xFF
|
0d00 0xFF
|
||||||
Track1:
|
Track1:
|
||||||
0d00 0d4
|
0d00 0d4
|
||||||
0d72 0d4
|
0d60 0d4
|
||||||
0d72 0d4
|
0d60 0d4
|
||||||
0d00 0xFF
|
0d00 0xFF
|
||||||
|
|
||||||
|
; Seven pairs each, and only the last of them differs: the octave, centred on 128. So the two
|
||||||
|
; voices below are asked for THE SAME NOTE NUMBER and answer an octave apart, which nothing
|
||||||
|
; but a patch of their own could do.
|
||||||
|
PatchLow:
|
||||||
|
0d8
|
||||||
|
0x00 0d2 ; Saw
|
||||||
|
0x01 0xFF ; at full gain
|
||||||
|
0x05 0d1 ; and switched on.
|
||||||
|
0x20 0d0 ; No attack
|
||||||
|
0x21 0d0 ; no decay
|
||||||
|
0x22 0xFF ; and held at full, so a note lasts exactly its ticks
|
||||||
|
0x23 0d5 ; and goes quickly when the gate drops, which the windows below
|
||||||
|
; depend on: a note still fading into the next voice's stretch is
|
||||||
|
; a second pitch in it, and a crossing counter given two answers
|
||||||
|
; with neither.
|
||||||
|
0x04 0d128 ; Octave, centred.
|
||||||
|
PatchHigh:
|
||||||
|
0d8
|
||||||
|
0x00 0d2
|
||||||
|
0x01 0xFF
|
||||||
|
0x05 0d1
|
||||||
|
0x20 0d0
|
||||||
|
0x21 0d0
|
||||||
|
0x22 0xFF
|
||||||
|
0x23 0d5
|
||||||
|
0x04 0d129 ; And this one an octave up.
|
||||||
|
|
||||||
#Vectors
|
#Vectors
|
||||||
Boot start
|
Boot start
|
||||||
Device 0x50 tick
|
Device 0x50 tick
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ vars.script 50
|
|||||||
blocks.script 343
|
blocks.script 343
|
||||||
loops.script 272
|
loops.script 272
|
||||||
tune.sbx 318
|
tune.sbx 318
|
||||||
Play.sbx 379
|
Play.sbx 740
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
+3
-2
@@ -180,8 +180,9 @@ printf '#! script\nfor a in 1 2\n for b in x y\n echo $a$b\n end\nend\nset
|
|||||||
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
|
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
|
||||||
"$ROOT/Programs/Examples/tune.asm" -o "$WORK/tune.sbx" >/dev/null
|
"$ROOT/Programs/Examples/tune.asm" -o "$WORK/tune.sbx" >/dev/null
|
||||||
"$TOOL" put "$DISKS/cosmos.img" "$WORK/tune.sbx" >/dev/null
|
"$TOOL" put "$DISKS/cosmos.img" "$WORK/tune.sbx" >/dev/null
|
||||||
# And Play, which is the same beat carrying four voices instead of one.
|
# And Play, which is the same beat carrying four voices instead of one - each with an
|
||||||
"$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \
|
# instrument of its own out of Sounds, which is what four patches at once looks like.
|
||||||
|
"$ROOT/Assembler" -I "$ROOT/Programs/Sounds" -I "$ROOT/Programs/CosmOS/Source" \
|
||||||
"$ROOT/Programs/CosmOS/Apps/Play.asm" -o "$WORK/Play.sbx" >/dev/null
|
"$ROOT/Programs/CosmOS/Apps/Play.asm" -o "$WORK/Play.sbx" >/dev/null
|
||||||
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Play.sbx" >/dev/null
|
"$TOOL" put "$DISKS/cosmos.img" "$WORK/Play.sbx" >/dev/null
|
||||||
printf 'this is not a program' > notes.txt
|
printf 'this is not a program' > notes.txt
|
||||||
|
|||||||
+23
-5
@@ -650,11 +650,15 @@ near "$EIGHTH" 523.3 2 \
|
|||||||
# track and its own count of how long the note it is holding lasts, so one can rest while
|
# track and its own count of how long the note it is holding lasts, so one can rest while
|
||||||
# another plays. That is the whole of what a channel cannot do on its own.
|
# another plays. That is the whole of what a channel cannot do on its own.
|
||||||
#
|
#
|
||||||
# The program stagger the two voices deliberately, so each gets a stretch where it is the only
|
# The program staggers the two voices deliberately, so each gets a stretch where it is the
|
||||||
# thing sounding and its pitch can be asked for. TWO NOTES AT ONCE CANNOT BE ASKED THEIR
|
# only thing sounding and its pitch can be asked for. TWO NOTES AT ONCE CANNOT BE ASKED THEIR
|
||||||
# PITCH: the crossing counter adds them and answers with neither, which is 785 hertz for the
|
# PITCH: a crossing counter given two answers with neither. So the overlap is checked for
|
||||||
# third window below - the sum of 262 and 523 and a fact about nothing. So the overlap is
|
# LEVEL instead, which is a question two notes can answer.
|
||||||
# checked for LEVEL instead, which is a question two notes can answer.
|
#
|
||||||
|
# The patches carry a release for the same reason. Without one the first voice's note was
|
||||||
|
# still fading into the second voice's stretch, and the window that should have read one note
|
||||||
|
# read 634 hertz - which is not a note, not an octave, and was measured before it was written
|
||||||
|
# down as an assertion.
|
||||||
run fourVoices 1700000 < "$ROOT/Programs/testPrograms/fourVoiceTest.asm" || exit 1
|
run fourVoices 1700000 < "$ROOT/Programs/testPrograms/fourVoiceTest.asm" || exit 1
|
||||||
|
|
||||||
COUNT="$(measure fourVoices count)"
|
COUNT="$(measure fourVoices count)"
|
||||||
@@ -672,6 +676,20 @@ near "$SECOND" 523.3 2 \
|
|||||||
&& result ok "and then they change places" "$SECOND hertz, an octave up, with the first one silent" \
|
&& result ok "and then they change places" "$SECOND hertz, an octave up, with the first one silent" \
|
||||||
|| result no "and then they change places" "$SECOND hertz, wanted the octave alone"
|
|| result no "and then they change places" "$SECOND hertz, wanted the octave alone"
|
||||||
|
|
||||||
|
# ---- And a patch belongs to its channel ----
|
||||||
|
#
|
||||||
|
# M3. BOTH TRACKS NAME NOTE 60. The octave between them is in their patches, which differ in
|
||||||
|
# one parameter, and the lower one is loaded FIRST - so a device where a patch was global
|
||||||
|
# would have the second overwrite it and both voices would answer in unison.
|
||||||
|
#
|
||||||
|
# This is the thing d361ea1 made possible and nothing had used: before it the LFOs belonged to
|
||||||
|
# the whole device, so whichever patch loaded last owned them for every voice at once.
|
||||||
|
RATIO="$(python3 -c "import sys; print('%.3f' % (float(sys.argv[1]) / float(sys.argv[2])))" \
|
||||||
|
"$SECOND" "$FIRST")"
|
||||||
|
near "$RATIO" 2.0 3 \
|
||||||
|
&& result ok "a patch belongs to its channel" "both tracks say note 60 and one sounds $RATIO times the other" \
|
||||||
|
|| result no "a patch belongs to its channel" "the two voices are $RATIO apart, and their patches say two"
|
||||||
|
|
||||||
# Both voices sounding is louder than either of them alone. Against the QUIETER of the two so
|
# Both voices sounding is louder than either of them alone. Against the QUIETER of the two so
|
||||||
# that the check cannot be passed by one voice getting louder, and by a margin well under the
|
# that the check cannot be passed by one voice getting louder, and by a margin well under the
|
||||||
# two-fold a clean sum would give, because two notes are not in phase and do not simply add.
|
# two-fold a clean sum would give, because two notes are not in phase and do not simply add.
|
||||||
|
|||||||
Reference in New Issue
Block a user