Shop OBEX P1 Docs P2 Docs Learn Events
Do want to play music on your propeller? (Propeller chiptune player) — Parallax Forums

Do want to play music on your propeller? (Propeller chiptune player)

Ahle2Ahle2 Posts: 1,178
edited 2012-06-12 16:58 in Propeller 1
Minimum requirements to run this software:

* You own a propeller board with a SD card
* You have a NES game pad or a keyboard connected to your propeller
* You have a PAL or NTSC display connected to your propeller
* You used to be (is) a C64 or an Atari ST owner (or Amstrad, MSX, Spectrum)
* You like music from these machines
* You are a nostalgic person

If you and your hardware meets the minimum requirements, please go ahead and try it out.

Instructions:
1. Unpack all files from the archive named "MixedChiptunes.zip" to a SD card.
2. Unpack "PropellerChipTunePlayer.zip"
3. Edit the pin configuration in the "con section" of "PropellerChipTunePlayer.spin" to suit your needs
(If you want to use a NES game pad, uncomment the "InputNES.spin" and edit the "con section" in that file)
4. Compile, upload and run the top object (PropellerChipTunePlayer.spin)
5. Enjoy

Keyboard controlls:
Space - Fast forward
Enter - Pause
Right arrow - next tune
Left arrow - prvious tune
Down arrow - next page (tune += 10)
Up arrow - previous page (tune -= 10)

NES controlls:
A button - Fast forward
Start button - Pause
Right arrow - next tune
Left arrow - prvious tune
Down arrow - next page (tune += 10)
Up arrow - previous page (tune -= 10)

Color coding:
Green background: AY38910/YM2149F sound chip (Atari ST, Amstrad CPC, MSX, Spectrum 128)
Blue background: MOS8580 sound chip (Commodore 64)

Comments

  • ColeyColey Posts: 1,108
    edited 2011-05-01 15:03
    :cool: Hey this looks great, thanks very much
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2011-05-01 15:05
    That's pretty slick!

    Suggestion,

    1) You should make it ignore any file extension that it doesn't recognize.

    2) Have the program start playing immediately for those who don't have
    a NES connected. (Example: This special)

    OBC
  • Cluso99Cluso99 Posts: 18,066
    edited 2011-05-01 20:17
    Nice... Now to find the time...
  • jazzedjazzed Posts: 11,803
    edited 2011-05-02 07:12
    I really appreciate your music contributions. This is perfect for something i'm working on.
  • Ahle2Ahle2 Posts: 1,178
    edited 2011-05-03 09:10
    @Coley
    Are you able to get it to work on the Hybrid running at 96 Mhz?

    @Oldbitcollector (Jeff)
    Good suggestions. I will fix these things in the next release. :)

    @Cluso99
    If you meet the minimum requirements, it shouldn't take more than a couple of minutes to test it out.

    @jazzed
    Thanks Jazzed !
    What exactly are you working on? Or is it a secret?
  • ColeyColey Posts: 1,108
    edited 2011-05-03 12:48
    Ahle2 wrote: »
    @Coley
    Are you able to get it to work on the Hybrid running at 96 Mhz?

    Yes with the necessary adjustments, I love it!!

    Was running a bit fast till I noticed you hard coded a delay to 80_000_000, I set it to clkfreq and it was sweet! :cool:

    Thanks,

    Coley
  • jazzedjazzed Posts: 11,803
    edited 2011-05-03 13:54
    Ahle2 wrote: »
    What exactly are you working on? Or is it a secret?
    It's a sub $100, 2"x2.7" (50mm x 70mm) "Propeller LCD in a box" tenatively named GameBaby.
    Audio unfortunately is monaural. I just don't have enough Prop pins or room for another chip.
  • Ahle2Ahle2 Posts: 1,178
    edited 2011-05-03 14:07
    Here is the latest version for both the C3 and normal propeller boards.

    Bug fixes:
    - Changed the "wait routine" to use clkfreq instead of a hardcoded value
    - YM tunes dumped from machines with lower than 2 Mhz clock freq now plays at the right pitch
    - Fixed so only valid files can be played
    - Plus at lot of small bug fixes

    C3_PropellerChipTunePlayer - Archive [Date 2011.05.03 Time 23.53].zip
    PropellerChipTunePlayer - Archive [Date 2011.05.03 Time 22.54].zip
  • pik33pik33 Posts: 2,344
    edited 2012-05-01 08:49
    Ahle2 wrote: »
    Minimum requirements to run this software:

    * You own a propeller board with a SD card..............................................................yes
    * You have a NES game pad or a keyboard connected to your propeller..................... yes (kbd)
    * You have a PAL or NTSC display connected to your propeller...................................NO!!!!!!!!!!!
    * You used to be (is) a C64 or an Atari ST owner (or Amstrad, MSX, Spectrum)........yes
    * You like music from these machines...................................................................yes
    * You are a nostalgic person.................................................................................yes


    This $%^&**&&^^$#@!@#$#$% tv.... :((((((


    Seems I have to learn fast and make a VGA replacements for all these several different tv drivers... Still can hear the old, beautiful sound of these beautiful machines
  • potatoheadpotatohead Posts: 10,253
    edited 2012-05-01 09:43
    You don't have a TV?

    VGA replacements are sometimes possible, but not always. TV has lower sweep frequencies, which means better tricks in the video pixel render loops. The color space is different too, though I don't see that as too big of a deal.

    Not that I'm advocating you don't knock up replacements. Many users would be pleased to have those. TV is cool though, I must say I love it because I can put a Propeller display on my laptop using a capture device. Great way to run a Prop! A serial terminal is a close second...

    VGA more or less means you've got to be somewhere around a screen. Why they don't make laptops with a basic VGA in, is beyond me. Would buy one in a second! Less even.
  • pik33pik33 Posts: 2,344
    edited 2012-05-01 10:35
    Capture device... it may be a solution. I had an old video capture card with no xp driver (Win95/98 only) but if I can remember, it may be still usable with Linux... so need to find it (I didn't see it since several years) and try it...
  • evanhevanh Posts: 15,091
    edited 2012-05-04 05:55
    potatohead wrote: »
    VGA replacements are sometimes possible, but not always. TV has lower sweep frequencies, which means better tricks in the video pixel render loops.

    It was a piece of cake for CRT type monitors to be designed to handle the lower frequencies but nope it almost never happened, and was called a multi-frequency monitor when it did allow it. Not that your average VGA capable monitor wasn't multi-frequency anyway.

    It's even simpler now with built-in scan converters inside all modern LCD monitors. The minimum horizontal scan rate of 30kHz is a totally arbitrary limit. Sad really.
  • evanhevanh Posts: 15,091
    edited 2012-05-04 05:58
    And the crazy thing is that dedicated conversion boxes also can't do both! That was a real frustration for me when trying to get CNC machinery up and running quickly. There is many an old machine that has 18-24kHz video displays.
  • Ahle2Ahle2 Posts: 1,178
    edited 2012-05-17 14:11
    I have updated the chiptune player with the latest versions of AYcog and SIDcog.... See first post!
  • onewheeltomonewheeltom Posts: 40
    edited 2012-06-07 12:46
    Any thought of making these emulated chips "playable" via an external MIDI keyboard? That would be quite useful for playing chiptune music.

    I received my Quickstart board last week and have been very impressed with all the Propeller chiptune emulators. My current experience is with a Midibox SID that I just finished -- uses a real SID chip

    --tom
  • average joeaverage joe Posts: 795
    edited 2012-06-07 17:34
    Hi tom,
    We can play these emulators with midi fairly simply. It takes very little code using objects in the obex, especially the Midi In object. I did a quick script to play sidcog from midi in. I can post code if interested. SidSynth is a very nice synth that will work on your quickstart with a simple midi in.

    I've been porting the chiptune player over to my hardware. The inital port is working if a bit buggy. I need to finish the UI and then I'll upload a video to youtube.
  • onewheeltomonewheeltom Posts: 40
    edited 2012-06-08 06:16
    Joe,

    The code would be great. I will have a booth at our local Maker Faire next weekend :

    http://makerfairenc.com

    and I'd like to have the Propeller synth there....to give the Propeller platform some exposure. It would be really cool to have multiple emulators running in different cogs, all controllable via MIDI. Perhaps a simple interface to map keyboards to cogs and it would be an great piece of gear for live performance. I'm still figuring this all out...I will have more time to do more experimenting after Maker Faire is over. At this point, I want to make sure I have finished projects to show.

    Is there a standard MIDI (in/out) library, or is everyone doing their own thing? A standard library for common stuff like MIDI would be great.

    It's funny, I discovered all this Propeller music stuff after happening upon one of your posts in the Midibx forum. Otherwise I would not even have thought to look over here.

    Thanks,
    Tom
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2012-06-08 07:53
    +1 here for adding MIDI to Tinysynth.

    I've incorporated the original version of your code in my PropellerBASIC, (I'm counting every byte or I would have used the current one.)
    I'd love to add MIDI translation to it.

    OBC
  • average joeaverage joe Posts: 795
    edited 2012-06-08 17:32
    Hey tom, Sorry I've been busy. This is my very basic "test code" It should give you some idea of using midi in with sidcog. The only thing I implemented in this is note on/off. Probably not the best example but I was just experimenting. Should be easy to do the same with any of the emulators. I will have more time next week since I'm currently in the middle of moving. Hope this helps.
    CON
    {''Hardware version 3.4.1 - see diagram.
    ''
    } 
     _clkmode       = xtal1 + pll16x                        ' use crystal x 16
     _xinfreq       = 5_000_000                             'with 5mhz crystal 
          
      
      doNoteOn            = $00000001                        ' noteOn for midi in object
      doNoteOff           = $00000002                         ' NoteOff for midi in object
      doAftertouch        = $00000004                        '
      doController        = $00000008
      doProgramChange     = $00000010
      doChannelPressure   = $00000020
      doPitchWheel        = $00000040
      doSysex             = $00000100
      doMTC               = $00000200
      doSongPosPtr        = $00000400
      doSongSelect        = $00000800
      doTuneRequest       = $00001000
      doMidiClock         = $00002000
      doMidiTick          = $00004000
      doMidiStart         = $00008000
      doMidiContinue      = $00010000
      doMidiStop          = $00020000
      doActiveSense       = $00040000
      doReset             = $00080000 
    
    
      MidiInMode = doNoteOn+doNoteOff               ' set midi mode to Note On and note off only
    
      LeftPin            = 24       '<-- Audio Out pins
      RightPin           = 27
    
    VAR
    
    OBJ 
         wait : "timing"  
         midi: "MidiIn"
         sid : "SidCog"
    
    PUB SidMidi | sco, channel, note, velocity, event, NotesPlayed[3]
    
               Midi.Start(26,MidiInMode)            'Start Midi In object in cog
    'Set sid patch here:           
    
                 SID.start(rightPin, leftPin)           'Start the emulated SID chip in one cog 
                 
                 SID.resetRegisters                         'Reset all SID registers
                 
                 SID.setVolume(15)                           'Set volume to max
                   'wait.pause1s(1)
                   
                 
                 SID.setWaveform(0, SID#SQUARE)             'Set waveform type on channel1 to square wave
                 
                 SID.setPulseWidth(0, 1928)                 'Set the pulse width on channel1 to 47:53
                 SID.setADSR(0, 2, 9, 5, 4)    'Set Envelope on channel1
                 
                 SID.setWaveform(1, SID#NOISE)               'Set waveform type on channel2 to noise (drum sound)
                 SID.setADSR(1, 0, 8, 4, 7)                  'Set Envelope on channel2
                 SID.setWaveform(2, SID#SAW)                 'Set waveform type on channel3 to saw wave
                 SID.setADSR(2, 7, 4, 8, 9)                  'Set Envelope on channel3
                                   'Lp    Bp     Hp       
              SID.setFilterType(true, false, false) 'Enable lowpass filter
    
                                   'Ch1   Ch2    Ch3
                 SID.setFilterMask(true, false, false) 'Enable filter on the "bass channel" (channel1)
    
                 SID.setResonance(15)         'Set the resonance value to max
    
                 SID.setCutoff(287)               'Set cutoff 
    
                 repeat sco from 0 to 2         ' Turn off all notes
                  SID.noteOff(sco)
          
    
     REPEAT                                        'Start main loop here
       event := Midi.evt                        'get midi event
       note := event                            'and copy it
       channel := note                         'to the variables 
       'Velocity := note                        'describing the event
    
       event := (event & $FF00_0000) >> 24           ' mask event type
       channel := (channel & $00FF_0000) >> 16   ' mask channel number
       note := (note & $0000_FF00) >> 8               ' mask not number
      ' Velocity &= $0000_00FF                            'mask velocity, not used
       
          if event == 1                                          'if note off
           
             SID.noteOff(channel)                       ' send note off to sid on that channel
           
          elseif event == 0                           ' check for Note on 
            SID.noteOn(channel, note2freq(note))   'and send note on to sid on channel, convert note number to frequency
          
    
    PUB note2freq(note) | octave
        octave := note/12
        note -= octave*12 
        return (noteTable[note]>>(8-octave))
        
    
    
    DAT
    noteTable word 16350, 17320, 18350, 19450, 20600, 21830, 23120, 24500, 25960, 27500, 29140, 30870
    
    midi in object here : http://obex.parallax.com/objects/229/

    *edit*
    I just commented this code to make for easier reading. I will start a post dedicated to PERFORMING music on the prop next week!
  • onewheeltomonewheeltom Posts: 40
    edited 2012-06-11 16:24
    Apparently there are multiple SD card drivers in use. Does this one support SDHC? I can't find a non HC micro SD card.

    It never crossed my mind that I would have to be concerned with SD card compatibility or different SD card drivers. I guess I'll go look in the code. I am using a plug in micro SD adapter from Gadget Gangster.

    --tom
  • pik33pik33 Posts: 2,344
    edited 2012-06-12 13:18
    This driver has a problem with sdhc. It can't see all files on this card, I don't know why, Some files are seen and played, some not. I had to find 2GB card and format it with fat16
    So I used Kye's sd driver in my vga player.
    Maybe the simplest way is to add some functions to this driver with the same names, as in fsrw, then replace fsrw with Kye's driver without changing rest of player's code.
  • average joeaverage joe Posts: 795
    edited 2012-06-12 14:44
    I have ported over to kye's driver due to using it in my current hardware. Let me first say that it's buggy, as in skipping forward and back in files does not work correctly. Still, this should help you get going:
    CON
        ENABLE_PAL   = false
    OBJ
    
      SID      : "SIDcog"
      AY       : "AYcog"
    
    ''***************Start chiptune Player VAR here
    VAR
      'byte  LineOfText2[25]
      'byte  LineOfText1[18]
      byte  playing
      byte  chipTuneType
      byte  prevChipTuneType
      byte  ffw
      word  playRate
      long  wait
      long  ct_fn
      long  nrOfTunes
      long  scrollSpeed  
      long  frameCounter
      long  scrollCounter
      long  textPointer
      long  AY_register
    
    
    PUB ChiptuneStart | i, oldStatus, fin,yval, xval
      RamErase
      SDBMPtoRam(string("Trans2.bmp"))
      sid.start(_rightChannelAudioPin, _leftChannelAudioPin)                           
      getNrOfTunes 
      Clearscreen(0)                        ' clear screen to black - uses the display driver above
      curx :=0
      cury :=0
      SetHeaderMessage(@message4)
      frameCounter := 0
      ct_fn   := 1
      chipTuneType := 1
      playRate     := 50
      scrollSpeed  := 2
      playing      := false
      ffw          := false
      wait         := cnt
    
      DrawBMPRam(0,0,280)
        
      'Main loop
      repeat
      ' Wait between register updates
        if (cnt - wait) > 0
          if ffw
            wait := cnt + (clkfreq/(playRate<<2))   
          else
            wait := cnt + (clkfreq/playRate)
        ' Update the PSG    
          if playing
            case chipTuneType
              1: updateSID
              2: updateAY
    
      ' Check for a change in tv status
    '    if oldStatus <> tv_status
    '      oldStatus := tv_status
    
    '    ' Check for vbl    
    '      if tv_status == 2
    '        scroll 
    '
    '      ' Handle user interactions  
    '     if input.getLastState <> input.getCurrentState
    
        SelectSPIGroup 
        yval := TouchYPercent                               ' decode yval 0-100%               
        xval := TouchXPercent                              ' decode xval 0-100%
        if (xval <> 255)  and (yval <> 255)
          'SelectMemGroup
          'hex(xval,2)      ' if display any debug messages need to restart the SPI cog as it has been stopped by the debug display
          'hex(yval,2)
          
          if (yval < 20)
            fat.changeDirectory(string(".."))
    
            RamErase                                              ' erase ram chip fat
            LoadDesktop                                           ' a image 240x320 for the desktop. Load first as there is a ramclear routine that does not delete the first entry
            DrawDesktop
            LoadIcons                                             ' load the mask and icons onto the screen
            ILISetcursor(0,0)                                     ' cursor for debugging to 0,0
            SelectSPIGroup                                        ' selects this group and starts the cog
            return
          
          if (yval > 89)
            SelectMemGroup
          ' Handle previous tune           
            if (xval < 19)
              handleMuting
              if ct_fn == 0
                 ct_fn := nrOfTunes + 1
                 ct_fn--
              openNextFile
              setScrollMessage(@songName +6)
    
    
           ' Handle pausing  
            if (xval > 37 and xval < 70)
              playing := not playing
              handleMuting     
                ifnot playing
                  setScrollMessage(@message2)     
                else
                  ffw := false
                  setScrollMessage(@songName +6)
    
           ' Handle next tune   
            if (xval > 79 and xval < 99)
              handleMuting
                if ct_fn == nrOfTunes
                  ct_fn := -1
                ct_fn++
                openNextFile                
                setScrollMessage(@songName + 6)
    
    PRI openNextFile | i, t,x, nameP
        ffw := false
        playing := true                                
        ' Iterate through files and find the file with fileNumber == X
        fat.closeFile 
    
        repeat i from 0 to ct_fn
          fat.listEntries("N")  
          nameP := fat.listname
        t:=0
        repeat until byte [nameP][t] == 0
          byte [@LineOfText1][t]:= byte[nameP][t]
          t++
         byte[@LineOfText1][t] := 0 
    
        prevChipTuneType := chipTuneType
        chipTuneType := 0
    
        
        t := 0
        x := 0
        repeat strsize(@directory)
          byte[@LineOfText3][x] := byte [@directory][x]
          x ++
    
        repeat strsize(@LineOfText1)
          byte[@LineOfText3][x] := byte [@LineOfText1][t]
          x ++
          t ++
          
        fat.openFile(@LineOfText3, "R")
    
      ' Find out what kind of file type we are dealing with
    
        if fat.readData(@LineOfText2, 4) < 0
    
        if byte[nameP - 3] == "D" and byte[nameP - 2] == "M" and byte[nameP - 1] == "P"
          chipTuneType := 1
            
        if LineOfText2[0] == "S" and LineOfText2[1] == "D" and LineOfText2[2] == "M" and LineOfText2[3] == "P"       ' SDMP
           chipTuneType := 1
          
        elseif LineOfText2[0] == "Y" and LineOfText2[1] == "M" and LineOfText2[2] == "6" and LineOfText2[3] == "!"  ' YM6!
          chipTuneType := 2
          
        else
          fat.closeFile
          AY.stop
          SID.stop
           setScrollMessage(@message1)   
          return
    
        ' Set some standard values in case the header doesn't provide any info
        playRate := 50
        bytefill(@songName + 10, 32, 15)
         intToString(@songName + 6, ct_fn, 5)
        
        repeat i from 0 to 15 
          if LineOfText1[i]
            byte[@songName + i + 10] := LineOfText1[i]
            
          else
            i := 16
    
        ' Init everything, read the header and start the PSG
        fat.openFile(@LineOfText1, "R")
        
        if chipTuneType == 1
          readHeaderSID
          initSID
          
        elseif chipTuneType == 2
          readHeaderAY
          initAY
    
        wait := cnt + 20_000_000
    
    PRI handleMuting
      case chipTuneType
        1:
          if playing
            SID.unmute
            
          else
            SID.mute
            
        2:
          if playing
            AY.unmute
            
          else
            AY.mute
    
    PRI initSID | registers
    
        if prevChipTuneType == 2
          AY.stop
          
        elseif prevChipTuneType == 1
          SID.stop
    
        registers := SID.start( _rightChannelAudioPin, _leftChannelAudioPin )
        SID.resetRegisters
    '    OSC.stop
    '    OSC.start( display_base, registers + 28, @tv_status, @scrollSpeed )
        chipTuneType := 1
    '    setSIDColor
    
    PRI initAY | registers
    
        if prevChipTuneType == 2
          AY.stop
          
        elseif prevChipTuneType == 1
          SID.stop
    
        registers := AY.start(_rightChannelAudioPin, _leftChannelAudioPin, AY_register)
        AY.resetRegisters
    '    OSC.stop
    '    OSC.start( display_base, registers + 16, @tv_status, @scrollSpeed )
        chipTuneType := 2
    '    setAYColor
    
    PRI updateSID
         if( fat.readData(@LineOfText2, 25) ) < 0
          ct_fn++
          openNextFile
    
        SID.updateRegisters(@LineOfText2)
    
    PRI updateAY
         if( fat.readData(@LineOfText2, 16) ) < 0
          ct_fn++
          openNextFile
    
        AY.updateRegisters(@LineOfText2)
    
    PRI readHeaderSID | i, t
       if( fat.readData(@LineOfText2, 25) ) => 0
      
        if LineOfText2[0] == "S" and LineOfText2[1] == "D" and LineOfText2[2] == "M" and LineOfText2[3] == "P"
          playRate := LineOfText2[4] | (LineOfText2[5]<<8)
          
          repeat i from 0 to 15
            t := LineOfText2[ i + 8 ]
            
            if t
              byte[ @songName + i + 10 ] := t
              
            else
              byte[ @songName + i + 10 ] := 32
    
    PRI readHeaderAY | extra, digiDrums, i, t
    
       if( fat.readData(@LineOfText2, 12)) => 0       ' 00 - read "YM6!" header ' 04 - read "LeOnArD!" identifier
       if( fat.readData(@LineOfText2, 4) ) => 0       ' 0c - number of VBL frames (play rate)
       if( fat.readData(@LineOfText2, 4) ) => 0       ' 10 - attributes
       if( fat.readData(@LineOfText2, 2) ) => 0       ' 14 - number of digi drum samples
        digiDrums := LineOfText2[0] | (LineOfText2[1]<<8)
    
       if( fat.readData(@LineOfText2, 4) ) => 0       ' 16 - YM2149 external frequency in Hz
        AY_register := LineOfText2[3] | (LineOfText2[2]<<8) | (LineOfText2[1] << 16) | (LineOfText2[0] << 24)
    
       if( fat.readData(@LineOfText2, 2) ) => 0       ' 1a - player frequency in Hz
        playRate := LineOfText2[1] | (LineOfText2[0]<<8)
        
       if( fat.readData(@LineOfText2, 4) ) => 0       ' 1c - frame where looping starts
    
       if( fat.readData(@LineOfText2, 2) ) => 0       ' 20 - extra bytes following (should be 0)
        extra := LineOfText2[0] | (LineOfText2[1]<<8)
    
      bytefill(@LineOfText2, 32, 15)
    
      if get_string                ' read song name
        repeat i from 0 to 14
          t := LineOfText2[i]
    
          if t
            byte[ @songName + i + 10 ] := t
    
          else
            byte[ @songName + i + 10 ] := 32
    
      get_string                   ' read author name
      get_string                   ' read comments / software
    
    PRI get_string | n, t
    
      repeat n from 0 to 127
        if (t := fat.readByte ) =< 0
          return n      
        else
          if n < 25
            LineOfText2[n] := t
    
    var byte firstFile[18]
    
    PRI getNrOfTunes    | t,i
      nrOfTunes := -1
        fat.closefile
      'propfont_string(                   )  
      fat.changeDirectory(string("tunes"))
      
      repeat until strcomp(@Dir2, t)     
        fat.listEntries("N") 
        t := fat.listname
        'propfont_String(t)
        
      fat.listEntries("N")  
      t := fat.listname
      'propfont_String(t)
      i := 0
      
      repeat until byte[t][i] == 0 
        firstFile[i] := byte[t] [i]
    '    propfont_out(".")
        i++
     crlf
      'propfont_string(string("FirstFile"))
      'propfont_string(@firstFile)
      
      t:= -1
      repeat until strcomp(@firstFile, t)                
        fat.listEntries("N")
        t := fat.listname
    '    propfont_String(t)
        nrOfTunes++
      if nrOfTunes < 1
        nrOfTunes -= 2
    
    
  • onewheeltomonewheeltom Posts: 40
    edited 2012-06-12 16:58
    Listening to this player right now. Works great except the video is unstable on my color LCD monitor. When I use a older black and white TV, the picture is fine, but I can't tell what the colors are.

    --tom
Sign In or Register to comment.