; Four voices on one tick, staggered so that each can be heard on its own. ; ; M2 of the music player. What is being checked is that the voices share the tick and NOTHING ; ELSE: each keeps its own place in its own track and its own count of how long the note it is ; holding lasts, so one can rest while another plays. ; ; Twelve ticks of 125,000 cycles, which is a sixteenth note at 120 beats a minute: ; ; ticks 0-3 voice 0 plays middle C voice 1 rests ; 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 ; ; 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 ; 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. ; ; THIS IS DELIBERATELY NOT Apps/Play.asm. It shares the design and not the code, and it is ; smaller: no track ever ends here, so there is no live flag and no count of what is still ; playing. What it has is the part worth pinning - a cursor and a countdown per voice, moved ; with LDD and STD. ; ; Written by Anachronaut #Program start: ; A patch each, in the format SoundPatch writes: a count and that many pairs. They differ in ; ONE parameter - the octave - and VoiceStart gives the low one to voice 0 and the high one ; to voice 1. 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. CALL loadStartPatches INIA 0x60 OUTA 0x46 ; 125,000 cycles a tick. The period before the control byte, because writing control with ; the run bit set is what loads it. INIA 0x01 OUTA 0x52 INIA 0xE8 OUTA 0x53 INIA 0x48 OUTA 0x54 INIA 0x07 OUTA 0x51 SIF ; Sixteen ticks. B survives the calls below, because a CALL saves it. INIB 0d16 tickLoop: SETD.1 Voice0 RSTA CALL stepVoice SETD.1 Voice1 INIA 0d1 CALL stepVoice DECB BRB lastTick WAIT BRI tickLoop lastTick: ; The last step started a note and nothing has waited for it yet. Without this the final ; tick is never rendered, and a window measuring it runs off the end of the samples. WAIT done: CIF RSTA OUTA 0x51 HALT tick: RETI #Data ; Middle C, then out of the way, then back - against the octave above doing the opposite. ; ---- The order lists, and what they are for ---- ; ; Four bars of four ticks each, and the SAME TWO SEQUENCES do nearly all of it. Beat is used ; twice by voice 0 and twice by voice 1 - four placings of one phrase, written once, and on ; two different voices, because the voice is a property of where a sequence is placed and not ; of the sequence. ; ; ticks 0-3 4-7 8-11 12-15 ; voice 0 Beat Quiet Beat Switch ; voice 1 Quiet Beat Beat (its order list ends here) Order0: 0d0 0d1 0d0 0d2 0d3 0xFF Order1: 0d1 0d0 0d0 0xFF ; And this one ENDS, so the last bar has voice 1 stopped rather ; than resting. A player that missed the terminator would read ; whatever follows as a sequence index and play it. Order2: 0d3 0xFF Order3: 0d3 0xFF PatchTable: PatchLow PatchHigh SequenceTable: Beat Quiet Switch Tail ; 0 to 3 VoiceStart: 0d0 0d1 0d0 0d0 Beat: 0d60 0d4 ; Note 60 on both voices. The octave between them is their patches. 0xFF Quiet: 0d00 0d4 0xFF Switch: 0x80 0d1 ; Voice 0 takes patch one, which is voice 1's, mid-piece. 0d60 0d4 ; The same note number it has played all along. 0xFF Tail: 0d00 0xFF ; Long enough that nothing runs off the end of its order list. 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. #Include player.asm #Vectors Boot start Device 0x50 tick