Creating ZX SOUND

Started by Baggey, February 01, 2021, 08:17:48

Previous topic - Next topic

col

'Sounds' interesting - pardon the pun ;D

Does this snippet of code help you at all?https://skoolkit.ca/disassemblies/manic_miner/asm/37596.html
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Baggey

#16
Ok. Very interesting site. Manic Miner Disassembly! Thankyou Col


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 so
37602 LD C,A         Copy the first byte of data for this note (which determines the duration) to C
37603 LD B,0         Initialise B, which will be used as a delay counter in the note-producing loop
37605 XOR A         Set A=0 (for no apparent reasaon)
37606 LD D,(IY+1) Pick up the second byte of data for this note
37609 LD A,D         Copy it to A
37610 CALL 37675 Calculate the attribute file address for the corresponding piano key
37613 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 note
37618 LD A,E         Copy it to A
37619 CALL 37675 Calculate the attribute file address for the corresponding piano key
37622 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 D
37627 JR NZ,37634
37629 LD D,(IY+1)
37632 XOR 24
37634 DEC E
37635 JR NZ,37642
37637 LD E,(IY+2)
37640 XOR 24
37642 DJNZ 37624
37644 DEC C
37645 JR NZ,37624
37647 CALL 37687 Check whether ENTER or the fire button is being pressed
37650 RET NZ         Return (with the zero flag reset) if it is
37651 LD A,(IY+1) Pick up the second byte of data for this note
37654 CALL 37675 Calculate the attribute file address for the corresponding piano key
37657 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 note
37662 CALL 37675 Calculate the attribute file address for the corresponding piano key
37665 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 tune
37669 INC IY
37671 INC IY
37673 JR 37596         Jump back to play the next note


"The Blue Danube"
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

Ive read through the Music playing code. And in a nut shell I think, from the Speakers point of view. We are literaly pulsing on and off. Within four loops.

Just looking at the first three bytes that are picked up.

There Are 4 Loops in play.

In a nut shell C=80 first byte and Pitch/Duration ie an outer loop executed 80 times.

B=0 The second loop which will always be executed 256 times and always starts at zero. Next inner loop of which the 2nd and 3rd Bytes are counted down.

The Third Loop which is D=128 (on first run) and the second byte is another timed loop within this.
The Fourth Loop which is E=129 (on first run) and the third byte.

Now the Third byte effects the initial condition of the speaker being on. When it goes through the Call 37675 it will come back with A=240 (on first Run).

This Long sentence may not be right! But I think this could give an out of sync delay of the (on/off). Depending on how different D and E are on First run? This would mean putting the third byte of every three bytes in the call and calculating the A value. On each start of the Note. But i think it could be ignored and assumed to be on unless its a silent note or pause. The human Ear might not hear this mistake as it would be so fast!? If the Third does need to be calculated its Subtracted by 8 then Rotated three bits to the right 3 times looping around on its self. Then Complementing the 1's and 0's. Then Oring with 224. So it might seem it does.

So Bit 5 of A is a 1 so when the OUT(254),240 is used the Piezo is turned on as bit 5 is a 1. So speaker is now on.

Now, D=128 and E=129 they are both decreased by one. When D=0 it will become D=128 again and the speaker turned off! and if E=0 it will become E=129 again and speaker turned off also.  NOTE the XOR 24 does the Speaker and the Mic bits not sure why?

The D and E loop are played exacatly 256 times or until B=0. Which will loop for 256 times again playing D and E. Then Fist Outer Loop decreases C=80 by 1 and does it all over again until C=0. This is the Pitch Loop.

Then we pick up the next three bytes in the TUNE and do the exact same thing all over again untill we hit 255 the tune terminator or start playing whole tune again. 

One iteration of this should produce the first note.  :o

Hope ive not made any errors and this makes sence. These loops and Z80 instructions can be done in Blitzmax.
But how the loops relate to timming of Playing through sound channels at sample's per second etc. God only knows  ;D

Kind Regards Baggey


Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Scaremonger

@col : Thanks, that is so useful.

@baggy : Your run through looks good. Can't wait to get some free time to work on it.

col

If you wanted a truly authentic reproduction of the tune I would think you could do it with some math.

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 Xor 24 is probably to do with a Speccy side effect. As you may (or may not) know the Ear (speaker) and Mic are both accessed through port 254. 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.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Scaremonger


Quote from: col on February 06, 2021, 15:18:03
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.
Thanks; I have already looked up the number of cycles for the OUT instruction on this site but hadn't considered the calling routine itself. @Baggey will probably have a seperate method within his emulator.

Quote from: col on February 06, 2021, 15:18:03
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.

Interesting that the microphone affects the volume.

Bits xxxxx111 appear to control the border color too.



Baggey

#20
Quote from: Scaremonger on February 06, 2021, 16:38:21

[quoteBits xxxxx111 appear to control the border color too.

The Border color is affected by the first 3 bits. The colour of the border is what's on the keys of the spectrum Keyboard. Incidently xxxxx111=7 is WHITE.

Just had a look over at that site. And he or she has written some of the opcodes differently which is interesting. As ive been thinking of doing this with the 6502. Which was in the "BBC_B". As the litreture for the 6502 is Horrendously documented  :-[ There's still alot of Missing opcodes there thou.

I haven't counted all of the Z80 Opcodes In my Emulator. Which i might call "SpecBlitz" or "SpecMax". But there can be upto 1792 instructions  :o feels like im in the region of at least 1300 right now! I think some of these have never been used as there undocumented.

Good luck with producing some sound. I could have a look at writing a small routine in Blitmax. Just to spit out the value of A for a given value of E if that helps?

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Scaremonger

Quote from: Baggey on February 06, 2021, 18:47:38
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?

I have done this tonight using the actual ZXSpectrum code converted in-place:


SuperStrict
' Manic Miner Audio Output

' 16 Bit Regsiters
Global BC16:Short
Global DE16:Short
Global HL16:Short
Global BC:Byte Ptr = Varptr BC16
Global DE:Byte Ptr = Varptr DE16
Global HL:Byte Ptr = Varptr HL16
Const B:Byte=1, C:Byte=0, D:Byte=1, E:Byte=0, H:Byte=1, L:Byte=0

' 8 Bit Registers
Global A:Byte
Global IY:Byte, IX:Byte

' FLAGS
Global F:Byte[8]
Const CF:Byte=0
Const ZR:Byte=1

' Music Data
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]

' Direct Code Conversion
Function 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 note
End 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 Mnumonic
Function _OUT( port:Byte, value:Byte)
If port=254
' bitmap of value is xxxSMBBB
' S=Sound M=Microphone B=Border
Print( value )
End If
End Function

' Play Music
IY = 0 ' Set pointer to start of music
CALL_37596()


Some of the code is not actually needed for the music, for example this piece (and the function it calls) appear to update an onscreen "Piano" to show the keys being played' so you'll find that commented out.

37609 LD A,D         Copy it to A
37610 CALL 37675 Calculate the attribute file address for the corresponding piano key
37613 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 A
37619 CALL 37675 Calculate the attribute file address for the corresponding piano key
37622 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 note
37654 CALL 37675 Calculate the attribute file address for the corresponding piano key
37657 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 note
37662 CALL 37675 Calculate the attribute file address for the corresponding piano key
37665 LD (HL),56         Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0)


The routine that interrupts the music when a key is pressed is also commented out:

37647 CALL 37687 Check whether ENTER or the fire button is being pressed
37650 RET NZ         Return (with the zero flag reset) if it is


Looking through the code in I think I know why there are two values after the duration. The code is attempting to simulate pressing two keys at once. The inner loop repeats 256 times and decreases both of these values (Register D and E), turning off/on the speaker to mimic a frequency... Pretty impressive.

PS. It doesn't play the music yet.

Baggey

#22
Well Impressed!

So you dived straight into the Z80 Opcodes ;D Writing an Emulator is a great way of learning the Z80 Opcodes.

Im currently rewriting my opcodes as functions in the quest for more speed rather than using long SELECT/CASE statements.

So Here are RRCA, DJNZ you can ignore the flags! for just simulating the Music Play.

I see you have already got round The "Jump relative instructions"
NOTE the DJNZ and JRNZ Instructions have two differnt timings on wether a TRUE condition or a FALSE condition are met. Again the timing is so fast this might not be recognized by the human ear thou! Oh and when the DJNZ starts which is initialized by B=0 because it started at ZERO it will count 256 times in the loop. Which will cause a small timing addition to the simulated loop. As there are many of these iterations of the loop. So this maybe needed to be be taken into account in the overall timing.
IY and IX are 16 bit register's but their being peeked for a byte ie, LET E=PEEK (IY+1), so it's looking at the address of (IY+1) seeing what's in that memory location and returning the byte to E. There are many UNDOCUMENTED codes on the Z80 and the IX,IY register's are even split into 8 Bit register's and become IYH, IYL, IXH, IXL But that's something else again ;D

Code (Blitzmax) Select
                     
  Case 15 ' RRCA
TempCARRY=(A & 1) <> 0
A=(A Shr 1)
If TempCARRY=1 Then A=(A | 128)
'
fSIGN = fSIGN ' Not affected
fZERO = fZERO ' Not affected
fFIVE= ((A & 32) <> 0)
fHALFCARRY = 0
fTHREE = ((A & 8) <> 0)
fPARITY = fPARITY ' Not affected
fADDSUB = 0
fCARRY = TempCARRY
SetFLAGS()
PC:+1 ; TCycles:+4
  Case 16 ' DJNZ,d
DisJump=(twosum[PC1]+2) ; B:-1 ; BC=(B Shl 8)+C
If B<>0 Then
  PC:+DisJump ; TCycles:+13
Else
  PC:+2 ; TCycles:+8
End If
  Case 47 ' CPL
A=(A ~ 255)
fSIGN = fSIGN ' Not affected
fZERO = fZERO ' Not affected
fFIVE = ((A & 32) <> 0)
fHALFCARRY = 1
fTHREE = ((A & 8) <> 0)
fPARITY = fPARITY 'Not affected
fADDSUB = 1
fCARRY = fCARRY ' Not affected
SetFLAGS()
        PC:+1 ; TCycles:+4


Here is the code for OR and XOR in Method's which are Function's. Again the flags can be ignored for Music play.

Code (Blitzmax) Select

  Method Or8(InB:Byte)
      ' All Flags affected.
      ' Sign Set if Bit 7 is One
      ' Zero Set if Answer is zero
      ' Halfcarry is Reset
              ' Parity Set if EVEN number of One's
      ' AddSub is Reset
      ' Carry is Reset
      A=(A | InB)
      '
      fSIGN = (A & 128) <> 0
      fZERO = (A = 0)
      fFIVE = (A & 32) <> 0
      fHALFCARRY = 0
      fTHREE = (A & 8) <> 0
      fPARITY = parity[A]
      fADDSUB = 0
      fCARRY = 0
      SetFLAGS()
  End Method

  Method Xor8(InB:Byte)
       ' All Flags affected.
       ' Sign Set if Bit 7 is One
       ' Zero Set if Answer is zero
       ' Halfcarry is Reset
       ' Parity Set if EVEN number of One's
       ' AddSub is Reset
       ' Carry is Reset
       A=(A ~ InB)
       '
       fSIGN = (A & 128) <> 0
       fZERO = (A = 0)
       fFIVE = (A & 32) <> 0
       fHALFCARRY = 0
       fTHREE = (A & 8) <> 0
       fPARITY = parity[A]
       fADDSUB = 0
       fCARRY = 0
       SetFLAGS()
  End Method


With the Out (254),A Instruction. Just for playing sound the first three bits are for the border. Which can be ignored unless you want some sort of visual effect  8)
The Tcycles are how long the instruction takes. Again how the timing relates to the Samples/rate within the Simulation is beyond me. That's why i started the thread to bring Musical life to my ZX Emulator.

I think the two pulsed loop is a way of simulating two channels at once. Because when you listen to the Tune it sounds kinda distorted or same note out of sync.

Also thinking of timming again.
The Check Routine wether ENTER is being pressed this is going to cause a timming delay.
I think as the CPU runs at 3.5Mhz. One TCycle 'time state' is callculated and then if an instruction takes, say 12,7, or 4 etc this can be taken into account as a pause in the loop.
But once worked out it becomes part of the loop permenantly. Maybe getting sound going. "All be it distorted or out of tune!" and then tweeking the loops for instruction timming might be necessary. Again these pause delays will then become permenant.

37647 CALL 37687 Check whether ENTER or the fire button is being pressed
37650 RET NZ         Return (with the zero flag reset) if it is


Thinking again. if the Z80 CPU runs at 3.5Mhz that's 3.5x10'6. This means that 1 Tcycle will take appronimatly 285 nSes that's 285x10'-9. So every instruction in the LOOPS will need this number setup as a CONSTANT and then multiplied by the individual TCycles of each instruction. Therefore this time can then be worked out on how this effects pitch/duration of the note at Samples/second.

For Example, RRCA has 4 Clock Cycles then 4x285x10'-9=1.14uSecs or 1.14x10'-6 in RealTime. So this needs to be taken into account when working out let's say the bandwith of the note to sound in tune. I try to steer away from the MATH but i think this is one's going to need it. Damm those Cobweb's

Hope that sort of makes's sence with the timming of the Z80 code but again how that effects the music it's self?  :-X

I do belive this is going to work.  :o Happy coding. ^-^

Kind Regards Baggey

Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

col

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... It can be found here:
https://github.com/theNestruo/z80-asm-meter-vscode
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Scaremonger

Quote from: col on February 07, 2021, 10:06:56
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...

I've recently started looking at vscode on Linux after finding out that there is a BlitzMax extension in development. I'll take a look at that one.

iWasAdam

Very impressed with how all of this is progressing. Excellent work and something to very proud of - emulating chips ;)

Scaremonger

Just in case anyone is following this and is interested in the TSTATE Cycle data:


TSTATES POINTER
19 37596 FN37596 LD A,(IY+0) PLAY MUSIC
7 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 NOTE
4 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 INPUT
7 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

Scaremonger

#27
I'm not sure if I have found a bug in the original code or what, but the music data doesn't seem to be correct after byte 210.

The total length of the music data without the endstop (255) is 285 bytes. The music data is in triplets but 284 is not equally divisable by 3...

This code should explain what I mean:

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 = 0
Local duration:Int
Local 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 :+ 3
Until False


If you look at the output, you'll see <CURSOR>) <DURATION>, <NOTE-A>, <NOTE-B>. We have already established the first number is the note duration (see below); however if you look at the output after cursor 210 something strange is happening which will mess up the tune.

100 is a Minim (Half Note)
80 is a Dotted Crochet (1/8 + 1/4)
50 is a Crotchet (Quarter note)
25 is a Quaver (Eighth note)


204) 50, 38, 48
207) 50, 38, 48
210) 50, 0, 0
213) 114, 115, 50   <- This is Wrong
216) 114, 115, 50
219) 96, 97, 50
222) 76, 77, 50
225) 76, 153, 50
228) 76, 77, 50

col

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
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Scaremonger

Quote from: col on February 10, 2021, 08:27:49
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

@col: Awesome thanks.

The correct Music array should be:


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]


Si...