diff --git a/src/apps/cdplayer/ButtonBitmaps.h b/src/apps/cdplayer/ButtonBitmaps.h index a26a0938f4..b836761252 100644 --- a/src/apps/cdplayer/ButtonBitmaps.h +++ b/src/apps/cdplayer/ButtonBitmaps.h @@ -15,6 +15,7 @@ #ifndef BUTTON_BITMAPS_H #define BUTTON_BITMAPS_H +#include // #pragma mark play diff --git a/src/apps/cdplayer/CDAudioDevice.cpp b/src/apps/cdplayer/CDAudioDevice.cpp index 180625e56e..a373332eb0 100644 --- a/src/apps/cdplayer/CDAudioDevice.cpp +++ b/src/apps/cdplayer/CDAudioDevice.cpp @@ -1,538 +1,26 @@ /* - * Copyright (c) 2006-2007, Haiku, Inc. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Author: - * DarkWyrm + * DarkWyrm, bpmagic@columbus.rr.com */ -#include "CDAudioDevice.h" -#include -#include -#include -#include -#include + +#include "CDAudioDevice.h" +#include "scsi.h" + #include #include #include #include +#include + #include -#include "scsi.h" - - -cdaudio_data::cdaudio_data(const int32 &id, const int32 &count, - const int32 &disclength) - : disc_id(id), - track_count(count), - length(disclength) -{ -} - - -cdaudio_data::cdaudio_data(const cdaudio_data &from) - : disc_id(from.disc_id), - track_count(from.track_count), - length(from.length) -{ -} - - -cdaudio_data & -cdaudio_data::operator=(const cdaudio_data &from) -{ - disc_id = from.disc_id; - track_count = from.track_count; - length = from.length; - frame_offsets = from.frame_offsets; - return *this; -} - - -cdaudio_time::cdaudio_time(const int32 min,const int32 &sec) - : minutes(min), - seconds(sec) -{ -} - - -cdaudio_time::cdaudio_time(const cdaudio_time &from) - : minutes(from.minutes), - seconds(from.seconds) -{ -} - - -cdaudio_time & -cdaudio_time::operator=(const cdaudio_time &from) -{ - minutes = from.minutes; - seconds = from.seconds; - return *this; -} - - -cdaudio_time -cdaudio_time::operator+(const cdaudio_time &from) -{ - cdaudio_time time; - - time.minutes = minutes + from.minutes; - time.seconds = seconds + from.seconds; - - while (time.seconds > 59) { - time.minutes++; - time.seconds-=60; - } - return time; -} - - -cdaudio_time -cdaudio_time::operator-(const cdaudio_time &from) -{ - cdaudio_time time; - - int32 tsec = ((minutes * 60) + seconds) - ((from.minutes * 60) + from.seconds); - if (tsec < 0) { - time.minutes = 0; - time.seconds = 0; - return time; - } - - time.minutes = tsec / 60; - time.seconds = tsec % 60; - - return time; -} - - -CDAudioDevice::CDAudioDevice(void) -{ - FindDrives("/dev/disk"); - if (CountDrives() > 0) - SetDrive(0); -} - - -CDAudioDevice::~CDAudioDevice(void) -{ - for (int32 i = 0; i < fDriveList.CountItems(); i++) - delete (BString*) fDriveList.ItemAt(i); -} - - -// This plays only one track - the track specified -bool -CDAudioDevice::Play(const int16 &track) -{ - if (GetState() == kNoCD) { - // no CD available, bail out - ioctl(fFileHandle, B_LOAD_MEDIA, 0, 0); - return false; - } - - scsi_play_track playtrack; - - playtrack.start_track = track; - playtrack.start_index = 1; - playtrack.end_track = track; - playtrack.end_index = 1; - - status_t result = ioctl(fFileHandle, B_SCSI_PLAY_TRACK, &playtrack); - if (result != B_OK) { - printf("Couldn't play track: %s\n", strerror(errno)); - return false; - } - - return true; -} - - -bool -CDAudioDevice::Pause(void) -{ - status_t result = ioctl(fFileHandle, B_SCSI_PAUSE_AUDIO); - if (result != B_OK) { - printf("Couldn't pause track: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::Resume(void) -{ - CDState state = GetState(); - if (state == kNoCD) { - // no CD available, bail out - ioctl(fFileHandle, B_LOAD_MEDIA, 0, 0); - return false; - } else { - if (state == kStopped) - return Play(0); - } - - status_t result = ioctl(fFileHandle, B_SCSI_RESUME_AUDIO); - if (result != B_OK) { - printf("Couldn't resume track: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::Stop(void) -{ - status_t result = ioctl(fFileHandle, B_SCSI_STOP_AUDIO); - if (result != B_OK) { - printf("Couldn't stop CD: %s\n", strerror(errno)); - return false; - } - return true; -} - - -// open or close the CD tray -bool -CDAudioDevice::Eject(void) -{ - status_t media_status = B_DEV_NO_MEDIA; - - // get the status first - ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); - - // if door open, load the media, else eject the CD - status_t result = ioctl(fFileHandle, - media_status == B_DEV_DOOR_OPEN ? - B_LOAD_MEDIA : B_EJECT_DEVICE); - - if (result != B_OK) { - printf("Couldn't eject CD: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::StartFastFwd(void) -{ - scsi_scan scan; - scan.direction = 1; - scan.speed = 1; - status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); - if (result != B_OK) { - printf("Couldn't fast forward: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::StopFastFwd(void) -{ - scsi_scan scan; - scan.direction = 0; - scan.speed = 1; - status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); - if (result != B_OK) { - printf("Couldn't stop fast forwarding: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::StartRewind(void) -{ - scsi_scan scan; - scan.direction = -1; - scan.speed = 1; - status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); - if (result != B_OK) { - printf("Couldn't rewind: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::StopRewind(void) -{ - scsi_scan scan; - scan.direction = 0; - scan.speed = 1; - status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); - if (result != B_OK) { - printf("Couldn't stop rewinding: %s\n", strerror(errno)); - return false; - } - return true; -} - - -bool -CDAudioDevice::SetVolume(uint8 value) -{ - scsi_volume vol; - - // change only port0's volume - vol.flags=2; - vol.port0_volume=value; - - status_t result = ioctl(fFileHandle,B_SCSI_SET_VOLUME,&vol); - if (result != B_OK) { - printf("Couldn't set volume: %s\n", strerror(errno)); - return false; - } - return true; -} - - -uint8 -CDAudioDevice::GetVolume(void) -{ - scsi_volume vol; - ioctl(fFileHandle, B_SCSI_GET_VOLUME, &vol); - return vol.port0_volume; -} - - -// check the current CD play state -CDState -CDAudioDevice::GetState(void) -{ - scsi_position pos; - status_t media_status = B_DEV_NO_MEDIA; - - ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); - if (media_status != B_OK) - return kNoCD; - - status_t result = ioctl(fFileHandle, B_SCSI_GET_POSITION, &pos); - if (result != B_OK) - return kNoCD; - else if ((!pos.position[1]) || (pos.position[1] >= 0x13) || - ((pos.position[1] == 0x12) && (!pos.position[6]))) - return kStopped; - else if (pos.position[1] == 0x11) - return kPlaying; - else - return kPaused; -} - - -int16 -CDAudioDevice::CountTracks(void) -{ - scsi_toc toc; - status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); - - if (result != B_OK) - return -1; - - return toc.toc_data[3]; -} - - -// Get the 0-based index of the current track -int16 -CDAudioDevice::GetTrack(void) -{ - scsi_position pos; - - status_t media_status = B_DEV_NO_MEDIA; - - ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); - if (media_status != B_OK) - return -1; - - status_t result = ioctl(fFileHandle, B_SCSI_GET_POSITION, &pos); - if (result != B_OK) - return -1; - - if (!pos.position[1] || pos.position[1] >= 0x13 - || (pos.position[1] == 0x12 && !pos.position[6])) - return 0; - else - return pos.position[6]; -} - - -uint8 -CDAudioDevice::CountDrives(void) -{ - return fDriveList.CountItems(); -} - - -bool -CDAudioDevice::SetDrive(const int32 &drive) -{ - BString *path = (BString*) fDriveList.ItemAt(drive); - - if (!path) - return false; - - int device = open(path->String(), O_RDONLY); - if (device >= 0) { - fFileHandle = device; - fDrivePath = path; - fDriveIndex = drive; - return true; - } - - return false; -} - - -const char * -CDAudioDevice::GetDrivePath(void) const -{ - if (!fDrivePath) - return NULL; - - return fDrivePath->String(); -} - - -int32 -CDAudioDevice::FindDrives(const char *path) -{ - BDirectory dir(path); - - if (dir.InitCheck() != B_OK) - return B_ERROR; - - dir.Rewind(); - - BEntry entry; - while (dir.GetNextEntry(&entry) >= 0) { - BPath path; - const char *name; - entry_ref e; - - if (entry.GetPath(&path) != B_OK) - continue; - - name = path.Path(); - if (entry.GetRef(&e) != B_OK) - continue; - - if (entry.IsDirectory()) { - // ignore floppy -- it is not silent - if (strcmp(e.name, "floppy") == 0) - continue; - else - if (strcmp(e.name, "ata") == 0) - continue; - - // Note that if we check for the count here, we could - // just search for one drive. However, we want to find *all* drives - // that are available, so we keep searching even if we've found one - FindDrives(name); - - } else { - int devfd; - device_geometry g; - - // ignore partitions - if (strcmp(e.name, "raw") != 0) - continue; - - 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) - fDriveList.AddItem(new BString(name)); - } - close(devfd); - } - } - return fDriveList.CountItems(); -} - - -bool -CDAudioDevice::GetTime(cdaudio_time &track, cdaudio_time &disc) -{ - scsi_position pos; - - // Sanity check - status_t media_status = B_DEV_NO_MEDIA; - ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); - if (media_status != B_OK) - return false; - - status_t result = ioctl(fFileHandle, B_SCSI_GET_POSITION, &pos); - - if (result != B_OK) - return false; - - 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. - return false; - } - - disc.minutes = pos.position[9]; - disc.seconds = pos.position[10]; - track.minutes = pos.position[13]; - track.seconds = pos.position[14]; - return true; -} - - -bool -CDAudioDevice::GetTimeForTrack(const int16 &index, cdaudio_time &track) -{ - scsi_toc toc; - status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); - - if (result != B_OK) - return false; - - int16 trackcount = toc.toc_data[3] - toc.toc_data[2] + 1; - - if (index < 1 || index > trackcount) - return false; - - TrackDescriptor *desc = (TrackDescriptor*)&(toc.toc_data[4]); - - int32 tracktime = (desc[index].min * 60) + desc[index].sec; - - tracktime -= (desc[index-1].min * 60) + desc[index-1].sec; - track.minutes = tracktime / 60; - track.seconds = tracktime % 60; - - return true; -} - - -bool -CDAudioDevice::GetTimeForDisc(cdaudio_time &disc) -{ - scsi_toc toc; - status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); - - if (result != B_OK) - return false; - - int16 trackcount = toc.toc_data[3] - toc.toc_data[2] + 1; - TrackDescriptor *desc = (TrackDescriptor*)&(toc.toc_data[4]); - - disc.minutes = desc[trackcount].min; - disc.seconds = desc[trackcount].sec; - - return true; -} +#include +#include +#include +#include struct ConvertedToc { @@ -555,30 +43,556 @@ cddb_sum(int n) } +// #pragma mark - + + +CDAudioData::CDAudioData(const int32 &id, const int32 &count, const int32 &discLength) + : + fDiscId(id), + fTrackCount(count), + fLength(discLength) +{ +} + + +CDAudioData::CDAudioData(const CDAudioData &from) + : + fDiscId(from.fDiscId), + fTrackCount(from.fTrackCount), + fLength(from.fLength) +{ +} + + +CDAudioData & +CDAudioData::operator=(const CDAudioData &from) +{ + fDiscId = from.fDiscId; + fTrackCount = from.fTrackCount; + fLength = from.fLength; + fFrameOffsets = from.fFrameOffsets; + return *this; +} + + +// #pragma mark - + + +CDAudioTime::CDAudioTime(const int32 min,const int32 &sec) + : + fMinutes(min), + fSeconds(sec) +{ +} + + +CDAudioTime::CDAudioTime(const CDAudioTime &from) + : + fMinutes(from.fMinutes), + fSeconds(from.fSeconds) +{ +} + + +CDAudioTime & +CDAudioTime::operator=(const CDAudioTime &from) +{ + fMinutes = from.fMinutes; + fSeconds = from.fSeconds; + return *this; +} + + +CDAudioTime +CDAudioTime::operator+(const CDAudioTime &from) +{ + CDAudioTime time; + + time.fMinutes = fMinutes + from.fMinutes; + time.fSeconds = fSeconds + from.fSeconds; + + while (time.fSeconds > 59) { + time.fMinutes++; + time.fSeconds -= 60; + } + return time; +} + + +CDAudioTime +CDAudioTime::operator-(const CDAudioTime &from) +{ + CDAudioTime time; + + int32 tsec = ((fMinutes * 60) + fSeconds) - ((from.fMinutes * 60) + from.fSeconds); + if (tsec < 0) { + time.fMinutes = 0; + time.fSeconds = 0; + return time; + } + + time.fMinutes = tsec / 60; + time.fSeconds = tsec % 60; + + return time; +} + + +// #pragma mark - + + +CDAudioDevice::CDAudioDevice() +{ + _FindDrives("/dev/disk"); + if (CountDrives() > 0) + SetDrive(0); +} + + +CDAudioDevice::~CDAudioDevice() +{ + for (int32 i = 0; i < fDriveList.CountItems(); i++) + delete (BString*) fDriveList.ItemAt(i); +} + + + +//! This plays only one track - the track specified +bool +CDAudioDevice::Play(const int16 &track) +{ + if (GetState() == kNoCD) { + // no CD available, bail out + ioctl(fFileHandle, B_LOAD_MEDIA, 0, 0); + return false; + } + + scsi_play_track playtrack; + + playtrack.start_track = track; + playtrack.start_index = 1; + playtrack.end_track = track; + playtrack.end_index = 1; + + status_t result = ioctl(fFileHandle, B_SCSI_PLAY_TRACK, &playtrack); + if (result != B_OK) { + printf("Couldn't play track: %s\n", strerror(errno)); + return false; + } + + return true; +} + + +bool +CDAudioDevice::Pause() +{ + status_t result = ioctl(fFileHandle, B_SCSI_PAUSE_AUDIO); + if (result != B_OK) { + printf("Couldn't pause track: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::Resume() +{ + CDState state = GetState(); + if (state == kNoCD) { + // no CD available, bail out + ioctl(fFileHandle, B_LOAD_MEDIA, 0, 0); + return false; + } else { + if (state == kStopped) + return Play(0); + } + + status_t result = ioctl(fFileHandle, B_SCSI_RESUME_AUDIO); + if (result != B_OK) { + printf("Couldn't resume track: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::Stop() +{ + status_t result = ioctl(fFileHandle, B_SCSI_STOP_AUDIO); + if (result != B_OK) { + printf("Couldn't stop CD: %s\n", strerror(errno)); + return false; + } + return true; +} + + +//! Open or close the CD tray +bool +CDAudioDevice::Eject() +{ + status_t media_status = B_DEV_NO_MEDIA; + + // get the status first + ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + + // if door open, load the media, else eject the CD + status_t result = ioctl(fFileHandle, + media_status == B_DEV_DOOR_OPEN ? B_LOAD_MEDIA : B_EJECT_DEVICE); + + if (result != B_OK) { + printf("Couldn't eject CD: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::StartFastFwd() +{ + scsi_scan scan; + scan.direction = 1; + scan.speed = 1; + status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); + if (result != B_OK) { + printf("Couldn't fast forward: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::StopFastFwd() +{ + scsi_scan scan; + scan.direction = 0; + scan.speed = 1; + status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); + if (result != B_OK) { + printf("Couldn't stop fast forwarding: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::StartRewind() +{ + scsi_scan scan; + scan.direction = -1; + scan.speed = 1; + status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); + if (result != B_OK) { + printf("Couldn't rewind: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::StopRewind() +{ + scsi_scan scan; + scan.direction = 0; + scan.speed = 1; + status_t result = ioctl(fFileHandle, B_SCSI_SCAN, &scan); + if (result != B_OK) { + printf("Couldn't stop rewinding: %s\n", strerror(errno)); + return false; + } + return true; +} + + +bool +CDAudioDevice::SetVolume(uint8 value) +{ + scsi_volume vol; + + // change only port0's volume + vol.flags = 2; + vol.port0_volume = value; + + status_t result = ioctl(fFileHandle, B_SCSI_SET_VOLUME, &vol); + if (result != B_OK) { + printf("Couldn't set volume: %s\n", strerror(errno)); + return false; + } + return true; +} + + +uint8 +CDAudioDevice::GetVolume() +{ + scsi_volume vol; + ioctl(fFileHandle, B_SCSI_GET_VOLUME, &vol); + return vol.port0_volume; +} + + +//! Check the current CD play state +CDState +CDAudioDevice::GetState() +{ + scsi_position pos; + status_t media_status = B_DEV_NO_MEDIA; + + ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + if (media_status != B_OK) + return kNoCD; + + status_t result = ioctl(fFileHandle, B_SCSI_GET_POSITION, &pos); + if (result != B_OK) + return kNoCD; + else if ((!pos.position[1]) || (pos.position[1] >= 0x13) || + ((pos.position[1] == 0x12) && (!pos.position[6]))) + return kStopped; + else if (pos.position[1] == 0x11) + return kPlaying; + else + return kPaused; +} + + +int16 +CDAudioDevice::CountTracks() +{ + scsi_toc toc; + status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); + + if (result != B_OK) + return -1; + + return toc.toc_data[3]; +} + + +//! Get the 0-based index of the current track +int16 +CDAudioDevice::GetTrack() +{ + scsi_position pos; + + status_t media_status = B_DEV_NO_MEDIA; + + ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + if (media_status != B_OK) + return -1; + + status_t result = ioctl(fFileHandle, B_SCSI_GET_POSITION, &pos); + if (result != B_OK) + return -1; + + if (!pos.position[1] || pos.position[1] >= 0x13 + || (pos.position[1] == 0x12 && !pos.position[6])) + return 0; + else + return pos.position[6]; +} + + +uint8 +CDAudioDevice::CountDrives() +{ + return fDriveList.CountItems(); +} + + +bool +CDAudioDevice::SetDrive(const int32 &drive) +{ + BString *path = (BString*) fDriveList.ItemAt(drive); + + if (!path) + return false; + + int device = open(path->String(), O_RDONLY); + if (device >= 0) { + fFileHandle = device; + fDrivePath = path; + fDriveIndex = drive; + return true; + } + + return false; +} + + +const char * +CDAudioDevice::GetDrivePath() const +{ + if (!fDrivePath) + return NULL; + + return fDrivePath->String(); +} + + int32 -CDAudioDevice::GetDiscID(void) +CDAudioDevice::_FindDrives(const char *path) +{ + BDirectory dir(path); + + if (dir.InitCheck() != B_OK) + return B_ERROR; + + dir.Rewind(); + + BEntry entry; + while (dir.GetNextEntry(&entry) >= 0) { + BPath path; + const char *name; + entry_ref e; + + if (entry.GetPath(&path) != B_OK) + continue; + + name = path.Path(); + if (entry.GetRef(&e) != B_OK) + continue; + + if (entry.IsDirectory()) { + // ignore floppy -- it is not silent + if (strcmp(e.name, "floppy") == 0) + continue; + else if (strcmp(e.name, "ata") == 0) + continue; + + // Note that if we check for the count here, we could + // just search for one drive. However, we want to find *all* drives + // that are available, so we keep searching even if we've found one + _FindDrives(name); + + } else { + int devfd; + device_geometry g; + + // ignore partitions + if (strcmp(e.name, "raw") != 0) + continue; + + 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) + fDriveList.AddItem(new BString(name)); + } + close(devfd); + } + } + return fDriveList.CountItems(); +} + + +bool +CDAudioDevice::GetTime(CDAudioTime &track, CDAudioTime &disc) +{ + scsi_position pos; + + // Sanity check + status_t media_status = B_DEV_NO_MEDIA; + ioctl(fFileHandle, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + if (media_status != B_OK) + return false; + + status_t result = ioctl(fFileHandle, B_SCSI_GET_POSITION, &pos); + + if (result != B_OK) + return false; + + 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. + return false; + } + + disc.SetMinutes(pos.position[9]); + disc.SetSeconds(pos.position[10]); + track.SetMinutes(pos.position[13]); + track.SetSeconds(pos.position[14]); + return true; +} + + +bool +CDAudioDevice::GetTimeForTrack(const int16 &index, CDAudioTime &track) +{ + scsi_toc toc; + status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); + + if (result != B_OK) + return false; + + int16 trackcount = toc.toc_data[3] - toc.toc_data[2] + 1; + + if (index < 1 || index > trackcount) + return false; + + TrackDescriptor *desc = (TrackDescriptor*)&(toc.toc_data[4]); + + int32 tracktime = (desc[index].min * 60) + desc[index].sec; + + tracktime -= (desc[index - 1].min * 60) + desc[index - 1].sec; + track.SetMinutes(tracktime / 60); + track.SetSeconds(tracktime % 60); + + return true; +} + + +bool +CDAudioDevice::GetTimeForDisc(CDAudioTime &disc) +{ + scsi_toc toc; + status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); + + if (result != B_OK) + return false; + + int16 trackcount = toc.toc_data[3] - toc.toc_data[2] + 1; + TrackDescriptor *desc = (TrackDescriptor*)&(toc.toc_data[4]); + + disc.SetMinutes(desc[trackcount].min); + disc.SetSeconds(desc[trackcount].sec); + + return true; +} + + +int32 +CDAudioDevice::GetDiscID() { // Read the disc scsi_toc toc; status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); - + if (result != B_OK) return -1; - - + + int32 id, numTracks; BString frameOffsetsString; - + ConvertedToc tocData[100]; // figure out the disc ID for (int index = 0; index < 100; index++) { - tocData[index].min = toc.toc_data[9 + 8*index]; - tocData[index].sec = toc.toc_data[10 + 8*index]; - tocData[index].frame = toc.toc_data[11 + 8*index]; + tocData[index].min = toc.toc_data[9 + 8 * index]; + tocData[index].sec = toc.toc_data[10 + 8 * index]; + tocData[index].frame = toc.toc_data[11 + 8 * index]; } numTracks = toc.toc_data[3] - toc.toc_data[2] + 1; - + int32 sum1 = 0; int32 sum2 = 0; for (int index = 0; index < numTracks; index++) { @@ -589,7 +603,7 @@ CDAudioDevice::GetDiscID(void) (tocData[index].min * 60 + tocData[index].sec); } id = ((sum1 % 0xff) << 24) + (sum2 << 8) + numTracks; - + return id; } @@ -599,19 +613,18 @@ CDAudioDevice::IsDataTrack(const int16 &track) { scsi_toc toc; status_t result = ioctl(fFileHandle, B_SCSI_GET_TOC, &toc); - + if (result != B_OK) return false; - + TrackDescriptor *trackindex = (TrackDescriptor*) &(toc.toc_data[4]); if (track > toc.toc_data[3]) return false; - + // At least under R5, the SCSI CD drive has each legitimate audio track // have a value of 0x10. Data tracks have a value of 0x14; if (trackindex[track].adr_control & 4) return true; - + return false; } - diff --git a/src/apps/cdplayer/CDAudioDevice.h b/src/apps/cdplayer/CDAudioDevice.h index 3b1f0da166..14f8d3776e 100644 --- a/src/apps/cdplayer/CDAudioDevice.h +++ b/src/apps/cdplayer/CDAudioDevice.h @@ -1,27 +1,28 @@ /* - * Copyright (c) 2006-2007, Haiku, Inc. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Author: - * DarkWyrm + * DarkWyrm, bpmagic@columbus.rr.com */ #ifndef CDAUDIODEVICE_H #define CDAUDIODEVICE_H -#include -#include #include +#include +#include + // The SCSI table of contents consists of a 4-byte header followed by 100 track // descriptors, which are each 8 bytes. We don't really need the first 5 bytes // of the track descriptor, so we'll just ignore them. All we really want is the -// length of each track, which happen to be the last 3 bytes of the descriptor. +// fLength of each track, which happen to be the last 3 bytes of the descriptor. typedef struct { uint8 reserved; uint8 adr_control; // bytes 0-3 are control, 4-7 are ADR uint8 track_number; uint8 reserved2; - + uint8 reserved3; uint8 min; uint8 sec; @@ -29,7 +30,7 @@ typedef struct { } TrackDescriptor; enum CDState { - kNoCD=0, + kNoCD = 0, kStopped, kPaused, kPlaying, @@ -38,79 +39,104 @@ enum CDState { kInit }; -class cdaudio_time -{ -public: - cdaudio_time(const int32 min=-1,const int32 &sec=-1); - cdaudio_time(const cdaudio_time &from); - cdaudio_time &operator=(const cdaudio_time &from); - cdaudio_time operator+(const cdaudio_time &from); - cdaudio_time operator-(const cdaudio_time &from); - - int32 minutes; - int32 seconds; + +class CDAudioTime { + public: + CDAudioTime(const int32 min = -1, const int32 &sec = -1); + CDAudioTime(const CDAudioTime &from); + CDAudioTime &operator=(const CDAudioTime &from); + CDAudioTime operator+(const CDAudioTime &from); + CDAudioTime operator-(const CDAudioTime &from); + + void SetMinutes(const int32& minutes) + { + fMinutes = minutes; + } + + void SetSeconds(const int32& seconds) + { + fSeconds = seconds; + } + + int32 GetMinutes() const + { + return fMinutes; + } + + int32 GetSeconds() const + { + return fSeconds; + } + + private: + int32 fMinutes; + int32 fSeconds; }; -class cdaudio_data -{ -public: - cdaudio_data(const int32 &id = -1, const int32 &count = -1, - const int32 &disclength = -1); - cdaudio_data(const cdaudio_data &from); - cdaudio_data &operator=(const cdaudio_data &from); - - int32 disc_id; - int32 track_count; - int32 length; - - BString frame_offsets; + +class CDAudioData { + public: + CDAudioData(const int32 &id = -1, const int32 &count = -1, + const int32 &discLength = -1); + CDAudioData(const CDAudioData &from); + CDAudioData &operator=(const CDAudioData &from); + + private: + int32 fDiscId; + int32 fTrackCount; + int32 fLength; + BString fFrameOffsets; }; -class CDAudioDevice -{ -public: - CDAudioDevice(void); - ~CDAudioDevice(void); - - bool Play(const int16 &track); - bool Pause(void); - bool Resume(void); - bool Stop(void); - bool Eject(void); - - bool StartFastFwd(void); - bool StopFastFwd(void); - - bool StartRewind(void); - bool StopRewind(void); - - bool SetVolume(uint8 value); - uint8 GetVolume(void); - - CDState GetState(void); - - int16 CountTracks(void); - int16 GetTrack(void); - - uint8 CountDrives(void); - bool SetDrive(const int32 &drive); - const char * GetDrivePath(void) const; - int32 GetDrive(void) const { return fDriveIndex; } - - bool GetTime(cdaudio_time &track, cdaudio_time &disc); - bool GetTimeForTrack(const int16 &index, cdaudio_time &track); - bool GetTimeForDisc(cdaudio_time &disc); - int32 GetDiscID(void); - - bool IsDataTrack(const int16 &track); - -private: - int32 FindDrives(const char *path); - - int fFileHandle; - BString * fDrivePath; - BList fDriveList; - int32 fDriveIndex; + +class CDAudioDevice { + public: + CDAudioDevice(); + ~CDAudioDevice(); + + bool Play(const int16 &track); + bool Pause(); + bool Resume(); + bool Stop(); + bool Eject(); + + bool StartFastFwd(); + bool StopFastFwd(); + + bool StartRewind(); + bool StopRewind(); + + bool SetVolume(uint8 value); + uint8 GetVolume(); + + CDState GetState(); + + int16 CountTracks(); + int16 GetTrack(); + + uint8 CountDrives(); + bool SetDrive(const int32 &drive); + const char* GetDrivePath() const; + + int32 GetDrive() const + { + return fDriveIndex; + } + + bool GetTime(CDAudioTime &track, CDAudioTime &disc); + bool GetTimeForTrack(const int16 &index, CDAudioTime &track); + bool GetTimeForDisc(CDAudioTime &disc); + int32 GetDiscID(); + + bool IsDataTrack(const int16 &track); + + private: + int32 _FindDrives(const char *path); + + int fFileHandle; + BString* fDrivePath; + BList fDriveList; + int32 fDriveIndex; }; -#endif +#endif // CDAUDIODEVICE_H diff --git a/src/apps/cdplayer/CDDBSupport.cpp b/src/apps/cdplayer/CDDBSupport.cpp index 05ba229996..af239731f3 100644 --- a/src/apps/cdplayer/CDDBSupport.cpp +++ b/src/apps/cdplayer/CDDBSupport.cpp @@ -6,27 +6,28 @@ #include "CDDBSupport.h" -#include #include +#include #include #include #include #include -#include #include +#include +#include #include #include +#include #include #include #include -#include #include #include #include #include #include -#include + //#define DEBUG_CDDB @@ -44,67 +45,108 @@ const int kTerminatingSignal = SIGINT; // SIGCONT; // length of each track, which happen to be the last 3 bytes of the descriptor. typedef struct TrackRecord { int8 unused[5]; - + int8 min; int8 sec; int8 frame; }; -CDDBData::CDDBData(int32 discid) - : fDiscID(discid), +static void +DoNothing(int) +{ +} + + +static int32 +cddb_sum(int n) +{ + char buf[12]; + int32 ret = 0; + + sprintf(buf, "%u", n); + for (const char *p = buf; *p != '\0'; p++) + ret += (*p - '0'); + return ret; +} + + +BString +GetLineFromString(const char *string) +{ + if (!string) + return NULL; + + BString out(string); + + int32 lineFeed = out.FindFirst("\n"); + + if (lineFeed > 0) + out.Truncate(lineFeed); + + return out; +} + + +// #pragma mark - + + +CDDBData::CDDBData(int32 discId) + : + fDiscID(discId), fYear(-1) { } CDDBData::CDDBData(const CDDBData &from) - : fDiscID(from.fDiscID), + : + fDiscID(from.fDiscID), fArtist(from.fArtist), fAlbum(from.fAlbum), fGenre(from.fGenre), fDiscTime(from.fDiscTime), - fYear(fYear) + fYear(from.fYear) { STRACE(("CDDBData::Copy Constructor\n")); - + for (int32 i = 0; i < from.fTrackList.CountItems(); i++) { BString *string = (BString*)from.fTrackList.ItemAt(i); - cdaudio_time *time = (cdaudio_time*)from.fTimeList.ItemAt(i); - + CDAudioTime *time = (CDAudioTime*)from.fTimeList.ItemAt(i); + if (!string || !time) continue; - - AddTrack(string->String(),*time); + + AddTrack(string->String(), *time); } } -CDDBData::~CDDBData(void) +CDDBData::~CDDBData() { STRACE(("CDDBData::~CDDBData\n")); - EmptyLists(); + _EmptyLists(); } CDDBData & CDDBData::operator=(const CDDBData &from) { - EmptyLists(); + _EmptyLists(); fDiscID = from.fDiscID; fArtist = from.fArtist; fAlbum = from.fAlbum; fGenre = from.fGenre; fDiscTime = from.fDiscTime; - fYear = fYear; - + fYear = from.fYear; + for (int32 i = 0; i < from.fTrackList.CountItems(); i++) { BString *string = (BString*)from.fTrackList.ItemAt(i); - cdaudio_time *time = (cdaudio_time*)from.fTimeList.ItemAt(i); - + CDAudioTime *time = (CDAudioTime*)from.fTimeList.ItemAt(i); + if (!string || !time) continue; - + AddTrack(string->String(),*time); } return *this; @@ -112,34 +154,34 @@ CDDBData::operator=(const CDDBData &from) void -CDDBData::MakeEmpty(void) +CDDBData::MakeEmpty() { STRACE(("CDDBData::MakeEmpty\n")); - - EmptyLists(); + + _EmptyLists(); fDiscID = -1; fArtist = ""; fAlbum = ""; fGenre = ""; - fDiscTime.minutes = -1; - fDiscTime.seconds = -1; + fDiscTime.SetMinutes(-1); + fDiscTime.SetSeconds(-1); fYear = -1; } void -CDDBData::EmptyLists(void) +CDDBData::_EmptyLists() { - STRACE(("CDDBData::EmptyLists\n")); + STRACE(("CDDBData::_EmptyLists\n")); for (int32 i = 0; i < fTrackList.CountItems(); i++) { BString *string = (BString*)fTrackList.ItemAt(i); delete string; } fTrackList.MakeEmpty(); - + for (int32 j = 0; j < fTimeList.CountItems(); j++) { - cdaudio_time *time = (cdaudio_time*)fTimeList.ItemAt(j); + CDAudioTime *time = (CDAudioTime*)fTimeList.ItemAt(j); delete time; } fTimeList.MakeEmpty(); @@ -149,127 +191,130 @@ CDDBData::EmptyLists(void) status_t CDDBData::Load(const entry_ref &ref) { - STRACE(("CDDBData::Load(%s)\n",ref.name)); - + STRACE(("CDDBData::Load(%s)\n", ref.name)); + BFile file(&ref, B_READ_ONLY); - + if (file.InitCheck() != B_OK) { STRACE(("CDDBData::Load failed\n")); return file.InitCheck(); } - + attr_info info; - - if (file.GetAttrInfo("Audio:Genre",&info) == B_OK && info.size > 0) { - char genredata[info.size + 2]; - - if (file.ReadAttr("Audio:Genre",B_STRING_TYPE,0,genredata,info.size) > 0) - fGenre = genredata; + + if (file.GetAttrInfo("Audio:Genre", &info) == B_OK && info.size > 0) { + char genreData[info.size + 2]; + + if (file.ReadAttr("Audio:Genre", B_STRING_TYPE, 0, genreData, info.size) > 0) + fGenre = genreData; } - if (file.GetAttrInfo("Audio:Year",&info)==B_OK && info.size > 0) { - int32 data; - - if (file.ReadAttr("Audio:Year",B_INT32_TYPE,0,&data,info.size) > 0) - fYear = data; + if (file.GetAttrInfo("Audio:Year", &info) == B_OK && info.size > 0) { + int32 yearData; + + if (file.ReadAttr("Audio:Year", B_INT32_TYPE, 0, &yearData, info.size) > 0) + fYear = yearData; } - + // TODO: Attempt reading the file before attempting to read the attributes - if (file.GetAttrInfo("CD:tracks",&info)==B_OK && info.size > 0) { - char trackdata[info.size + 2]; - - if (file.ReadAttr("CD:tracks",B_STRING_TYPE,0,trackdata,info.size) > 0) { - trackdata[info.size] = 0; - BString tmp = GetLineFromString(trackdata); + if (file.GetAttrInfo("CD:tracks", &info) == B_OK && info.size > 0) { + char trackData[info.size + 2]; + + if (file.ReadAttr("CD:tracks", B_STRING_TYPE, 0, trackData, info.size) > 0) { + trackData[info.size] = 0; + BString tmp = GetLineFromString(trackData); char *index; - + if (fTrackList.CountItems() > 0) - EmptyLists(); - + _EmptyLists(); + fArtist = tmp; fArtist.Truncate(fArtist.FindFirst(" - ")); - STRACE(("CDDBData::Load: Artist set to %s\n",fArtist.String())); - + STRACE(("CDDBData::Load: Artist set to %s\n", fArtist.String())); + fAlbum = tmp.String() + (tmp.FindFirst(" - ") + 3); - STRACE(("CDDBData::Load: Album set to %s\n",fAlbum.String())); - - index = strchr(trackdata,'\n') + 1; + STRACE(("CDDBData::Load: Album set to %s\n", fAlbum.String())); + + index = strchr(trackData, '\n') + 1; while (*index) { tmp = GetLineFromString(index); - + if (tmp.CountChars() > 0) { - BString *newtrack = new BString(tmp); - cdaudio_time *time = new cdaudio_time; - time->minutes = 0; - time->seconds = 0; - - STRACE(("CDDBData::Load: Adding Track %s (%ld:%ld)\n",newtrack->String(), - time->minutes,time->seconds)); - - fTrackList.AddItem(newtrack); + BString *newTrack = new BString(tmp); + CDAudioTime *time = new CDAudioTime; + time->SetMinutes(0); + time->SetSeconds(0); + + STRACE(("CDDBData::Load: Adding Track %s (%ld:%ld)\n", newTrack->String(), + time->minutes, time->seconds)); + + fTrackList.AddItem(newTrack); fTimeList.AddItem(time); } - + index = strchr(index,'\n') + 1; } - + // We return this so that the caller knows to initialize tracktimes return B_NO_INIT; } } - + return B_ERROR; } + status_t -CDDBData::Load(void) +CDDBData::Load() { // This uses the default R5 path - + BPath path; if (find_directory(B_USER_DIRECTORY, &path, true) != B_OK) return B_ERROR; - + path.Append("cd"); create_directory(path.Path(), 0755); - + BString filename(path.Path()); filename << "/" << Artist() << " - " << Album(); - - if (filename.Compare("Artist")==0) + + if (filename.Compare("Artist") == 0) filename << "." << DiscID(); - + BEntry entry(filename.String()); if (entry.InitCheck() != B_OK) return entry.InitCheck(); - + entry_ref ref; entry.GetRef(&ref); - + return Load(ref); } + status_t -CDDBData::Save(void) +CDDBData::Save() { // This uses the default R5 path - + BPath path; if (find_directory(B_USER_DIRECTORY, &path, true) != B_OK) return B_ERROR; - + path.Append("cd"); create_directory(path.Path(), 0755); - + BString filename(path.Path()); filename << "/" << Artist() << " - " << Album(); - + if (filename.Compare("Artist")==0) filename << "." << DiscID(); - + return Save(filename.String()); } + status_t CDDBData::Save(const char *filename) { @@ -277,183 +322,197 @@ CDDBData::Save(const char *filename) STRACE(("CDDBData::Save failed - NULL filename\n")); return B_ERROR; } - + BFile file(filename, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); if (file.InitCheck() != B_OK) { - STRACE(("CDDBData::Save failed - couldn't create file %s\n",filename)); + STRACE(("CDDBData::Save failed - couldn't create file %s\n", filename)); return file.InitCheck(); } - + BString entry; char timestring[10]; - - sprintf(timestring,"%.2ld:%.2ld",fDiscTime.minutes, fDiscTime.seconds); - + + sprintf(timestring,"%.2ld:%.2ld", fDiscTime.GetMinutes(), fDiscTime.GetSeconds()); + entry << fArtist << " - " << fAlbum << "\t" << timestring << "\n"; - file.Write(entry.String(),entry.Length()); - - STRACE(("CDDBData::Save: wrote first line: %s",entry.String())); - + file.Write(entry.String(), entry.Length()); + + STRACE(("CDDBData::Save: wrote first line: %s", entry.String())); + BString tracksattr(fArtist); tracksattr << " - " << fAlbum << "\n"; - + for (int32 i = 0; i < fTrackList.CountItems(); i++) { BString *trackstr = (BString *)fTrackList.ItemAt(i); - cdaudio_time *time= (cdaudio_time*)fTimeList.ItemAt(i); - + CDAudioTime *time= (CDAudioTime*)fTimeList.ItemAt(i); + if (!trackstr || !time) continue; - + entry = *trackstr; - - sprintf(timestring,"%.2ld:%.2ld",time->minutes, time->seconds); - + + sprintf(timestring,"%.2ld:%.2ld", time->GetMinutes(), time->GetSeconds()); + entry << "\t" << timestring << "\n"; - file.Write(entry.String(),entry.Length()); - STRACE(("CDDBData::Save: Wrote line: %s",entry.String())); + file.Write(entry.String(), entry.Length()); + STRACE(("CDDBData::Save: Wrote line: %s", entry.String())); tracksattr << *trackstr << "\n"; } - + file.WriteAttr("CD:key", B_INT32_TYPE, 0, &fDiscID, sizeof(int32)); - STRACE(("CDDBData::Save: Wrote CD identifier: %ld(%lx)\n",fDiscID,fDiscID)); + STRACE(("CDDBData::Save: Wrote CD identifier: %ld(%lx)\n", fDiscID, fDiscID)); file.WriteAttr("CD:tracks", B_STRING_TYPE, 0, tracksattr.String(), tracksattr.Length() + 1); - + if (fGenre.CountChars() > 0) - file.WriteAttr("Audio:Genre",B_STRING_TYPE,0, fGenre.String(), fGenre.Length() + 1); - + file.WriteAttr("Audio:Genre",B_STRING_TYPE, 0, fGenre.String(), fGenre.Length() + 1); + if (fYear > 0) - file.WriteAttr("Audio:Year",B_INT32_TYPE,0,&fYear,sizeof(int32)); - + file.WriteAttr("Audio:Year", B_INT32_TYPE, 0, &fYear, sizeof(int32)); + return B_OK; } + uint16 -CDDBData::CountTracks(void) const +CDDBData::CountTracks() const { return fTrackList.CountItems(); } + bool -CDDBData::RenameTrack(const int32 &index, const char *newname) +CDDBData::RenameTrack(const int32 &index, const char *newName) { - if (!newname) { - STRACE(("CDDBData::RenameTrack failed - NULL newname\n")); + if (!newName) { + STRACE(("CDDBData::RenameTrack failed - NULL newName\n")); return false; } - + BString *name = (BString*)fTrackList.ItemAt(index); if (name) { - STRACE(("CDDBData::RenameTrack(%ld,%s)\n",index,newname)); - name->SetTo(newname); + STRACE(("CDDBData::RenameTrack(%ld,%s)\n", index, newName)); + name->SetTo(newName); return true; } - + STRACE(("CDDBData::RenameTrack failed - invalid index\n")); return false; } + void -CDDBData::AddTrack(const char *track, const cdaudio_time &time, - const int16 &index) +CDDBData::AddTrack(const char *track, const CDAudioTime &time, + const int16 &index) { if (!track) { STRACE(("CDDBData::AddTrack failed - NULL name\n")); return; } - STRACE(("CDDBData::AddTrack(%s, %ld:%.2ld,%d)\n",track,time.minutes,time.seconds,index)); - + STRACE(("CDDBData::AddTrack(%s, %ld:%.2ld,%d)\n", track, time.minutes, time.seconds, index)); + fTrackList.AddItem(new BString(track)); - fTimeList.AddItem(new cdaudio_time(time)); + fTimeList.AddItem(new CDAudioTime(time)); } + void CDDBData::RemoveTrack(const int16 &index) { // This breaks the general following of the BList style because // removing a track would require returning 2 pointers - + fTrackList.RemoveItem(index); fTimeList.RemoveItem(index); - - STRACE(("CDDBData::RemoveTrack(%d)\n",index)); + + STRACE(("CDDBData::RemoveTrack(%d)\n", index)); } - + + const char * CDDBData::TrackAt(const int16 &index) const { BString *track = (BString*)fTrackList.ItemAt(index); if (!track) return NULL; - + return track->String(); } -cdaudio_time * + +CDAudioTime * CDDBData::TrackTimeAt(const int16 &index) { - return (cdaudio_time *)fTimeList.ItemAt(index); + return (CDAudioTime *)fTimeList.ItemAt(index); } + +// #pragma mark - + + CDDBQuery::CDDBQuery(const char *server, int32 port) - : fServerName(server), - fPort(port), - fConnected(false), - fState(kInitial) + : + fServerName(server), + fPort(port), + fConnected(false), + fState(kInitial) { } -CDDBQuery::~CDDBQuery(void) + +CDDBQuery::~CDDBQuery() { kill_thread(fThread); } + void CDDBQuery::SetToSite(const char *server, int32 port) { - Disconnect(); + _Disconnect(); fServerName = server; fPort = port; fState = kInitial; } + void CDDBQuery::SetToCD(const char *path) { 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; - + status_t result = ioctl(device, B_SCSI_GET_TOC, &fSCSIData); - + close(device); - + if (result != B_OK) return; - + // Calculate the disc's CDDB ID if (fState == kInitial) { fCDData.SetDiscID(GetDiscID(&fSCSIData)); fCDData.SetDiscTime(GetDiscTime(&fSCSIData)); } else { int32 discID = GetDiscID(&fSCSIData); - + if (fCDData.DiscID() == discID) return; - + fCDData.SetDiscID(discID); fCDData.SetDiscTime(GetDiscTime(&fSCSIData)); fFrameOffsetString = OffsetsToString(&fSCSIData); } - + result = B_OK; fState = kReading; - fThread = spawn_thread(&CDDBQuery::QueryThread, "CDDBLookup", B_NORMAL_PRIORITY, this); - + fThread = spawn_thread(&CDDBQuery::_QueryThread, "CDDBLookup", B_NORMAL_PRIORITY, this); + if (fThread >= 0) resume_thread(fThread); else { @@ -462,20 +521,16 @@ CDDBQuery::SetToCD(const char *path) } } -static void -DoNothing(int) -{ -} const char * -CDDBQuery::GetToken(const char *stream, BString &result) +CDDBQuery::_GetToken(const char *stream, BString &result) { result = ""; while (*stream && *stream <= ' ') stream++; while (*stream && *stream > ' ') result += *stream++; - + return stream; } @@ -484,24 +539,24 @@ status_t CDDBQuery::GetSites(bool (*eachFunc)(const char *site, int port, const char *latitude, const char *longitude, const char *description, void *state), void *passThru) { - if (!IsConnected()) - Connect(); - + if (!_IsConnected()) + _Connect(); + BString tmp; - + tmp = "sites\n"; STRACE((">%s", tmp.String())); - if (fSocket.Send(tmp.String(), tmp.Length())==-1) + if (fSocket.Send(tmp.String(), tmp.Length()) == -1) return B_ERROR; - - ReadLine(tmp); + + _ReadLine(tmp); if (tmp.FindFirst("210") == -1) { - Disconnect(); + _Disconnect(); return B_ERROR; } - + for (;;) { BString site; int32 sitePort; @@ -509,33 +564,34 @@ CDDBQuery::GetSites(bool (*eachFunc)(const char *site, int port, const char *lat BString longitude; BString description; - ReadLine(tmp); + _ReadLine(tmp); if (tmp == ".") break; const char *scanner = tmp.String(); - scanner = GetToken(scanner, site); + scanner = _GetToken(scanner, site); BString portString; - scanner = GetToken(scanner, portString); + scanner = _GetToken(scanner, portString); sitePort = atoi(portString.String()); - scanner = GetToken(scanner, latitude); - scanner = GetToken(scanner, longitude); + scanner = _GetToken(scanner, latitude); + scanner = _GetToken(scanner, longitude); description = scanner; - + if (eachFunc(site.String(), sitePort, latitude.String(), longitude.String(), description.String(), passThru)) break; } - Disconnect(); + _Disconnect(); return B_OK; } + bool CDDBQuery::GetData(CDDBData *data, bigtime_t timeout) { if (!data) return false; - + bigtime_t deadline = system_time() + timeout; while (fState == kReading) { snooze(50000); @@ -544,23 +600,12 @@ CDDBQuery::GetData(CDDBData *data, bigtime_t timeout) } if (fState != kDone) return false; - + *data = fCDData; - + return true; } -static int32 -cddb_sum(int n) -{ - char buf[12]; - int32 ret = 0; - - sprintf(buf, "%u", n); - for (const char *p = buf; *p != '\0'; p++) - ret += (*p - '0'); - return ret; -} int32 CDDBQuery::GetDiscID(const scsi_toc *toc) @@ -569,34 +614,35 @@ CDDBQuery::GetDiscID(const scsi_toc *toc) TrackRecord *tocData = (TrackRecord*)&(toc->toc_data[4]); int32 numTracks = toc->toc_data[3] - toc->toc_data[2] + 1; - + int32 sum1 = 0; int32 sum2 = 0; for (int index = 0; index < numTracks; index++) { sum1 += cddb_sum((tocData[index].min * 60) + tocData[index].sec); - + // the following is probably running over too far sum2 += (tocData[index + 1].min * 60 + tocData[index + 1].sec) - (tocData[index].min * 60 + tocData[index].sec); } int32 discID = ((sum1 % 0xff) << 24) + (sum2 << 8) + numTracks; - + return discID; } + BString CDDBQuery::OffsetsToString(const scsi_toc *toc) { TrackRecord *tocData = (TrackRecord*)&(toc->toc_data[4]); - + int32 numTracks = toc->toc_data[3] - toc->toc_data[2] + 1; - + BString string; for (int index = 0; index < numTracks; index++) { string << tocData[index].min * 4500 + tocData[index].sec * 75 + tocData[index].frame << ' '; } - + return string; } @@ -607,98 +653,101 @@ CDDBQuery::GetTrackCount(const scsi_toc *toc) return toc->toc_data[3] - toc->toc_data[2] + 1; } -cdaudio_time + +CDAudioTime CDDBQuery::GetDiscTime(const scsi_toc *toc) { int16 trackcount = toc->toc_data[3] - toc->toc_data[2] + 1; TrackRecord *desc = (TrackRecord*)&(toc->toc_data[4]); - - cdaudio_time disc; - disc.minutes = desc[trackcount].min; - disc.seconds = desc[trackcount].sec; + + CDAudioTime disc; + disc.SetMinutes(desc[trackcount].min); + disc.SetSeconds(desc[trackcount].sec); return disc; } + void -CDDBQuery::GetTrackTimes(const scsi_toc *toc, vector ×) +CDDBQuery::GetTrackTimes(const scsi_toc *toc, vector ×) { TrackRecord *tocData = (TrackRecord*)&(toc->toc_data[4]); int16 trackCount = toc->toc_data[3] - toc->toc_data[2] + 1; - + for (int index = 0; index < trackCount + 1; index++) { - cdaudio_time cdtime; - cdtime.minutes = tocData[index].min; - cdtime.seconds = tocData[index].sec; + CDAudioTime cdtime; + cdtime.SetMinutes(tocData[index].min); + cdtime.SetSeconds(tocData[index].sec); times.push_back(cdtime); } } + status_t -CDDBQuery::ReadFromServer(BString &data) +CDDBQuery::_ReadFromServer(BString &data) { // This function queries the given CDDB server for the existence of the disc's data and // saves the data to file once obtained. - + // Query for the existence of the disc in the database char idString[10]; sprintf(idString, "%08lx", fCDData.DiscID()); BString query; - + int32 trackCount = GetTrackCount(&fSCSIData); BString offsetString = OffsetsToString(&fSCSIData); - int32 discLength = (fCDData.DiscTime()->minutes * 60) + fCDData.DiscTime()->seconds; - + int32 discLength = (fCDData.DiscTime()->GetMinutes() * 60) + fCDData.DiscTime()->GetSeconds(); + query << "cddb query " << idString << ' ' << trackCount << ' ' << offsetString << ' ' << discLength << '\n'; - + STRACE((">%s", query.String())); - if (fSocket.Send(query.String(), query.Length())==-1) { - Disconnect(); + if (fSocket.Send(query.String(), query.Length()) == -1) { + _Disconnect(); return B_ERROR; } - + BString tmp; - ReadLine(tmp); + _ReadLine(tmp); STRACE(("<%s", tmp.String())); - + BString category; BString queryDiscID(idString); - + if (tmp.FindFirst("200") != 0) { if (tmp.FindFirst("211") == 0) { // A 211 means that the query was not exact. To make sure that we don't // have a problem with this in the future, we will choose the first entry that // the server returns. This may or may not be wise, but in my experience, the first // one has been the right one. - - ReadLine(tmp); - + + _ReadLine(tmp); + // Get the category from the what the server returned - GetToken(tmp.String(), category); - + _GetToken(tmp.String(), category); + // Now we will get the disc ID for the CD. We will need this when we query for // the track name list. If we send the track name query with the real discID, nothing // will be returned. However, if we send the one from the entry, we'll get the names // and we can take these names attach them to the disc that we have. - GetToken(tmp.String() + category.CountChars(),queryDiscID); - + _GetToken(tmp.String() + category.CountChars(), queryDiscID); + // This is to suck up any more search results that the server sends us. BString throwaway; - ReadLine(throwaway); + _ReadLine(throwaway); while (throwaway.ByteAt(0) != '.') - ReadLine(throwaway); + _ReadLine(throwaway); } else { // We get here for any time the CDDB server does not recognize the CD, amongst other things - STRACE(("CDDB lookup error: %s\n",tmp.String())); + STRACE(("CDDB lookup error: %s\n", tmp.String())); fCDData.SetGenre("misc"); return B_NAME_NOT_FOUND; } } else { - GetToken(tmp.String() + 3, category); + _GetToken(tmp.String() + 3, category); } - STRACE(("CDDBQuery::ReadFromServer: Genre: %s\n",category.String())); + STRACE(("CDDBQuery::_ReadFromServer: Genre: %s\n", category.String())); if (!category.Length()) { STRACE(("Set genre to 'misc'\n")); category = "misc"; @@ -707,56 +756,59 @@ CDDBQuery::ReadFromServer(BString &data) // Query for the disc's data - artist, album, tracks, etc. query = ""; query << "cddb read " << category << ' ' << queryDiscID << '\n' ; - if (fSocket.Send(query.String(), query.Length())==-1) { - Disconnect(); + if (fSocket.Send(query.String(), query.Length()) == -1) { + _Disconnect(); return B_ERROR; } - + while (true) { - ReadLine(tmp); - + _ReadLine(tmp); + if (tmp == "." || tmp == ".\n") break; - + data << tmp << '\n'; } - + return B_OK; } + status_t -CDDBQuery::Connect() +CDDBQuery::_Connect() { if (fConnected) - Disconnect(); - + _Disconnect(); + BNetAddress address; - + status_t status = address.SetTo(fServerName.String(), fPort); if (status != B_OK) return status; - + status = fSocket.Connect(address); if (status != B_OK) return status; - + fConnected = true; BString tmp; - ReadLine(tmp); - IdentifySelf(); - + _ReadLine(tmp); + _IdentifySelf(); + return B_OK; } + bool -CDDBQuery::IsConnected() const +CDDBQuery::_IsConnected() const { return fConnected; } + void -CDDBQuery::Disconnect() +CDDBQuery::_Disconnect() { if (fConnected) { fSocket.Close(); @@ -764,17 +816,18 @@ CDDBQuery::Disconnect() } } + void -CDDBQuery::ReadLine(BString &buffer) +CDDBQuery::_ReadLine(BString &buffer) { buffer = ""; unsigned char ch; - + for (;;) { if (fSocket.Receive(&ch, 1) <= 0) break; - - + + // This function is more work than it should have to be. FreeDB lookups can sometimes // be in a non-ASCII encoding, such as Latin-1 or UTF8. The problem lies in Be's implementation // of BString, which does not support UTF8 string assignments. The Be Book says we have to @@ -783,14 +836,14 @@ CDDBQuery::ReadLine(BString &buffer) // Obviously non-ASCII character detected. Let's see if it's Latin-1 or UTF8. unsigned char *string, *stringindex; int32 length = buffer.Length(); - + // The first byte of a UTF8 string will be 110xxxxx if ( ((ch & 0xe0) == 0xc0)) { // This is UTF8. Get the next byte unsigned char ch2; if (fSocket.Receive(&ch2, 1) <= 0) break; - + if ( (ch2 & 0xc0) == 0x80) { string = (unsigned char *)buffer.LockBuffer(length + 10); stringindex = string + length; @@ -805,21 +858,21 @@ CDDBQuery::ReadLine(BString &buffer) continue; } } - + // Nope. Just Latin-1. Convert to UTF8 and assign char srcstr[2], deststr[5]; int32 srclen, destlen, state; - + srcstr[0] = ch; srcstr[1] = '\0'; srclen = 1; destlen = 5; - memset(deststr,0,5); - - if (convert_to_utf8(B_ISO1_CONVERSION,srcstr,&srclen,deststr,&destlen,&state)==B_OK) { + memset(deststr, 0, 5); + + if (convert_to_utf8(B_ISO1_CONVERSION, srcstr, &srclen, deststr, &destlen, &state) == B_OK) { // We succeeded. Amazing. Now we hack the string into having the character length = buffer.Length(); - + string = (unsigned char *)buffer.LockBuffer(length + 10); stringindex = string + length; @@ -828,7 +881,7 @@ CDDBQuery::ReadLine(BString &buffer) if (!deststr[i]) break; } - + buffer.UnlockBuffer(); } else { // well, we tried. Append the character to the string and live with it @@ -836,54 +889,56 @@ CDDBQuery::ReadLine(BString &buffer) } } else buffer += ch; - + if (ch == '\n') break; } - + buffer.RemoveAll("\r"); STRACE(("<%s", buffer.String())); } + status_t -CDDBQuery::IdentifySelf() +CDDBQuery::_IdentifySelf() { - BString username,hostname; - + BString username, hostname; + username = getenv("USER"); hostname = getenv("HOSTNAME"); - + if (username.Length() < 1) username = "baron"; - + if (hostname.Length() < 1) hostname = "haiku"; - + BString tmp; tmp << "cddb hello " << username << " " << hostname << " HaikuCDPlayer 1.0\n"; STRACE((">%s", tmp.String())); if (fSocket.Send(tmp.String(), tmp.Length())==-1) { - Disconnect(); + _Disconnect(); return B_ERROR; } - - ReadLine(tmp); - + + _ReadLine(tmp); + return B_OK; } + status_t -CDDBQuery::OpenContentFile(const int32 &discID) +CDDBQuery::_OpenContentFile(const int32 &discID) { // Makes sure that the lookup has a valid file to work with for the CD content. // Returns true if there is an existing file, false if a lookup is required. - + BFile file; BString predicate; predicate << "CD:key == " << discID; entry_ref ref; - + BVolumeRoster roster; BVolume volume; roster.Rewind(); @@ -891,7 +946,7 @@ CDDBQuery::OpenContentFile(const int32 &discID) if (volume.IsReadOnly() || !volume.IsPersistent() || !volume.KnowsAttr() || !volume.KnowsQuery()) continue; - + // make sure the volume we are looking at is indexed right fs_create_index(volume.Device(), "CD:key", B_INT32_TYPE, 0); @@ -900,188 +955,192 @@ CDDBQuery::OpenContentFile(const int32 &discID) query.SetPredicate(predicate.String()); if (query.Fetch() != B_OK) continue; - + if (query.GetNextRef(&ref) == B_OK) break; } - + status_t status = fCDData.Load(ref); if (status == B_NO_INIT) { // We receive this error when the Load() function couldn't load the track times // This just means that we get it from the SCSI data given to us in SetToCD - vector times; + vector times; GetTrackTimes(&fSCSIData,times); - + for (int32 i = 0; i < fCDData.CountTracks(); i++) { - cdaudio_time *item = fCDData.TrackTimeAt(i); + CDAudioTime *item = fCDData.TrackTimeAt(i); *item = times[i + 1] - times[i]; } - + status = B_OK; } - + return status; } + int32 -CDDBQuery::QueryThread(void *owner) +CDDBQuery::_QueryThread(void *owner) { CDDBQuery *query = (CDDBQuery *)owner; - + signal(kTerminatingSignal, DoNothing); - - if (query->OpenContentFile(query->fCDData.DiscID()) != B_OK) { + + if (query->_OpenContentFile(query->fCDData.DiscID()) != B_OK) { // new content file, read it in from the server - if (query->Connect()==B_OK) { + if (query->_Connect() == B_OK) { BString data; - - query->ReadFromServer(data); - query->ParseData(data); - query->WriteFile(); + + query->_ReadFromServer(data); + query->_ParseData(data); + query->_WriteFile(); } else { // We apparently couldn't connect to the server, so we'll need to handle // creating tracknames. Note that we do not save to disk. This is because it should // be up to the user what to do. - query->SetDefaultInfo(); + query->_SetDefaultInfo(); } } - + query->fState = kDone; query->fThread = -1; query->fResult = B_OK; - + return 0; } + void -CDDBQuery::WriteFile(void) +CDDBQuery::_WriteFile() { BPath path; if (find_directory(B_USER_DIRECTORY, &path, true) != B_OK) return; - + path.Append("cd"); create_directory(path.Path(), 0755); - + BString filename(path.Path()); filename << "/" << fCDData.Artist() << " - " << fCDData.Album(); - - if (filename.Compare("Artist")==0) + + if (filename.Compare("Artist") == 0) filename << "." << fCDData.DiscID(); - + fCDData.Save(filename.String()); } + void -CDDBQuery::SetDefaultInfo(void) +CDDBQuery::_SetDefaultInfo() { for (int16 i = fCDData.CountTracks(); i >= 0; i--) fCDData.RemoveTrack(i); - - vector trackTimes; - GetTrackTimes(&fSCSIData,trackTimes); + + vector trackTimes; + GetTrackTimes(&fSCSIData, trackTimes); int32 trackCount = GetTrackCount(&fSCSIData); - + fCDData.SetArtist("Artist"); fCDData.SetAlbum("Audio CD"); fCDData.SetGenre("Misc"); - + for (int32 i = 0; i < trackCount; i++) { BString trackname("Track "); - + if (i < 9) trackname << "0"; - + trackname << i + 1; - - cdaudio_time time = trackTimes[i + 1] - trackTimes[i]; - fCDData.AddTrack(trackname.String(),time); + + CDAudioTime time = trackTimes[i + 1] - trackTimes[i]; + fCDData.AddTrack(trackname.String(), time); } } + void -CDDBQuery::ParseData(const BString &data) +CDDBQuery::_ParseData(const BString &data) { // Can't simply call MakeEmpty() because the thread is spawned when the discID kept in fCDData // is not the same as what's in the drive and MakeEmpty invalidates *everything* in the object. // Considering that we reassign everything here, simply emptying the track list should be sufficient for (int16 i = fCDData.CountTracks(); i >= 0; i--) fCDData.RemoveTrack(i); - - vector trackTimes; + + vector trackTimes; GetTrackTimes(&fSCSIData,trackTimes); int32 trackCount = GetTrackCount(&fSCSIData); - + if (data.CountChars() < 1) { // This case occurs when the CDDB lookup fails. On these occasions, we need to generate // the file ourselves. This is actually pretty easy. fCDData.SetArtist("Artist"); fCDData.SetAlbum("Audio CD"); fCDData.SetGenre("Misc"); - + for (int32 i = 0; i < trackCount; i++) { BString trackname("Track "); - + if (i < 9) trackname << "0"; - + trackname << i + 1; - - cdaudio_time time = trackTimes[i + 1] - trackTimes[i]; - fCDData.AddTrack(trackname.String(),time); + + CDAudioTime time = trackTimes[i + 1] - trackTimes[i]; + fCDData.AddTrack(trackname.String(), time); } } - + // TODO: This function is dog slow, but it works. Optimize. - + // Ideally, the search should be done sequentially using GetLineFromString() and strchr(). // Order: genre(category), frame offsets, disc length, artist/album, track titles - + int32 pos; - + pos = data.FindFirst("DYEAR="); if (pos > 0) { BString artist,album; artist = album = GetLineFromString(data.String() + sizeof("DYEAR") + pos); - + // TODO: finish, once I find an entry which actually has a year in it - BAlert *alert = new BAlert("SimplyVorbis","DYEAR entry found\n","OK"); + BAlert *alert = new BAlert("SimplyVorbis", "DYEAR entry found\n", "OK"); alert->Go(); } - + pos = data.FindFirst("DTITLE="); if (pos > 0) { BString artist,album; artist = album = GetLineFromString(data.String() + sizeof("DTITLE") + pos); - + pos = artist.FindFirst(" / "); if (pos > 0) artist.Truncate(pos); fCDData.SetArtist(artist.String()); - + album = album.String() + pos + sizeof(" / ") - 1; fCDData.SetAlbum(album.String()); } - + BString category = GetLineFromString(data.String() + 4); pos = category.FindFirst(" "); if (pos > 0) category.Truncate(pos); fCDData.SetGenre(category.String()); - + pos = data.FindFirst("TTITLE0="); if (pos > 0) { int32 trackCount = 0; BString searchString = "TTITLE0="; - + while (pos > 0) { BString trackName = data.String() + pos + searchString.Length(); trackName.Truncate(trackName.FindFirst("\n")); - - cdaudio_time tracktime = trackTimes[trackCount + 1] - trackTimes[trackCount]; + + CDAudioTime tracktime = trackTimes[trackCount + 1] - trackTimes[trackCount]; fCDData.AddTrack(trackName.String(),tracktime); - + trackCount++; searchString = "TTITLE"; searchString << trackCount << "="; @@ -1090,23 +1149,8 @@ CDDBQuery::ParseData(const BString &data) } } + void CDDBQuery::SetData(const CDDBData &data) { fCDData = data; } - -BString -GetLineFromString(const char *string) -{ - if (!string) - return NULL; - - BString out(string); - - int32 linefeed = out.FindFirst("\n"); - - if (linefeed > 0) - out.Truncate(linefeed); - - return out; -} diff --git a/src/apps/cdplayer/CDDBSupport.h b/src/apps/cdplayer/CDDBSupport.h index d8d8774547..df3c724e77 100644 --- a/src/apps/cdplayer/CDDBSupport.h +++ b/src/apps/cdplayer/CDDBSupport.h @@ -1,149 +1,212 @@ #ifndef CDDBSUPPORT_H #define CDDBSUPPORT_H -#include -#include -#include -#include +#include "CDAudioDevice.h" + #include #include -#include "CDAudioDevice.h" +#include +#include + +#include +#include using std::vector; -class CDDBData -{ -public: - CDDBData(int32 discid=-1); - CDDBData(const CDDBData &from); - ~CDDBData(void); - CDDBData & operator=(const CDDBData &from); - - status_t Load(const entry_ref &ref); - status_t Save(const char *filename); - - status_t Load(void); - status_t Save(void); - - void MakeEmpty(void); - void SetDiscID(const int32 &id) { fDiscID=id; } - int32 DiscID(void) const { return fDiscID; } - - uint16 CountTracks(void) const; - const char * TrackAt(const int16 &index) const; - bool RenameTrack(const int32 &index, const char *newname); - void AddTrack(const char *track, const cdaudio_time &time, - const int16 &index=-1); - void RemoveTrack(const int16 &index); - - cdaudio_time * TrackTimeAt(const int16 &index); - - void SetDiscTime(const cdaudio_time time) { fDiscTime = time; } - cdaudio_time * DiscTime(void) { return &fDiscTime; } - - void SetGenre(const char *genre) { fGenre=genre; } - const char * Genre(void) { return fGenre.String(); } - - void SetArtist(const char *artist) { fArtist=artist; } - const char * Artist(void) const { return fArtist.String(); } - - void SetAlbum(const char *album) { fAlbum=album; } - const char * Album(void) const { return fAlbum.String(); } - - void SetYear(const int16 &year) { fYear=year; } - int16 Year(void) const { return fYear; } - -private: - void EmptyLists(void); - - int32 fDiscID; - - BString fArtist; - BString fAlbum; - BString fGenre; - - BList fTrackList; - BList fTimeList; - - cdaudio_time fDiscTime; - int32 fYear; +class CDDBData { + public: + CDDBData(int32 discid = -1); + CDDBData(const CDDBData &from); + ~CDDBData(); + CDDBData& operator=(const CDDBData &from); + + status_t Load(const entry_ref &ref); + status_t Save(const char *filename); + + status_t Load(); + status_t Save(); + + void MakeEmpty(); + + void SetDiscID(const int32 &id) + { + fDiscID = id; + } + + int32 DiscID() const + { + return fDiscID; + } + + uint16 CountTracks() const; + const char* TrackAt(const int16 &index) const; + bool RenameTrack(const int32 &index, const char *newname); + void AddTrack(const char *track, const CDAudioTime &time, + const int16 &index=-1); + void RemoveTrack(const int16 &index); + + CDAudioTime* TrackTimeAt(const int16 &index); + + void SetDiscTime(const CDAudioTime time) + { + fDiscTime = time; + } + + CDAudioTime* DiscTime() + { + return &fDiscTime; + } + + void SetGenre(const char *genre) + { + fGenre=genre; + } + + const char* Genre() + { + return fGenre.String(); + } + + void SetArtist(const char *artist) + { + fArtist = artist; + } + + const char* Artist() const + { + return fArtist.String(); + } + + void SetAlbum(const char *album) + { + fAlbum = album; + } + + const char* Album() const + { + return fAlbum.String(); + } + + void SetYear(const int16 &year) + { + fYear = year; + } + + int16 Year() const + { + return fYear; + } + + private: + void _EmptyLists(); + + int32 fDiscID; + + BString fArtist; + BString fAlbum; + BString fGenre; + + BList fTrackList; + BList fTimeList; + + CDAudioTime fDiscTime; + int32 fYear; }; + // based on Jukebox by Chip Paul -class CDDBQuery -{ -public: - CDDBQuery(const char *server, int32 port = 888); - ~CDDBQuery(void); - void SetToSite(const char *server, int32 port); - status_t GetSites(bool (*)(const char *site, int port, - const char *latitude, const char *longitude, - const char *description, void *state), void *); - void SetToCD(const char *devicepath); - - const char * GetArtist(void) { return fCDData.Artist(); } - const char * GetAlbum(void) { return fCDData.Album(); } - const char * GetGenre(void) { return fCDData.Genre(); } - - bool GetData(CDDBData *data, bigtime_t timeout); - void SetData(const CDDBData &data); - - bool Ready() const { return fState == kDone; } - int32 CurrentDiscID() const { return fCDData.DiscID(); } +class CDDBQuery { + public: + CDDBQuery(const char *server, int32 port = 888); + ~CDDBQuery(); + void SetToSite(const char *server, int32 port); + status_t GetSites(bool (*)(const char *site, int port, + const char *latitude, const char *longitude, + const char *description, void *state), void *); - static int32 GetDiscID(const scsi_toc *); - static int32 GetTrackCount(const scsi_toc *); - static cdaudio_time GetDiscTime(const scsi_toc *); - static void GetTrackTimes(const scsi_toc *, vector ×); - static BString OffsetsToString(const scsi_toc *); - -private: - status_t Connect(); - void Disconnect(); - bool IsConnected() const; - - static int32 QueryThread(void *); + void SetToCD(const char *devicepath); - // cached retrieved data - enum State - { - kInitial, - kReading, - kDone, - kInterrupting, - kError - }; - void SetDefaultInfo(void); - status_t OpenContentFile(const int32 &discID); - - status_t ReadFromServer(BString &data); - void ParseData(const BString &data); - void WriteFile(void); - - void ReadLine(BString &); - status_t IdentifySelf(); + const char* GetArtist() + { + return fCDData.Artist(); + } - const char * GetToken(const char *, BString &); + const char* GetAlbum() + { + return fCDData.Album(); + } + + const char* GetGenre() + { + return fCDData.Genre(); + } + + bool GetData(CDDBData *data, bigtime_t timeout); + void SetData(const CDDBData &data); + + bool Ready() const + { + return fState == kDone; + } + + int32 CurrentDiscID() const + { + return fCDData.DiscID(); + } + + static int32 GetDiscID(const scsi_toc *); + static int32 GetTrackCount(const scsi_toc *); + static CDAudioTime GetDiscTime(const scsi_toc *); + static void GetTrackTimes(const scsi_toc *, vector ×); + static BString OffsetsToString(const scsi_toc *); + + private: + status_t _Connect(); + void _Disconnect(); + bool _IsConnected() const; + + static int32 _QueryThread(void *); + + // cached retrieved data + enum State { + kInitial, + kReading, + kDone, + kInterrupting, + kError + }; + + void _SetDefaultInfo(); + status_t _OpenContentFile(const int32 &discID); + + status_t _ReadFromServer(BString &data); + void _ParseData(const BString &data); + void _WriteFile(); + + void _ReadLine(BString &); + status_t _IdentifySelf(); + + const char* _GetToken(const char*, BString &); + + // state data + BString fServerName; + BNetEndpoint fSocket; + int32 fPort; + bool fConnected; + + thread_id fThread; + State fState; + status_t fResult; - // state data - BString fServerName; - BNetEndpoint fSocket; - int32 fPort; - bool fConnected; - - thread_id fThread; - State fState; - status_t fResult; - - // disc information - CDDBData fCDData; - BString fFrameOffsetString; - scsi_toc fSCSIData; + // disc information + CDDBData fCDData; + BString fFrameOffsetString; + scsi_toc fSCSIData; }; BString GetLineFromString(const char *string); -#endif +#endif // CDDBSUPPORT_H diff --git a/src/apps/cdplayer/CDPlayer.cpp b/src/apps/cdplayer/CDPlayer.cpp index 980861b866..da849a6a6e 100644 --- a/src/apps/cdplayer/CDPlayer.cpp +++ b/src/apps/cdplayer/CDPlayer.cpp @@ -1,13 +1,22 @@ /* - * Copyright (c) 2006-2007, Haiku, Inc. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Author: - * DarkWyrm + * DarkWyrm, bpmagic@columbus.rr.com */ + + +#include "ButtonBitmaps.h" +#include "CDPlayer.h" +#include "DrawButton.h" +#include "DoubleShotDrawButton.h" +#include "TwoStateDrawButton.h" + #include #include #include +#include #include #include #include @@ -17,20 +26,14 @@ #include #include #include +#include +#include +#include #include #include #include -#include "ButtonBitmaps.h" -#include "CDPlayer.h" -#include "DrawButton.h" -#include "DoubleShotDrawButton.h" -#include "TwoStateDrawButton.h" -#include -#include -#include -#include enum { M_STOP = 'mstp', @@ -47,46 +50,50 @@ enum { M_SET_CD_TITLE }; -class CDPlayerWindow : public BWindow -{ -public: - CDPlayerWindow(void); - bool QuitRequested(void); + +class CDPlayerWindow : public BWindow { + public: + CDPlayerWindow(); + bool QuitRequested(); }; + inline void SetLabel(BStringView *label, const char *text) { - if (strcmp(label->Text(),text) != 0) + if (strcmp(label->Text(), text) != 0) label->SetText(text); } +// #pragma mark - + + 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), fCDQuery("freedb.freedb.org") { SetViewColor(216,216,216); - + fVolume = 255; - + BuildGUI(); - + if (fCDDrive.CountDrives() < 1) { - BAlert *alert = new BAlert("CDPlayer","It appears that there are no CD drives" + BAlert *alert = new BAlert("CDPlayer", "It appears that there are no CD drives" " on your computer or there is no system software" - " to support one. Sorry.","OK"); + " to support one. Sorry.", "OK"); alert->Go(); be_app->PostMessage(B_QUIT_REQUESTED); } - + fWindowState = fCDDrive.GetState(); fVolumeSlider->SetValue(fCDDrive.GetVolume()); if (fVolumeSlider->Value() <= 2) { fCDDrive.SetVolume(255); fVolumeSlider->SetValue(255); } - WatchCDState(); + _WatchCDState(); } @@ -97,147 +104,143 @@ CDPlayer::~CDPlayer() void -CDPlayer::BuildGUI(void) +CDPlayer::BuildGUI() { 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(Bounds().InsetByCopy(10,10)); - BBox *box = new BBox(r,"",B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + + BRect r(Bounds().InsetByCopy(10, 10)); + BBox *box = new BBox(r, "", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); AddChild(box); - r = box->Bounds().InsetByCopy(10,10); + r = box->Bounds().InsetByCopy(10, 10); r.bottom = 25; - + float labelWidth, labelHeight; - fCDTitle = new BStringView(r,"CDTitle","CD drive is empty", B_FOLLOW_LEFT_RIGHT); + fCDTitle = new BStringView(r, "CDTitle", "CD drive is empty", B_FOLLOW_LEFT_RIGHT); fCDTitle->GetPreferredSize(&labelWidth, &labelHeight); fCDTitle->ResizeTo(r.Width(), labelHeight); box->AddChild(fCDTitle); - + r.bottom = r.top + labelHeight; r.OffsetBy(0, r.Height() + 5); - - fCurrentTrack = new BStringView(r,"TrackNumber","",B_FOLLOW_LEFT_RIGHT); + + fCurrentTrack = new BStringView(r, "TrackNumber", "", B_FOLLOW_LEFT_RIGHT); box->AddChild(fCurrentTrack); - + r.OffsetBy(0, r.Height() + 5); r.right = r.left + (r.Width() / 2); - fTrackTime = new BStringView(r,"TrackTime","Track: --:-- / --:--",B_FOLLOW_LEFT_RIGHT); + fTrackTime = new BStringView(r, "TrackTime", "Track: --:-- / --:--", B_FOLLOW_LEFT_RIGHT); box->AddChild(fTrackTime); - + r.OffsetTo(box->Bounds().right / 2, r.top); - fDiscTime = new BStringView(r,"DiscTime","Disc: --:-- / --:--",B_FOLLOW_RIGHT); + fDiscTime = new BStringView(r, "DiscTime", "Disc: --:-- / --:--", B_FOLLOW_RIGHT); fDiscTime->ResizeToPreferred(); - fDiscTime->ResizeBy(10,0); + fDiscTime->ResizeBy(10, 0); box->AddChild(fDiscTime); - + box->ResizeTo(fCDTitle->Frame().right + 5, fDiscTime->Frame().bottom + 10); - - fStop = new DrawButton(BRect(0,0,1,1), "Stop", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_down"), - new BMessage(M_STOP), B_FOLLOW_BOTTOM, B_WILL_DRAW); + + fStop = new DrawButton(BRect(0, 0, 1, 1), "Stop", + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "stop_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "stop_down"), + new BMessage(M_STOP), B_FOLLOW_BOTTOM, B_WILL_DRAW); fStop->ResizeToPreferred(); fStop->MoveTo(10, box->Frame().bottom + 15); - fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT,"stop_disabled")); + fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT, "stop_disabled")); AddChild(fStop); float stopTop = fStop->Frame().top; - - - fPlay = new TwoStateDrawButton(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_up_on"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down"), - new BMessage(M_PLAY), B_FOLLOW_NONE, B_WILL_DRAW); + + + fPlay = new TwoStateDrawButton(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_up_on"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down"), + new BMessage(M_PLAY), B_FOLLOW_NONE, B_WILL_DRAW); fPlay->ResizeToPreferred(); fPlay->MoveTo(fStop->Frame().right + 2, stopTop); AddChild(fPlay); - - fPrevTrack = new DrawButton(BRect(0,0,1,1), "PrevTrack", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"prev_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"prev_down"), - new BMessage(M_PREV_TRACK), 0, - B_WILL_DRAW); + + fPrevTrack = new DrawButton(BRect(0, 0, 1, 1), "PrevTrack", + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "prev_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "prev_down"), + new BMessage(M_PREV_TRACK), 0, B_WILL_DRAW); fPrevTrack->ResizeToPreferred(); fPrevTrack->MoveTo(fPlay->Frame().right + 20, stopTop); AddChild(fPrevTrack); - - fNextTrack = new DrawButton(BRect(0,0,1,1), "NextTrack", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"next_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"next_down"), - new BMessage(M_NEXT_TRACK), 0, - B_WILL_DRAW); + + fNextTrack = new DrawButton(BRect(0, 0, 1, 1), "NextTrack", + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "next_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "next_down"), + new BMessage(M_NEXT_TRACK), 0, B_WILL_DRAW); fNextTrack->ResizeToPreferred(); fNextTrack->MoveTo(fPrevTrack->Frame().right + 1, stopTop); AddChild(fNextTrack); - - fRewind = new DoubleShotDrawButton(BRect(0,0,1,1), "Rewind", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"rew_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"rew_down"), - new BMessage(M_REWIND), 0, B_WILL_DRAW); + + fRewind = new DoubleShotDrawButton(BRect(0, 0, 1, 1), "Rewind", + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "rew_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "rew_down"), + new BMessage(M_REWIND), 0, B_WILL_DRAW); fRewind->ResizeToPreferred(); fRewind->MoveTo(fNextTrack->Frame().right + 20, stopTop); AddChild(fRewind); - - fFastFwd = new DoubleShotDrawButton(BRect(0,0,1,1), "FastFwd", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"ffwd_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"ffwd_down"), - new BMessage(M_FFWD), 0, B_WILL_DRAW); + + fFastFwd = new DoubleShotDrawButton(BRect(0, 0, 1, 1), "FastFwd", + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "ffwd_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "ffwd_down"), + new BMessage(M_FFWD), 0, B_WILL_DRAW); fFastFwd->ResizeToPreferred(); fFastFwd->MoveTo(fRewind->Frame().right + 1, stopTop); AddChild(fFastFwd); - + r.left = 10; r.right = fPlay->Frame().right; r.top = fStop->Frame().bottom + 14; r.bottom = r.top + kVolumeSliderBitmapHeight - 1.0; - fVolumeSlider = new VolumeSlider(r,"VolumeSlider",0,255, new BMessage(M_SET_VOLUME), - this); + fVolumeSlider = new VolumeSlider(r, "VolumeSlider", + 0, 255, new BMessage(M_SET_VOLUME), this); fVolumeSlider->ResizeToPreferred(); AddChild(fVolumeSlider); - - fRepeat = new TwoStateDrawButton( BRect(0,0,1,1), "Repeat", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up_off"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_down"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"repeat_up_on"), - 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_off"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_down"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_up_on"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_down"), + new BMessage(M_REPEAT), B_FOLLOW_NONE, B_WILL_DRAW); fRepeat->ResizeToPreferred(); - fRepeat->MoveTo(fPrevTrack->Frame().left, - fVolumeSlider->Frame().top - - ((fRepeat->Frame().Height() - fVolumeSlider->Frame().Height()) / 2)); + fRepeat->MoveTo(fPrevTrack->Frame().left, fVolumeSlider->Frame().top - + ((fRepeat->Frame().Height() - fVolumeSlider->Frame().Height()) / 2)); AddChild(fRepeat); - - fShuffle = new TwoStateDrawButton(BRect(0,0,1,1), "Shuffle", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up_off"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_down"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"shuffle_up_on"), - 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_off"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_down"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_up_on"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_down"), + new BMessage(M_SHUFFLE), B_FOLLOW_NONE, B_WILL_DRAW); fShuffle->ResizeToPreferred(); - fShuffle->MoveTo(fRepeat->Frame().right + 2,fRepeat->Frame().top); + fShuffle->MoveTo(fRepeat->Frame().right + 2, fRepeat->Frame().top); AddChild(fShuffle); - - fEject = new DrawButton(BRect(0,0,1,1), "Eject", - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"eject_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"eject_down"), - new BMessage(M_EJECT), 0, B_WILL_DRAW); + + fEject = new DrawButton(BRect(0, 0, 1, 1), "Eject", + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "eject_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "eject_down"), + new BMessage(M_EJECT), 0, B_WILL_DRAW); fEject->ResizeToPreferred(); fEject->MoveTo(fFastFwd->Frame().left, fShuffle->Frame().top); AddChild(fEject); - - ResizeTo(box->Frame().right + 10, fVolumeSlider->Frame().bottom + 10); - + + ResizeTo(box->Frame().right + 10, fVolumeSlider->Frame().bottom + 10); } @@ -245,44 +248,45 @@ void CDPlayer::MessageReceived(BMessage *msg) { switch (msg->what) { - case M_SET_VOLUME: { + case M_SET_VOLUME: fCDDrive.SetVolume(fVolumeSlider->Value()); break; - } - case M_STOP: { + + case M_STOP: if (fWindowState == kPaused) { - fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down")); + fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down")); fPlay->SetState(1); } fWindowState = kStopped; fCDDrive.Stop(); break; - } - case M_PLAY: { + + case M_PLAY: // If we are currently playing, then we will be showing // the pause images and will want to switch back to the play images if (fWindowState == kPlaying) { fWindowState = kPaused; fCDDrive.Pause(); - fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT,"paused_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down")); + fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT, "paused_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down")); } else if (fWindowState == kPaused) { fWindowState = kPlaying; fCDDrive.Resume(); - fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_up"), - BTranslationUtils::GetBitmap(B_PNG_FORMAT,"play_down")); + fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_up"), + BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down")); } else { fWindowState = kPlaying; fCDDrive.Play(fPlayList.GetCurrentTrack()); } break; - } - case M_EJECT: { + + case M_EJECT: fCDDrive.Eject(); break; - } - case M_NEXT_TRACK: { + + case M_NEXT_TRACK: + { int16 next = fPlayList.GetNextTrack(); if (next <= 0) { // force a "wrap around" when possible. This makes it @@ -290,11 +294,11 @@ CDPlayer::MessageReceived(BMessage *msg) // back to the first track from the last one with 1 button push next = fPlayList.GetFirstTrack(); } - + if (next > 0) { CDState state = fCDDrive.GetState(); if (state == kPlaying) { - while(!fCDDrive.Play(next)) { + while (!fCDDrive.Play(next)) { next = fPlayList.GetNextTrack(); if (next < 1) { fWindowState = kStopped; @@ -312,11 +316,13 @@ CDPlayer::MessageReceived(BMessage *msg) fPlayList.SetCurrentTrack(next); // Force an update for better responsiveness - WatchCDState(); + _WatchCDState(); } break; } - case M_PREV_TRACK: { + + case M_PREV_TRACK: + { int16 prev = fPlayList.GetPreviousTrack(); if (prev <= 0) { // force a "wrap around" when possible. This makes it @@ -324,11 +330,11 @@ CDPlayer::MessageReceived(BMessage *msg) // back to the first track from the last one with 1 button push prev = fPlayList.GetLastTrack(); } - + if (prev > 0) { CDState state = fCDDrive.GetState(); if (state == kPlaying) { - while(!fCDDrive.Play(prev)) { + while (!fCDDrive.Play(prev)) { prev = fPlayList.GetPreviousTrack(); if (prev < 1) { fWindowState = kStopped; @@ -344,25 +350,26 @@ CDPlayer::MessageReceived(BMessage *msg) fPlayList.SetCurrentTrack(prev); // Force an update for better responsiveness - WatchCDState(); + _WatchCDState(); } break; } - case M_FFWD: { + + case M_FFWD: if (fFastFwd->Value() == B_CONTROL_ON) fCDDrive.StartFastFwd(); else fCDDrive.StopFastFwd(); break; - } - case M_REWIND: { + + case M_REWIND: if (fRewind->Value() == B_CONTROL_ON) fCDDrive.StartRewind(); else fCDDrive.StopRewind(); break; - } - case M_SHUFFLE: { + + case M_SHUFFLE: if (fPlayList.IsShuffled()) { int16 track = fPlayList.GetCurrentTrack(); fPlayList.SetShuffle(false); @@ -375,8 +382,8 @@ CDPlayer::MessageReceived(BMessage *msg) fShuffle->SetState(1); } break; - } - case M_REPEAT: { + + case M_REPEAT: if (fPlayList.IsLoop()) { fPlayList.SetLoop(false); fRepeat->SetState(0); @@ -385,11 +392,11 @@ CDPlayer::MessageReceived(BMessage *msg) fRepeat->SetState(1); } break; - } - default: { + + default: BView::MessageReceived(msg); break; - } + } } @@ -412,203 +419,206 @@ CDPlayer::AttachedToWindow() void CDPlayer::Pulse() { - WatchCDState(); + _WatchCDState(); } void -CDPlayer::WatchCDState(void) +CDPlayer::_WatchCDState() { // One watcher function to rule them all // first, watch the one setting independent of having a CD: volume - uint8 drivevolume = fCDDrive.GetVolume(); - if (fVolume == drivevolume) { - fVolume = drivevolume; + uint8 driveVolume = fCDDrive.GetVolume(); + if (fVolume == driveVolume) { + fVolume = driveVolume; fVolumeSlider->SetValue(fVolume); } - + // Second, establish whether or not we have a CD in the drive - CDState playstate = fCDDrive.GetState(); - bool internal_track_change = false; - - if (playstate == kNoCD) { + CDState playState = fCDDrive.GetState(); + bool internalTrackChange = false; + + if (playState == kNoCD) { // Yes, we have no bananas! - + // Do something only if there is a change in the app's play state if (fWindowState != kNoCD) { // We have just discovered that we have no bananas fWindowState = kNoCD; - + // Because we are changing play states, we will need to update the GUI fCDData.SetDiscID(-1); - SetLabel(fCDTitle,"CD drive is empty"); - - SetLabel(fCurrentTrack,""); - SetLabel(fTrackTime,"Track: --:-- / --:--"); - SetLabel(fDiscTime,"Disc: --:-- / --:--"); + SetLabel(fCDTitle, "CD drive is empty"); + + SetLabel(fCurrentTrack, ""); + SetLabel(fTrackTime, "Track: --:-- / --:--"); + SetLabel(fDiscTime, "Disc: --:-- / --:--"); fPlayList.SetTrackCount(0); fPlayList.SetStartingTrack(1); fPlayList.SetCurrentTrack(1); - + if (fPlay->GetState() == 1) fPlay->SetState(0); } - + return; } - + // Now otherwise handle the play state - if (playstate == kStopped) { + if (playState == kStopped) { if (fWindowState == kPlaying) { - internal_track_change = true; - + internalTrackChange = true; + // This means that the drive finished playing the song, so get the next one // from the list and play it int16 next = fPlayList.GetNextTrack(); if (next > 0) fCDDrive.Play(next); } - + if (fPlay->GetState() == 1) fPlay->SetState(0); - } else if (playstate == kPlaying) { + } else if (playState == kPlaying) { if (fPlay->GetState() == 0) fPlay->SetState(1); - } else if (playstate == kPaused) { + } else if (playState == kPaused) fPlay->SetState(0); - } - + // If we got this far, then there must be a CD in the drive. The next order on the agenda // is to find out which CD it is - int32 discid = fCDDrive.GetDiscID(); - bool update_track_gui = false; - - if (discid != fCDData.DiscID()) { - update_track_gui = true; - + int32 discId = fCDDrive.GetDiscID(); + bool updateTrackGui = false; + + if (discId != fCDData.DiscID()) { + updateTrackGui = true; + // Apparently the disc has changed since we last looked. - if (fCDQuery.CurrentDiscID() != discid) + if (fCDQuery.CurrentDiscID() != discId) fCDQuery.SetToCD(fCDDrive.GetDrivePath()); - + if (fCDQuery.Ready()) { // Note that we only update the CD title for now. We still need a track number // in order to update the display for the selected track if (fCDQuery.GetData(&fCDData, 1000000)) { BString display(fCDData.Artist()); display << " - " << fCDData.Album(); - SetLabel(fCDTitle,display.String()); - } else { - SetLabel(fCDTitle,"Audio CD"); - } + SetLabel(fCDTitle, display.String()); + } else + SetLabel(fCDTitle, "Audio CD"); } } - + // Now that we know which CD it is, update the track info - int16 drivecount = fCDDrive.CountTracks(); - int16 drivetrack = fCDDrive.GetTrack(); - - int16 playlisttrack = fPlayList.GetCurrentTrack(); - int16 playlistcount = fPlayList.TrackCount(); - - if (playstate == kPlaying) { - if (playlisttrack != drivetrack) { - playlisttrack = drivetrack; - - if (!internal_track_change) { + int16 driveCount = fCDDrive.CountTracks(); + int16 driveTrack = fCDDrive.GetTrack(); + + int16 playlistTrack = fPlayList.GetCurrentTrack(); + int16 playlistCount = fPlayList.TrackCount(); + + if (playState == kPlaying) { + if (playlistTrack != driveTrack) { + playlistTrack = driveTrack; + + if (!internalTrackChange) { // The main thing is that we need to make sure that the playlist and the drive's track // stay in sync. The CD's track may have been changed by an outside source, so if // the drive is playing, check for playlist sync. - fPlayList.SetTrackCount(drivecount); - fPlayList.SetCurrentTrack(drivetrack); + fPlayList.SetTrackCount(driveCount); + fPlayList.SetCurrentTrack(driveTrack); } } - update_track_gui = true; + updateTrackGui = true; } else { - if (playlistcount != drivecount) { + if (playlistCount != driveCount) { // This happens only when CDs are changed - if (drivecount < 0) { + if (driveCount < 0) { // There is no CD in the drive. The playlist needs to have its track // count set to 0 and it also needs to be rewound. fPlayList.SetStartingTrack(1); fPlayList.SetTrackCount(0); - playlisttrack = 1; - playlistcount = 0; + playlistTrack = 1; + playlistCount = 0; } else { // Two possible cases here: playlist is empty or playlist has a different // number of tracks. In either case, the playlist needs to be reinitialized // to the current track data fPlayList.SetStartingTrack(1); - fPlayList.SetTrackCount(drivecount); - playlisttrack = fPlayList.GetCurrentTrack(); - playlistcount = drivecount; + fPlayList.SetTrackCount(driveCount); + playlistTrack = fPlayList.GetCurrentTrack(); + playlistCount = driveCount; } } else { // update only with a track change - if (playlisttrack != drivetrack) - update_track_gui = true; + if (playlistTrack != driveTrack) + updateTrackGui = true; } } - - if (update_track_gui) { + + if (updateTrackGui) { BString currentTrackName; - - if (playlisttrack >= 0) { - int16 whichtrack = playlisttrack; - - if (whichtrack == 0) - whichtrack++; - - currentTrackName << "Track " << whichtrack << ": " << fCDData.TrackAt(whichtrack-1); - - SetLabel(fCurrentTrack,currentTrackName.String()); - - } else { - SetLabel(fCurrentTrack,""); - } + + if (playlistTrack >= 0) { + int16 whichTrack = playlistTrack; + + if (whichTrack == 0) + whichTrack++; + + currentTrackName << "Track " << whichTrack << ": " << fCDData.TrackAt(whichTrack - 1); + + SetLabel(fCurrentTrack, currentTrackName.String()); + + } else + SetLabel(fCurrentTrack, ""); } - + // Now update the time info - cdaudio_time tracktime; - cdaudio_time disctime; - cdaudio_time tracktotal; - cdaudio_time disctotal; - char timestring[1024]; - - if (fCDDrive.GetTime(tracktime, disctime)) { - fCDDrive.GetTimeForDisc(disctotal); - sprintf(timestring,"Disc: %ld:%.2ld / %ld:%.2ld",disctime.minutes,disctime.seconds, - disctotal.minutes,disctotal.seconds); - SetLabel(fDiscTime,timestring); - - fCDDrive.GetTimeForTrack(playlisttrack,tracktotal); - sprintf(timestring,"Track: %ld:%.2ld / %ld:%.2ld",tracktime.minutes,tracktime.seconds, - tracktotal.minutes,tracktotal.seconds); - SetLabel(fTrackTime,timestring); + CDAudioTime trackTime; + CDAudioTime discTime; + CDAudioTime trackTotal; + CDAudioTime discTotal; + char timeString[1024]; + + if (fCDDrive.GetTime(trackTime, discTime)) { + fCDDrive.GetTimeForDisc(discTotal); + sprintf(timeString, "Disc: %ld:%.2ld / %ld:%.2ld", discTime.GetMinutes(), + discTime.GetSeconds(), discTotal.GetMinutes(), discTotal.GetSeconds()); + SetLabel(fDiscTime, timeString); + + fCDDrive.GetTimeForTrack(playlistTrack, trackTotal); + sprintf(timeString, "Track: %ld:%.2ld / %ld:%.2ld", trackTime.GetMinutes(), + trackTime.GetSeconds(), trackTotal.GetMinutes(), trackTotal.GetSeconds()); + SetLabel(fTrackTime, timeString); } else { - SetLabel(fTrackTime,"Track: --:-- / --:--"); - SetLabel(fDiscTime,"Disc: --:-- / --:--"); + SetLabel(fTrackTime, "Track: --:-- / --:--"); + SetLabel(fDiscTime, "Disc: --:-- / --:--"); } } -CDPlayerWindow::CDPlayerWindow(void) - : BWindow(BRect (100, 100, 405, 280), "CD Player", B_TITLED_WINDOW, B_NOT_RESIZABLE | - B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) +// #pragma mark - + + +CDPlayerWindow::CDPlayerWindow() + : BWindow(BRect (100, 100, 405, 280), "CD Player", B_TITLED_WINDOW, B_NOT_RESIZABLE | + B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) { } bool -CDPlayerWindow::QuitRequested(void) +CDPlayerWindow::QuitRequested() { be_app->PostMessage(B_QUIT_REQUESTED); return true; } +// #pragma mark - + + CDPlayerApplication::CDPlayerApplication() - : BApplication("application/x-vnd.Haiku-CDPlayer") + : BApplication("application/x-vnd.Haiku-CDPlayer") { BWindow *window = new CDPlayerWindow(); BView *view = new CDPlayer(window->Bounds(), "CD"); diff --git a/src/apps/cdplayer/CDPlayer.h b/src/apps/cdplayer/CDPlayer.h index 5e63d75119..61ae5c456f 100644 --- a/src/apps/cdplayer/CDPlayer.h +++ b/src/apps/cdplayer/CDPlayer.h @@ -7,84 +7,81 @@ #ifndef CDPLAYER_H #define CDPLAYER_H -#include -#include -#include -#include -#include -#include -#include - #include "CDAudioDevice.h" #include "CDDBSupport.h" #include "PlayList.h" #include "VolumeSlider.h" +#include +#include +#include +#include +#include +#include + + class DrawButton; class DoubleShotDrawButton; class TwoStateDrawButton; -class CDPlayer : public BView -{ -public: - CDPlayer(BRect frame, const char *name, - uint32 resizeMask = B_FOLLOW_ALL, - uint32 flags = B_WILL_DRAW | B_NAVIGABLE | - B_PULSE_NEEDED); - virtual ~CDPlayer(); - - void BuildGUI(void); - - virtual void AttachedToWindow(); - virtual void Pulse(); - virtual void MessageReceived(BMessage *); -private: - void WatchCDState(void); - - DrawButton *fStop, - *fNextTrack, - *fPrevTrack, - *fEject; - - DoubleShotDrawButton - *fFastFwd, - *fRewind; - - TwoStateDrawButton *fShuffle, - *fRepeat, - *fPlay; - - VolumeSlider *fVolumeSlider; - - BStringView *fCDTitle, - *fCurrentTrack, - *fTrackTime, - *fDiscTime; - - BBox *fCDBox, - *fTrackBox, - *fTimeBox; - - CDState fCDState; - - rgb_color fStopColor; - rgb_color fPlayColor; - - CDAudioDevice fCDDrive; - PlayList fPlayList; - CDState fWindowState; - CDDBQuery fCDQuery; - CDDBData fCDData; - uint8 fVolume; +class CDPlayer : public BView { + public: + CDPlayer(BRect frame, const char *name, uint32 resizeMask = B_FOLLOW_ALL, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); + virtual ~CDPlayer(); + + void BuildGUI(); + + virtual void AttachedToWindow(); + virtual void Pulse(); + virtual void MessageReceived(BMessage *); + + private: + void _WatchCDState(); + + DrawButton *fStop, + *fNextTrack, + *fPrevTrack, + *fEject; + + DoubleShotDrawButton + *fFastFwd, + *fRewind; + + TwoStateDrawButton *fShuffle, + *fRepeat, + *fPlay; + + VolumeSlider *fVolumeSlider; + + BStringView *fCDTitle, + *fCurrentTrack, + *fTrackTime, + *fDiscTime; + + BBox *fCDBox, + *fTrackBox, + *fTimeBox; + + CDState fCDState; + + rgb_color fStopColor; + rgb_color fPlayColor; + + CDAudioDevice fCDDrive; + PlayList fPlayList; + CDState fWindowState; + CDDBQuery fCDQuery; + CDDBData fCDData; + uint8 fVolume; }; -class CDPlayerApplication : public BApplication -{ -public: - CDPlayerApplication(); +class CDPlayerApplication : public BApplication { + public: + CDPlayerApplication(); }; -#endif +#endif // CDPLAYER_H