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 24GB 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

#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

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


...back from Egypt

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. :)

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 24GB 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

#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

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 24GB 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

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



...back from Egypt

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.

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 24GB 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

#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 24GB 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

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

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 24GB 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

#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 24GB 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

#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)

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 24GB 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

#10
Here is a simulation of a rolling counter:

AnimCounterKlein.gif





runnable demo:
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
...back from Egypt

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 24GB 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!

_PJ_

"Ooooooooooooooo---blip"
"Oooooooooooooooshkxzshkxzkzshkshkzxzkhsshskzhkszhkshkzxhzkzxhkkxshkzs!"

R-Tape Loading Error