SyntaxBomb - Indie Coders

Languages & Coding => BlitzMax / BlitzMax NG => Topic started by: Baggey on April 11, 2024, 18:45:53

Title: Cassette Emulator
Post by: Baggey on April 11, 2024, 18:45:53
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
Title: Re: Cassette Emulator
Post by: Midimaster on April 12, 2024, 07:00:05
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


Title: Re: Cassette Emulator
Post by: Baggey on April 12, 2024, 08:58:56

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

Title: Re: Cassette Emulator
Post by: Baggey on April 12, 2024, 09:04:23
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
Title: Re: Cassette Emulator
Post by: Midimaster on April 12, 2024, 12:43:19
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



Title: Re: Cassette Emulator
Post by: Baggey on April 12, 2024, 17:33:19
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
Title: Re: Cassette Emulator
Post by: Baggey on April 12, 2024, 17:42:03
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
Title: Re: Cassette Emulator
Post by: Baggey on April 13, 2024, 10:20:14
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
Title: Re: Cassette Emulator
Post by: Baggey on April 13, 2024, 11:30:58
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
Title: Re: Cassette Emulator
Post by: Baggey on April 13, 2024, 17:33:20
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
Title: Re: Cassette Emulator
Post by: Midimaster on April 14, 2024, 08:18:45
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
Title: Re: Cassette Emulator
Post by: Baggey on April 14, 2024, 09:37:14
Thats an UBER cool counter effect, scrolling like that. Going to be implementing that for sure 8)

Kind Regards Baggey
Title: Re: Cassette Emulator
Post by: _PJ_ on April 29, 2024, 14:29:15
"Ooooooooooooooo---blip"
"Oooooooooooooooshkxzshkxzkzshkshkzxzkhsshskzhkszhkshkzxhzkzxhkkxshkzs!"

R-Tape Loading Error