37596 LD A,(IY+0) Pick up the next byte of tune data from the table at 33902 "THE START OF OUR DATA STRING"37599 CP 255 Has the tune finished?37601 RET Z Return (with the zero flag set) if so37602 LD C,A Copy the first byte of data for this note (which determines the duration) to C37603 LD B,0 Initialise B, which will be used as a delay counter in the note-producing loop37605 XOR A Set A=0 (for no apparent reasaon)37606 LD D,(IY+1) Pick up the second byte of data for this note37609 LD A,D Copy it to A37610 CALL 37675 Calculate the attribute file address for the corresponding piano key37613 LD (HL),80 Set the attribute byte for the piano key to 80 (INK 0: PAPER 2: BRIGHT 1)37615 LD E,(IY+2) Pick up the third byte of data for this note37618 LD A,E Copy it to A37619 CALL 37675 Calculate the attribute file address for the corresponding piano key37622 LD (HL),40 Set the attribute byte for the piano key to 40 (INK 0: PAPER 5: BRIGHT 0)37624 OUT (254),A Produce a sound based on the frequency parameters in the second and third bytes of data for this note (copied into D and E)37626 DEC D37627 JR NZ,3763437629 LD D,(IY+1)37632 XOR 2437634 DEC E37635 JR NZ,3764237637 LD E,(IY+2)37640 XOR 2437642 DJNZ 3762437644 DEC C37645 JR NZ,3762437647 CALL 37687 Check whether ENTER or the fire button is being pressed37650 RET NZ Return (with the zero flag reset) if it is37651 LD A,(IY+1) Pick up the second byte of data for this note37654 CALL 37675 Calculate the attribute file address for the corresponding piano key37657 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0)37659 LD A,(IY+2) Pick up the third byte of data for this note37662 CALL 37675 Calculate the attribute file address for the corresponding piano key37665 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0)37667 INC IY Move IY along to the data for the next note in the tune37669 INC IY37671 INC IY37673 JR 37596 Jump back to play the next note
80,128,129,80,102,103,80,86,87,50,86,87,50,171,203,50,43,51,50,43,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,96,86,50,171,192,50,43,48,50,43,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,192,50,38,48,50,38,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,203,50,38,51,50,38,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,171,50,32,43,50,32,43,50,128,171,50,43,51,50,43,51,50,128,171,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,152,50,32,38,50,32,38,50,128,152,50,38,48,50,38,48,50,0,0,114,115,50,114,115,50,96,97,50,76,77,50,76,153,50,76,77,50,76,77,50,76,153,50,91,92,50,86,87,50,51,205,50,51,52,50,51,52,50,51,205,50,64,65,50,102,103,100,102,103,50,114,115,100,76,77,50,86,87,50,128,203,25,128,0,25,128,129,50,128,203,255
Using the Z80 manual you could get the TState timings for each instruction. Knowing the 3.5Mhz that the Z80 is running at you can work out the on/off rate of the piezo speaker for each frequency.
The value 24 in 8bit binary in 00011000 with the 5th bit (0001) being the speaker and the 4th bit (1000) for the Mic. The side effect is that if you output to both of these at the same time then it increased the volume of the output.
[quoteBits xxxxx111 appear to control the border color too.
I could have a look at writing a small routine in Blitmax. Just to spit out the value of A for a give value of E if that helps?
SuperStrict' Manic Miner Audio Output' 16 Bit RegsitersGlobal BC16:ShortGlobal DE16:ShortGlobal HL16:ShortGlobal BC:Byte Ptr = Varptr BC16Global DE:Byte Ptr = Varptr DE16Global HL:Byte Ptr = Varptr HL16Const B:Byte=1, C:Byte=0, D:Byte=1, E:Byte=0, H:Byte=1, L:Byte=0' 8 Bit RegistersGlobal A:ByteGlobal IY:Byte, IX:Byte' FLAGSGlobal F:Byte[8]Const CF:Byte=0Const ZR:Byte=1' Music DataGlobal data:Byte[] = [80,128,129,80,102,103,80,86,87,50,86,87,50,171,203,50,43,51,50,43,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,96,86,50,171,192,50,43,48,50,43,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,192,50,38,48,50,38,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,203,50,38,51,50,38,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,171,50,32,43,50,32,43,50,128,171,50,43,51,50,43,51,50,128,171,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,152,50,32,38,50,32,38,50,128,152,50,38,48,50,38,48,50,0,0,114,115,50,114,115,50,96,97,50,76,77,50,76,153,50,76,77,50,76,77,50,76,153,50,91,92,50,86,87,50,51,205,50,51,52,50,51,52,50,51,205,50,64,65,50,102,103,100,102,103,50,114,115,100,76,77,50,86,87,50,128,203,25,128,0,25,128,129,50,128,203,255]' Direct Code ConversionFunction CALL_37596:Int() While True A = data[IY] '37596 LD A,(IY+0) Pick up the next byte of tune data from the table at 33902 If A=255 '37599 CP 255 Has the tune finished? Return True '37601 RET Z Return (with the zero flag set) if so End If BC[C] = A '37602 LD C,A Copy the first byte of data for this note (which determines the duration) to C BC[B] = 0 '37603 LD B,0 Initialise B, which will be used as a delay counter in the note-producing loop A = 0 '37605 XOR A Set A=0 (for no apparent reasaon) DE[D] = data[IY+1] '37606 LD D,(IY+1) Pick up the second byte of data for this note '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = DE[D] '37609 LD A,D Copy it to A 'CALL_37675() '37610 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,80) '37613 LD (HL),80 Set the attribute byte for the piano key to 80 (INK 0: PAPER 2: BRIGHT 1) DE[E] = data[IY+2] '37615 LD E,(IY+2) Pick up the third byte of data for this note '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = DE[E] '37618 LD A,E Copy it to A 'CALL_37675() '37619 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,40) '37622 LD (HL),40 Set the attribute byte for the piano key to 40 (INK 0: PAPER 5: BRIGHT 0)'Print( "A ---"+Right(Hex(A),2)+" BC-"+Right(Hex(BC16),4)+" DE-"+Right(Hex(DE16),4)+" HL-"+Right(Hex(HL16),4) ) Repeat ' until C=0 (at 37645) Repeat ' until B=0 (at 37642) _OUT(254,A) '37624 OUT (254),A Produce a sound based on the frequency parameters in the second and third bytes of data for this note (copied into D and E) DE[D] :- 1 '37626 DEC D If DE[D]=0 '37627 JR NZ,37634 DE[D] = data[IY+1] '37629 LD D,(IY+1) A = A~24 '37632 XOR 24 End If DE[E] :- 1 '37634 DEC E If DE[E]=0 '37635 JR NZ,37642 DE[E] = data[IY+2] '37637 LD E,(IY+2) A = A~24 '37640 XOR 24 End If'Print( "A ---"+Right(Hex(A),2)+" BC-"+Right(Hex(BC16),4)+" DE-"+Right(Hex(DE16),4)+" HL-"+Right(Hex(HL16),4) ) BC[B] :- 1 '37642 DJNZ 37624 Until BC[B]=0 ' "" "" BC[C] :- 1 '37644 DEC C Until C=0 '37645 JR NZ,37624 '##### KEYBOARD INTERACTION 'If CALL_37687() '37647 CALL 37687 Check whether ENTER or the fire button is being pressed ' Return False '37650 RET NZ Return (with the zero flag reset) if it is 'End If '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = data[IY+1] '37651 LD A,(IY+1) Pick up the second byte of data for this note 'CALL_37675() '37654 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,56) '37657 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0) '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = data[IY+2] '37659 LD A,(IY+2) Pick up the third byte of data for this note 'CALL_37675() '37662 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,56) '37665 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0) IY :+ 3 '37667 INC IY Move IY along to the data for the next note in the tune '37669 INC IY '37671 INC IY Wend '37673 JR 37596 Jump back to play the next noteEnd Function' Direct Code Conversion' Calculates which on-screen piano key will be shown pressed' We dont need this, so it has been commented out'Function CALL_37675()' A :- 8 '37675 SUB 8 Compute the piano key index (K) based on the frequency parameter (F), and store it in bits 0-4 of A: K=31-INT((F-8)/8)' _RRCA() '37677 RRCA' _RRCA() '37678 RRCA' _RRCA() '37679 RRCA' A = ~A '37680 CPL ' A :| 224 '37681 OR 224 A=224+K; this is the LSB' HL[L] = A '37683 LD L,A Set HL to the attribute file address for the piano key' HL[H] = 89 '37684 LD H,89' Return '37686 RET'End Function' Keyboard input' Not required, so has been commented out'Function CALL_37687:Int()' Return False'End Function' Z80 Mnumonic Rotate Bits Right with Carry'Function _RRCA()' Local x:Byte = A & $01' A = ( A Shr 1 | ( A & $01 ) Shl 7 )' F[CF] = x'End Function' Z80 MnumonicFunction _OUT( port:Byte, value:Byte) If port=254 ' bitmap of value is xxxSMBBB ' S=Sound M=Microphone B=Border Print( value ) End IfEnd Function' Play MusicIY = 0 ' Set pointer to start of musicCALL_37596()
37609 LD A,D Copy it to A37610 CALL 37675 Calculate the attribute file address for the corresponding piano key37613 LD (HL),80 Set the attribute byte for the piano key to 80 (INK 0: PAPER 2: BRIGHT 1)37618 LD A,E Copy it to A37619 CALL 37675 Calculate the attribute file address for the corresponding piano key37622 LD (HL),40 Set the attribute byte for the piano key to 40 (INK 0: PAPER 5: BRIGHT 0)37651 LD A,(IY+1) Pick up the second byte of data for this note37654 CALL 37675 Calculate the attribute file address for the corresponding piano key37657 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0)37659 LD A,(IY+2) Pick up the third byte of data for this note37662 CALL 37675 Calculate the attribute file address for the corresponding piano key37665 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0)
37647 CALL 37687 Check whether ENTER or the fire button is being pressed37650 RET NZ Return (with the zero flag reset) if it is
To save bending your brain too much on the math there is a super handy z80 extension for vscode (if you use it) that will calculate the tstates for you...
TSTATES POINTER 19 37596 FN37596 LD A,(IY+0) PLAY MUSIC7 37599 CP 255 11 37601 RET Z 4 37602 LD C,A 7 37603 LD B,0 4 37605 XOR A 19 37606 LD D,(IY+1) 4 37609 LD A,D 17 37610 CALL 37675 10 37613 LD (HL),80 19 37615 LD E,(IY+2) 4 37618 LD A,E 17 37619 CALL 37675 10 37622 LD (HL),40 11 37624 LOOP OUT (254),A 4 37626 DEC D 12 37627 JR NZ,37634 19 37629 LD D,(IY+1) 7 37632 XOR 24 4 37634 DEC E 12 37635 JR NZ,37642 19 37637 LD E,(IY+2) 7 37640 XOR 24 13 37642 DJNZ 37624 4 37644 DEC C 12 37645 JR NZ,37624 17 37647 CALL 37687 11 37650 RET NZ 19 37651 LD A,(IY+1) 17 37654 CALL 37675 10 37657 LD (HL),56 19 37659 LD A,(IY+2) 17 37662 CALL 37675 10 37665 LD (HL),56 10 37667 INC IY 10 37669 INC IY 10 37671 INC IY 12 37673 JR 37596 7 37675 FN37675 SUB 8 IDENTIFY KEY FROM NOTE4 37677 RRCA 4 37678 RRCA 4 37679 RRCA 4 37680 CPL 7 37681 OR 224 4 37683 LD L,A 7 37684 LD H,89 10 37686 RET 13 37687 FN37687 LD A,(33881) KEYBOARD INPUT7 37690 OR A 12 37691 JR Z,37698 13 37693 IN A,(31) 8 37695 BIT 4,A 11 37697 RET NZ 10 37698 LD BC,49150 12 37701 IN A,(C) 7 37703 AND 1 7 37705 CP 1 10 37707 RET
SuperStrict' Music Data (Blue Danube from Manic Miner)Global data:Byte[] = [80,128,129,80,102,103,80,86,87,50,86,87,50,171,203,50,43,51,50,43,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,96,86,50,171,192,50,43,48,50,43,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,192,50,38,48,50,38,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,203,50,38,51,50,38,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,171,50,32,43,50,32,43,50,128,171,50,43,51,50,43,51,50,128,171,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,152,50,32,38,50,32,38,50,128,152,50,38,48,50,38,48,50,0,0,114,115,50,114,115,50,96,97,50,76,77,50,76,153,50,76,77,50,76,77,50,76,153,50,91,92,50,86,87,50,51,205,50,51,52,50,51,52,50,51,205,50,64,65,50,102,103,100,102,103,50,114,115,100,76,77,50,86,87,50,128,203,25,128,0,25,128,129,50,128,203,255]Print( "DATA LENGTH: "+Len(data) )Local cursor:Int = 0Local duration:IntLocal note:Byte[2]Repeat If data[cursor]=255 cursor=0 ' Reached the end? - Start again ' Read music data duration = data[cursor] note[0] = data[cursor+1] note[1] = data[cursor+2] Print( cursor+") "+duration+", "+note[0]+", "+note[1] ) cursor :+ 3Until False
204) 50, 38, 48207) 50, 38, 48210) 50, 0, 0213) 114, 115, 50 <- This is Wrong216) 114, 115, 50219) 96, 97, 50222) 76, 77, 50225) 76, 153, 50228) 76, 77, 50
I would say the data has been copied wrong. Take a look at the original music data and you can see the culprit at address 34115.Music data:https://skoolkit.ca/disassemblies/manic_miner/asm/33902.html
Global data:Byte[] = [80,128,129,80,102,103,80,86,87,50,86,87,50,171,203,50,43,51,50,43,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,96,86,50,171,192,50,43,48,50,43,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,192,50,38,48,50,38,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,203,50,38,51,50,38,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,171,50,32,43,50,32,43,50,128,171,50,43,51,50,43,51,50,128,171,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,152,50,32,38,50,32,38,50,128,152,50,38,48,50,38,48,50,0,0,50,114,115,50,114,115,50,96,97,50,76,77,50,76,153,50,76,77,50,76,77,50,76,153,50,91,92,50,86,87,50,51,205,50,51,52,50,51,52,50,51,205,50,64,65,50,102,103,100,102,103,50,114,115,100,76,77,50,86,87,50,128,203,25,128,0,25,128,129,50,128,203,255]