Major internal code refactoring -- separated the actual SCSI-call interface with the CD drive from the rest of the app

CDEngine now uses the PlayList class to track which track to play - Shuffle and Loop now work properly
Track name is a little darker when the player is no longer active


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13353 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
DarkWyrm 2005-06-29 18:42:22 +00:00
parent a66e28b1ff
commit 4f39b358ee
10 changed files with 548 additions and 651 deletions

View File

@ -76,18 +76,38 @@ CDDBQuery::SetToSite(const char *server, int32 port)
}
void
CDDBQuery::SetToCD(const scsi_toc *toc)
CDDBQuery::SetToCD(const char *path)
{
if (state == kInitial) {
GetDiscID(toc, discID, numTracks, discLength, frameOffsetString, discIDStr);
} else {
if(!path)
return;
// Get the SCSI table of contents from the device passed to us
int device = open(path, O_RDONLY);
if(device < 0)
return;
scsi_toc toc;
status_t result = ioctl(device, B_SCSI_GET_TOC, &toc);
close(device);
if(result != B_OK)
return;
if (state == kInitial)
{
GetDiscID(&toc, discID, numTracks, discLength, frameOffsetString, discIDStr);
}
else
{
int32 tmpDiscID;
int32 tmpDiscLength;
int32 tmpNumTracks;
BString tmpFrameOffsetString;
BString tmpDiscIDStr;
GetDiscID(toc, tmpDiscID, tmpNumTracks, tmpDiscLength, tmpFrameOffsetString,
GetDiscID(&toc, tmpDiscID, tmpNumTracks, tmpDiscLength, tmpFrameOffsetString,
tmpDiscIDStr);
if (discID == tmpDiscID && discLength == tmpDiscLength && numTracks == tmpNumTracks
@ -343,8 +363,10 @@ CDDBQuery::ReadFromServer(BDataIO *stream)
BString tmp;
ReadLine(tmp);
if (tmp.FindFirst("200") != 0)
{
printf("Error: %s\n",tmp.String());
return;
}
BString category;
GetToken(tmp.String() + 3, category);
if (!category.Length())
@ -474,7 +496,7 @@ CDDBQuery::IdentifySelf()
strcpy(hostname, "unknown");
BString tmp;
tmp << "cddb hello " << username << " " << hostname << " CDButton v1.0\n";
tmp << "cddb hello " << username << " " << hostname << " Haiku_CD_Player v1.0\n";
if (log)
printf(">%s", tmp.String());
@ -535,7 +557,9 @@ CDDBQuery::FindOrCreateContentFileForDisk(BFile *file, entry_ref *fileRef, int32
return false;
}
#if 0
/*
#include "CDEngine.h"
bool
PrintSite(const char *site, int port, const char *latitude,
@ -549,35 +573,33 @@ PrintSite(const char *site, int port, const char *latitude,
int
main()
{
try {
CDDBQuery query("us.cddb.com", 888, true);
// query.GetSites(&PrintSite, NULL);
CDDBQuery query("us.freedb.org", 888, true);
int32 device = CDEngine::FindCDPlayerDevice();
if (!device) {
if (!device)
{
printf("no device %s\n", strerror(device));
return 0;
}
CDEngine engine(device);
scsi_toc toc;
engine.GetToc(&toc);
ioctl(device, B_SCSI_GET_TOC, &toc);
int32 discID = query.GetDiscID(&toc);
query.SetToCD(&toc);
BString title;
vector<BString> trackTitles;
query.GetTitles(title, trackTitles, 10000000);
query.GetTitles(&title, &trackTitles, 10000000);
printf("CD Title:%s\n", title.String());
printf("CD Title: %s, ID: %lx\n", title.String(), discID);
int32 index = 0;
for (vector<BString>::iterator iterator = trackTitles.begin();
iterator != trackTitles.end(); index++, iterator++)
printf("%d: %s\n", index, (*iterator).String());
printf("%ld: %s\n", index, (*iterator).String());
} catch(status_t error) {
printf("error %s\n", strerror(error));
}
return 0;
}
#endif
*/

View File

@ -9,14 +9,15 @@
// based on Jukebox by Chip Paul
class CDDBQuery {
class CDDBQuery
{
public:
CDDBQuery(const char *server, int32 port = 888, bool log = false);
void SetToSite(const char *server, int32 port);
void GetSites(bool (*)(const char *site, int port, const char *latitude,
const char *longitude, const char *description, void *state), void *);
void SetToCD(const scsi_toc *);
void SetToCD(const char *devicepath);
bool GetTitles(BString *title, vector<BString> *tracks, bigtime_t timeout);
// title or tracks may be NULL if you are only interrested in one, not the other
@ -39,25 +40,26 @@ private:
static int32 LookupBinder(void *);
class Connector {
public:
Connector(CDDBQuery *client)
: client(client),
wasConnected(client->IsConnected())
{
if (!wasConnected)
client->Connect();
}
~Connector()
{
if (!wasConnected)
client->Disconnect();
}
class Connector
{
public:
Connector(CDDBQuery *client)
: client(client),
wasConnected(client->IsConnected())
{
if (!wasConnected)
client->Connect();
}
private:
CDDBQuery *client;
bool wasConnected;
~Connector()
{
if (!wasConnected)
client->Disconnect();
}
private:
CDDBQuery *client;
bool wasConnected;
};
bool FindOrCreateContentFileForDisk(BFile *file, entry_ref *ref, int32 discID);
@ -87,7 +89,8 @@ private:
BString discIDStr;
// cached retrieved data
enum State {
enum State
{
kInitial,
kReading,
kDone,

View File

@ -14,23 +14,18 @@
#include <errno.h>
#include "scsi.h"
#include "CDEngine.h"
#include "PlayList.h"
static PlayList sPlayList;
static CDAudioDevice sCDDevice;
const bigtime_t kPulseRate = 500000;
PeriodicWatcher::PeriodicWatcher(int devicefd)
: Notifier(),
devicefd(devicefd)
PeriodicWatcher::PeriodicWatcher(void)
{
}
PeriodicWatcher::PeriodicWatcher(BMessage *)
: devicefd(-1)
{
// not implemented yet
PRINT(("under construction"));
}
BHandler *
PeriodicWatcher::RecipientHandler() const
{
@ -52,34 +47,29 @@ PeriodicWatcher::UpdateNow()
}
PlayState::PlayState(int devicefd)
: PeriodicWatcher(devicefd),
oldState(kNoCD)
PlayState::PlayState(CDEngine *engine)
: oldState(kNoCD),
fEngine(engine)
{
}
bool
PlayState::UpdateState()
PlayState::UpdateState(void)
{
// check the current CD play state and force a notification to
// be sent if it changed from last time
scsi_position pos;
status_t media_status = B_DEV_NO_MEDIA;
ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status));
if (media_status != B_NO_ERROR)
return CurrentState(kNoCD);
status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos);
if (result != B_NO_ERROR)
return CurrentState(kNoCD);
else if ((!pos.position[1]) || (pos.position[1] >= 0x13) ||
((pos.position[1] == 0x12) && (!pos.position[6])))
return CurrentState(kStopped);
else if (pos.position[1] == 0x11)
return CurrentState(kPlaying);
else
return CurrentState(kPaused);
CDState state = sCDDevice.GetState();
if( state == kStopped && fEngine->GetState() == kPlaying)
{
// this means we have come to the end of a song, but probably not
// the last song in the playlist
int16 next = sPlayList.GetNextTrack();
if(next > 0)
{
sCDDevice.Play(next);
return CurrentState(kPlaying);
}
}
return CurrentState(state);
}
CDState
@ -91,16 +81,16 @@ PlayState::GetState() const
bool
PlayState::CurrentState(CDState newState)
{
if (newState != oldState) {
if (newState != oldState)
{
oldState = newState;
return true;
}
return false;
}
TrackState::TrackState(int devicefd)
: PeriodicWatcher(devicefd),
currentTrack(0)
TrackState::TrackState(void)
: currentTrack(0)
{
}
@ -113,46 +103,20 @@ TrackState::GetTrack() const
bool
TrackState::UpdateState()
{
// check the current CD track number and force a notification to
// be sent if it changed from last time
scsi_position pos;
status_t media_status = B_DEV_NO_MEDIA;
ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status));
if (media_status != B_NO_ERROR)
return CurrentState(-1);
status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos);
if (result != B_NO_ERROR)
return CurrentState(-1);
if (!pos.position[1] || pos.position[1] >= 0x13
|| (pos.position[1] == 0x12 && !pos.position[6]))
return CurrentState(0);
else
return CurrentState(pos.position[6]);
return CurrentState(sPlayList.GetCurrentTrack());
}
int32
TrackState::GetNumTracks() const
{
// get the number of tracks on the current CD
scsi_toc toc;
status_t result = ioctl(devicefd, B_SCSI_GET_TOC, &toc);
if (result != B_NO_ERROR)
return 0;
return toc.toc_data[3];
return sCDDevice.CountTracks();
}
bool
TrackState::CurrentState(int32 track)
{
if (track != currentTrack) {
if (track != currentTrack)
{
currentTrack = track;
return true;
}
@ -165,28 +129,19 @@ TimeState::UpdateState()
// check the current CD time and force a notification to
// be sent if it changed from last time
// currently only supports global time
scsi_position pos;
status_t media_status = B_DEV_NO_MEDIA;
ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status));
if (media_status != B_NO_ERROR)
return CurrentState(-1, -1, -1, -1);
status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos);
cdaudio_time track;
cdaudio_time disc;
if (result != B_NO_ERROR)
return CurrentState(-1, -1, -1, -1);
else
if ((!pos.position[1]) || (pos.position[1] >= 0x13) ||
((pos.position[1] == 0x12) && (!pos.position[6])))
if(sCDDevice.GetTime(track,disc))
{
// This indicates that we have a CD, but we are stopped. We *could* simply
// return all 0's, but because the GUI expects valid numbers or -1's, we
// return -1's.
return CurrentState(-1, -1, -1, -1);
return CurrentState(disc.minutes, disc.seconds, track.minutes, track.seconds);
}
else
return CurrentState(pos.position[9], pos.position[10], pos.position[13], pos.position[14]);
{
CurrentState(-1, -1, -1, -1);
return false;
}
}
bool
@ -218,17 +173,8 @@ TimeState::GetTrackTime(int32 &minutes, int32 &seconds) const
}
CDContentWatcher::CDContentWatcher(int devicefd)
: PeriodicWatcher(devicefd),
cddbQuery("us.freedb.org", 888, true),
discID(-1),
fReady(false)
{
}
CDContentWatcher::CDContentWatcher(BMessage *message)
: PeriodicWatcher(message),
cddbQuery("us.freedb.org", 888, true),
CDContentWatcher::CDContentWatcher(void)
: cddbQuery("us.freedb.org", 888, true),
discID(-1),
fReady(false)
{
@ -249,15 +195,13 @@ CDContentWatcher::UpdateState()
// from the old one whenever there is a CD in the drive
if (engine->PlayStateWatcher()->GetState() != kNoCD)
{
scsi_toc toc;
ioctl(devicefd, B_SCSI_GET_TOC, &toc);
newDiscID = cddbQuery.GetDiscID(&toc);
newDiscID = sCDDevice.GetDiscID();
if (discID == newDiscID)
return false;
// We have changed CDs, so we are not ready until the CDDB lookup finishes
cddbQuery.SetToCD(&toc);
cddbQuery.SetToCD(sCDDevice.GetDrivePath());
fReady=false;
}
@ -274,21 +218,19 @@ CDContentWatcher::UpdateState()
return result;
}
VolumeState::VolumeState(int devicefd)
: PeriodicWatcher(devicefd),
fVolume(-1)
VolumeState::VolumeState(void)
: fVolume(-1)
{
}
bool
VolumeState::UpdateState(void)
{
scsi_volume vol;
ioctl(devicefd, B_SCSI_GET_VOLUME, &vol);
if(vol.port0_volume == fVolume)
uint8 volume = sCDDevice.GetVolume();
if(fVolume == volume)
return false;
fVolume = vol.port0_volume;
fVolume = volume;
return true;
}
@ -298,32 +240,16 @@ VolumeState::GetVolume(void) const
return fVolume;
}
CDEngine::CDEngine(int devicefd)
CDEngine::CDEngine(void)
: BHandler("CDEngine"),
devicefd(devicefd),
playState(devicefd),
trackState(devicefd),
timeState(devicefd),
volumeState(devicefd),
contentWatcher(devicefd)
{
}
CDEngine::CDEngine(BMessage *message)
: BHandler(message),
devicefd(-1),
playState(message),
trackState(message),
timeState(message),
volumeState(message),
contentWatcher(devicefd)
playState(this),
fEngineState(kStopped)
{
sPlayList.SetTrackCount(sCDDevice.CountTracks());
}
CDEngine::~CDEngine()
{
if(devicefd >= 0)
close(devicefd);
}
void
@ -337,249 +263,137 @@ CDEngine::AttachedToLooper(BLooper *looper)
contentWatcher.AttachedToLooper(this);
}
void
CDEngine::PlayOrPause()
{
// if paused, or stopped, plays, if playing, pauses
playState.UpdateNow();
switch (playState.GetState()) {
case kNoCD:
Play();
return;
case kStopped:
Play();
break;
case kPaused:
PlayContinue();
break;
case kPlaying:
Pause();
break;
default:
break;
}
}
void
CDEngine::Pause()
{
// pause the CD
status_t result = ioctl(devicefd, B_SCSI_PAUSE_AUDIO);
if (result != B_NO_ERROR) {
PRINT(("error %s pausing\n", strerror(errno)));
return;
}
sCDDevice.Pause();
fEngineState = sCDDevice.GetState();
}
void
CDEngine::Play()
{
// play the CD
if (playState.GetState() == kNoCD)
if(fEngineState == kPaused)
{
// no CD available, bail out
ioctl(devicefd, B_LOAD_MEDIA, 0, 0);
return;
sCDDevice.Resume();
fEngineState = sCDDevice.GetState();
}
scsi_play_track track;
track.start_track = 1;
track.start_index = 1;
track.end_track = 99;
track.end_index = 1;
status_t result = ioctl(devicefd, B_SCSI_PLAY_TRACK, &track);
if (result != B_NO_ERROR)
else
if(fEngineState == kPlaying)
{
PRINT(("error %s playing track\n", strerror(errno)));
return;
Pause();
}
}
void
CDEngine::PlayContinue()
{
// continue after a pause
status_t result = ioctl(devicefd, B_SCSI_RESUME_AUDIO);
if (result != B_NO_ERROR)
else
{
PRINT(("error %s resuming\n", strerror(errno)));
return;
sCDDevice.Play(sPlayList.GetCurrentTrack());
fEngineState = sCDDevice.GetState();
}
}
void
CDEngine::Stop()
{
// stop a playing CD
status_t result = ioctl(devicefd, B_SCSI_STOP_AUDIO);
if (result != B_OK)
{
PRINT(("error %s stopping\n", strerror(errno)));
return;
}
fEngineState = kStopped;
sCDDevice.Stop();
}
void
CDEngine::Eject()
{
// eject or load a CD
status_t media_status = B_DEV_NO_MEDIA;
// get the status first
ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status));
// if door open, load the media, else eject the CD
status_t result = ioctl(devicefd,
media_status == B_DEV_DOOR_OPEN ? B_LOAD_MEDIA : B_EJECT_DEVICE);
if (result != B_OK)
{
PRINT(("error %s ejecting\n", strerror(errno)));
return;
}
sCDDevice.Eject();
fEngineState = sCDDevice.GetState();
}
void
CDEngine::SkipOneForward()
{
// skip forward by one track
CDState state = playState.GetState();
if (state == kNoCD)
int16 track = sPlayList.GetNextTrack();
if(track <= 0)
return;
bool wasPaused = state == kPaused
|| state == kStopped;
SelectTrack(trackState.GetTrack() + 1);
if (wasPaused)
// make sure we don't start playing if we were paused before
Pause();
CDState state = sCDDevice.GetState();
if(state == kPlaying)
sCDDevice.Play(track);
// if(state == kPaused)
// sCDDevice.Pause();
}
void
CDEngine::SkipOneBackward()
{
// skip backward by one track
CDState state = playState.GetState();
if (state == kNoCD)
int16 track = sPlayList.GetPreviousTrack();
if(track <= 0)
return;
bool wasPaused = state == kPaused
|| state == kStopped;
int32 track = trackState.GetTrack();
if (track > 1)
track--;
CDState state = sCDDevice.GetState();
SelectTrack(track);
if (wasPaused)
// make sure we don't start playing if we were paused before
Pause();
if(state == kPlaying)
sCDDevice.Play(track);
// if(state == kPaused)
// sCDDevice.Pause();
}
void
CDEngine::StartSkippingBackward()
{
// start skipping
CDState state = playState.GetState();
if (state == kNoCD)
return;
scsi_scan scan;
scan.direction = -1;
scan.speed = 1;
status_t result = ioctl(devicefd, B_SCSI_SCAN, &scan);
if (result != B_NO_ERROR) {
PRINT(("error %s skipping backward\n", strerror(errno)));
return;
}
sCDDevice.StartRewind();
}
void
CDEngine::StartSkippingForward()
{
// start skipping
CDState state = playState.GetState();
if (state == kNoCD)
return;
scsi_scan scan;
scan.direction = 1;
scan.speed = 1;
status_t result = ioctl(devicefd, B_SCSI_SCAN, &scan);
if (result != B_NO_ERROR) {
PRINT(("error %s skipping forward\n", strerror(errno)));
return;
}
sCDDevice.StartFastFwd();
}
void
CDEngine::StopSkipping()
{
// stop skipping
CDState state = playState.GetState();
if (state == kNoCD)
return;
scsi_scan scan;
scan.direction = 0;
scan.speed = 1;
status_t result = ioctl(devicefd, B_SCSI_SCAN, &scan);
if (result != B_NO_ERROR) {
PRINT(("error %s in stop skipping\n", strerror(errno)));
return;
}
result = ioctl(devicefd, B_SCSI_RESUME_AUDIO);
if (result != B_NO_ERROR) {
PRINT(("error %s resuming\n", strerror(errno)));
return;
}
sCDDevice.StopFastFwd();
}
void
CDEngine::SelectTrack(int32 trackNumber)
{
// go to a selected track
if (playState.GetState() == kNoCD)
return;
scsi_play_track track;
track.start_track = trackNumber;
track.start_index = 1;
track.end_track = 99;
track.end_index = 1;
status_t result = ioctl(devicefd, B_SCSI_PLAY_TRACK, &track);
if (result != B_NO_ERROR) {
PRINT(("error %s playing track\n", strerror(errno)));
return;
}
sCDDevice.Play(trackNumber);
}
void
CDEngine::SetVolume(uint8 value)
{
scsi_volume vol;
// change only port0's volume
vol.flags=2;
vol.port0_volume=value;
ioctl(devicefd,B_SCSI_SET_VOLUME,&vol);
sCDDevice.SetVolume(value);
}
void
CDEngine::ToggleShuffle(void)
{
if(sPlayList.IsShuffled())
{
// If already in random mode, we will play to the end of the cd
int16 track = sPlayList.GetCurrentTrack();
sPlayList.SetShuffle(false);
sPlayList.SetStartingTrack(track);
sPlayList.SetTrackCount(sCDDevice.CountTracks());
}
else
{
// Not shuffled, so we will play the entire CD and randomly pick
sPlayList.SetTrackCount(sCDDevice.CountTracks());
sPlayList.SetShuffle(true);
}
}
void
CDEngine::ToggleRepeat(void)
{
if(sPlayList.IsLoop())
sPlayList.SetLoop(false);
else
sPlayList.SetLoop(true);
}
void
CDEngine::DoPulse()
{
@ -605,75 +419,8 @@ CDEngine::DoPulse()
void
CDEngine::MessageReceived(BMessage *message)
{
if (message->what == 'slTk') {
// handle message from menu selection
int32 track;
if (message->FindInt32("track", &track) == B_OK)
SelectTrack(track);
} else
// handle observing
if (!Notifier::HandleObservingMessages(message)
&& !CDEngineFunctorFactory::DispatchIfFunctionObject(message))
// handle observing
if (!Notifier::HandleObservingMessages(message) &&
!CDEngineFunctorFactory::DispatchIfFunctionObject(message))
BHandler::MessageReceived(message);
}
static int
try_dir(const char *directory)
{
BDirectory dir;
dir.SetTo(directory);
if(dir.InitCheck() != B_NO_ERROR) {
return false;
}
dir.Rewind();
BEntry entry;
while(dir.GetNextEntry(&entry) >= 0) {
BPath path;
const char *name;
entry_ref e;
if(entry.GetPath(&path) != B_NO_ERROR)
continue;
name = path.Path();
if(entry.GetRef(&e) != B_NO_ERROR)
continue;
if(entry.IsDirectory()) {
if(strcmp(e.name, "floppy") == 0)
continue; // ignore floppy (it is not silent)
int devfd = try_dir(name);
if(devfd >= 0)
return devfd;
}
else {
int devfd;
device_geometry g;
if(strcmp(e.name, "raw") != 0)
continue; // ignore partitions
devfd = open(name, O_RDONLY);
if(devfd < 0)
continue;
if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
if(g.device_type == B_CD)
{
return devfd;
}
}
close(devfd);
}
}
return B_ERROR;
}
int
CDEngine::FindCDPlayerDevice()
{
return try_dir("/dev/disk");
}

View File

@ -15,222 +15,209 @@
#include <vector>
#include "CDAudioDevice.h"
#include "Observer.h"
#include "FunctionObjectMessage.h"
#include "CDDBSupport.h"
#include "PlayList.h"
class CDEngine;
class PeriodicWatcher : public Notifier {
// watcher sits somewhere were it can get pulses and makes sure
// notices get sent if state changes
class PeriodicWatcher : public Notifier
{
public:
PeriodicWatcher(int devicefd);
PeriodicWatcher(BMessage *);
virtual ~PeriodicWatcher() {}
PeriodicWatcher(void);
virtual ~PeriodicWatcher() {}
void DoPulse();
void UpdateNow();
void AttachedToLooper(CDEngine *engine)
{ this->engine = engine; }
virtual BHandler *RecipientHandler() const;
void DoPulse();
void UpdateNow();
void AttachedToLooper(CDEngine *engine)
{ this->engine = engine; }
virtual BHandler *RecipientHandler() const;
protected:
virtual bool UpdateState() = 0;
virtual bool UpdateState() = 0;
int devicefd;
CDEngine *engine;
CDEngine *engine;
};
enum CDState {
kNoCD=0,
kStopped,
kPaused,
kPlaying,
kSkipping
};
class PlayState : public PeriodicWatcher {
// this watcher sends notices to observers that are interrested
// about play state changes
// this watcher sends notices to observers that are interrested
// about play state changes
class PlayState : public PeriodicWatcher
{
public:
PlayState(int devicefd);
PlayState(BMessage *message)
: PeriodicWatcher(message)
{}
PlayState(CDEngine *engine);
CDState GetState() const;
CDState GetState() const;
private:
bool UpdateState();
bool CurrentState(CDState);
CDState oldState;
bool UpdateState();
bool CurrentState(CDState);
CDState oldState;
CDEngine *fEngine;
};
class TrackState : public PeriodicWatcher {
// this watcher sends notices to observers that are interested
// about changes in the current track
// this watcher sends notices to observers that are interested
// about changes in the current track
class TrackState : public PeriodicWatcher
{
public:
TrackState(int devicefd);
TrackState(BMessage *message)
: PeriodicWatcher(message)
{}
TrackState(void);
int32 GetTrack() const;
int32 GetNumTracks() const;
int32 GetTrack() const;
int32 GetNumTracks() const;
private:
bool UpdateState();
bool CurrentState(int32);
int32 currentTrack;
bool UpdateState();
bool CurrentState(int32);
int32 currentTrack;
};
class TimeState : public PeriodicWatcher {
// this watcher sends notices to observers that are interested
// about changes in the current time
// this watcher sends notices to observers that are interested
// about changes in the current time
class TimeState : public PeriodicWatcher
{
public:
TimeState(int devicefd)
: PeriodicWatcher(devicefd)
{ }
TimeState(BMessage *message)
: PeriodicWatcher(message)
{}
TimeState(void) : PeriodicWatcher() { }
void GetDiscTime(int32 &minutes, int32 &seconds) const;
void GetTrackTime(int32 &minutes, int32 &seconds) const;
void GetDiscTime(int32 &minutes, int32 &seconds) const;
void GetTrackTime(int32 &minutes, int32 &seconds) const;
private:
bool UpdateState();
bool CurrentState(int32 dmin, int32 dsec, int32 tmin, int32 tsec);
bool UpdateState();
bool CurrentState(int32 dmin, int32 dsec, int32 tmin, int32 tsec);
int32 fDiscMinutes;
int32 fDiscSeconds;
int32 fDiscMinutes;
int32 fDiscSeconds;
int32 fTrackMinutes;
int32 fTrackSeconds;
int32 fTrackMinutes;
int32 fTrackSeconds;
};
class CDContentWatcher : public PeriodicWatcher {
class CDContentWatcher : public PeriodicWatcher
{
public:
CDContentWatcher(int devicefd);
CDContentWatcher(BMessage *message);
CDContentWatcher(void);
bool GetContent(BString *title, vector<BString> *tracks);
bool GetContent(BString *title, vector<BString> *tracks);
private:
bool UpdateState();
bool UpdateState();
CDDBQuery cddbQuery;
int32 discID;
bool fReady;
CDDBQuery cddbQuery;
int32 discID;
bool fReady;
};
class VolumeState : public PeriodicWatcher {
// this watcher sends notices to observers that are interested
// about changes in the current volume
// currently not used yet
// this watcher sends notices to observers that are interested
// about changes in the current volume
// currently not used yet
class VolumeState : public PeriodicWatcher
{
public:
VolumeState(int devicefd);
VolumeState(BMessage *message)
: PeriodicWatcher(message)
{}
bool UpdateState();
int32 GetVolume() const;
VolumeState(void);
bool UpdateState();
int32 GetVolume() const;
private:
int32 fVolume;
int32 fVolume;
};
class CDEngine : public BHandler {
// The CD engine defines all the different CD control calls; also,
// it hosts the different state watchers and helps them send notices
// to observers about the CD state changes
// The CD engine defines all the different CD control calls; also,
// it hosts the different state watchers and helps them send notices
// to observers about the CD state changes
class CDEngine : public BHandler
{
public:
CDEngine(int devicefd);
CDEngine(BMessage *);
CDEngine(void);
virtual ~CDEngine();
virtual ~CDEngine();
// observing supprt
virtual void MessageReceived(BMessage *);
void AttachedToLooper(BLooper *);
void DoPulse();
// observing support
virtual void MessageReceived(BMessage *);
void AttachedToLooper(BLooper *);
void DoPulse();
// control calls
void PlayOrPause();
void PlayContinue();
void Play();
void Pause();
void Stop();
void Eject();
void SkipOneForward();
void SkipOneBackward();
void StartSkippingBackward();
void StartSkippingForward();
void StopSkipping();
void SelectTrack(int32);
// control calls
void Play();
void Pause();
void Stop();
void Eject();
void SkipOneForward();
void SkipOneBackward();
void StartSkippingBackward();
void StartSkippingForward();
void StopSkipping();
void SelectTrack(int32);
void SetVolume(uint8 value);
void ToggleShuffle(void);
void ToggleRepeat(void);
void SetVolume(uint8 value);
CDState GetState(void) const { return fEngineState; }
// to find the current Track, you may call the GetTrack function
// TrackState defines
TrackState *TrackStateWatcher()
{ return &trackState; }
// to find the current Track, you may call the GetTrack function
// TrackState defines
// to find the current play state, you may call the GetState function
// PlayState defines
PlayState *PlayStateWatcher()
{ return &playState; }
// to find the current play state, you may call the GetState function
// PlayState defines
// to find the current location on the CD, you may call the GetTime function
// TimeState defines
TimeState *TimeStateWatcher()
{ return &timeState; }
// to find the current location on the CD, you may call the GetTime function
// TimeState defines
CDContentWatcher *ContentWatcher()
{ return &contentWatcher; }
// to find the current location on the CD, you may call the GetVolume function
// VolumeState defines
VolumeState *VolumeStateWatcher()
// to find the current location on the CD, you may call the GetVolume function
// VolumeState defines
{ return &volumeState; }
static int FindCDPlayerDevice();
private:
int devicefd;
PlayState playState;
TrackState trackState;
TimeState timeState;
VolumeState volumeState;
CDContentWatcher contentWatcher;
PlayState playState;
TrackState trackState;
TimeState timeState;
VolumeState volumeState;
CDContentWatcher contentWatcher;
bigtime_t lastPulse;
bigtime_t lastPulse;
CDState fEngineState;
};
// some function object glue
class CDEngineFunctorFactory : public FunctorFactoryCommon {
class CDEngineFunctorFactory : public FunctorFactoryCommon
{
public:
static BMessage *NewFunctorMessage(void (CDEngine::*func)(),
CDEngine *target)
{
PlainMemberFunctionObject<void (CDEngine::*)(),
CDEngine> tmp(func, target);
return NewMessage(&tmp);
}
CDEngine *target)
{
PlainMemberFunctionObject<void (CDEngine::*)(),
CDEngine> tmp(func, target);
return NewMessage(&tmp);
}
static BMessage *NewFunctorMessage(void (CDEngine::*func)(ulong),
CDEngine *target, ulong param)
{
SingleParamMemberFunctionObject<void (CDEngine::*)(ulong),
CDEngine, ulong> tmp(func, target, param);
return NewMessage(&tmp);
}
CDEngine *target, ulong param)
{
SingleParamMemberFunctionObject<void (CDEngine::*)(ulong),
CDEngine, ulong> tmp(func, target, param);
return NewMessage(&tmp);
}
};

View File

@ -21,7 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include "CDButton.h"
#include "CDPlayer.h"
#include "DrawButton.h"
#include "TwoStateDrawButton.h"
#include <TranslationUtils.h>
@ -45,13 +45,13 @@ enum
M_SET_CD_TITLE
};
CDButton::CDButton(BRect frame, const char *name, uint32 resizeMask, uint32 flags)
CDPlayer::CDPlayer(BRect frame, const char *name, uint32 resizeMask, uint32 flags)
: BView(frame, name, resizeMask, flags | B_FRAME_EVENTS)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
// TODO: Support multiple CD drives
engine = new CDEngine(CDEngine::FindCDPlayerDevice());
engine = new CDEngine;
BuildGUI();
@ -66,18 +66,29 @@ CDButton::CDButton(BRect frame, const char *name, uint32 resizeMask, uint32 flag
fFastFwd->SetEnabled(false);
fRewind->SetEnabled(false);
fSave->SetEnabled(false);
fCurrentTrack->SetHighColor(fStopColor);
}
}
CDButton::~CDButton()
CDPlayer::~CDPlayer()
{
engine->Stop();
delete engine;
}
void CDButton::BuildGUI(void)
void CDPlayer::BuildGUI(void)
{
fStopColor.red = 80;
fStopColor.green = 164;
fStopColor.blue = 80;
fStopColor.alpha = 255;
fPlayColor.red = 40;
fPlayColor.green = 230;
fPlayColor.blue = 40;
fPlayColor.alpha = 255;
BRect r(5,5,230,25);
// Assemble the CD Title box
@ -88,7 +99,7 @@ void CDButton::BuildGUI(void)
view->SetViewColor(20,20,20);
fCDBox->AddChild(view);
fCDTitle = new BStringView(view->Bounds(),"CDTitle","");
fCDTitle = new BStringView(view->Bounds(),"CDTitle","", B_FOLLOW_ALL);
view->AddChild(fCDTitle);
fCDTitle->SetHighColor(200,200,200);
fCDTitle->SetFont(be_bold_font);
@ -103,7 +114,7 @@ void CDButton::BuildGUI(void)
fCurrentTrack = new BStringView( view->Bounds(),"TrackNumber","Track:",B_FOLLOW_ALL);
view->AddChild(fCurrentTrack);
fCurrentTrack->SetHighColor(40,230,40);
fCurrentTrack->SetHighColor(fPlayColor);
fCurrentTrack->SetFont(be_bold_font);
r.OffsetBy(0, r.Height() + 5);
@ -142,7 +153,6 @@ void CDButton::BuildGUI(void)
fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_disabled"));
AddChild(fStop);
// TODO: Play is a special button. Implement as two-state buttons
fPlay = new DrawButton( BRect(0,0,1,1), "Play", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"),
new BMessage(M_PLAY), B_FOLLOW_BOTTOM, B_WILL_DRAW);
@ -201,29 +211,30 @@ void CDButton::BuildGUI(void)
AddChild(fSave);
fSave->SetEnabled(false);
// TODO: Shuffle and Repeat are special buttons. Implement as two-state buttons
fShuffle = new DrawButton( BRect(0,0,1,1), "Shuffle", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_down"), new BMessage(M_SHUFFLE),
B_FOLLOW_NONE, B_WILL_DRAW);
fShuffle = new TwoStateDrawButton( BRect(0,0,1,1), "Shuffle",
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_down"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up_on"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_down_on"),
new BMessage(M_SHUFFLE), B_FOLLOW_NONE, B_WILL_DRAW);
fShuffle->ResizeToPreferred();
fShuffle->MoveTo(fSave->Frame().right + 2, Bounds().bottom - 5 - fShuffle->Frame().Height());
fShuffle->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_disabled"));
AddChild(fShuffle);
fShuffle->SetEnabled(false);
fRepeat = new DrawButton( BRect(0,0,1,1), "Repeat", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_down"), new BMessage(M_REPEAT),
B_FOLLOW_NONE, B_WILL_DRAW);
fRepeat = new TwoStateDrawButton( BRect(0,0,1,1), "Repeat",
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_down"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up_on"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_down_on"),
new BMessage(M_REPEAT), B_FOLLOW_NONE, B_WILL_DRAW);
fRepeat->ResizeToPreferred();
fRepeat->MoveTo(fShuffle->Frame().right + 2, Bounds().bottom - 5 - fRepeat->Frame().Height());
fRepeat->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_disabled"));
AddChild(fRepeat);
fRepeat->SetEnabled(false);
}
void
CDButton::MessageReceived(BMessage *msg)
CDPlayer::MessageReceived(BMessage *msg)
{
if(msg->WasDropped())
{
@ -292,7 +303,7 @@ CDButton::MessageReceived(BMessage *msg)
}
case M_STOP:
{
if(engine->PlayStateWatcher()->GetState()==kPlaying)
if(engine->GetState()==kPlaying)
{
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"));
@ -304,7 +315,7 @@ CDButton::MessageReceived(BMessage *msg)
{
// If we are currently playing, then we will be showing
// the pause images and will want to switch back to the play images
if(engine->PlayStateWatcher()->GetState()==kPlaying)
if(engine->GetState()==kPlaying)
{
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"));
@ -315,7 +326,7 @@ CDButton::MessageReceived(BMessage *msg)
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"pause_up"),
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"pause_down"));
}
engine->PlayOrPause();
engine->Play();
break;
}
case M_NEXT_TRACK:
@ -350,12 +361,12 @@ CDButton::MessageReceived(BMessage *msg)
}
case M_SHUFFLE:
{
// TODO: Implement
engine->ToggleShuffle();
break;
}
case M_REPEAT:
{
// TODO: Implement
engine->ToggleRepeat();
break;
}
default:
@ -372,7 +383,7 @@ CDButton::MessageReceived(BMessage *msg)
}
void
CDButton::NoticeChange(Notifier *notifier)
CDPlayer::NoticeChange(Notifier *notifier)
{
PlayState *ps;
TrackState *trs;
@ -402,10 +413,10 @@ CDButton::NoticeChange(Notifier *notifier)
fRewind->SetEnabled(false);
fSave->SetEnabled(false);
}
fCurrentTrack->SetHighColor(fStopColor);
fCurrentTrack->SetText("Track: ");
fTrackTime->SetText("Track --:-- / --:--");
fDiscTime->SetText("Disc --:-- / --:--");
printf("Notification: No CD\n");
break;
}
case kStopped:
@ -418,12 +429,14 @@ CDButton::NoticeChange(Notifier *notifier)
fPrevTrack->SetEnabled(true);
fFastFwd->SetEnabled(true);
fRewind->SetEnabled(true);
fSave->SetEnabled(true);
// TODO: Enable when Save is implemented
// fSave->SetEnabled(true);
}
fCurrentTrack->SetText("Track: ");
fCurrentTrack->SetHighColor(fStopColor);
fCurrentTrack->Invalidate();
fTrackTime->SetText("Track --:-- / --:--");
fDiscTime->SetText("Disc --:-- / --:--");
printf("Notification: CD Stopped\n");
break;
}
case kPaused:
@ -437,9 +450,11 @@ CDButton::NoticeChange(Notifier *notifier)
fPrevTrack->SetEnabled(true);
fFastFwd->SetEnabled(true);
fRewind->SetEnabled(true);
fSave->SetEnabled(true);
// TODO: Enable when Save is implemented
// fSave->SetEnabled(true);
}
printf("Notification: CD Paused\n");
fCurrentTrack->SetHighColor(fPlayColor);
break;
}
case kPlaying:
@ -452,9 +467,12 @@ CDButton::NoticeChange(Notifier *notifier)
fPrevTrack->SetEnabled(true);
fFastFwd->SetEnabled(true);
fRewind->SetEnabled(true);
fSave->SetEnabled(true);
// TODO: Enable when Save is implemented
// fSave->SetEnabled(true);
}
printf("Notification: CD Playing\n");
fCurrentTrack->SetHighColor(fPlayColor);
fCurrentTrack->Invalidate();
break;
}
case kSkipping:
@ -467,9 +485,11 @@ CDButton::NoticeChange(Notifier *notifier)
fPrevTrack->SetEnabled(true);
fFastFwd->SetEnabled(true);
fRewind->SetEnabled(true);
fSave->SetEnabled(true);
// TODO: Enable when Save is implemented
// fSave->SetEnabled(true);
}
printf("Notification: CD Skipping\n");
fCurrentTrack->SetHighColor(fStopColor);
break;
}
default:
@ -502,7 +522,7 @@ CDButton::NoticeChange(Notifier *notifier)
}
void
CDButton::UpdateCDInfo(void)
CDPlayer::UpdateCDInfo(void)
{
BString CDName, currentTrackName;
vector<BString> trackNames;
@ -525,7 +545,7 @@ CDButton::UpdateCDInfo(void)
}
void
CDButton::UpdateTimeInfo(void)
CDPlayer::UpdateTimeInfo(void)
{
int32 min,sec;
char string[1024];
@ -546,7 +566,7 @@ CDButton::UpdateTimeInfo(void)
}
void
CDButton::AttachedToWindow()
CDPlayer::AttachedToWindow()
{
// start observing
engine->AttachedToLooper(Window());
@ -570,7 +590,7 @@ CDButton::AttachedToWindow()
}
void
CDButton::FrameResized(float new_width, float new_height)
CDPlayer::FrameResized(float new_width, float new_height)
{
// We implement this method because there is no resizing mode to split the window's
// width into two and have a box fill each half
@ -595,13 +615,13 @@ CDButton::FrameResized(float new_width, float new_height)
}
void
CDButton::Pulse()
CDPlayer::Pulse()
{
engine->DoPulse();
}
void
CDButton::SetBitmap(BBitmap *bitmap)
CDPlayer::SetBitmap(BBitmap *bitmap)
{
if(!bitmap)
{
@ -615,14 +635,14 @@ CDButton::SetBitmap(BBitmap *bitmap)
Invalidate();
}
class CDButtonWindow : public BWindow
class CDPlayerWindow : public BWindow
{
public:
CDButtonWindow(void);
CDPlayerWindow(void);
bool QuitRequested(void);
};
CDButtonWindow::CDButtonWindow(void)
CDPlayerWindow::CDPlayerWindow(void)
: BWindow(BRect (100, 100, 610, 200), "CD Player", B_TITLED_WINDOW, B_NOT_V_RESIZABLE |
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
{
@ -634,17 +654,17 @@ CDButtonWindow::CDButtonWindow(void)
SetSizeLimits(wmin,wmax,hmin,hmax);
}
bool CDButtonWindow::QuitRequested(void)
bool CDPlayerWindow::QuitRequested(void)
{
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
CDButtonApplication::CDButtonApplication()
CDPlayerApplication::CDPlayerApplication()
: BApplication("application/x-vnd.Haiku-CDPlayer")
{
BWindow *window = new CDButtonWindow();
BView *button = new CDButton(window->Bounds(), "CD");
BWindow *window = new CDPlayerWindow();
BView *button = new CDPlayer(window->Bounds(), "CD");
window->AddChild(button);
window->Show();
}
@ -652,7 +672,7 @@ CDButtonApplication::CDButtonApplication()
int
main(int, char **argv)
{
(new CDButtonApplication())->Run();
(new CDPlayerApplication())->Run();
return 0;
}

View File

@ -4,8 +4,8 @@
*/
// This defines the replicant button
#ifndef __CD_BUTTON__
#define __CD_BUTTON__
#ifndef CDPLAYER_H
#define CDPLAYER_H
#include <Application.h>
#include <View.h>
@ -16,21 +16,20 @@
#include <TextControl.h>
#include <StringView.h>
#include "PlayList.h"
#include "Observer.h"
#include "CDEngine.h"
class DrawButton;
class TwoStateDrawButton;
class CDButton : public BView, private Observer
class CDPlayer : public BView, private Observer
{
public:
CDButton(BRect frame, const char *name,
CDPlayer(BRect frame, const char *name,
uint32 resizeMask = B_FOLLOW_ALL,
uint32 flags = B_WILL_DRAW | B_NAVIGABLE |
B_PULSE_NEEDED);
virtual ~CDButton();
virtual ~CDPlayer();
void BuildGUI(void);
@ -46,36 +45,46 @@ public:
virtual void NoticeChange(Notifier *);
private:
void UpdateCDInfo(void);
void UpdateTimeInfo(void);
void SetBitmap(BBitmap *bitmap);
void UpdateCDInfo(void);
void UpdateTimeInfo(void);
void SetBitmap(BBitmap *bitmap);
CDEngine *engine;
CDEngine *engine;
DrawButton *fStop, *fPlay, *fNextTrack, *fPrevTrack;
DrawButton *fFastFwd, *fRewind, *fEject, *fSave, *fShuffle, *fRepeat;
BSlider *fVolume;
BStringView *fCDTitle;
BStringView *fCurrentTrack;
BStringView *fTrackTime;
BStringView *fDiscTime;
BBox *fCDBox;
BBox *fTrackBox;
BBox *fTimeBox;
CDState fCDState;
PlayList fPlaylist;
DrawButton *fStop,
*fPlay,
*fNextTrack,
*fPrevTrack,
*fFastFwd,
*fRewind,
*fEject,
*fSave;
TwoStateDrawButton *fShuffle,
*fRepeat;
BSlider *fVolume;
BStringView *fCDTitle,
*fCurrentTrack,
*fTrackTime,
*fDiscTime;
BBox *fCDBox,
*fTrackBox,
*fTimeBox;
CDState fCDState;
rgb_color fStopColor;
rgb_color fPlayColor;
};
class CDButtonApplication : public BApplication
class CDPlayerApplication : public BApplication
{
public:
CDButtonApplication();
CDPlayerApplication();
};

View File

@ -2,9 +2,10 @@ SubDir OBOS_TOP src apps cdplayer ;
AddResources CDPlayer : CDPlayer.rdef ;
App CDPlayer :
CDButton.cpp
CDAudioDevice.cpp
CDDBSupport.cpp
CDEngine.cpp
CDPlayer.cpp
DrawButton.cpp
FunctionObjectMessage.cpp
Observer.cpp

View File

@ -3,20 +3,36 @@
#include <stdlib.h>
#include <string.h>
PlayList::PlayList(int16 tracks)
: fTrackCount(0),
PlayList::PlayList(int16 count, int16 start)
: fTrackCount(count),
fTrackIndex(0),
fStartingTrack(start),
fRandom(false),
fLoop(false)
{
srand(real_time_clock_usecs());
SetTrackCount(tracks);
if(fTrackCount < 0)
fTrackCount = 0;
else
if(fTrackCount > 500)
fTrackCount = 500;
if(fStartingTrack >= fTrackCount)
fStartingTrack = fTrackCount - 1;
if(fStartingTrack < 1)
fStartingTrack = 1;
memset(fTrackList,-1,500);
Unrandomize();
}
void
PlayList::SetTrackCount(const int16 &count)
{
fLocker.Lock();
if(count < 0)
fTrackCount = 0;
else
@ -27,57 +43,140 @@ PlayList::SetTrackCount(const int16 &count)
memset(fTrackList,-1,500);
SetShuffle(IsShuffled());
fLocker.Unlock();
}
void
PlayList::SetStartingTrack(const int16 &start)
{
fLocker.Lock();
if(start >= TrackCount())
fStartingTrack = TrackCount() - 1;
else
if(start < 1)
fStartingTrack = 1;
else
fStartingTrack = start;
fLocker.Unlock();
}
void
PlayList::Rewind(void)
{
fLocker.Lock();
fTrackIndex = 0;
fLocker.Unlock();
}
void
PlayList::SetShuffle(const bool &random)
{
fLocker.Lock();
if(random)
Randomize();
else
Unrandomize();
fLocker.Unlock();
}
void
PlayList::SetLoop(const bool &loop)
{
fLocker.Lock();
fLoop = loop;
fLocker.Unlock();
}
int16
PlayList::GetCurrentTrack(void)
{
fLocker.Lock();
int16 value = fTrackList[fTrackIndex];
fLocker.Unlock();
return value;
}
int16
PlayList::GetNextTrack(void)
{
if(fTrackCount < 1)
return -1;
fLocker.Lock();
if(fTrackIndex == fTrackCount)
if(fTrackCount < 1)
{
fLocker.Unlock();
return -1;
}
if(fTrackIndex > (fTrackCount - fStartingTrack))
{
if(fLoop)
fTrackIndex = 0;
else
{
fLocker.Unlock();
return -1;
}
}
else
fTrackIndex++;
int16 value = fTrackList[fTrackIndex];
fLocker.Unlock();
return value;
}
int16
PlayList::GetPreviousTrack(void)
{
fLocker.Lock();
if(fTrackCount < 1)
{
fLocker.Unlock();
return -1;
}
return fTrackList[fTrackIndex++];
if(fTrackIndex == 0)
{
if(fLoop)
fTrackIndex = (fTrackCount - fStartingTrack);
else
{
fLocker.Unlock();
return -1;
}
}
else
fTrackIndex--;
int16 value = fTrackList[fTrackIndex];
fLocker.Unlock();
return value;
}
void
PlayList::Randomize(void)
{
// Reinitialize the count
for(int16 i=0; i<fTrackCount; i++)
fTrackList[i] = i;
for(int16 i=fStartingTrack; i<=fTrackCount; i++)
fTrackList[i - fStartingTrack] = i;
// There are probably *much* better ways to do this,
// but this is the only one I could think of. :(
int32 swapcount = fTrackCount * 2;
int32 listcount = (fTrackCount - fStartingTrack);
int32 swapcount = listcount* 2;
int16 temp, first, second;
for(int32 i=0; i< swapcount; i++)
@ -86,8 +185,8 @@ PlayList::Randomize(void)
// This way we are sure to not have any duplicates and still have
// all tracks eventually be played.
first = (int16)(fTrackCount * ((float)rand()/RAND_MAX));
second = (int16)(fTrackCount * ((float)rand()/RAND_MAX));
first = (int16)(listcount * ((float)rand()/RAND_MAX));
second = (int16)(listcount * ((float)rand()/RAND_MAX));
temp = fTrackList[first];
fTrackList[first] = fTrackList[second];
@ -98,7 +197,7 @@ PlayList::Randomize(void)
void
PlayList::Unrandomize(void)
{
for(int16 i=0; i<fTrackCount; i++)
fTrackList[i] = i;
for(int16 i=fStartingTrack; i<=fTrackCount; i++)
fTrackList[i - fStartingTrack] = i;
}

View File

@ -2,15 +2,19 @@
#define PLAYLIST_H
#include <SupportDefs.h>
#include <Locker.h>
class PlayList
{
public:
PlayList(int16 tracks = 0);
PlayList(int16 tracks = 0, int16 startingtrack = 1);
void SetTrackCount(const int16 &count);
int16 TrackCount(void) const { return fTrackCount; }
void SetStartingTrack(const int16 &start);
int16 StartingTrack(void) const { return fStartingTrack; }
void Rewind(void);
void SetShuffle(const bool &random);
@ -19,7 +23,9 @@ public:
void SetLoop(const bool &loop);
bool IsLoop(void) const { return fLoop; }
int16 GetCurrentTrack(void);
int16 GetNextTrack(void);
int16 GetPreviousTrack(void);
private:
void Randomize(void);
@ -27,12 +33,13 @@ private:
int16 fTrackCount;
int16 fTrackIndex;
int16 fStartingTrack;
int16 fTrackList[500]; // This should be big enough. :)
bool fRandom;
bool fLoop;
BLocker fLocker;
};
#endif

View File

@ -25,6 +25,8 @@ public:
void MouseUp(BPoint pt);
// void MessageReceived(BMessage *msg);
int32 GetState(void) { return fButtonState ? 1 : 0; };
private:
BBitmap *fUpOne,