Cassette Emulator

Started by Baggey, April 11, 2024, 18:45:53

Previous topic - Next topic

Baggey

Hi Everyone,

Ive designed a Retro Sinclair Cassette Player for my emulator. Another step closer to completion ;D

CassettePLAYER.png

I need some help ideas.

I want to take the cassette out and create a viewport so i can Mask over another picture image. So it looks like the cassette is in side the lid!?

I also want to make the Buttons move up and down or give them a shadow effect when they are clicked with the mouse.

Early days yet but id like some ideas on how to use Mask Blend Alpha etc.. I have no idea on how to use them yet :-[

Finally i want to create an effect of the tape spooling from oneside to the other with rotating cogs. Again i have no idea how todo this yet.

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

#1
I would divide the picture in three layers:

The "background" layer is the tape. It as an AnimatedImage, which can show tape on the left, tape on the right and various intermediate steps. You can simulate "action" by rumbling the x/y position per random. Afterwards you can define several static and moving sequences of that AnimatedImage.

The middle layer is the non changing part of the player. It is a 24bit alpha image with a transparent part, where the cassette window is.

On top of this you put another AnimatedImage where the buttons are, This AnimatedImage contains all possible states of the buttons as a whole.
Save each posssible state combination of the player's button field as one frame.

Here is an example:


AnimRecorder.gif

Code: BASIC
Graphics 500,400
Global Cassette:TImage = LoadAnimImage("RotateCassette.png",154,88,0,2)
Global Player:TImage   = LoadImage ("StillCassette.png")
Global Buttons:TImage  = LoadAnimImage("ButtonCassette.png",175,65,0,2) 


Global State:Int, Frame:Int, Timer:Int
Repeat
	Cls
	State=0
	If MouseDown(1) Then State=1
	If State=1
		If Timer<MilliSecs()
			timer= MilliSecs() +100
			frame=1-frame
		EndIf 
	EndIf 
	DrawText "Press FORWARD BUTTON to animate",30,30
	DrawImage Cassette,130,130,Frame
	DrawImage Player  ,100,100
	DrawImage Buttons ,120,228,State
	Flip 1
Until AppTerminate()

You need this images:
StillCassette.png


RotateCassette.png

ButtonCassette.png


...on the way to China.

Baggey


QuoteI would divide the picture in three layers:

The "background" layer is the tape. It as an AnimatedImage, which can show tape on the left, tape on the right and various intermediate steps. You can simulate "action" by rumbling the x/y position per random. Afterwards you can define several static and moving sequences of that AnimatedImage.

So, This morning i went back through one of Midimasters tutorials and got my Alpha blended casette working.

CassettePLAYER1.pngland.png

and Runable BlitzMaxNG code to use it of course. :)

Code: BASIC
SuperStrict

SetGraphicsDriver(GLMax2DDriver())
Graphics 1200,600

Global BackGrouund:TImage=LoadImage("Land.png",FILTEREDIMAGE)
Global Player:     TImage=LoadImage("CassettePLAYER1.png",FILTEREDIMAGE)

SetBlend Alphablend


While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

	Cls()

	SetAlpha(1)
	DrawImage(BackGrouund,0,0)

	SetAlpha(1)
	DrawImage(Player,MouseX(),MouseY())
	
	Flip(0)

Wend AppTerminate()

Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

#3
Quote from: Midimaster on April 12, 2024, 07:00:05I would divide the picture in three layers:

The "background" layer is the tape. It as an AnimatedImage, which can show tape on the left, tape on the right and various intermediate steps. You can simulate "action" by rumbling the x/y position per random. Afterwards you can define several static and moving sequences of that AnimatedImage.

The middle layer is the non changing part of the player. It is a 24bit alpha image with a transparent part, where the cassette window is.

On top of this you put another AnimatedImage where the buttons are, This AnimatedImage contains all possible states of the buttons as a whole.
Save each posssible state combination of the player's button field as one frame.

Here is an example:


AnimRecorder.gif

Code: BASIC
Graphics 500,400
Global Cassette:TImage = LoadAnimImage("RotateCassette.png",154,88,0,2)
Global Player:TImage   = LoadImage ("StillCassette.png")
Global Buttons:TImage  = LoadAnimImage("ButtonCassette.png",175,65,0,2) 


Global State:Int, Frame:Int, Timer:Int
Repeat
    Cls
    State=0
    If MouseDown(1) Then State=1
    If State=1
        If Timer<MilliSecs()
            timer= MilliSecs() +100
            frame=1-frame
        EndIf 
    EndIf 
    DrawText "Press FORWARD BUTTON to animate",30,30
    DrawImage Cassette,130,130,Frame
    DrawImage Player  ,100,100
    DrawImage Buttons ,120,228,State
    Flip 1
Until AppTerminate()

You need this images:
StillCassette.png


RotateCassette.png

ButtonCassette.png



Awsome. Did you use Pixelformer?

BlitmaxNG really is a good Language. It still amazes me after 3 years of learning my journey has just began. lots to learn 8)

Love the shadow effect of when the buttons are pressed. Im in for a Busy weekend of coding  :-X

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

I have i some more explanation about Toggle switch buttons and their shadows.

This is a AnimImage with 6 Buttons. Each is 66x124 pixel.

If you need neighbour buttons, that can be pressed at the same time you need 4 types

A= normal not pressed button
B= left neighbour of a "double pressed"
C= right neighbour of a "double pressed" 
D= single pressed button

So in the example picture you see (from left to right) the types

A B C A D A

RealButtons.png


The red band at the top is only for showing you where the 66pix width ends.

Colored they could look like this:

ButtonsGilb.png



...on the way to China.

Baggey

#5
So thankyou for the ideas! ;D

You will need the attached files to compile it.

Here is runnable code in BlitzMaxNG for the player so far.

Code: BASIC
SuperStrict

AppTitle="ZX Spectrum Cassette Player"

SetGraphicsDriver(GLMax2DDriver())
Graphics 444,400

Global Cassette:TImage   =LoadAnimImage("RotateCASSETTE.png",114,32,0,2)
Global Player:TImage     =    LoadImage("CassettePLAYER1.png")
Global Buttons:TImage    =LoadAnimImage("CassetteBUTTONS.png",176,62,0,2)
Global JetpacINLAY:TImage=    LoadImage("JetpacINLAY.png")


Global State:Int, Frame:Int, Timer:Int

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

 Cls
 State=0

 If MouseDown(1) Then State=1

 If State=1 Then

 If Timer<MilliSecs() Then
 timer= MilliSecs() +100
 frame=1-frame
 EndIf

 EndIf

 DrawText "Click Left Mouse Button to Animate cogs",30,30

  DrawImage JetPACINLAY,137,134

 DrawImage Cassette,152,156,Frame
 DrawImage Player  ,100,100
 DrawImage Buttons ,120,228,State

 Flip(0)

Wend

CassetteBUTTONS.pngRotateCASSETTE.pngJetpacINLAY.pngCassettePLAYER.png

If anybody fancys doing casette inlay logos they need tobe 143x73 .png

Im trying to put a demo together with the cassette loading in to my Emulator Soon. ::)

For nostalga purposes the player can be played in Realtime and TURBO! 8)

Now i just need to get the tape spooling from left to right with the counter :-\

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

#6
Ive made the Counter numbers and the relevant bits for Tape Spooling.
SpoolBACKGROUND.png
SpoolEDGE.png
SpoolMIDDLE.png
SpoolGAP.png
TapeNUMBERS.png

Oh and finally the tape count reset button TapeCountRESET.png

Im starting to run out of function keys to implement additional features so im now thinking of doing some 8bit logos to click on! ie, to implement other stuff. I dont want windows drop down menus thou ::)

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

So Here's the latest code in BlitzMaxNG to Spool the Tape from oneside to another.

And now on to the counter counting. I need to make the spooling a lot slower? :-X

Code: BASIC
SuperStrict

AppTitle="ZX Spectrum Cassette Player"

SetGraphicsDriver(GLMax2DDriver())
Graphics 444,400

Global Cassette:TImage   =LoadAnimImage("RotateCASSETTE.png",114,32,0,2)
Global Player:TImage     =LoadAnimImage("CassettePLAYER.png",256,192,0,3)
Global Buttons:TImage    =LoadAnimImage("CassetteBUTTONS.png",176,62,0,7)
Global JetpacINLAY:TImage=    LoadImage("JetpacINLAY.png")
Global SpoolGap:TImage=       LoadImage("SpoolGAP.png")
Global SpoolEdge:TImage=      LoadImage("SpoolEdge.png")
Global SpoolMIDDLE:TImage=    LoadImage("SpoolMIDDLE.png")


Global State:Int, Frame:Int, Timer:Int, TapeSpoolCount:Int
Global SpoolMIDDLE_X:Long=0

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

	Cls
	State=0

	If MouseDown(1) Then State=5 

	If State=5 Then

		If Timer<MilliSecs() Then
			timer= MilliSecs() +100
			frame=1-frame
      TapeSpoolCount:+1

      ' need to make this a lot slower spooling?
      If (TapeSpoolCount Mod 80000) Then 
          If (212-SpoolMIDDLE_X)>186 Then SpoolMIDDLE_X:+1
      End If
		EndIf

	EndIf


	DrawText "Click Left Mouse Button to Animate cogs",30,30

  DrawImage(SpoolGAP ,(182-SpoolMIDDLE_X),161)

  DrawImage JetPACINLAY,137,134

	DrawImage(Cassette,152,156,Frame)
	If state=5 Then DrawImage Player  ,100,100,2 Else DrawImage(Player  ,100,100,1)
	DrawImage(Buttons ,120,228,State)


	Flip(0)

Wend

Ive not played around with images like this before so i hope someone else can learn from the example so far as i am. :D

Kindest Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

#8
So the Tape counter is a little puzzle for me.

I wondering wether todo three counters and ripple them on a Mod of 10.

Or use TapeSpoolCount = TapeSpoolcount Mod 1000

Which will give me 0 to 999 count. But then would i separate into three nibbles like binary coded decimal.

Or just the old fashioned 100,s  10,s and units. God my math's is rusty. :-[

Not sure which way to go about this bit? ::)

My last thought is to use a 12bit counter separated into 3 x BCD and then Ripple count.  So the BCD digit becomes the DrawImage frame number.

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

#9
Todays Effort in BlitmaxNG

Ive added a function to do a Denary counter using the frames for the image. To make the counter work. Need to slow things down a lot thou?

Almost ready to put into SpecBlitz 128K 8)

Code: BASIC
SuperStrict

AppTitle="ZX Spectrum Cassette Player"

SetGraphicsDriver(GLMax2DDriver())
Graphics 444,400

Global Cassette:TImage   =LoadAnimImage("RotateCASSETTE.png",114,32,0,2)
Global Player:TImage     =LoadAnimImage("CassettePLAYER.png",256,192,0,3)
Global Buttons:TImage    =LoadAnimImage("CassetteBUTTONS.png",176,62,0,7)
Global TapeNUMBERS:TImage=LoadAnimImage("TapeNumbers.png",7,9,0,10)
Global JetpacINLAY:TImage=    LoadImage("JetpacINLAY.png")
Global SpoolGap:TImage=       LoadImage("SpoolGAP.png")

Global State:Int, Frame:Int, Timer:Int, TapeSpoolCount:Int
Global TapeCount:Short, BCD:Byte
Global SpoolMIDDLE_X:Long=0
Global GlTapeCOUNT:Byte[3]

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

    Cls
    State=0

  If MouseDown(2) Then 

    SpoolMIDDLE_X=0
    'GlTapeCOUNT[0]=0 ; GlTapeCOUNT[1]=0 ; GlTapeCOUNT[2]=0

  End If

    If MouseDown(1) Then 

      State=5 

      DoDenaryCount()

      If TapeCount >= 999 Then TapeCount=0

  End If

    If State=5 Then

        If Timer<MilliSecs() Then
            timer= MilliSecs() +100
            frame=1-frame
      TapeSpoolCount:+1
      
      ' need to make this a lot slower spooling?
      If (TapeSpoolCount Mod 800000) Then 
          If (212-SpoolMIDDLE_X)>186 Then SpoolMIDDLE_X:+1
      End If
        EndIf

    EndIf

  SetColor(220,220,220)
    DrawText "Click Left Mouse Button to Animate cogs",30,30

  DrawText "Click Right Mouse Button to Reset",30,350
  SetColor(255,255,255)

  DrawImage(SpoolGAP ,(182-SpoolMIDDLE_X),161)

  DrawImage(JetPACINLAY,137,134)

    DrawImage(Cassette,152,156,Frame)
    If state=5 Then DrawImage(Player  ,100,100,2) Else DrawImage(Player  ,100,100,1)
    DrawImage(Buttons ,120,228,State)

  DrawImage(TapeNUMBERS, 308,180,(GlTapeCOUNT[2]))
  DrawImage(TapeNUMBERS, 316,180,(GlTapeCOUNT[1]))
  DrawImage(TapeNUMBERS, 324,180,(GlTapeCOUNT[0]))


    Flip(0)

Wend

Function DoDenaryCount()

    BCD:+1   

   Select True

          Case (BCD Mod 100)=0

                          If GlTapeCOUNT[2]<9 Then 
                                                GlTapeCOUNT[2]:+1 ; GlTapeCOUNT[0]=0 ; GlTapeCOUNT[1]=0
                            Else
                                GlTapeCOUNT[0]=0 ; GlTapeCOUNT[1]=0 ; GlTapeCOUNT[2]=0
                                BCD=0
                          End If      


           Case (BCD Mod 10)=0

                          If GlTapeCOUNT[1]<9 Then 
                                                GlTapeCOUNT[1]:+1 ; GlTapeCOUNT[0]=0
                            Else 
                                GlTapeCOUNT[0]:+1
                          End If
       
                                       
           Default  GLTapeCOUNT[0]:+1
           

      End Select

End Function

I wish someone would fix the code pasting window without having to click "Toggle Source View" :-[

Im wondering wether to change the cassette deck back ground from Orange to Dark Red?

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

#10
Here is a simulation of a rolling counter:

AnimCounterKlein.gif





runnable demo:
Code: BASIC
Graphics 200,300
Global CounterRoll:TImage  = LoadImage("CounterRoll.png") 
Global Pulse:Int, Y:Int[3]

Repeat
    Cls
    
    Pulse:+1
    Y[0] = (Y[0] + 1) Mod 100
    
    If Pulse Mod 100 >89
        Y[1] = (Y[1] + 1) Mod 100
    EndIf
    
    If Pulse Mod 1000 >989
        Y[2] = (Y[2] + 1) Mod 100
    EndIf

    DrawImage CounterRoll,50,100 + y[2]
    DrawImage CounterRoll,60,100 + y[1]
    DrawImage CounterRoll,70,100 + y[0]

    SetViewport 100,212,40,10
        DrawImage CounterRoll,100,100 + y[2]
        DrawImage CounterRoll,110,100 + y[1]
        DrawImage CounterRoll,120,100 + y[0]
    SetViewport 0,0,500,400
    Flip 1
Until AppTerminate()

You need this PNG to run the demo:
CounterRoll.png
...on the way to China.

Baggey

#11
Thats an UBER cool counter effect, scrolling like that. Going to be implementing that for sure 8)

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

_PJ_

"Ooooooooooooooo---blip"
"Oooooooooooooooshkxzshkxzkzshkshkzxzkhsshskzhkszhkshkzxhzkzxhkkxshkzs!"

R-Tape Loading Error