Creating ZX SOUND

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

Previous topic - Next topic

Baggey

WOW, Just had a listen  :o

How have you arrived at 750,000 is there a mathimatical explanation.

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!

Midimaster

#61
If you want to write code it is always a good way not to write the complete code idea and then start testing. Better is to work step by step down into the problem and test each step before diving deeper into the final code.

In your case this means first to understand the DATA[] field and write a BlitzMax Code which  produces the song as expected. Then you know, what the goal is. And you can verify, that the DATA[] field really contains good datas. Here I recognized that your example ("Jig") is valid. In this step I did not define BYTE variables, but INTEGERs.

The Data[] field of "Danube" has 286 Byte which means 95 tones + one STOP command. Each of this tone make a variable C count down to 0. Depending on the tone C varies between 50-80 representing the length of the tone. Inside each of this 50-80 loops there is another inner loop, where B runs from 255 downto 0. In total this can be upto 1.938.000 samples.
95*80*255= 1.938.000

to investigate the total number of samples you let the code run without doing anything with audio, but only count the calls of the OUT-function. In my test code with B=max 150 the result was 736.543. It is always a good idea to insert a lot of PRINT command, so you can follow, what happens and what is the state of all this loops.

Already at this moment I recognized that Scaremongers code was infinite and never reached the song end. Defining IY as Byte allows not a song length>255.

Now, when you know that you will need 736.543 samples you create a Byte Array that will be big enough to contain all these loops. During testing it is never a good idea to create an array of 736.543 bytes if you will need this number. Think big! Take 750.000 (or 2.000.000!!). Later you can state it more precisely.

The target is always not to produce additional bugs, because of beeing too stingy.

If you have been able to get running your problem in a more tolerant "surrounding", you can now dive deeper and modify your code towards the real target. But you will see, that these steps are now very easy and fast to reach. One of this steps is to check whether all variables can be changed to BYTE. Next step can be to simulate this 16bit registers. and so on...

f.e. the step to use Chunks instead of one big TAudioSample needed only 5 min after knowing that the prior code was already working. At the end you will code faster if you divide your problem in more little stages.





...back from Egypt

Scaremonger

@Midimaster: Nice one. I like the approach to build up the sound and then play it in chunks.

Baggey

#63
Quote from: Midimaster on February 18, 2021, 09:40:38

The next step would be now to cut into single TAudioSample chunks of 100msecs. It is reacting faster but you will get more artifacts:
Code (BlitzMax) Select

...
'workaround: now you can set B back to  255 (or remove this code line)
B=255
Repeat ' until B=0 (at 37642)
OUT_CHUNKS(254,A) '37624 OUT (254),A
...

Function OUT_CHUNKS(Port%, Value%)
Const SAMPLE_RATE%=44100
Global NextSample:TAudioSample, PlayTime%
If Counter=0
Print "Sample created"
NextSample = CreateAudioSample(4410, SAMPLE_RATE, SF_MONO8 )
EndIf

Select Value & 8
Case 0
NextSample.Samples[Counter]=50
Case 8
NextSample.Samples[Counter]=200
End Select
Counter=Counter + 1
If counter=4408
NextSample.Samples[4408]=0
NextSample.Samples[4409]=0
Local Audio:TSound = LoadSound( NextSample )
Repeat
Delay 1
Until PlayTime<MilliSecs()
Print "play TSound"
PlayTime=MilliSecs()+100
PlaySound Audio
Counter=0
EndIf
End Function



WOW! We are really getting there  8)

Haven't had enough time to review everything! But had a good day coding and Playing with your routines. The closest ive got is, to using your OUT_CHUNKS Code successfully. Within my Emulator "SpecBlitz". Thanks to MIDI MASTER  ;D

Love the idea of the Sound Chip Type. But the Scretchy sound of Manic Miner just isnt there thou. Ive played with some off the values and got Bassier sounds and Higher Pitched sounds as well. the saw wave example is an excellent twist to the Zx Spectrum. It's almost like using Band Pass filters. Not sure how to alter the Sound Chip type to achieve the scretchy Sound of Manic Miner Thou.

So ive created a mini ZX Emulator to use your OUT_CHUNKS routine. This Routine is Directly Runable In BlitzMax 1.5 and here it is :-

Code (Blitzmax) Select
' ManicMiner Player Using BlitzMax 1.5

SuperStrict

Graphics 800,600

Global RunSpeed:Int=16 ' Using Blitzmax 1.5 Gives roughly a 50Hz Frame Delay!

' Registers 16 Bit
Global IY:Short, BC:Short, DE:Short, HL:Short

' Registers 8 Bit
Global A:Byte, B:Byte, C:Byte, D:Byte, E:Byte, H:Byte, L:Byte

' Control Registers
Global TCycles:Int
Global fZERO:Byte
Global ENTER:Byte=0
Global Counter:Int

' Music Data
Global MusicData:Int[] = [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]
Print
Print "Length of MusicData = "+(Len MusicData)

Init()

Function MainLoop()
    Local starttime:Int = MilliSecs()
   
    While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)
       
Run()
        Local endtime:Int = MilliSecs()
        Local diff:Int = endtime - starttime
       
        Local pausedelay:Int = RunSPEED ' About 50Hz ie one TV frame

        If pausedelay > 0 Then
            Delay(pausedelay)
        Else
            pausedelay = 0
        End If
        starttime = endtime+pausedelay
    Wend
End Function

Function Call_37596:Byte()

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

' LD A,(IY+0) '  Get next Byte of Tune Data from 33902
A=MusicData[IY]  ; TCycles:+19
' CP 255 '  Has the tune finished?
If (A-255)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7
' RET Z         ' Return if ZERO flag is Set
If fZERO=1 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If
' LD C,A ' Copy the first byte of MusicData for this note (which determines the duration) into C
C=A ; BC=(B Shl 8)+C ; TCycles:+4
' LD B,0 ' Load B with 0, which will be used as a delay counter in the note-producing loop
B=0 ; BC=(B Shl 8)+C ; TCycles:+7
' XOR A          ' XOR A  Equivalent to LOAD A with 0 ( Incerting a delay of 4 TCycles )
A=(A ~ A) ; TCycles:+4
' LD D,(IY+1) ' Get second byte of MusicData for this note
D=MusicData[IY+1] ; DE=(D Shl 8)+E ; TCycles:+19
' LD A,D ' Load A with D
A=D ; TCycles:+4
'
' FIRST CALL
'
' CALL 37675 ' Update on screen piano Key
TCycles:+17 ' 17 Clock Cycles for the call
' Code there is irelevant, but time must br acounted for!
' LD (HL),80   ' Set the Atribute colour of piano key 80 (INK 0: PAPER 2: BRIGHT 1)
TCycles:+10  ' 10 Clock Cycles for the LD(HL),40
' LD E,(IY+2) ' Get Third byte of MusicData for this note
E=MusicData[IY+2] ; D=(D Shl 8)+E ; TCycles:+19
' LD A,E   ' Load A with E
A=E ; TCycles:+4
'
' SECOND CALL
'
' CALL 37675 ' Note A is returned with the value for the OUT(254),A! Also Update's on screen piano Key
A=Call_37675() ' A IS RETURNED ALTERD CRUCIAL FOR THE VALUE OF A!
TCycles:+17 ' 17 Clock Cycles for the call
' Code there is irelevant, but time must br acounted for!
' LD (HL),40
TCycles:+10  ' 10 Clock Cycles for the LD(HL),40
Repeat ' C LOOP until C=0
' Part of the DJNZ
Repeat ' B LOOP until B=0
'For Local DJNZ:Int=B To 0 Step -1 ' until B=0
'Print "B="+B
' OUT (254),A ' Turn Piezo on or off
OUT_CHUNKS(254,A) ; TCycles:+11
' DEC D ' Decrease D by One
D:-1 ; DE=(D Shl 8)+E ; TCycles:+4
If D=0 Then fZERO=1 Else fZERO=0 ' If D=0 then set Zero flag
' JR NZ,37634
If fZERO=1 Then
' LD D,(IY+1)
D = MusicData[IY+1] ; DE=(D Shl 8)+E ; TCycles:+19
' XOR 24
A = (A ~ 24)
TCycles:+7 ' Condition not met
Else
TCycles:+12 ' Condition met
End If
' DEC E
E:-1 ; DE=(D Shl 8)+E ; TCycles:+4
If E=0 Then fZERO=1 Else fZERO=0 ' If E=0 then set Zero flag
' JR NZ,37642
If fZERO=1 Then
' LD E,(IY+1)
E = MusicData[IY+2] ; TCycles:+19
' XOR 24
A = (A ~ 24)
TCycles:+7 ' Condition not met
Else
TCycles:+12 ' Condition met
End If
' DJNZ
'DisJump=(twosum[PC1]+2) ; B:-1 ; BC=(B Shl 8)+C
If B<>0 Then 
TCycles:+13 ' Condition met
Else
TCycles:+8 ' Condition not met
End If
B:-1 ; BC=(B Shl 8)+C
'
Until (B=0) ' B=0
' DEC C ' Decrease C by one
C:-1 ; BC=(B Shl 8)+C ; TCycles:+4
If C=0 Then fZERO=1 Else fZERO=0 ' If E=0 then set Zero flag
Until (fZERO=1)
' Check KEYBOARD and JOYSTICK
CALL_37687() ; TCycles:+17 ' Check wether Enter or Fire is being pressed Code ignored but timing needed!
' RET NZ          ' Return if ZERO flag is ReSet, if it is
If fZERO=0 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If
' Pick up Keys AGAIN! This time we are Painting the keys WHITE Updating them
' Code is irrelevant but the timming is!
' LD A,(IY+1) '  Get 2nd Byte of Tune Data from 33902
A=MusicData[IY+1]  ; TCycles:+19
' CALL 37675 ' Note A is returned with the value for the OUT(254),A! Also Update's on screen piano Key
A=Call_37675() ' A IS RETURNED ALTERD CRUCIAL FOR THE VALUE OF A!
TCycles:+17 ' 17 Clock Cycles for the call
' Code there is irelevant, but time must be acounted for!
' LD (HL),56
TCycles:+10  ' 10 Clock Cycles for the LD(HL),40. Paints Piano key WHITE
' LD A,(IY+2) '  Get 3rd Byte of Tune Data from 33902
A=MusicData[IY+2]  ; TCycles:+19
' CALL 37675 ' Note A is returned with the value for the OUT(254),A! Also Update's on screen piano Key
A=Call_37675() ' A IS RETURNED ALTERD CRUCIAL FOR THE VALUE OF A!
TCycles:+17 ' 17 Clock Cycles for the call
' Code there is irelevant, but time must be acounted for!
' LD (HL),56
TCycles:+10  ' 10 Clock Cycles for the LD(HL),40
' INC IY ' Increase IY by one
IY:+1 ; TCycles:+10
' INC IY ' Increase IY by one
IY:+1 ; TCycles:+10
' INC IY ' Increase IY by one
IY:+1 ; TCycles:+10
' JR 37596
TCycles:+12
Wend
End Function

' Check Wether ENTER Or FIRE is being pressed
Function Call_37687:Byte()
Print "Checking Keyboard"
' LD A,(33881)
A=0 ; TCycles:+13 ' Load A with Peek(33881). This Value will be 0 for this Purpose
' OR A ' Is Joystick Connected
A=(A | A)
'Print "A is "+A ; Repeat Until KeyDown(Key_SPACE)
If A=0 Then fZERO=1 Else fZERO=0 ; TCycles:+4
'Print "GOT HERE!" ' For Testing Key Press FLAG Loop!
' JR Z,37698 ' Jump Forwrad if not
If fZERO=0 Then
' IN A,(31) ' Kempston Joystick PORT
A=0 ; TCycles:+11 ' Assume FIRE is not being pressed, So we PASS back a 0!
' BIT 4,A ' Was FIRE pressed?
Local Ans:Byte
Ans=(16 & A) ' Test Bit 4 ie, 2^4=16
If Ans=0 Then fZERO=1 Else fZERO=0 ; TCycles:+8
' RET NZ ' Return the ZERO FLAG if FIRE Pressed, Which it won't be
If fZERO=1 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If
End If
' Print "GOT HERE!" ' For Testing Key Press FLAG Loop!
' LD BC,49140 ' Load BC ready to Read the Key Buffer for Keys_H_to_ENT
BC=49150 ; TCycles:+10
' Print "GOT HERE!" ' For Testing Key Press FLAG Loop!
' IN A,(C)
If KeyDown(Key_ENTER) Then
A=254 ; ENTER=1
'Print "A is "+A
'Print "Key_ENTER" ; Repeat Until KeyDown(Key_SPACE)
Else
A=255 ; ENTER=0
'Print "A is "+A
'Print "Key_ENTER" ; Repeat Until KeyDown(Key_SPACE)
End If
TCycles:+11 ' if ENTER then A=254 else A=255
' AND 1
A=(A & 1)
If A=0 Then fZERO=1 Else fZERO=0
TCycles:+7
' CP 1 '  Has ENTER been pressed?
If (A-1)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7
' RET
TCycles:+10
End Function

' Update Keyboard Piano key and Value of A
Function Call_37675:Byte()
' SUB 8
A=A-8 ; TCycles:+7
Local TempCARRY:Byte
' RRCA
TempCARRY=(A & 1) <> 0
If TempCARRY=0 Then A=(A Shr 1) Else A=((A Shr 1) | 128)
TCycles:+4
' RRCA
TempCARRY=(A & 1) <> 0
If TempCARRY=0 Then A=(A Shr 1) Else A=((A Shr 1) | 128)
TCycles:+4
' RRCA
TempCARRY:Byte=(A & 1) <> 0
If TempCARRY=0 Then A=(A Shr 1) Else A=((A Shr 1) | 128)
TCycles:+4
' CPL
A=(A ~ 255) ; TCycles:+4
' OR 224
A=(A | 224) ; TCycles:+7
' LD L,A
L=A ; TCycles:+4
' LD H,89
H=89 ; TCycles:+7
' RET
TCycles:+10 ; Return A
End Function

Function OUT_CHUNKS(Port%, Value%)

        Const SAMPLE_RATE%=44100
        Global NextSample:TAudioSample, PlayTime:Int
        If Counter=0
                Print "Sample created"
                NextSample = CreateAudioSample(4410, SAMPLE_RATE, SF_MONO8 )
Print
Print "IY="+(RSet(IY, 3).Replace(" ", "0"))+" ... MusicData[IY]="+(RSet$(musicDATA[IY+2],3).Replace(" ","0"))+" ... A Register="+(RSet$(A,3).Replace(" ","0"))+" ... BIT4="+((A & 16) <> 0)
Print "OUT_CHUNKS CALLED!"
        EndIf

        Select Value & 8
                Case 0
                        NextSample.Samples[Counter]=50
                Case 8
                        NextSample.Samples[Counter]=200
        End Select
        Counter=Counter + 1
        If counter=4408
                NextSample.Samples[4408]=0     
                NextSample.Samples[4409]=0     
                Local Audio:TSound = LoadSound( NextSample )
                Repeat
                  ' Delay 1
                Until PlayTime<MilliSecs()
                Print "play TSound"
                PlayTime=MilliSecs()+100
                PlaySound Audio
                Counter=0
        EndIf
End Function

Function Init()
' Reset Registers
IY=0 ; A=0 ; B=0 ; C=0
' START SpecBlitz
MainLoop()
End Function

Function run()
Call_37596()
If fZERO=1 And Enter=0 Then
Print
Print "TUNE FINISHED"
Print "IY="+IY+" ... MusicData[IY]="+musicDATA[IY]
End
End If
'Print Key_Enter
If ENTER=1 Then Print "ENTER was Pressed!" ; End
EndFunction


If you read through my mini Emulator. There is a Delay routine that slows down BlitzMax 1.5 to the ZX Spectrum speed. Ive put in all the Tstate time Cycles of each Instruction. And just can't see away through the tree's  ??? On how to integrate this into your counter timer loop within OUT_CHUNKS. Anyone?

Conclusion
I really dont have a clue on how to use the TSound functions to create what i need hence the start of "Creating ZX SOUND" thread :-[

The code as is need's to be left intact! And only the "OUT_CHUNKS" routine using the Global TCycles somehow or the "Sound chip type" Routine to reference time within the Emulator. Using the Tcycles as a reference count. Being able todo this should allow other games or programs to use the "OUT_CHUNKS" function for sound as well. Rather than being unique to Manic Miner it's self.

Is there away the sound can be sped up or slowed down only using a GLOBAL DELAY? I see you used a DELAY instruction in there?

Side Tracking a bit BlitzMax 1.5 Really Dosen't explain how to use the TSOUND functions Clearly in Help >:( Any pointers on the Syntax to make the Penny drop would be much appriciated!

However, enjoy the Mini Zx Emulator and OUT_CHUNKS Playing the BLUE DANUBE from Manic Miner.

Thankyou to all who are helping and giving idea's.

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!

Midimaster

HOW TCYCLES IN OUT()?
I would think the OUT command in Z80 is no software function, which would consum time. It is the last step to hardware and only the call needs the 11 TCycles you already added.

MY DELAY
The circumstance that OUT is now a function is only "Windows"-related to simulate the hardware. You should calculte 0msec for it. The reason why I added a DELAY is also only windowsrelated. We have to care about that the next PlaySound exactly starts 100msec after the former PlaySound had started.
If your TCycles-timer ever will work perfect my DELAY will have no longer any effect. (but keep activated the code line for "security reasons".)


WOULD OUT_CHUNK WORK FOR EVERY Z80-CODE?
Yes! My OUT_CHUNK (please rename it as "OUT") is a possible way to simulate the hardware speaker with a BlitzMax TSound. You can "feed" it with any Value and it will always do what the Z80-speaker would have done. The only restrictions are...

1. The sound always starts with an latency of 100msec
2. Sounds shorter than 100msec are not played
3. The last 100msec of a sequence will be cutted away.

You can optimize this behavoir (2. and 3.), when you use a TimerEvent() based function (f.e. every 10msec) which periodically will have a look on the TAudioSample, whether it now should be played now. In this method the OUT()-function would only fill the TAudioSample but is not longer responisble for playing it.

TUNING THE SONG AND RISING SPEED
you can adjust the tuning of the music by changing Const SAMPLE_RATE towards lower values. F.e. 22.000 makes it sounding deeper. You can speed up the song by Changing the line B=255. f.e. B=125 plays it with double speed. If you need to do this inside the OUT, you could try to "forget" OUT calls. f.e.
Code (BlitzMax) Select
Function OUT(port%, value%)
     Global SwapIt=1-SwapIt
     If SwapIt=1 Return
     ....

This would make the song playing 2 times faster

A HINT FOR TCYLCES
You are doing right in collecting the TCYCLES for simulating the processor speed of the Z80. you add them, and when they reached a crititical sum (f.e. 3500) you could pause the BlitzMax-Code for 1msec with a DELAY 1. This way you would not need a high resolution timer and the speed would be controlled 1.000 times a second.

Code (BlitzMax) Select
Function SlowDown()
     Global Realtime:INT
     If RealTime=0
          RealTime=Millisecs()
     Endif
     If TCycles>3500
          TCyles=TCyles-3500
          RealTime=RealTime+1
     Endif
     While RealTime>Millisecs()
          Delay 1
     wend
End Function


This would interupt the simultator without slowing down the whole windows (and the other processes)
...back from Egypt

Baggey

#65
Oh my god,

I feel like a "kid in a sweet shop" or in a "toy shop" not sure what translate's best but Kudos! Does that translate as well!

Daz ist gut!

I have four hours of play tomorrow until next weekend  :'(

For anyone who may be interseted this has been a long journey of passion! interest and tinasity if that's a word :-X

As i explained earlier in another thread writing an emulator from scratch takes a long time. If i ever get it working fully i promise to mention the people on the way "Kevin Picone" who helped me to get started. Midi Master and Scaremonger

A thread for Sound help!
https://www.underwaredesign.com/forums/index.php?topic=3946.0

My OLD Emulator which aint so OLD now! ;)
https://www.underwaredesign.com/forums/index.php?topic=3890.0

Again i think this deserves:-



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!

Baggey

Im Interested in trying this with OpenAL but can't seem to get anything to work ive installed the .ExE filen for openAL.
But get this error anyone?

Building untitled1
Compiling:untitled1.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 3331 bytes.
Linking:untitled1.exe
Executing:untitled1.exe
No access to OpenAL capture Device !
Process complete


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

You should keep an eye on this link.

https://www.syntaxbomb.com/index.php/topic,8377.0.html

@Midimaster is creating a pretty awesome ringbuffer.


Baggey

Finally somemore time to tinker.

So, Thought id have ago at doing JetSet Willy Theme tune. In the Z80 Emulation format.
This runs in BlitzMax 1.5

' JetSet Willy Player Using BlitzMax 1.5

SuperStrict

Graphics 800,600

Global RunSpeed:Int=16 ' Using Blitzmax 1.5 Gives roughly a 50Hz Frame Delay!

' Registers 16 Bit
Global IY:Short, BC:Short, DE:Short, HL:Short, AF:Short

' Registers 8 Bit
Global A:Byte, B:Byte, C:Byte, D:Byte, E:Byte, H:Byte, L:Byte, F:Byte

' Registers 16 Bit
Global AF_:Short

' Alternate 8 Bit
Global A_:Byte, F_:Byte

' Control Registers
Global TCycles:Int
Global fZERO:Byte
Global fCARRY:Byte=0
Global ENTER:Byte=0
Global Counter:Int

' Temp Values
Global TempA:Short
Global Ans:Short
Global sum:Byte
Global Copy_of_bit7:Byte

' Music Data
Global MusicData:Int[] = [81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,76,60,51,76,60,51,76,57,45,76,57,45,81,64,45,81,60,51,81,60,54,91,64,54,102,81,60,81,60,51,81,60,51,40,60,40,40,54,45,81,54,45,81,54,45,40,54,40,40,60,51,81,60,51,38,60,79,45,76,60,45,40,64,51,81,64,51,45,64,54,32,64,54,61,121,61,255]
Print
Print "Length of MusicData = "+(Len MusicData)

Init()

Function MainLoop()
    Local starttime:Int = MilliSecs()
   
    While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)
       
Run()
        Local endtime:Int = MilliSecs()
        Local diff:Int = endtime - starttime
       
        Local pausedelay:Int = RunSPEED ' About 50Hz ie one TV frame

        If pausedelay > 0 Then
            Delay(pausedelay)
        Else
            pausedelay = 0
        End If
        starttime = endtime+pausedelay
    Wend
End Function

Function Call_38562:Byte()

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

' LD A,(HL) '  Get next Byte of Tune Data from 34299. In this case 0
A=MusicData[HL]  ; TCycles:+19

' CP 255 '  Has the tune finished?
sum=A-255
Print "A-255="+sum
If (A-255)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7

' RET Z         ' Return if ZERO flag is Set
If fZERO=1 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If

' LD BC,100 ' Load BC with 100. B=0 (short note Counter). C=100 (Short Note Counter)
B=0 ; C=100 ; BC=(B Shl 8)+C ; TCycles:+10

' XOR A          ' XOR A  Equivalent to LOAD A with 0 ( Incerting a delay of 4 TCycles )
' Border Colour and Speaker state
A=(A ~ A) ; TCycles:+4

' LD E,(HL) ' Load E with byte of MusicData During the short note loop
E=MusicData[HL] ; DE=(D Shl 8)+E ; TCycles:+19

' LD D,E ' Load D with (Pitch delay counter)
D=E ; DE=(D Shl 8)+E ; TCycles:+4
'
Repeat ' C is OUTER LOOP Until C=0
' Part of the DJNZ
'
Repeat ' B is iner LOOP until B=0
'For Local DJNZ:Int=B To 0 Step -1 ' until B=0
'Print "B="+B

' OUT (254),A ' Produce a short note ( 0.003s ) Whose pitch is determined by E
OUT_254(254,A) ; TCycles:+11

' DEC D ' Decrease D by One
D:-1 ; DE=(D Shl 8)+E ; TCycles:+4
If D=0 Then fZERO=1 Else fZERO=0 ' If D=0 then set Zero flag

' JR NZ,38580
If fZERO=1 Then
' LD D,E
D = E ; DE=(D Shl 8)+E ; TCycles:+19
' XOR 24
A = (A ~ 24)
TCycles:+7 ' Condition not met
Else
TCycles:+12 ' Condition met
End If

' DJNZ
'DisJump=(twosum[PC1]+2) ; B:-1 ; BC=(B Shl 8)+C
If B<>0 Then 
TCycles:+13 ' Condition met
Else
TCycles:+8 ' Condition not met
End If
B:-1 ; BC=(B Shl 8)+C
'
Until (B=0) ' B=0

' EX AF,AF_ ' Exchange AF with AF_ Alternate registers
TempA=A ; A=TempA ; TCycles:+7

' LD A,C   ' Load A with C
A=C ; TCycles:+4

' CP 50 '  Is the short note counter down to 50 yet?
If (A-50)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7

' JR NZ,38590 ' Jump if not otherwise
If fZERO=1 Then
' RL E ' Double value in E
Copy_of_bit7=(E & 128) <> 0
Ans=(E Shl 1)
Ans = Ans & 255
'
'fSIGN=(Ans & 128) <> 0
fZERO = (Ans=0)
'fFIVE = (Ans & 32) <> 0
'fHALFCARRY = 0
'fTHREE = (Ans & 8) <> 0
'fPARITY=parity[Ans]
'fADDSUB = 0
fCARRY = Copy_of_bit7
'SetFLAGS()
E=Ans

' XOR 24
A = (A ~ 24)
TCycles:+7 ' Condition not met
Else
TCycles:+12 ' Condition met
End If

' EX AF,AF_ ' Exchange AF with AF_ Alternate registers
TempA=A ; A=TempA ; TCycles:+7


' DEC C ' Decrease C by one
C:-1 ; BC=(B Shl 8)+C ; TCycles:+4
If C=0 Then fZERO=1 Else fZERO=0 ' If E=0 then set Zero flag


' JR NZ ' Jump back until we've finished playing 50 notes
'
Until (C=0) ' C=0

' Check KEYBOARD and JOYSTICK
CALL_38601() ; TCycles:+17 ' Check wether Enter or Fire is being pressed Code ignored but timing needed!

' RET NZ          ' Return if ZERO flag is ReSet, if it is
If fZERO=0 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If

' INC HL ' Increase HL by one
HL:+1 ; TCycles:+10

' JR 38562
TCycles:+12
Wend
End Function

' Check Wether ENTER Or FIRE is being pressed
Function Call_38601:Byte()
Print "Checking Keyboard"
' LD A,(34254)
A=0 ; TCycles:+13 ' Load A with Peek(34254). This Value will be 0 for this Purpose
' OR A ' Is Joystick Connected
A=(A | A)
'Print "A is "+A ; Repeat Until KeyDown(Key_SPACE)
If A=0 Then fZERO=1 Else fZERO=0 ; TCycles:+4
'Print "GOT HERE!" ' For Testing Key Press FLAG Loop!
' JR Z,38612 ' Jump Forwrad if not
If fZERO=0 Then
' IN A,(31) ' Kempston Joystick PORT
A=0 ; TCycles:+11 ' Assume FIRE is not being pressed, So we PASS back a 0!
' BIT 4,A ' Was FIRE pressed?
Local Ans:Byte
Ans=(16 & A) ' Test Bit 4 ie, 2^4=16
If Ans=0 Then fZERO=1 Else fZERO=0 ; TCycles:+8
' RET NZ ' Return the ZERO FLAG if FIRE Pressed, Which it won't be
If fZERO=1 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If
End If
' Print "GOT HERE!" ' For Testing Key Press FLAG Loop!
' LD BC,45054 ' Load BC ready to Read the Key Buffer for Keys_H_to_ENT and 6-7-8-9-0
BC=45054 ; TCycles:+10
' Print "GOT HERE!" ' For Testing Key Press FLAG Loop!
' IN A,(C)
If KeyDown(Key_ENTER) Then
A=254 ; ENTER=1
'Print "A is "+A
'Print "Key_ENTER" ; Repeat Until KeyDown(Key_SPACE)
Else
A=255 ; ENTER=0
'Print "A is "+A
'Print "Key_ENTER" ; Repeat Until KeyDown(Key_SPACE)
End If
TCycles:+11 ' if ENTER then A=254 else A=255
' AND 1
A=(A & 1)
If A=0 Then fZERO=1 Else fZERO=0
TCycles:+7
' CP 1 '  Has ENTER been pressed?
If (A-1)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7
' RET
TCycles:+10
End Function

Function OUT_254(Port:Byte, Value:Byte)
' The three lines of code speed the song up ie Twice the speed!
'Global SwapIt:Byte
      'SwapIt=1-SwapIt
      'If SwapIt=1 Return
'
        Const SAMPLE_RATE:Short=44100
        Global NextSample:TAudioSample, PlayTime:Int
        If Counter=0
                Print "Sample created"
                NextSample = CreateAudioSample(4410, SAMPLE_RATE, SF_MONO8 )
Print
Print "HL="+(RSet(HL, 3).Replace(" ", "0"))+" ... MusicData[HL]="+(RSet$(musicDATA[HL],3).Replace(" ","0"))+" ... A Register="+(RSet$(A,3).Replace(" ","0"))+" ... BIT4="+((A & 16) <> 0)
Print "OUT_254 Called!"
        EndIf

        Select Value & 8
                Case 0
                        NextSample.Samples[Counter]=50
                Case 8
                        NextSample.Samples[Counter]=200
        End Select
        Counter=Counter + 1
        If counter=4408
                NextSample.Samples[4408]=0     
                'NextSample.Samples[4409]=0     
                Local Audio:TSound = LoadSound( NextSample )
                Repeat
                  ' Delay 1
                Until PlayTime<MilliSecs()
                Print "play TSound"
                PlayTime=MilliSecs()+100
                PlaySound Audio
                Counter=0
        EndIf
End Function

Function Init()
' Reset Registers
IY=0 ; A=0 ; B=0 ; C=0 ; D=0 ; E=0 ; F=0 ; TempA=0
' START SpecBlitz
MainLoop()
End Function

Function run()
Call_38562()
If fZERO=1 And Enter=0 Then
Print
Print "TUNE FINISHED"
Print "HL="+HL+" ... MusicData[HL]="+musicDATA[HL]
End
End If
'Print Key_Enter
If ENTER=1 Then Print "ENTER was Pressed!" ; End
EndFunction


Something wrong here, in the loops as i think each note is being played 3 times. Anyway you can here the Midnight Sonata in there. But something's not quite write?

Been staring at this most of the day and can't see my mistake.

Kind Rgards 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!

Midimaster

#69
Did you check the quality of the DATA[]-field with my StandAlone-Player from post#56?

How does it sound for you here?


And... Is it the correct number of values?

The size needs to be (3*x+1), so 100 would fit perfect, but there are 101 elements. The player crashs.

Do you have a link, how the music should sound? What is "midnight sonata"? Beethoven?



...back from Egypt

Baggey

#70
POST HAS BEEN UPDATED

Will play somemore latter on. Ill check post 56. It's Beethoven i believe.

Ive now checked post #56 and it sounds nothing like it should.

The machine code routine that plays the tune in Manic Miner is slightly different to the machine code that plays the tune in Jet Set Willy. Out 254 would do the same thing to the speaker though!?

I think Manic Miner use's 3 bytes to make the tune and Jet Set willy uses 2 bytes (2*X+1). I think it's all to do with timing in the Loops themselves. Looking forward to experimenting with the Ring buffer wrapper. Hope it works with BlitzMax 1.5 and is easy to install.  :D

Latter on today ill check ive ripped the music data properly!

For now it should sound like this. https://youtu.be/l0lHXNqXFvg

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!

Baggey

#71
JetSet Willy Tune Data actually in memory:-

So ripped data from Memory in my SpecBlitz Emulator so data is spot on!  ;D

There are 99 Bytes of Data. With the last byte being 255 terminator for the loop. If we count the Zero we have 100.

Will have a look at the Z80 Machine code emulation as i think ive got a loop wrong!

Building Spectrum emulator
Compiling:ZXio.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 11441 bytes.
Compiling:Z80.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 277502 bytes.
Compiling:video.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 5916 bytes.
Compiling:videoMemory.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 9359 bytes.
Compiling:OO.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 143179 bytes.
Compiling:CB.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 107819 bytes.
Compiling:ED.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 39351 bytes.
Compiling:DD.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 46811 bytes.
Compiling:FD.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 55618 bytes.
Compiling:DDCB.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 115762 bytes.
Compiling:FDCB.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 159967 bytes.
Compiling:Spectrum emulator.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 61637 bytes.
Linking:Spectrum emulator.exe
Executing:Spectrum emulator.exe
start ADDRESS
PEEK(34299)=81
PEEK(34300)=60
PEEK(34301)=51
PEEK(34302)=81
PEEK(34303)=60
PEEK(34304)=51
PEEK(34305)=81
PEEK(34306)=60
PEEK(34307)=51
PEEK(34308)=81
PEEK(34309)=60
PEEK(34310)=51
PEEK(34311)=81
PEEK(34312)=60
PEEK(34313)=51
PEEK(34314)=81
PEEK(34315)=60
PEEK(34316)=51
PEEK(34317)=81
PEEK(34318)=60
PEEK(34319)=51
PEEK(34320)=81
PEEK(34321)=60
PEEK(34322)=51
PEEK(34323)=76
PEEK(34324)=60
PEEK(34325)=51
PEEK(34326)=76
PEEK(34327)=60
PEEK(34328)=51
PEEK(34329)=76
PEEK(34330)=57
PEEK(34331)=45
PEEK(34332)=76
PEEK(34333)=57
PEEK(34334)=45
PEEK(34335)=81
PEEK(34336)=64
PEEK(34337)=45
PEEK(34338)=81
PEEK(34339)=60
PEEK(34340)=51
PEEK(34341)=81
PEEK(34342)=60
PEEK(34343)=54
PEEK(34344)=91
PEEK(34345)=64
PEEK(34346)=54
PEEK(34347)=102
PEEK(34348)=81
PEEK(34349)=60
PEEK(34350)=81
PEEK(34351)=60
PEEK(34352)=51
PEEK(34353)=81
PEEK(34354)=60
PEEK(34355)=51
PEEK(34356)=40
PEEK(34357)=60
PEEK(34358)=40
PEEK(34359)=40
PEEK(34360)=54
PEEK(34361)=45
PEEK(34362)=81
PEEK(34363)=54
PEEK(34364)=45
PEEK(34365)=81
PEEK(34366)=54
PEEK(34367)=45
PEEK(34368)=40
PEEK(34369)=54
PEEK(34370)=40
PEEK(34371)=40
PEEK(34372)=60
PEEK(34373)=51
PEEK(34374)=81
PEEK(34375)=60
PEEK(34376)=51
PEEK(34377)=38
PEEK(34378)=60
PEEK(34379)=45
PEEK(34380)=76
PEEK(34381)=60
PEEK(34382)=45
PEEK(34383)=40
PEEK(34384)=64
PEEK(34385)=51
PEEK(34386)=81
PEEK(34387)=64
PEEK(34388)=51
PEEK(34389)=45
PEEK(34390)=64
PEEK(34391)=54
PEEK(34392)=32
PEEK(34393)=64
PEEK(34394)=54
PEEK(34395)=61
PEEK(34396)=121
PEEK(34397)=61
PEEK(34398)=255
end ADDRESS


And as a Cut and Paste string :-

Building Spectrum emulator
Compiling:ZXio.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 11441 bytes.
Compiling:Z80.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 277089 bytes.
Compiling:video.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 5916 bytes.
Compiling:videoMemory.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 9359 bytes.
Compiling:OO.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 143179 bytes.
Compiling:CB.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 107819 bytes.
Compiling:ED.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 39351 bytes.
Compiling:DD.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 46811 bytes.
Compiling:FD.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 55618 bytes.
Compiling:DDCB.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 115762 bytes.
Compiling:FDCB.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
4 passes, 159967 bytes.
Compiling:Spectrum emulator.bmx
flat assembler  version 1.69.14  (1572863 kilobytes memory)
3 passes, 61637 bytes.
Linking:Spectrum emulator.exe
Executing:Spectrum emulator.exe
Start ADDRESS 34299
81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,76,60,51,76,60,51,76,57,45,76,57,45,81,64,45,81,60,51,81,60,54,91,64,54,102,81,60,81,60,51,81,60,51,40,60,40,40,54,45,81,54,45,81,54,45,40,54,40,40,60,51,81,60,51,38,60,45,76,60,45,40,64,51,81,64,51,45,64,54,32,64,54,61,121,61,255,
End ADDRESS 34398


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!

Midimaster

The audio sample compared with the datas I would guess that each byte is a new sound and the lenght of all is the same (fix).
...back from Egypt

Baggey

#73
Quote from: Midimaster on April 03, 2021, 11:29:06
The audio sample compared with the datas I would guess that each byte is a new sound and the lenght of all is the same (fix).

Done it! the Out Function is fine. There where three errors in my Emulation of the Z80 code.

Sometimes it pays to have a break and walk away, and then come back to the code. As i found some silly errors quite quickly after a good walk and some fresh air  ^-^

id not emulated the RL E properly which just need doubling and the Exchange EX AF,AF_ was getting the same value and there was an extra XOR 24 ie on off of the speaker that wasn't needed  ;D in one off the loops.

I hope the wrapper will be able to play faster sounds than 100 mSecs as some sounds arnt being played quick enough i think. ie not heard.
Ive noticed with this tune a slight ringing? At the end of every note.

So here is executable code to play JetSet Willy. Midnight sonata by Beethoven :-


' JetSet Willy Player Using BlitzMax 1.5

SuperStrict

Graphics 800,600

Global RunSpeed:Int=16 ' Using Blitzmax 1.5 Gives roughly a 50Hz Frame Delay!

' Registers 16 Bit
Global BC:Short, DE:Short, HL:Short

' Registers 8 Bit
Global A:Byte, B:Byte, C:Byte, D:Byte, E:Byte, H:Byte, L:Byte

' Alternate 8 Bit
Global A_:Byte

' Control Registers
Global TCycles:Int
Global fZERO:Byte
Global ENTER:Byte=0
Global Counter:Int

' Temp Values
Global TempA:Byte
Global Ans:Short

' Music Data
Global MusicData:Int[] = [81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,76,60,51,76,60,51,76,57,45,76,57,45,81,64,45,81,60,51,81,60,54,91,64,54,102,81,60,81,60,51,81,60,51,40,60,40,40,54,45,81,54,45,81,54,45,40,54,40,40,60,51,81,60,51,38,60,45,76,60,45,40,64,51,81,64,51,45,64,54,32,64,54,61,121,61,255]
Print
Print "Length of MusicData = "+(Len MusicData)

Init()

Function MainLoop()
    Local starttime:Int = MilliSecs()
   
    While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)
       
Run()
        Local endtime:Int = MilliSecs()
        Local diff:Int = endtime - starttime
       
        Local pausedelay:Int = RunSPEED ' About 50Hz ie one TV frame

        If pausedelay > 0 Then
            Delay(pausedelay)
        Else
            pausedelay = 0
        End If
        starttime = endtime+pausedelay
    Wend
End Function

Function Call_38562:Byte()

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

' LD A,(HL) '  Get next Byte of Tune Data from 34299. In this case 0
A=MusicData[HL]  ; TCycles:+19

' CP 255 '  Has the tune finished?
If (A-255)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7

' RET Z         ' Return if ZERO flag is Set
If fZERO=1 Then
TCycles:+11 ; Return fZERO ' Exit Function End of Tune
Else
TCycles:+5
End If

' LD BC,100 ' Load BC with 100. B=0 (short note Counter). C=100 (Short Note Counter)
B=0 ; C=100 ; BC=(B Shl 8)+C ; TCycles:+10

' XOR A         ' XOR A  Equivalent to LOAD A with 0 ( Incerting a delay of 4 TCycles )
A=(A ~ A) ; TCycles:+4 ' Border Colour and Speaker state

' LD E,(HL) ' Load E with byte of MusicData During the short note loop
E=MusicData[HL] ; DE=(D Shl 8)+E ; TCycles:+19

' LD D,E ' Load D with (Pitch delay counter)
D=E ; DE=(D Shl 8)+E ; TCycles:+4
'
Repeat ' C is OUTER LOOP Until C=0
' Part of the DJNZ
'
Repeat ' B is iner LOOP until B=0
'Print "B="+B
'
' OUT (254),A ' Produce a short note ( 0.003s ) Whose pitch is determined by E
OUT_254(254,A) ; TCycles:+11

' DEC D ' Decrease D by One
D:-1 ; DE=(D Shl 8)+E ; TCycles:+4
If D=0 Then fZERO=1 Else fZERO=0 ' If D=0 then set Zero flag

' JR NZ,38580
If fZERO=1 Then
' LD D,E
D=E ; DE=(D Shl 8)+E ; TCycles:+19
' XOR 24
A=(A ~ 24)
TCycles:+7 ' Condition not met
Else
TCycles:+12 ' Condition met
End If

' DJNZ
If B<>0 Then 
TCycles:+13 ' Condition met
Else
TCycles:+8 ' Condition not met
End If
B:-1 ; BC=(B Shl 8)+C
'
Until (B=0) ' B=0

' EX AF,AF_ ' Exchange AF with AF_ Alternate registers
'Print "A Before exchange ="+A
TempA=A_ ; A_=A ; A=TempA ; TCycles:+7 ' For this emulation focus on A
'Print "A after exchange ="+A

' LD A,C   ' Load A with C
A=C ; TCycles:+4

' CP 50 '  Is the short note counter down to 50 yet?
If (A-50)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7

' JR NZ,38590 ' Jump if not otherwise
If fZERO=1 Then
' RL E ' Double value in E ' Rotating left is same as * by 2
Print "E="+E
E:+E ; DE=(D Shl 8)+E
Print "E Doubled ="+E
TCycles:+7 ' Condition not met
Else
TCycles:+12 ' Condition met
End If

' EX AF,AF_ ' Exchange AF with AF_ Alternate registers
TempA=A_ ; A_=A ; A=TempA ; TCycles:+7

' DEC C ' Decrease C by one
C:-1 ; BC=(B Shl 8)+C ; TCycles:+4
If C=0 Then fZERO=1 Else fZERO=0 ' If C=0 then set Zero flag

' JR NZ ' Jump back until we've finished playing 50 notes
'
Until (C=0) ' C=0

' Check KEYBOARD and JOYSTICK
CALL_38601() ; TCycles:+17 ' Check wether Enter or Fire is being pressed Code ignored but timing needed!

' RET NZ     ' Return if ZERO flag is ReSet, if it is
If fZERO=0 Then
TCycles:+11 ; Return fZERO ' Enter or fire was pressed
Else
TCycles:+5
End If

' INC HL ' Increase HL by one
HL:+1 ; TCycles:+10

' JR 38562
TCycles:+12
Wend
End Function

' Check Wether ENTER Or FIRE is being pressed
Function Call_38601:Byte()
Print "Checking Keyboard"
' LD A,(34254)
A=0 ; TCycles:+13 ' Load A with Peek(34254). This Value will be 0 for this Purpose

' OR A ' Is Joystick Connected
A=(A | A)
'Print "A is "+A ; Repeat Until KeyDown(Key_SPACE)
If A=0 Then fZERO=1 Else fZERO=0 ; TCycles:+4
'Print "GOT HERE!" ' For Testing Key Press FLAG Loop!

' JR Z,38612 ' Jump Forwrad if not
If fZERO=0 Then
' IN A,(31) ' Kempston Joystick PORT
A=0 ; TCycles:+11 ' Assume FIRE is not being pressed, So we PASS back a 0!
' BIT 4,A ' Was FIRE pressed?
Local Ans:Byte
Ans=(16 & A) ' Test Bit 4 ie, 2^4=16
If Ans=0 Then fZERO=1 Else fZERO=0 ; TCycles:+8
' RET NZ ' Return the ZERO FLAG if FIRE Pressed, Which it won't be
If fZERO=1 Then
TCycles:+11 ; Return fZERO
Else
TCycles:+5
End If
End If
' Print "GOT HERE!" ' For Testing Key Press FLAG Loop!

' LD BC,45054 ' Load BC ready to Read the Key Buffer for Keys_H_to_ENT and 6-7-8-9-0
BC=45054 ; TCycles:+10
' Print "GOT HERE!" ' For Testing Key Press FLAG Loop!

' IN A,(C)
If KeyDown(Key_ENTER) Then
A=254 ; ENTER=1
'Print "A is "+A
'Print "Key_ENTER" ; Repeat Until KeyDown(Key_SPACE)
Else
A=255 ; ENTER=0
'Print "A is "+A
'Print "Key_ENTER" ; Repeat Until KeyDown(Key_SPACE)
End If
TCycles:+11 ' if ENTER then A=254 else A=255

' AND 1
A=(A & 1)
If A=0 Then fZERO=1 Else fZERO=0
TCycles:+7

' CP 1 '  Has ENTER been pressed?
If (A-1)=0 Then fZERO=1 Else fZERO=0 ; TCycles:+7

' RET
TCycles:+10
End Function

Function OUT_254(Port:Byte, Value:Byte)
' The three lines of code speed the song up ie Twice the speed!
'Global SwapIt:Byte
    'SwapIt=1-SwapIt
    'If SwapIt=1 Return
'
        Const SAMPLE_RATE:Short=44100
        Global NextSample:TAudioSample, PlayTime:Int
        If Counter=0
                Print "Sample created"
                NextSample = CreateAudioSample(4410, SAMPLE_RATE, SF_MONO8 )
Print
Print "HL="+(RSet(HL, 3).Replace(" ", "0"))+" ... MusicData[HL]="+(RSet$(musicDATA[HL],3).Replace(" ","0"))+" ... A Register="+(RSet$(A,3).Replace(" ","0"))+" ... BIT4="+((A & 16) <> 0)
Print "OUT_254 Called!"
        EndIf

        Select Value & 8
                Case 0
                        NextSample.Samples[Counter]=50
                Case 8
                        NextSample.Samples[Counter]=200
        End Select
        Counter=Counter + 1
        If counter=4408
                NextSample.Samples[4408]=0     
                'NextSample.Samples[4409]=0     
                Local Audio:TSound = LoadSound( NextSample )
                Repeat
                  ' Delay 1
                Until PlayTime<MilliSecs()
                Print "play TSound"
                PlayTime=MilliSecs()+100
                PlaySound Audio
                Counter=0
        EndIf
End Function

Function Init()
' Reset Registers
A=0 ; B=0 ; C=0 ; D=0 ; E=0 ; A_=0 ; TempA=0
' START SpecBlitz
MainLoop()
End Function

Function run()
Call_38562()
If fZERO=1 And Enter=0 Then
Print
Print "TUNE FINISHED"
Print "HL="+HL+" ... MusicData[HL]="+musicDATA[HL]
End
End If
'Print Key_Enter
If ENTER=1 Then Print "ENTER was Pressed!" ; End
EndFunction


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!

Midimaster

#74
you can simply speed up if you reduce the value of C here:
' LD BC,100 ' Load BC with 100. B=0 (short note Counter). C=100 (Short Note Counter)
B=0 ; C=30 ; BC=(B Shl 8)+C ; TCycles:+10


I changed C=100 to C=30

Try also 10 or 5 or 3 to see, how special effects can be made....
did you already succeed in motor sound, etc...?

by the way...

here is the update OnlyPlayer-Version for testing 1Byte-Song-Data:
Code (BlitzMax) Select
    SuperStrict
     
    Graphics 800,600
   
Global Data:Int[] = [81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,81,60,51,76,60,51,76,60,51,76,57,45,76,57,45,81,64,45,81,60,51,81,60,54,91,64,54,102,81,60,81,60,51,81,60,51,40,60,40,40,54,45,81,54,45,81,54,45,40,54,40,40,60,51,81,60,51,38,60,45,76,60,45,40,64,51,81,64,51,45,64,54,32,64,54,61,121,61,255]

    Global NextTime%, ReadPos%
     
     
    Repeat
            Wait
            If Data[ReadPos]=255 End
    Until AppTerminate()
     
     
    Function Wait()
            If NextTime<MilliSecs()
                    Print ReadPos + " " + data[ReadPos] + " " + data[ReadPos+1] + " " + data[ReadPos+2]
Local duration%=100
                    NextTime=MilliSecs()+Duration
                   MakeSound Duration, Data[ReadPos], 0
     
                    ReadPos=ReadPos+1
            EndIf 
    End Function
     
     
    Function MakeSound(Duration%,PulseA%, PulseB%)
            Const SAMPLERATE% = 22000'Hz
            Local SampleLen%, Half%
            Local SampleA:TAudioSample, SampleB:TAudioSample, AudioA:TSound, AudioB:TSound
           
            SampleLen = SAMPLERATE*Duration/1000
            If PulseA>0   
                            SampleA = CreateAudioSample( SampleLen, SAMPLERATE, SF_MONO8 )
                            Half = PulseA/2
                            For Local n:Int=0 Until SampleLen-1
                                    If (n Mod PulseA) < half
                                            SampleA.samples[n] = 200
                                    Else
                                            SampleA.samples[n] = 55
                                    End If
                            Next
                            AudioA = LoadSound( SampleA )
            EndIf
            If PulseB>0           
                            SampleB = CreateAudioSample( SampleLen, SAMPLERATE, SF_MONO8 )         
                            Half = PulseB/2
                            For Local n:Int=0 Until SampleLen-1
                                    If (n Mod PulseB)<half
                                            SampleB.samples[n] = 200
                                    Else
                                            SampleB.samples[n] = 55
                                    End If
                            Next           
                            AudioB = LoadSound( SampleB )
            EndIf
            If PulseA>0   
                    PlaySound AudioA
            EndIf
            If PulseB>0
                    PlaySound AudioB
            EndIf
    End Function
...back from Egypt