#include #include #include #include #include "cd.h" #if defined(OS_LINUX) #include "cd_ll_linux.h" #elif defined(OS_BSD) #include "cd_ll_bsd.h" #else #error "You haven't defined your platform!" #endif // initialize cd::cd(void) : m_mode(NORMAL), m_status(NO_CD_INSIDE), m_tracks(0), m_volume(255), m_looping(false), m_random(true), m_track(0), m_one_track_only(false), m_ind(0), m_programmed(0) { srand( (unsigned int) time(NULL) ); #if defined(OS_LINUX) m_ll = new cd_ll_linux(); #elif defined(OS_BSD) m_ll = new cd_ll_bsd(); #endif // this is clever :) // 27.11.99: apparently too clever as I no longer have any idea // what the above comment and/or code means... m_tr[0]=0; open(); read_volume(); read_status(); } // close the cd cd::~cd() { m_ll->close(); } // new cd in drive, initialize all data void cd::new_cd(void) { if (m_status == NO_CD_INSIDE) return; read_info(); read_status(); init_tracks(); } // read the number of tracks void cd::read_info(void) { if (m_status == NO_CD_INSIDE) return; cd_ll_toc_header toc_hdr; int x = m_ll->read_toc_header(&toc_hdr); if (x == -1) return; m_tracks = toc_hdr.tracks; } // open cd-rom device void cd::open(void) { if (m_ll->is_open()) return; m_ll->open(); if (m_ll->is_open() == false) { fprintf(stderr, "Cannot open CD-ROM device, exiting.\n"); exit(1); } } // close cd-rom device void cd::close(void) { if (m_ll->is_open() == false) return; m_ll->close(); } // read current status // if track changed, play next track. meaning of "next track" varies // with the mode. // also detects cd insertions/ejections void cd::read_status(void) { cd_ll_status st; int x = m_ll->read_status(&st); // new cd inserted if ((m_status == NO_CD_INSIDE) && (x != -1)) { // the cd could be playing or paused, but it doesn't matter // since new_cd() calls read_status() again which then sets it // to the correct value m_status=STOPPED; new_cd(); return; } else if (x == -1) { // cd ejected m_status=NO_CD_INSIDE; m_tracks=0; m_ind=0; m_track=0; m_programmed=0; clear_tracks(); return; } switch (st.audio_status) { case CD_LL_PLAYING: m_status = PLAYING; m_track = st.track; break; case CD_LL_PAUSED: m_status = PAUSED; break; case CD_LL_NO_STATUS: case CD_LL_INVALID: // many drives report INVALID for stopped status m_status = STOPPED; break; case CD_LL_PLAY_COMPLETED: if (m_one_track_only) { m_one_track_only=false; // this is needed on some drives, for example on mine, // since for some reason they don't automatically stop // spinning after completing a track, resulting in a very // annoying humming noise requiring you to manually press // the 'S' key to stop the drive. this achieves the same // effect automatically. stop(); } else next(); break; } } // play a single track void cd::play_one(int track) { m_one_track_only=true; play(track); } // play the track and continue after it with the current mode void cd::play(int track) { if (m_status == NO_CD_INSIDE) { m_one_track_only=false; return; } if ( (track < 1) || (track > m_tracks) ) { m_one_track_only=false; return; } stop(); // start spinning the drive. // necessary on some drives m_ll->start(); cd_ll_tracks t; t.start_track = track; t.end_track = track; m_ll->play(&t); } // continue playing from where we stopped, or if we're at the start of // the disc from the beginning. if we're at the start and in random // mode, shuffle the right amount of tracks void cd::play(void) { if (m_status == NO_CD_INSIDE) return; if (m_ind < 1) { if ((m_mode == PROGRAMMED) && m_random) shuffle_tracks(m_programmed); else if ((m_mode == NORMAL) && m_random) shuffle_tracks(m_tracks); m_ind=1; } // it shouldn't be possible for m_ind to grow beyond its limits play(m_tr[m_ind]); } // stop void cd::stop(void) { if (m_status == NO_CD_INSIDE) return; m_ll->stop(); } // pause void cd::pause(void) { if (m_status != PLAYING) return; m_ll->pause(); } // resume void cd::resume(void) { if (m_status != PAUSED) return; m_ll->resume(); } // eject void cd::eject(void) { stop(); m_ll->eject(); } // set volume void cd::set_volume(int volume) { cd_ll_volume vol; if (volume > 255) volume=255; else if (volume < 0) volume=0; m_volume = volume; vol.left = volume; vol.right = volume; m_ll->set_volume(&vol); } // read volume void cd::read_volume(void) { cd_ll_volume vol; int x = m_ll->read_volume(&vol); if (x == -1) return; m_volume = vol.left; } // return volume int cd::get_volume(void) { return m_volume; } // next track void cd::next(void) { m_ind++; // have we played through the whole array? if ( (m_ind > MAX_TRACKS) || (m_tr[m_ind] == -1) ) { tracks_played(); return; } else play(m_tr[m_ind]); } // clear the track array void cd::clear_tracks(void) { for (int i=1; i <= MAX_TRACKS; i++) m_tr[i]=-1; } // set mode void cd::set_mode(mode m) { m_mode=m; init_tracks(); } // init track array according to current mode void cd::init_tracks(void) { if (m_status == NO_CD_INSIDE) return; m_ind=0; m_programmed=0; clear_tracks(); if (m_mode == NORMAL) { for (int i=1; i <= m_tracks; i++) m_tr[i]=i; } } // shuffle first n entries of m_tr void cd::shuffle_tracks(int n) { for (int i=1; i <= n; i++) { int temp=m_tr[i]; int t=(rand() % n)+1; m_tr[i]=m_tr[t]; m_tr[t]=temp; } } // called when all tracks in array are played // if we're not looping, stop playing. // if we're looping, start over at the beginning of the array. void cd::tracks_played(void) { if (!m_looping) { stop(); return; } m_ind=0; play(); } // if we're in PROGRAMMED mode, add a new track to be played void cd::push_track(int track) { if (m_mode != PROGRAMMED) return; if (m_programmed >= MAX_TRACKS) return; if ( (track < 1) || (track > m_tracks) ) return; m_programmed++; m_tr[m_programmed]=track; }