diff --git a/Programs/Examples/tune.asm b/Programs/Examples/tune.asm index 44d9f88..1997bc0 100644 --- a/Programs/Examples/tune.asm +++ b/Programs/Examples/tune.asm @@ -8,26 +8,28 @@ ; does not interrupt, so a program that only had the sound device could play a tune at ; whatever speed the machine happened to run at, which is not a tune. ; -; The screen finishes a frame sixty times a second and will say so. That is the only regular -; beat on this machine, and it is counted in the machine's own cycles, so this plays at the -; same speed whether the emulator is running at a megahertz or as fast as it can go. Every -; duration below is in frames: 30 is half a second. +; The timer is the other half. A period in cycles, a repeat bit, and a line when one has gone +; by: a beat this program SETS rather than one it borrows. Every duration below is a count of +; ticks, and the tick is named in the machine's own cycles, so this plays at the same speed +; whether the emulator is running at a megahertz or as fast as it can go. ; -; A programmable timer is the device that ought to be doing this, and it does not exist yet. -; Borrowing the screen's frame costs nothing and works, which is the whole reason to notice -; that a beat is a beat wherever it comes from. +; ---- The tick is a sixteenth note, and that is the whole point ---- ; -; ---- What borrowing it costs ---- +; 125,000 cycles, which is a sixteenth note at 120 beats a minute. ; -; The frame is not slow. It is FIXED, and that is the different complaint. Every duration here -; is a whole number of 16.67 ms, so a note worth a third of a beat cannot be written at all - -; and the way round it is to pick a tempo whose subdivisions happen to land on whole frames, -; which is making the tune fit the machine rather than the other way round. The theme below -; was written to the frame and is a few cents of tempo away from what it wants to be. +; This program used to count the SCREEN's frames, because until the timer existed the frame +; was the only regular beat on the machine. A frame is 16,667 cycles, so a sixteenth note is +; seven and a half of them and could not be asked for at all. The arpeggio below was written +; as seven frames, the nearest whole one, which is six and a half per cent fast; and the way +; round the rest of it was to pick a tempo whose subdivisions happened to land on whole +; frames, which is making the tune fit the machine rather than the other way round. ; -; So what the timer wants is an ARBITRARY tick rather than a faster fixed one, and the reason -; the screen should not be the clock is that a display refresh and a music routine have no -; reason to share a rate. +; SO THE DURATIONS HERE ARE NOT A CONVERSION OF THE OLD ONES. They are what the music wanted +; in the first place, now that it can be written down: an eighth is two ticks, a quarter is +; four, and the arpeggio is one each rather than a fast approximation of one. +; +; The reason the screen should not have been the clock is not that a frame is slow. It is that +; a display refresh and a music routine have no reason to share a rate. ; ; ---- What a patch costs and what a note costs ---- ; @@ -143,10 +145,18 @@ start: ; ---- The beat ---- ; - ; Ask the screen to interrupt at each frame, and let interrupts in. The screen does not do - ; this unless it is asked. + ; The period first and the control byte second, because writing the control byte with the + ; run bit set is what LOADS the period. Doing it the other way round starts a timer on + ; whatever it was holding before. INIA 0x01 - OUTA 0x35 + OUTA 0x52 + INIA 0xE8 + OUTA 0x53 + INIA 0x48 + OUTA 0x54 ; 0x01E848 is 125,000. + + INIA 0x07 + OUTA 0x51 ; Run, repeat, interrupt. SIF ; ---- The tune ---- @@ -160,11 +170,11 @@ nextNote: BRA finished OUTA 0x44 ; Writing the note is what starts it. INCD.0 - LDB.0 ; How many frames it lasts. + LDB.0 ; How many ticks it lasts. INCD.0 holdNote: - WAIT ; Nothing at all until the screen says a frame has gone by. + WAIT ; Nothing at all until the timer says a tick has gone by. DECB BNB holdNote @@ -175,9 +185,10 @@ holdNote: BRI nextNote finished: - ; Let the last note ring out rather than cutting it off, then put the screen back the way it - ; was found - and stop asking to be interrupted before taking away what catches it. - INIB 0d45 + ; Let the last note ring out rather than cutting it off, then give the timer back - stopping + ; it before taking away what catches it, because this program is about to stop existing and + ; an interrupt with no handler installed is a fault. + INIB 0d6 lastRing: WAIT DECB @@ -185,13 +196,17 @@ lastRing: CIF RSTA - OUTA 0x35 + OUTA 0x51 SWI osExit -; Sixty times a second, and it has nothing to do. WAIT only needs something to have happened, -; and this is the something. A handler still has to exist: an interrupt with nothing installed -; to catch it is a fault. -frame: +; The tick has nothing to do: the loop above is the player, and WAIT only needs something to +; have HAPPENED. A handler still has to exist, because an interrupt with nothing installed to +; catch it is a fault. +; +; Nothing reads the status port here, and that is not an oversight. Taking the interrupt is +; what brings the line down. A program that POLLED the timer instead would have to read 0x50, +; because looking at it is the only thing that answers a tick nobody was interrupted by. +tick: RETI #Data @@ -200,85 +215,85 @@ frame: ; ---- Notes and how long they last ---- ; -; Pairs: a MIDI note, then a count of frames. 60 is middle C and every 12 is an octave. A zero +; Pairs: a MIDI note, then a count of ticks. 60 is middle C and every 12 is an octave. A zero ; note ends it, which is why there are no rests in here - a rest would want a duration with no ; note, and this table has no way to say that. Adding one is a byte of flag or a note number ; nothing plays, and this program did not need it. Tune: - 0d60 0d15 ; C - 0d64 0d15 ; E - 0d67 0d15 ; G - 0d72 0d30 ; C, an octave up, held twice as long - 0d71 0d15 ; B - 0d67 0d15 ; G - 0d64 0d15 ; E - 0d60 0d45 ; and home + 0d60 0d2 ; C + 0d64 0d2 ; E + 0d67 0d2 ; G + 0d72 0d4 ; C, an octave up, held twice as long + 0d71 0d2 ; B + 0d67 0d2 ; G + 0d64 0d2 ; E + 0d60 0d6 ; and home 0x00 Theme: - 0x30 0d15 ; C - 0x35 0d15 ; F - 0x3C 0d15 ; C+ - 0x40 0d30 ; E+ - 0x48 0d30 ; C++ - 0x45 0d30 ; A+ - 0x47 0d30 ; B+ - 0x43 0d45 ; G+ + 0x30 0d2 ; C + 0x35 0d2 ; F + 0x3C 0d2 ; C+ + 0x40 0d4 ; E+ + 0x48 0d4 ; C++ + 0x45 0d4 ; A+ + 0x47 0d4 ; B+ + 0x43 0d6 ; G+ ; repeat four times. - 0x2A 0d7 ; Gs - 0x33 0d7 ; Ef - 0x3C 0d7 ; C+ + 0x2A 0d1 ; Gs + 0x33 0d1 ; Ef + 0x3C 0d1 ; C+ ; - 0x2A 0d7 ; Gs - 0x33 0d7 ; Ef - 0x3C 0d7 ; C+ + 0x2A 0d1 ; Gs + 0x33 0d1 ; Ef + 0x3C 0d1 ; C+ ; - 0x2A 0d7 ; Gs - 0x33 0d7 ; Ef - 0x3C 0d7 ; C+ + 0x2A 0d1 ; Gs + 0x33 0d1 ; Ef + 0x3C 0d1 ; C+ ; - 0x2A 0d7 ; Gs - 0x33 0d7 ; Ef - 0x3C 0d7 ; C+ + 0x2A 0d1 ; Gs + 0x33 0d1 ; Ef + 0x3C 0d1 ; C+ ; next chord - 0x2E 0d7 ; Bf - 0x35 0d7 ; F - 0x3E 0d7 ; D+ + 0x2E 0d1 ; Bf + 0x35 0d1 ; F + 0x3E 0d1 ; D+ ; next chord - 0x2E 0d7 ; Bf - 0x35 0d7 ; F - 0x3E 0d7 ; D+ + 0x2E 0d1 ; Bf + 0x35 0d1 ; F + 0x3E 0d1 ; D+ ; ; next chord - 0x2E 0d7 ; Bf - 0x35 0d7 ; F - 0x3E 0d7 ; D+ + 0x2E 0d1 ; Bf + 0x35 0d1 ; F + 0x3E 0d1 ; D+ ; ; next chord - 0x2E 0d7 ; Bf - 0x35 0d7 ; F - 0x3E 0d7 ; D+ + 0x2E 0d1 ; Bf + 0x35 0d1 ; F + 0x3E 0d1 ; D+ ; Finally on the C major - 0x30 0d7 ; C - 0x37 0d7 ; G - 0x40 0d7 ; E+ + 0x30 0d1 ; C + 0x37 0d1 ; G + 0x40 0d1 ; E+ ; - 0x30 0d7 ; C - 0x37 0d7 ; G - 0x40 0d7 ; E+ + 0x30 0d1 ; C + 0x37 0d1 ; G + 0x40 0d1 ; E+ ; - 0x30 0d7 ; C - 0x37 0d7 ; G - 0x40 0d7 ; E+ + 0x30 0d1 ; C + 0x37 0d1 ; G + 0x40 0d1 ; E+ ; - 0x30 0d7 ; C - 0x37 0d7 ; G - 0x40 0d7 ; E+ + 0x30 0d1 ; C + 0x37 0d1 ; G + 0x40 0d1 ; E+ ; - 0x18 0d60 ; C bass + 0x18 0d8 ; C bass 0x00 #Vectors Boot start - Device 0x30 frame + Device 0x50 tick diff --git a/Tests/expected/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out index 09f5559..f1d45e8 100644 --- a/Tests/expected/cosmosCrossDisk.out +++ b/Tests/expected/cosmosCrossDisk.out @@ -31,7 +31,7 @@ Crash.sbx 632 vars.script 50 blocks.script 343 loops.script 272 -tune.sbx 306 +tune.sbx 318 notes.txt 21 Apps