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:
@@ -76,18 +76,38 @@ CDDBQuery::SetToSite(const char *server, int32 port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDDBQuery::SetToCD(const scsi_toc *toc)
|
CDDBQuery::SetToCD(const char *path)
|
||||||
{
|
{
|
||||||
if (state == kInitial) {
|
if(!path)
|
||||||
GetDiscID(toc, discID, numTracks, discLength, frameOffsetString, discIDStr);
|
return;
|
||||||
} else {
|
|
||||||
|
// 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 tmpDiscID;
|
||||||
int32 tmpDiscLength;
|
int32 tmpDiscLength;
|
||||||
int32 tmpNumTracks;
|
int32 tmpNumTracks;
|
||||||
BString tmpFrameOffsetString;
|
BString tmpFrameOffsetString;
|
||||||
BString tmpDiscIDStr;
|
BString tmpDiscIDStr;
|
||||||
|
|
||||||
GetDiscID(toc, tmpDiscID, tmpNumTracks, tmpDiscLength, tmpFrameOffsetString,
|
GetDiscID(&toc, tmpDiscID, tmpNumTracks, tmpDiscLength, tmpFrameOffsetString,
|
||||||
tmpDiscIDStr);
|
tmpDiscIDStr);
|
||||||
|
|
||||||
if (discID == tmpDiscID && discLength == tmpDiscLength && numTracks == tmpNumTracks
|
if (discID == tmpDiscID && discLength == tmpDiscLength && numTracks == tmpNumTracks
|
||||||
@@ -343,8 +363,10 @@ CDDBQuery::ReadFromServer(BDataIO *stream)
|
|||||||
BString tmp;
|
BString tmp;
|
||||||
ReadLine(tmp);
|
ReadLine(tmp);
|
||||||
if (tmp.FindFirst("200") != 0)
|
if (tmp.FindFirst("200") != 0)
|
||||||
|
{
|
||||||
|
printf("Error: %s\n",tmp.String());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
BString category;
|
BString category;
|
||||||
GetToken(tmp.String() + 3, category);
|
GetToken(tmp.String() + 3, category);
|
||||||
if (!category.Length())
|
if (!category.Length())
|
||||||
@@ -474,7 +496,7 @@ CDDBQuery::IdentifySelf()
|
|||||||
strcpy(hostname, "unknown");
|
strcpy(hostname, "unknown");
|
||||||
|
|
||||||
BString tmp;
|
BString tmp;
|
||||||
tmp << "cddb hello " << username << " " << hostname << " CDButton v1.0\n";
|
tmp << "cddb hello " << username << " " << hostname << " Haiku_CD_Player v1.0\n";
|
||||||
|
|
||||||
if (log)
|
if (log)
|
||||||
printf(">%s", tmp.String());
|
printf(">%s", tmp.String());
|
||||||
@@ -535,7 +557,9 @@ CDDBQuery::FindOrCreateContentFileForDisk(BFile *file, entry_ref *fileRef, int32
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
/*
|
||||||
|
|
||||||
|
#include "CDEngine.h"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PrintSite(const char *site, int port, const char *latitude,
|
PrintSite(const char *site, int port, const char *latitude,
|
||||||
@@ -549,35 +573,33 @@ PrintSite(const char *site, int port, const char *latitude,
|
|||||||
int
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
try {
|
CDDBQuery query("us.freedb.org", 888, true);
|
||||||
CDDBQuery query("us.cddb.com", 888, true);
|
|
||||||
// query.GetSites(&PrintSite, NULL);
|
|
||||||
|
|
||||||
int32 device = CDEngine::FindCDPlayerDevice();
|
int32 device = CDEngine::FindCDPlayerDevice();
|
||||||
if (!device) {
|
if (!device)
|
||||||
|
{
|
||||||
printf("no device %s\n", strerror(device));
|
printf("no device %s\n", strerror(device));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
CDEngine engine(device);
|
|
||||||
scsi_toc toc;
|
scsi_toc toc;
|
||||||
engine.GetToc(&toc);
|
|
||||||
|
|
||||||
|
ioctl(device, B_SCSI_GET_TOC, &toc);
|
||||||
|
int32 discID = query.GetDiscID(&toc);
|
||||||
|
|
||||||
query.SetToCD(&toc);
|
query.SetToCD(&toc);
|
||||||
|
|
||||||
BString title;
|
BString title;
|
||||||
vector<BString> trackTitles;
|
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;
|
int32 index = 0;
|
||||||
for (vector<BString>::iterator iterator = trackTitles.begin();
|
for (vector<BString>::iterator iterator = trackTitles.begin();
|
||||||
iterator != trackTitles.end(); index++, iterator++)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
*/
|
||||||
|
|||||||
@@ -9,14 +9,15 @@
|
|||||||
|
|
||||||
// based on Jukebox by Chip Paul
|
// based on Jukebox by Chip Paul
|
||||||
|
|
||||||
class CDDBQuery {
|
class CDDBQuery
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
CDDBQuery(const char *server, int32 port = 888, bool log = false);
|
CDDBQuery(const char *server, int32 port = 888, bool log = false);
|
||||||
void SetToSite(const char *server, int32 port);
|
void SetToSite(const char *server, int32 port);
|
||||||
void GetSites(bool (*)(const char *site, int port, const char *latitude,
|
void GetSites(bool (*)(const char *site, int port, const char *latitude,
|
||||||
const char *longitude, const char *description, void *state), void *);
|
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);
|
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
|
// 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 *);
|
static int32 LookupBinder(void *);
|
||||||
|
|
||||||
class Connector {
|
class Connector
|
||||||
public:
|
{
|
||||||
Connector(CDDBQuery *client)
|
public:
|
||||||
: client(client),
|
Connector(CDDBQuery *client)
|
||||||
wasConnected(client->IsConnected())
|
: client(client),
|
||||||
{
|
wasConnected(client->IsConnected())
|
||||||
if (!wasConnected)
|
{
|
||||||
client->Connect();
|
if (!wasConnected)
|
||||||
}
|
client->Connect();
|
||||||
|
}
|
||||||
~Connector()
|
|
||||||
{
|
|
||||||
if (!wasConnected)
|
|
||||||
client->Disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
~Connector()
|
||||||
CDDBQuery *client;
|
{
|
||||||
bool wasConnected;
|
if (!wasConnected)
|
||||||
|
client->Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CDDBQuery *client;
|
||||||
|
bool wasConnected;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool FindOrCreateContentFileForDisk(BFile *file, entry_ref *ref, int32 discID);
|
bool FindOrCreateContentFileForDisk(BFile *file, entry_ref *ref, int32 discID);
|
||||||
@@ -87,7 +89,8 @@ private:
|
|||||||
BString discIDStr;
|
BString discIDStr;
|
||||||
|
|
||||||
// cached retrieved data
|
// cached retrieved data
|
||||||
enum State {
|
enum State
|
||||||
|
{
|
||||||
kInitial,
|
kInitial,
|
||||||
kReading,
|
kReading,
|
||||||
kDone,
|
kDone,
|
||||||
|
|||||||
+121
-374
@@ -14,23 +14,18 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "scsi.h"
|
#include "scsi.h"
|
||||||
#include "CDEngine.h"
|
#include "CDEngine.h"
|
||||||
|
#include "PlayList.h"
|
||||||
|
|
||||||
|
static PlayList sPlayList;
|
||||||
|
static CDAudioDevice sCDDevice;
|
||||||
|
|
||||||
const bigtime_t kPulseRate = 500000;
|
const bigtime_t kPulseRate = 500000;
|
||||||
|
|
||||||
PeriodicWatcher::PeriodicWatcher(int devicefd)
|
PeriodicWatcher::PeriodicWatcher(void)
|
||||||
: Notifier(),
|
|
||||||
devicefd(devicefd)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PeriodicWatcher::PeriodicWatcher(BMessage *)
|
|
||||||
: devicefd(-1)
|
|
||||||
{
|
|
||||||
// not implemented yet
|
|
||||||
PRINT(("under construction"));
|
|
||||||
}
|
|
||||||
|
|
||||||
BHandler *
|
BHandler *
|
||||||
PeriodicWatcher::RecipientHandler() const
|
PeriodicWatcher::RecipientHandler() const
|
||||||
{
|
{
|
||||||
@@ -52,34 +47,29 @@ PeriodicWatcher::UpdateNow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PlayState::PlayState(int devicefd)
|
PlayState::PlayState(CDEngine *engine)
|
||||||
: PeriodicWatcher(devicefd),
|
: oldState(kNoCD),
|
||||||
oldState(kNoCD)
|
fEngine(engine)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PlayState::UpdateState()
|
PlayState::UpdateState(void)
|
||||||
{
|
{
|
||||||
// check the current CD play state and force a notification to
|
CDState state = sCDDevice.GetState();
|
||||||
// be sent if it changed from last time
|
if( state == kStopped && fEngine->GetState() == kPlaying)
|
||||||
scsi_position pos;
|
{
|
||||||
status_t media_status = B_DEV_NO_MEDIA;
|
// this means we have come to the end of a song, but probably not
|
||||||
ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status));
|
// the last song in the playlist
|
||||||
if (media_status != B_NO_ERROR)
|
int16 next = sPlayList.GetNextTrack();
|
||||||
return CurrentState(kNoCD);
|
if(next > 0)
|
||||||
|
{
|
||||||
status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos);
|
sCDDevice.Play(next);
|
||||||
|
return CurrentState(kPlaying);
|
||||||
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(state);
|
||||||
return CurrentState(kStopped);
|
|
||||||
else if (pos.position[1] == 0x11)
|
|
||||||
return CurrentState(kPlaying);
|
|
||||||
else
|
|
||||||
return CurrentState(kPaused);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDState
|
CDState
|
||||||
@@ -91,16 +81,16 @@ PlayState::GetState() const
|
|||||||
bool
|
bool
|
||||||
PlayState::CurrentState(CDState newState)
|
PlayState::CurrentState(CDState newState)
|
||||||
{
|
{
|
||||||
if (newState != oldState) {
|
if (newState != oldState)
|
||||||
|
{
|
||||||
oldState = newState;
|
oldState = newState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackState::TrackState(int devicefd)
|
TrackState::TrackState(void)
|
||||||
: PeriodicWatcher(devicefd),
|
: currentTrack(0)
|
||||||
currentTrack(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,46 +103,20 @@ TrackState::GetTrack() const
|
|||||||
bool
|
bool
|
||||||
TrackState::UpdateState()
|
TrackState::UpdateState()
|
||||||
{
|
{
|
||||||
// check the current CD track number and force a notification to
|
return CurrentState(sPlayList.GetCurrentTrack());
|
||||||
// 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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
TrackState::GetNumTracks() const
|
TrackState::GetNumTracks() const
|
||||||
{
|
{
|
||||||
// get the number of tracks on the current CD
|
return sCDDevice.CountTracks();
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TrackState::CurrentState(int32 track)
|
TrackState::CurrentState(int32 track)
|
||||||
{
|
{
|
||||||
if (track != currentTrack) {
|
if (track != currentTrack)
|
||||||
|
{
|
||||||
currentTrack = track;
|
currentTrack = track;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -165,28 +129,19 @@ TimeState::UpdateState()
|
|||||||
// check the current CD time and force a notification to
|
// check the current CD time and force a notification to
|
||||||
// be sent if it changed from last time
|
// be sent if it changed from last time
|
||||||
// currently only supports global 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)
|
if(sCDDevice.GetTime(track,disc))
|
||||||
return CurrentState(-1, -1, -1, -1);
|
|
||||||
else
|
|
||||||
if ((!pos.position[1]) || (pos.position[1] >= 0x13) ||
|
|
||||||
((pos.position[1] == 0x12) && (!pos.position[6])))
|
|
||||||
{
|
{
|
||||||
// This indicates that we have a CD, but we are stopped. We *could* simply
|
return CurrentState(disc.minutes, disc.seconds, track.minutes, track.seconds);
|
||||||
// return all 0's, but because the GUI expects valid numbers or -1's, we
|
|
||||||
// return -1's.
|
|
||||||
return CurrentState(-1, -1, -1, -1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return CurrentState(pos.position[9], pos.position[10], pos.position[13], pos.position[14]);
|
{
|
||||||
|
CurrentState(-1, -1, -1, -1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -218,17 +173,8 @@ TimeState::GetTrackTime(int32 &minutes, int32 &seconds) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CDContentWatcher::CDContentWatcher(int devicefd)
|
CDContentWatcher::CDContentWatcher(void)
|
||||||
: PeriodicWatcher(devicefd),
|
: cddbQuery("us.freedb.org", 888, true),
|
||||||
cddbQuery("us.freedb.org", 888, true),
|
|
||||||
discID(-1),
|
|
||||||
fReady(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CDContentWatcher::CDContentWatcher(BMessage *message)
|
|
||||||
: PeriodicWatcher(message),
|
|
||||||
cddbQuery("us.freedb.org", 888, true),
|
|
||||||
discID(-1),
|
discID(-1),
|
||||||
fReady(false)
|
fReady(false)
|
||||||
{
|
{
|
||||||
@@ -249,15 +195,13 @@ CDContentWatcher::UpdateState()
|
|||||||
// from the old one whenever there is a CD in the drive
|
// from the old one whenever there is a CD in the drive
|
||||||
if (engine->PlayStateWatcher()->GetState() != kNoCD)
|
if (engine->PlayStateWatcher()->GetState() != kNoCD)
|
||||||
{
|
{
|
||||||
scsi_toc toc;
|
newDiscID = sCDDevice.GetDiscID();
|
||||||
ioctl(devicefd, B_SCSI_GET_TOC, &toc);
|
|
||||||
newDiscID = cddbQuery.GetDiscID(&toc);
|
|
||||||
|
|
||||||
if (discID == newDiscID)
|
if (discID == newDiscID)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We have changed CDs, so we are not ready until the CDDB lookup finishes
|
// We have changed CDs, so we are not ready until the CDDB lookup finishes
|
||||||
cddbQuery.SetToCD(&toc);
|
cddbQuery.SetToCD(sCDDevice.GetDrivePath());
|
||||||
fReady=false;
|
fReady=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,21 +218,19 @@ CDContentWatcher::UpdateState()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeState::VolumeState(int devicefd)
|
VolumeState::VolumeState(void)
|
||||||
: PeriodicWatcher(devicefd),
|
: fVolume(-1)
|
||||||
fVolume(-1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
VolumeState::UpdateState(void)
|
VolumeState::UpdateState(void)
|
||||||
{
|
{
|
||||||
scsi_volume vol;
|
uint8 volume = sCDDevice.GetVolume();
|
||||||
ioctl(devicefd, B_SCSI_GET_VOLUME, &vol);
|
if(fVolume == volume)
|
||||||
if(vol.port0_volume == fVolume)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fVolume = vol.port0_volume;
|
fVolume = volume;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,32 +240,16 @@ VolumeState::GetVolume(void) const
|
|||||||
return fVolume;
|
return fVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDEngine::CDEngine(int devicefd)
|
CDEngine::CDEngine(void)
|
||||||
: BHandler("CDEngine"),
|
: BHandler("CDEngine"),
|
||||||
devicefd(devicefd),
|
playState(this),
|
||||||
playState(devicefd),
|
fEngineState(kStopped)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
sPlayList.SetTrackCount(sCDDevice.CountTracks());
|
||||||
}
|
}
|
||||||
|
|
||||||
CDEngine::~CDEngine()
|
CDEngine::~CDEngine()
|
||||||
{
|
{
|
||||||
if(devicefd >= 0)
|
|
||||||
close(devicefd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -337,249 +263,137 @@ CDEngine::AttachedToLooper(BLooper *looper)
|
|||||||
contentWatcher.AttachedToLooper(this);
|
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
|
void
|
||||||
CDEngine::Pause()
|
CDEngine::Pause()
|
||||||
{
|
{
|
||||||
// pause the CD
|
sCDDevice.Pause();
|
||||||
status_t result = ioctl(devicefd, B_SCSI_PAUSE_AUDIO);
|
fEngineState = sCDDevice.GetState();
|
||||||
if (result != B_NO_ERROR) {
|
|
||||||
PRINT(("error %s pausing\n", strerror(errno)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::Play()
|
CDEngine::Play()
|
||||||
{
|
{
|
||||||
// play the CD
|
if(fEngineState == kPaused)
|
||||||
if (playState.GetState() == kNoCD)
|
|
||||||
{
|
{
|
||||||
// no CD available, bail out
|
sCDDevice.Resume();
|
||||||
ioctl(devicefd, B_LOAD_MEDIA, 0, 0);
|
fEngineState = sCDDevice.GetState();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
scsi_play_track track;
|
if(fEngineState == kPlaying)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
PRINT(("error %s playing track\n", strerror(errno)));
|
Pause();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
void
|
|
||||||
CDEngine::PlayContinue()
|
|
||||||
{
|
|
||||||
// continue after a pause
|
|
||||||
status_t result = ioctl(devicefd, B_SCSI_RESUME_AUDIO);
|
|
||||||
if (result != B_NO_ERROR)
|
|
||||||
{
|
{
|
||||||
PRINT(("error %s resuming\n", strerror(errno)));
|
sCDDevice.Play(sPlayList.GetCurrentTrack());
|
||||||
return;
|
fEngineState = sCDDevice.GetState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::Stop()
|
CDEngine::Stop()
|
||||||
{
|
{
|
||||||
// stop a playing CD
|
fEngineState = kStopped;
|
||||||
status_t result = ioctl(devicefd, B_SCSI_STOP_AUDIO);
|
sCDDevice.Stop();
|
||||||
if (result != B_OK)
|
|
||||||
{
|
|
||||||
PRINT(("error %s stopping\n", strerror(errno)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::Eject()
|
CDEngine::Eject()
|
||||||
{
|
{
|
||||||
// eject or load a CD
|
sCDDevice.Eject();
|
||||||
status_t media_status = B_DEV_NO_MEDIA;
|
fEngineState = sCDDevice.GetState();
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::SkipOneForward()
|
CDEngine::SkipOneForward()
|
||||||
{
|
{
|
||||||
// skip forward by one track
|
int16 track = sPlayList.GetNextTrack();
|
||||||
CDState state = playState.GetState();
|
if(track <= 0)
|
||||||
|
|
||||||
if (state == kNoCD)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool wasPaused = state == kPaused
|
CDState state = sCDDevice.GetState();
|
||||||
|| state == kStopped;
|
if(state == kPlaying)
|
||||||
|
sCDDevice.Play(track);
|
||||||
SelectTrack(trackState.GetTrack() + 1);
|
|
||||||
if (wasPaused)
|
// if(state == kPaused)
|
||||||
// make sure we don't start playing if we were paused before
|
// sCDDevice.Pause();
|
||||||
Pause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::SkipOneBackward()
|
CDEngine::SkipOneBackward()
|
||||||
{
|
{
|
||||||
// skip backward by one track
|
int16 track = sPlayList.GetPreviousTrack();
|
||||||
CDState state = playState.GetState();
|
if(track <= 0)
|
||||||
|
|
||||||
if (state == kNoCD)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool wasPaused = state == kPaused
|
|
||||||
|| state == kStopped;
|
|
||||||
|
|
||||||
int32 track = trackState.GetTrack();
|
|
||||||
|
|
||||||
if (track > 1)
|
CDState state = sCDDevice.GetState();
|
||||||
track--;
|
|
||||||
|
|
||||||
SelectTrack(track);
|
if(state == kPlaying)
|
||||||
|
sCDDevice.Play(track);
|
||||||
if (wasPaused)
|
|
||||||
// make sure we don't start playing if we were paused before
|
// if(state == kPaused)
|
||||||
Pause();
|
// sCDDevice.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::StartSkippingBackward()
|
CDEngine::StartSkippingBackward()
|
||||||
{
|
{
|
||||||
// start skipping
|
sCDDevice.StartRewind();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::StartSkippingForward()
|
CDEngine::StartSkippingForward()
|
||||||
{
|
{
|
||||||
// start skipping
|
sCDDevice.StartFastFwd();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::StopSkipping()
|
CDEngine::StopSkipping()
|
||||||
{
|
{
|
||||||
// stop skipping
|
sCDDevice.StopFastFwd();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::SelectTrack(int32 trackNumber)
|
CDEngine::SelectTrack(int32 trackNumber)
|
||||||
{
|
{
|
||||||
// go to a selected track
|
sCDDevice.Play(trackNumber);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDEngine::SetVolume(uint8 value)
|
CDEngine::SetVolume(uint8 value)
|
||||||
{
|
{
|
||||||
scsi_volume vol;
|
sCDDevice.SetVolume(value);
|
||||||
|
|
||||||
// change only port0's volume
|
|
||||||
vol.flags=2;
|
|
||||||
vol.port0_volume=value;
|
|
||||||
|
|
||||||
ioctl(devicefd,B_SCSI_SET_VOLUME,&vol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
void
|
||||||
CDEngine::DoPulse()
|
CDEngine::DoPulse()
|
||||||
{
|
{
|
||||||
@@ -605,75 +419,8 @@ CDEngine::DoPulse()
|
|||||||
void
|
void
|
||||||
CDEngine::MessageReceived(BMessage *message)
|
CDEngine::MessageReceived(BMessage *message)
|
||||||
{
|
{
|
||||||
if (message->what == 'slTk') {
|
// handle observing
|
||||||
// handle message from menu selection
|
if (!Notifier::HandleObservingMessages(message) &&
|
||||||
int32 track;
|
!CDEngineFunctorFactory::DispatchIfFunctionObject(message))
|
||||||
if (message->FindInt32("track", &track) == B_OK)
|
|
||||||
SelectTrack(track);
|
|
||||||
|
|
||||||
} else
|
|
||||||
// handle observing
|
|
||||||
if (!Notifier::HandleObservingMessages(message)
|
|
||||||
&& !CDEngineFunctorFactory::DispatchIfFunctionObject(message))
|
|
||||||
BHandler::MessageReceived(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");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+125
-138
@@ -15,222 +15,209 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "CDAudioDevice.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "FunctionObjectMessage.h"
|
#include "FunctionObjectMessage.h"
|
||||||
#include "CDDBSupport.h"
|
#include "CDDBSupport.h"
|
||||||
|
#include "PlayList.h"
|
||||||
|
|
||||||
class CDEngine;
|
class CDEngine;
|
||||||
class PeriodicWatcher : public Notifier {
|
|
||||||
// watcher sits somewhere were it can get pulses and makes sure
|
// watcher sits somewhere were it can get pulses and makes sure
|
||||||
// notices get sent if state changes
|
// notices get sent if state changes
|
||||||
|
class PeriodicWatcher : public Notifier
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
PeriodicWatcher(int devicefd);
|
PeriodicWatcher(void);
|
||||||
PeriodicWatcher(BMessage *);
|
virtual ~PeriodicWatcher() {}
|
||||||
|
|
||||||
virtual ~PeriodicWatcher() {}
|
|
||||||
|
|
||||||
void DoPulse();
|
void DoPulse();
|
||||||
void UpdateNow();
|
void UpdateNow();
|
||||||
|
|
||||||
void AttachedToLooper(CDEngine *engine)
|
void AttachedToLooper(CDEngine *engine)
|
||||||
{ this->engine = engine; }
|
{ this->engine = engine; }
|
||||||
|
virtual BHandler *RecipientHandler() const;
|
||||||
virtual BHandler *RecipientHandler() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool UpdateState() = 0;
|
virtual bool UpdateState() = 0;
|
||||||
|
|
||||||
int devicefd;
|
CDEngine *engine;
|
||||||
CDEngine *engine;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CDState {
|
// this watcher sends notices to observers that are interrested
|
||||||
kNoCD=0,
|
// about play state changes
|
||||||
kStopped,
|
class PlayState : public PeriodicWatcher
|
||||||
kPaused,
|
{
|
||||||
kPlaying,
|
|
||||||
kSkipping
|
|
||||||
};
|
|
||||||
|
|
||||||
class PlayState : public PeriodicWatcher {
|
|
||||||
// this watcher sends notices to observers that are interrested
|
|
||||||
// about play state changes
|
|
||||||
public:
|
public:
|
||||||
PlayState(int devicefd);
|
PlayState(CDEngine *engine);
|
||||||
PlayState(BMessage *message)
|
|
||||||
: PeriodicWatcher(message)
|
|
||||||
{}
|
|
||||||
|
|
||||||
CDState GetState() const;
|
CDState GetState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UpdateState();
|
bool UpdateState();
|
||||||
bool CurrentState(CDState);
|
bool CurrentState(CDState);
|
||||||
CDState oldState;
|
CDState oldState;
|
||||||
|
|
||||||
|
CDEngine *fEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TrackState : public PeriodicWatcher {
|
// this watcher sends notices to observers that are interested
|
||||||
// this watcher sends notices to observers that are interested
|
// about changes in the current track
|
||||||
// about changes in the current track
|
class TrackState : public PeriodicWatcher
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
TrackState(int devicefd);
|
TrackState(void);
|
||||||
TrackState(BMessage *message)
|
|
||||||
: PeriodicWatcher(message)
|
|
||||||
{}
|
|
||||||
|
|
||||||
int32 GetTrack() const;
|
int32 GetTrack() const;
|
||||||
int32 GetNumTracks() const;
|
int32 GetNumTracks() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UpdateState();
|
bool UpdateState();
|
||||||
bool CurrentState(int32);
|
bool CurrentState(int32);
|
||||||
int32 currentTrack;
|
int32 currentTrack;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TimeState : public PeriodicWatcher {
|
// this watcher sends notices to observers that are interested
|
||||||
// this watcher sends notices to observers that are interested
|
// about changes in the current time
|
||||||
// about changes in the current time
|
class TimeState : public PeriodicWatcher
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
TimeState(int devicefd)
|
TimeState(void) : PeriodicWatcher() { }
|
||||||
: PeriodicWatcher(devicefd)
|
|
||||||
{ }
|
|
||||||
TimeState(BMessage *message)
|
|
||||||
: PeriodicWatcher(message)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void GetDiscTime(int32 &minutes, int32 &seconds) const;
|
void GetDiscTime(int32 &minutes, int32 &seconds) const;
|
||||||
void GetTrackTime(int32 &minutes, int32 &seconds) const;
|
void GetTrackTime(int32 &minutes, int32 &seconds) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UpdateState();
|
bool UpdateState();
|
||||||
bool CurrentState(int32 dmin, int32 dsec, int32 tmin, int32 tsec);
|
bool CurrentState(int32 dmin, int32 dsec, int32 tmin, int32 tsec);
|
||||||
|
|
||||||
int32 fDiscMinutes;
|
int32 fDiscMinutes;
|
||||||
int32 fDiscSeconds;
|
int32 fDiscSeconds;
|
||||||
|
|
||||||
int32 fTrackMinutes;
|
int32 fTrackMinutes;
|
||||||
int32 fTrackSeconds;
|
int32 fTrackSeconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDContentWatcher : public PeriodicWatcher {
|
class CDContentWatcher : public PeriodicWatcher
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
CDContentWatcher(int devicefd);
|
CDContentWatcher(void);
|
||||||
CDContentWatcher(BMessage *message);
|
|
||||||
|
|
||||||
bool GetContent(BString *title, vector<BString> *tracks);
|
bool GetContent(BString *title, vector<BString> *tracks);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UpdateState();
|
bool UpdateState();
|
||||||
|
|
||||||
CDDBQuery cddbQuery;
|
CDDBQuery cddbQuery;
|
||||||
int32 discID;
|
int32 discID;
|
||||||
bool fReady;
|
bool fReady;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VolumeState : public PeriodicWatcher {
|
// this watcher sends notices to observers that are interested
|
||||||
// this watcher sends notices to observers that are interested
|
// about changes in the current volume
|
||||||
// about changes in the current volume
|
// currently not used yet
|
||||||
// currently not used yet
|
class VolumeState : public PeriodicWatcher
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
VolumeState(int devicefd);
|
VolumeState(void);
|
||||||
VolumeState(BMessage *message)
|
|
||||||
: PeriodicWatcher(message)
|
bool UpdateState();
|
||||||
{}
|
int32 GetVolume() const;
|
||||||
bool UpdateState();
|
|
||||||
int32 GetVolume() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32 fVolume;
|
int32 fVolume;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDEngine : public BHandler {
|
// The CD engine defines all the different CD control calls; also,
|
||||||
// The CD engine defines all the different CD control calls; also,
|
// it hosts the different state watchers and helps them send notices
|
||||||
// it hosts the different state watchers and helps them send notices
|
// to observers about the CD state changes
|
||||||
// to observers about the CD state changes
|
class CDEngine : public BHandler
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
CDEngine(int devicefd);
|
CDEngine(void);
|
||||||
CDEngine(BMessage *);
|
|
||||||
|
|
||||||
virtual ~CDEngine();
|
virtual ~CDEngine();
|
||||||
|
|
||||||
// observing supprt
|
// observing support
|
||||||
virtual void MessageReceived(BMessage *);
|
virtual void MessageReceived(BMessage *);
|
||||||
void AttachedToLooper(BLooper *);
|
void AttachedToLooper(BLooper *);
|
||||||
void DoPulse();
|
void DoPulse();
|
||||||
|
|
||||||
// control calls
|
// control calls
|
||||||
void PlayOrPause();
|
void Play();
|
||||||
void PlayContinue();
|
void Pause();
|
||||||
void Play();
|
void Stop();
|
||||||
void Pause();
|
void Eject();
|
||||||
void Stop();
|
void SkipOneForward();
|
||||||
void Eject();
|
void SkipOneBackward();
|
||||||
void SkipOneForward();
|
void StartSkippingBackward();
|
||||||
void SkipOneBackward();
|
void StartSkippingForward();
|
||||||
void StartSkippingBackward();
|
void StopSkipping();
|
||||||
void StartSkippingForward();
|
void SelectTrack(int32);
|
||||||
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()
|
TrackState *TrackStateWatcher()
|
||||||
{ return &trackState; }
|
{ 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()
|
PlayState *PlayStateWatcher()
|
||||||
{ return &playState; }
|
{ 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()
|
TimeState *TimeStateWatcher()
|
||||||
{ return &timeState; }
|
{ return &timeState; }
|
||||||
// to find the current location on the CD, you may call the GetTime function
|
|
||||||
// TimeState defines
|
|
||||||
|
|
||||||
CDContentWatcher *ContentWatcher()
|
CDContentWatcher *ContentWatcher()
|
||||||
{ return &contentWatcher; }
|
{ return &contentWatcher; }
|
||||||
|
|
||||||
|
// to find the current location on the CD, you may call the GetVolume function
|
||||||
|
// VolumeState defines
|
||||||
VolumeState *VolumeStateWatcher()
|
VolumeState *VolumeStateWatcher()
|
||||||
// to find the current location on the CD, you may call the GetVolume function
|
|
||||||
// VolumeState defines
|
|
||||||
{ return &volumeState; }
|
{ return &volumeState; }
|
||||||
|
|
||||||
static int FindCDPlayerDevice();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int devicefd;
|
PlayState playState;
|
||||||
|
TrackState trackState;
|
||||||
|
TimeState timeState;
|
||||||
|
VolumeState volumeState;
|
||||||
|
CDContentWatcher contentWatcher;
|
||||||
|
|
||||||
PlayState playState;
|
bigtime_t lastPulse;
|
||||||
TrackState trackState;
|
|
||||||
TimeState timeState;
|
CDState fEngineState;
|
||||||
VolumeState volumeState;
|
|
||||||
CDContentWatcher contentWatcher;
|
|
||||||
|
|
||||||
bigtime_t lastPulse;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// some function object glue
|
// some function object glue
|
||||||
class CDEngineFunctorFactory : public FunctorFactoryCommon {
|
class CDEngineFunctorFactory : public FunctorFactoryCommon
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
static BMessage *NewFunctorMessage(void (CDEngine::*func)(),
|
static BMessage *NewFunctorMessage(void (CDEngine::*func)(),
|
||||||
CDEngine *target)
|
CDEngine *target)
|
||||||
{
|
{
|
||||||
PlainMemberFunctionObject<void (CDEngine::*)(),
|
PlainMemberFunctionObject<void (CDEngine::*)(),
|
||||||
CDEngine> tmp(func, target);
|
CDEngine> tmp(func, target);
|
||||||
return NewMessage(&tmp);
|
return NewMessage(&tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BMessage *NewFunctorMessage(void (CDEngine::*func)(ulong),
|
static BMessage *NewFunctorMessage(void (CDEngine::*func)(ulong),
|
||||||
CDEngine *target, ulong param)
|
CDEngine *target, ulong param)
|
||||||
{
|
{
|
||||||
SingleParamMemberFunctionObject<void (CDEngine::*)(ulong),
|
SingleParamMemberFunctionObject<void (CDEngine::*)(ulong),
|
||||||
CDEngine, ulong> tmp(func, target, param);
|
CDEngine, ulong> tmp(func, target, param);
|
||||||
return NewMessage(&tmp);
|
return NewMessage(&tmp);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "CDButton.h"
|
#include "CDPlayer.h"
|
||||||
#include "DrawButton.h"
|
#include "DrawButton.h"
|
||||||
#include "TwoStateDrawButton.h"
|
#include "TwoStateDrawButton.h"
|
||||||
#include <TranslationUtils.h>
|
#include <TranslationUtils.h>
|
||||||
@@ -45,13 +45,13 @@ enum
|
|||||||
M_SET_CD_TITLE
|
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)
|
: BView(frame, name, resizeMask, flags | B_FRAME_EVENTS)
|
||||||
{
|
{
|
||||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
|
||||||
// TODO: Support multiple CD drives
|
// TODO: Support multiple CD drives
|
||||||
engine = new CDEngine(CDEngine::FindCDPlayerDevice());
|
engine = new CDEngine;
|
||||||
|
|
||||||
BuildGUI();
|
BuildGUI();
|
||||||
|
|
||||||
@@ -66,18 +66,29 @@ CDButton::CDButton(BRect frame, const char *name, uint32 resizeMask, uint32 flag
|
|||||||
fFastFwd->SetEnabled(false);
|
fFastFwd->SetEnabled(false);
|
||||||
fRewind->SetEnabled(false);
|
fRewind->SetEnabled(false);
|
||||||
fSave->SetEnabled(false);
|
fSave->SetEnabled(false);
|
||||||
|
|
||||||
|
fCurrentTrack->SetHighColor(fStopColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CDButton::~CDButton()
|
CDPlayer::~CDPlayer()
|
||||||
{
|
{
|
||||||
engine->Stop();
|
engine->Stop();
|
||||||
|
|
||||||
delete engine;
|
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);
|
BRect r(5,5,230,25);
|
||||||
|
|
||||||
// Assemble the CD Title box
|
// Assemble the CD Title box
|
||||||
@@ -88,7 +99,7 @@ void CDButton::BuildGUI(void)
|
|||||||
view->SetViewColor(20,20,20);
|
view->SetViewColor(20,20,20);
|
||||||
fCDBox->AddChild(view);
|
fCDBox->AddChild(view);
|
||||||
|
|
||||||
fCDTitle = new BStringView(view->Bounds(),"CDTitle","");
|
fCDTitle = new BStringView(view->Bounds(),"CDTitle","", B_FOLLOW_ALL);
|
||||||
view->AddChild(fCDTitle);
|
view->AddChild(fCDTitle);
|
||||||
fCDTitle->SetHighColor(200,200,200);
|
fCDTitle->SetHighColor(200,200,200);
|
||||||
fCDTitle->SetFont(be_bold_font);
|
fCDTitle->SetFont(be_bold_font);
|
||||||
@@ -103,7 +114,7 @@ void CDButton::BuildGUI(void)
|
|||||||
|
|
||||||
fCurrentTrack = new BStringView( view->Bounds(),"TrackNumber","Track:",B_FOLLOW_ALL);
|
fCurrentTrack = new BStringView( view->Bounds(),"TrackNumber","Track:",B_FOLLOW_ALL);
|
||||||
view->AddChild(fCurrentTrack);
|
view->AddChild(fCurrentTrack);
|
||||||
fCurrentTrack->SetHighColor(40,230,40);
|
fCurrentTrack->SetHighColor(fPlayColor);
|
||||||
fCurrentTrack->SetFont(be_bold_font);
|
fCurrentTrack->SetFont(be_bold_font);
|
||||||
|
|
||||||
r.OffsetBy(0, r.Height() + 5);
|
r.OffsetBy(0, r.Height() + 5);
|
||||||
@@ -142,7 +153,6 @@ void CDButton::BuildGUI(void)
|
|||||||
fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_disabled"));
|
fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_disabled"));
|
||||||
AddChild(fStop);
|
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"),
|
fPlay = new DrawButton( BRect(0,0,1,1), "Play", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"),
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"),
|
||||||
new BMessage(M_PLAY), B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
new BMessage(M_PLAY), B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
||||||
@@ -201,29 +211,30 @@ void CDButton::BuildGUI(void)
|
|||||||
AddChild(fSave);
|
AddChild(fSave);
|
||||||
fSave->SetEnabled(false);
|
fSave->SetEnabled(false);
|
||||||
|
|
||||||
// TODO: Shuffle and Repeat are special buttons. Implement as two-state buttons
|
fShuffle = new TwoStateDrawButton( BRect(0,0,1,1), "Shuffle",
|
||||||
fShuffle = new DrawButton( BRect(0,0,1,1), "Shuffle", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up"),
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up"),
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_down"), new BMessage(M_SHUFFLE),
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_down"),
|
||||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
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->ResizeToPreferred();
|
||||||
fShuffle->MoveTo(fSave->Frame().right + 2, Bounds().bottom - 5 - fShuffle->Frame().Height());
|
fShuffle->MoveTo(fSave->Frame().right + 2, Bounds().bottom - 5 - fShuffle->Frame().Height());
|
||||||
fShuffle->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_disabled"));
|
|
||||||
AddChild(fShuffle);
|
AddChild(fShuffle);
|
||||||
fShuffle->SetEnabled(false);
|
|
||||||
|
|
||||||
fRepeat = new DrawButton( BRect(0,0,1,1), "Repeat", BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up"),
|
fRepeat = new TwoStateDrawButton( BRect(0,0,1,1), "Repeat",
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_down"), new BMessage(M_REPEAT),
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up"),
|
||||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
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->ResizeToPreferred();
|
||||||
fRepeat->MoveTo(fShuffle->Frame().right + 2, Bounds().bottom - 5 - fRepeat->Frame().Height());
|
fRepeat->MoveTo(fShuffle->Frame().right + 2, Bounds().bottom - 5 - fRepeat->Frame().Height());
|
||||||
fRepeat->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_disabled"));
|
|
||||||
AddChild(fRepeat);
|
AddChild(fRepeat);
|
||||||
fRepeat->SetEnabled(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::MessageReceived(BMessage *msg)
|
CDPlayer::MessageReceived(BMessage *msg)
|
||||||
{
|
{
|
||||||
if(msg->WasDropped())
|
if(msg->WasDropped())
|
||||||
{
|
{
|
||||||
@@ -292,7 +303,7 @@ CDButton::MessageReceived(BMessage *msg)
|
|||||||
}
|
}
|
||||||
case M_STOP:
|
case M_STOP:
|
||||||
{
|
{
|
||||||
if(engine->PlayStateWatcher()->GetState()==kPlaying)
|
if(engine->GetState()==kPlaying)
|
||||||
{
|
{
|
||||||
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
|
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"));
|
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
|
// If we are currently playing, then we will be showing
|
||||||
// the pause images and will want to switch back to the play images
|
// 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"),
|
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"),
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"));
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"));
|
||||||
@@ -315,7 +326,7 @@ CDButton::MessageReceived(BMessage *msg)
|
|||||||
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"pause_up"),
|
fPlay->SetBitmaps(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"pause_up"),
|
||||||
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"pause_down"));
|
BTranslationUtils::GetBitmap(B_PNG_FORMAT,"pause_down"));
|
||||||
}
|
}
|
||||||
engine->PlayOrPause();
|
engine->Play();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_NEXT_TRACK:
|
case M_NEXT_TRACK:
|
||||||
@@ -350,12 +361,12 @@ CDButton::MessageReceived(BMessage *msg)
|
|||||||
}
|
}
|
||||||
case M_SHUFFLE:
|
case M_SHUFFLE:
|
||||||
{
|
{
|
||||||
// TODO: Implement
|
engine->ToggleShuffle();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M_REPEAT:
|
case M_REPEAT:
|
||||||
{
|
{
|
||||||
// TODO: Implement
|
engine->ToggleRepeat();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -372,7 +383,7 @@ CDButton::MessageReceived(BMessage *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::NoticeChange(Notifier *notifier)
|
CDPlayer::NoticeChange(Notifier *notifier)
|
||||||
{
|
{
|
||||||
PlayState *ps;
|
PlayState *ps;
|
||||||
TrackState *trs;
|
TrackState *trs;
|
||||||
@@ -402,10 +413,10 @@ CDButton::NoticeChange(Notifier *notifier)
|
|||||||
fRewind->SetEnabled(false);
|
fRewind->SetEnabled(false);
|
||||||
fSave->SetEnabled(false);
|
fSave->SetEnabled(false);
|
||||||
}
|
}
|
||||||
|
fCurrentTrack->SetHighColor(fStopColor);
|
||||||
fCurrentTrack->SetText("Track: ");
|
fCurrentTrack->SetText("Track: ");
|
||||||
fTrackTime->SetText("Track --:-- / --:--");
|
fTrackTime->SetText("Track --:-- / --:--");
|
||||||
fDiscTime->SetText("Disc --:-- / --:--");
|
fDiscTime->SetText("Disc --:-- / --:--");
|
||||||
printf("Notification: No CD\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kStopped:
|
case kStopped:
|
||||||
@@ -418,12 +429,14 @@ CDButton::NoticeChange(Notifier *notifier)
|
|||||||
fPrevTrack->SetEnabled(true);
|
fPrevTrack->SetEnabled(true);
|
||||||
fFastFwd->SetEnabled(true);
|
fFastFwd->SetEnabled(true);
|
||||||
fRewind->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 --:-- / --:--");
|
fTrackTime->SetText("Track --:-- / --:--");
|
||||||
fDiscTime->SetText("Disc --:-- / --:--");
|
fDiscTime->SetText("Disc --:-- / --:--");
|
||||||
printf("Notification: CD Stopped\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kPaused:
|
case kPaused:
|
||||||
@@ -437,9 +450,11 @@ CDButton::NoticeChange(Notifier *notifier)
|
|||||||
fPrevTrack->SetEnabled(true);
|
fPrevTrack->SetEnabled(true);
|
||||||
fFastFwd->SetEnabled(true);
|
fFastFwd->SetEnabled(true);
|
||||||
fRewind->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;
|
break;
|
||||||
}
|
}
|
||||||
case kPlaying:
|
case kPlaying:
|
||||||
@@ -452,9 +467,12 @@ CDButton::NoticeChange(Notifier *notifier)
|
|||||||
fPrevTrack->SetEnabled(true);
|
fPrevTrack->SetEnabled(true);
|
||||||
fFastFwd->SetEnabled(true);
|
fFastFwd->SetEnabled(true);
|
||||||
fRewind->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;
|
break;
|
||||||
}
|
}
|
||||||
case kSkipping:
|
case kSkipping:
|
||||||
@@ -467,9 +485,11 @@ CDButton::NoticeChange(Notifier *notifier)
|
|||||||
fPrevTrack->SetEnabled(true);
|
fPrevTrack->SetEnabled(true);
|
||||||
fFastFwd->SetEnabled(true);
|
fFastFwd->SetEnabled(true);
|
||||||
fRewind->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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -502,7 +522,7 @@ CDButton::NoticeChange(Notifier *notifier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::UpdateCDInfo(void)
|
CDPlayer::UpdateCDInfo(void)
|
||||||
{
|
{
|
||||||
BString CDName, currentTrackName;
|
BString CDName, currentTrackName;
|
||||||
vector<BString> trackNames;
|
vector<BString> trackNames;
|
||||||
@@ -525,7 +545,7 @@ CDButton::UpdateCDInfo(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::UpdateTimeInfo(void)
|
CDPlayer::UpdateTimeInfo(void)
|
||||||
{
|
{
|
||||||
int32 min,sec;
|
int32 min,sec;
|
||||||
char string[1024];
|
char string[1024];
|
||||||
@@ -546,7 +566,7 @@ CDButton::UpdateTimeInfo(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::AttachedToWindow()
|
CDPlayer::AttachedToWindow()
|
||||||
{
|
{
|
||||||
// start observing
|
// start observing
|
||||||
engine->AttachedToLooper(Window());
|
engine->AttachedToLooper(Window());
|
||||||
@@ -570,7 +590,7 @@ CDButton::AttachedToWindow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
// 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
|
// width into two and have a box fill each half
|
||||||
@@ -595,13 +615,13 @@ CDButton::FrameResized(float new_width, float new_height)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::Pulse()
|
CDPlayer::Pulse()
|
||||||
{
|
{
|
||||||
engine->DoPulse();
|
engine->DoPulse();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CDButton::SetBitmap(BBitmap *bitmap)
|
CDPlayer::SetBitmap(BBitmap *bitmap)
|
||||||
{
|
{
|
||||||
if(!bitmap)
|
if(!bitmap)
|
||||||
{
|
{
|
||||||
@@ -615,14 +635,14 @@ CDButton::SetBitmap(BBitmap *bitmap)
|
|||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
class CDButtonWindow : public BWindow
|
class CDPlayerWindow : public BWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDButtonWindow(void);
|
CDPlayerWindow(void);
|
||||||
bool QuitRequested(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 |
|
: BWindow(BRect (100, 100, 610, 200), "CD Player", B_TITLED_WINDOW, B_NOT_V_RESIZABLE |
|
||||||
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
|
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
|
||||||
{
|
{
|
||||||
@@ -634,17 +654,17 @@ CDButtonWindow::CDButtonWindow(void)
|
|||||||
SetSizeLimits(wmin,wmax,hmin,hmax);
|
SetSizeLimits(wmin,wmax,hmin,hmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDButtonWindow::QuitRequested(void)
|
bool CDPlayerWindow::QuitRequested(void)
|
||||||
{
|
{
|
||||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDButtonApplication::CDButtonApplication()
|
CDPlayerApplication::CDPlayerApplication()
|
||||||
: BApplication("application/x-vnd.Haiku-CDPlayer")
|
: BApplication("application/x-vnd.Haiku-CDPlayer")
|
||||||
{
|
{
|
||||||
BWindow *window = new CDButtonWindow();
|
BWindow *window = new CDPlayerWindow();
|
||||||
BView *button = new CDButton(window->Bounds(), "CD");
|
BView *button = new CDPlayer(window->Bounds(), "CD");
|
||||||
window->AddChild(button);
|
window->AddChild(button);
|
||||||
window->Show();
|
window->Show();
|
||||||
}
|
}
|
||||||
@@ -652,7 +672,7 @@ CDButtonApplication::CDButtonApplication()
|
|||||||
int
|
int
|
||||||
main(int, char **argv)
|
main(int, char **argv)
|
||||||
{
|
{
|
||||||
(new CDButtonApplication())->Run();
|
(new CDPlayerApplication())->Run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
// This defines the replicant button
|
// This defines the replicant button
|
||||||
|
|
||||||
#ifndef __CD_BUTTON__
|
#ifndef CDPLAYER_H
|
||||||
#define __CD_BUTTON__
|
#define CDPLAYER_H
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
@@ -16,21 +16,20 @@
|
|||||||
#include <TextControl.h>
|
#include <TextControl.h>
|
||||||
#include <StringView.h>
|
#include <StringView.h>
|
||||||
|
|
||||||
#include "PlayList.h"
|
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "CDEngine.h"
|
#include "CDEngine.h"
|
||||||
|
|
||||||
class DrawButton;
|
class DrawButton;
|
||||||
class TwoStateDrawButton;
|
class TwoStateDrawButton;
|
||||||
|
|
||||||
class CDButton : public BView, private Observer
|
class CDPlayer : public BView, private Observer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDButton(BRect frame, const char *name,
|
CDPlayer(BRect frame, const char *name,
|
||||||
uint32 resizeMask = B_FOLLOW_ALL,
|
uint32 resizeMask = B_FOLLOW_ALL,
|
||||||
uint32 flags = B_WILL_DRAW | B_NAVIGABLE |
|
uint32 flags = B_WILL_DRAW | B_NAVIGABLE |
|
||||||
B_PULSE_NEEDED);
|
B_PULSE_NEEDED);
|
||||||
virtual ~CDButton();
|
virtual ~CDPlayer();
|
||||||
|
|
||||||
void BuildGUI(void);
|
void BuildGUI(void);
|
||||||
|
|
||||||
@@ -46,36 +45,46 @@ public:
|
|||||||
virtual void NoticeChange(Notifier *);
|
virtual void NoticeChange(Notifier *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateCDInfo(void);
|
void UpdateCDInfo(void);
|
||||||
void UpdateTimeInfo(void);
|
void UpdateTimeInfo(void);
|
||||||
void SetBitmap(BBitmap *bitmap);
|
void SetBitmap(BBitmap *bitmap);
|
||||||
|
|
||||||
CDEngine *engine;
|
CDEngine *engine;
|
||||||
|
|
||||||
DrawButton *fStop, *fPlay, *fNextTrack, *fPrevTrack;
|
DrawButton *fStop,
|
||||||
DrawButton *fFastFwd, *fRewind, *fEject, *fSave, *fShuffle, *fRepeat;
|
*fPlay,
|
||||||
|
*fNextTrack,
|
||||||
|
*fPrevTrack,
|
||||||
BSlider *fVolume;
|
*fFastFwd,
|
||||||
|
*fRewind,
|
||||||
BStringView *fCDTitle;
|
*fEject,
|
||||||
BStringView *fCurrentTrack;
|
*fSave;
|
||||||
BStringView *fTrackTime;
|
|
||||||
BStringView *fDiscTime;
|
TwoStateDrawButton *fShuffle,
|
||||||
|
*fRepeat;
|
||||||
BBox *fCDBox;
|
|
||||||
BBox *fTrackBox;
|
BSlider *fVolume;
|
||||||
BBox *fTimeBox;
|
|
||||||
|
BStringView *fCDTitle,
|
||||||
CDState fCDState;
|
*fCurrentTrack,
|
||||||
PlayList fPlaylist;
|
*fTrackTime,
|
||||||
|
*fDiscTime;
|
||||||
|
|
||||||
|
BBox *fCDBox,
|
||||||
|
*fTrackBox,
|
||||||
|
*fTimeBox;
|
||||||
|
|
||||||
|
CDState fCDState;
|
||||||
|
|
||||||
|
rgb_color fStopColor;
|
||||||
|
rgb_color fPlayColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CDButtonApplication : public BApplication
|
class CDPlayerApplication : public BApplication
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDButtonApplication();
|
CDPlayerApplication();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2,9 +2,10 @@ SubDir OBOS_TOP src apps cdplayer ;
|
|||||||
|
|
||||||
AddResources CDPlayer : CDPlayer.rdef ;
|
AddResources CDPlayer : CDPlayer.rdef ;
|
||||||
App CDPlayer :
|
App CDPlayer :
|
||||||
CDButton.cpp
|
CDAudioDevice.cpp
|
||||||
CDDBSupport.cpp
|
CDDBSupport.cpp
|
||||||
CDEngine.cpp
|
CDEngine.cpp
|
||||||
|
CDPlayer.cpp
|
||||||
DrawButton.cpp
|
DrawButton.cpp
|
||||||
FunctionObjectMessage.cpp
|
FunctionObjectMessage.cpp
|
||||||
Observer.cpp
|
Observer.cpp
|
||||||
|
|||||||
+113
-14
@@ -3,20 +3,36 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
PlayList::PlayList(int16 tracks)
|
PlayList::PlayList(int16 count, int16 start)
|
||||||
: fTrackCount(0),
|
: fTrackCount(count),
|
||||||
fTrackIndex(0),
|
fTrackIndex(0),
|
||||||
|
fStartingTrack(start),
|
||||||
fRandom(false),
|
fRandom(false),
|
||||||
fLoop(false)
|
fLoop(false)
|
||||||
{
|
{
|
||||||
srand(real_time_clock_usecs());
|
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
|
void
|
||||||
PlayList::SetTrackCount(const int16 &count)
|
PlayList::SetTrackCount(const int16 &count)
|
||||||
{
|
{
|
||||||
|
fLocker.Lock();
|
||||||
|
|
||||||
if(count < 0)
|
if(count < 0)
|
||||||
fTrackCount = 0;
|
fTrackCount = 0;
|
||||||
else
|
else
|
||||||
@@ -27,57 +43,140 @@ PlayList::SetTrackCount(const int16 &count)
|
|||||||
|
|
||||||
memset(fTrackList,-1,500);
|
memset(fTrackList,-1,500);
|
||||||
SetShuffle(IsShuffled());
|
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
|
void
|
||||||
PlayList::Rewind(void)
|
PlayList::Rewind(void)
|
||||||
{
|
{
|
||||||
|
fLocker.Lock();
|
||||||
|
|
||||||
fTrackIndex = 0;
|
fTrackIndex = 0;
|
||||||
|
|
||||||
|
fLocker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayList::SetShuffle(const bool &random)
|
PlayList::SetShuffle(const bool &random)
|
||||||
{
|
{
|
||||||
|
fLocker.Lock();
|
||||||
|
|
||||||
if(random)
|
if(random)
|
||||||
Randomize();
|
Randomize();
|
||||||
else
|
else
|
||||||
Unrandomize();
|
Unrandomize();
|
||||||
|
|
||||||
|
fLocker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayList::SetLoop(const bool &loop)
|
PlayList::SetLoop(const bool &loop)
|
||||||
{
|
{
|
||||||
|
fLocker.Lock();
|
||||||
|
|
||||||
fLoop = loop;
|
fLoop = loop;
|
||||||
|
|
||||||
|
fLocker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16
|
||||||
|
PlayList::GetCurrentTrack(void)
|
||||||
|
{
|
||||||
|
fLocker.Lock();
|
||||||
|
|
||||||
|
int16 value = fTrackList[fTrackIndex];
|
||||||
|
|
||||||
|
fLocker.Unlock();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
int16
|
int16
|
||||||
PlayList::GetNextTrack(void)
|
PlayList::GetNextTrack(void)
|
||||||
{
|
{
|
||||||
if(fTrackCount < 1)
|
fLocker.Lock();
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(fTrackIndex == fTrackCount)
|
if(fTrackCount < 1)
|
||||||
|
{
|
||||||
|
fLocker.Unlock();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fTrackIndex > (fTrackCount - fStartingTrack))
|
||||||
{
|
{
|
||||||
if(fLoop)
|
if(fLoop)
|
||||||
fTrackIndex = 0;
|
fTrackIndex = 0;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
fLocker.Unlock();
|
||||||
return -1;
|
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
|
void
|
||||||
PlayList::Randomize(void)
|
PlayList::Randomize(void)
|
||||||
{
|
{
|
||||||
// Reinitialize the count
|
// Reinitialize the count
|
||||||
for(int16 i=0; i<fTrackCount; i++)
|
for(int16 i=fStartingTrack; i<=fTrackCount; i++)
|
||||||
fTrackList[i] = i;
|
fTrackList[i - fStartingTrack] = i;
|
||||||
|
|
||||||
// There are probably *much* better ways to do this,
|
// There are probably *much* better ways to do this,
|
||||||
// but this is the only one I could think of. :(
|
// 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;
|
int16 temp, first, second;
|
||||||
for(int32 i=0; i< swapcount; i++)
|
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
|
// This way we are sure to not have any duplicates and still have
|
||||||
// all tracks eventually be played.
|
// all tracks eventually be played.
|
||||||
|
|
||||||
first = (int16)(fTrackCount * ((float)rand()/RAND_MAX));
|
first = (int16)(listcount * ((float)rand()/RAND_MAX));
|
||||||
second = (int16)(fTrackCount * ((float)rand()/RAND_MAX));
|
second = (int16)(listcount * ((float)rand()/RAND_MAX));
|
||||||
|
|
||||||
temp = fTrackList[first];
|
temp = fTrackList[first];
|
||||||
fTrackList[first] = fTrackList[second];
|
fTrackList[first] = fTrackList[second];
|
||||||
@@ -98,7 +197,7 @@ PlayList::Randomize(void)
|
|||||||
void
|
void
|
||||||
PlayList::Unrandomize(void)
|
PlayList::Unrandomize(void)
|
||||||
{
|
{
|
||||||
for(int16 i=0; i<fTrackCount; i++)
|
for(int16 i=fStartingTrack; i<=fTrackCount; i++)
|
||||||
fTrackList[i] = i;
|
fTrackList[i - fStartingTrack] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,19 @@
|
|||||||
#define PLAYLIST_H
|
#define PLAYLIST_H
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
class PlayList
|
class PlayList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PlayList(int16 tracks = 0);
|
PlayList(int16 tracks = 0, int16 startingtrack = 1);
|
||||||
|
|
||||||
void SetTrackCount(const int16 &count);
|
void SetTrackCount(const int16 &count);
|
||||||
int16 TrackCount(void) const { return fTrackCount; }
|
int16 TrackCount(void) const { return fTrackCount; }
|
||||||
|
|
||||||
|
void SetStartingTrack(const int16 &start);
|
||||||
|
int16 StartingTrack(void) const { return fStartingTrack; }
|
||||||
|
|
||||||
void Rewind(void);
|
void Rewind(void);
|
||||||
|
|
||||||
void SetShuffle(const bool &random);
|
void SetShuffle(const bool &random);
|
||||||
@@ -19,7 +23,9 @@ public:
|
|||||||
void SetLoop(const bool &loop);
|
void SetLoop(const bool &loop);
|
||||||
bool IsLoop(void) const { return fLoop; }
|
bool IsLoop(void) const { return fLoop; }
|
||||||
|
|
||||||
|
int16 GetCurrentTrack(void);
|
||||||
int16 GetNextTrack(void);
|
int16 GetNextTrack(void);
|
||||||
|
int16 GetPreviousTrack(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Randomize(void);
|
void Randomize(void);
|
||||||
@@ -27,12 +33,13 @@ private:
|
|||||||
|
|
||||||
int16 fTrackCount;
|
int16 fTrackCount;
|
||||||
int16 fTrackIndex;
|
int16 fTrackIndex;
|
||||||
|
int16 fStartingTrack;
|
||||||
int16 fTrackList[500]; // This should be big enough. :)
|
int16 fTrackList[500]; // This should be big enough. :)
|
||||||
|
|
||||||
bool fRandom;
|
bool fRandom;
|
||||||
bool fLoop;
|
bool fLoop;
|
||||||
|
|
||||||
|
BLocker fLocker;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public:
|
|||||||
void MouseUp(BPoint pt);
|
void MouseUp(BPoint pt);
|
||||||
// void MessageReceived(BMessage *msg);
|
// void MessageReceived(BMessage *msg);
|
||||||
|
|
||||||
|
int32 GetState(void) { return fButtonState ? 1 : 0; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
BBitmap *fUpOne,
|
BBitmap *fUpOne,
|
||||||
|
|||||||
Reference in New Issue
Block a user