mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
321 lines
7.1 KiB
C++
321 lines
7.1 KiB
C++
|
#include "WindacPlay.h"
|
||
|
#include "api__in_cdda.h"
|
||
|
|
||
|
int WindacPlay::threadProc2()
|
||
|
{
|
||
|
while (1)
|
||
|
{
|
||
|
if (need_seek != -1)
|
||
|
{
|
||
|
current_sector = start_sector;
|
||
|
current_sector += ((need_seek * 75) / 1000);
|
||
|
bytes_in_sbuf = 0;
|
||
|
line.outMod->Flush(need_seek);
|
||
|
decode_pos_ms = need_seek;
|
||
|
need_seek = -1;
|
||
|
}
|
||
|
if (!killswitch && bytes_in_sbuf <= 0 && current_sector.GetHSG() < end_sector.GetHSG())
|
||
|
{
|
||
|
if (!scsi->Get_DriveStatus().CDPresent)
|
||
|
{
|
||
|
//infos->error("No CD present!");
|
||
|
PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
|
||
|
return 0;
|
||
|
}
|
||
|
unsigned char *s = sbuf;
|
||
|
while ((bytes_in_sbuf < buf_size*2352) && (current_sector.GetHSG() < end_sector.GetHSG()) && !killswitch)
|
||
|
{
|
||
|
int n = min((int)16, (int)(end_sector.GetHSG() - current_sector.GetHSG()));
|
||
|
memset(s, 0, n*2352);
|
||
|
scsi->ReadCDDA(current_sector, n, s);
|
||
|
while (!scsi->WaitCDDA() && !killswitch) Sleep(66);
|
||
|
bytes_in_sbuf += n * 2352;
|
||
|
s += n * 2352;
|
||
|
current_sector += n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bytes_in_sbuf && !killswitch)
|
||
|
{
|
||
|
//wait for output to be finished
|
||
|
line.outMod->Write(NULL, 0);
|
||
|
while (!killswitch && line.outMod->IsPlaying()) Sleep(10);
|
||
|
if (!killswitch)
|
||
|
PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (killswitch) return 0;
|
||
|
|
||
|
char sample_buffer[576*4*2] = {0};
|
||
|
int bytes = sizeof(sample_buffer) / 2; // enough room for dsp bullcrap
|
||
|
bytes = min((int)bytes_in_sbuf, (int)bytes);
|
||
|
memcpy(sample_buffer, sbuf, bytes);
|
||
|
if (bytes_in_sbuf > bytes) memcpy(sbuf, sbuf + bytes, bytes_in_sbuf - bytes);
|
||
|
bytes_in_sbuf -= bytes;
|
||
|
|
||
|
int obytes = bytes;
|
||
|
|
||
|
line.VSAAddPCMData(sample_buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/);
|
||
|
line.SAAddPCMData(sample_buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/);
|
||
|
|
||
|
if (line.dsp_isactive())
|
||
|
bytes = line.dsp_dosamples((short *)sample_buffer, bytes / g_nch / 2, 16, g_nch, 44100) * (g_nch * 2);
|
||
|
|
||
|
while (line.outMod->CanWrite() < bytes && !killswitch) Sleep(66);
|
||
|
if (killswitch) return 0;
|
||
|
|
||
|
line.outMod->Write(sample_buffer, bytes);
|
||
|
|
||
|
decode_pos_ms += ((obytes / g_nch / 2) * 1000) / 44100;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void WindacPlay::stop()
|
||
|
{
|
||
|
if (hThread)
|
||
|
{
|
||
|
killswitch = 1;
|
||
|
WaitForSingleObject(hThread, INFINITE);
|
||
|
}
|
||
|
if (needsToClose)
|
||
|
{
|
||
|
needsToClose = false;
|
||
|
}
|
||
|
line.outMod->Close();
|
||
|
}
|
||
|
|
||
|
int WindacPlay::open(wchar_t drive, int track) //called by winampGetExtendedRead
|
||
|
{
|
||
|
g_drive = drive;
|
||
|
if (!inited && !LoadASPI())
|
||
|
{
|
||
|
g_drive = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
inited = 1;
|
||
|
|
||
|
int drivenum = 0;
|
||
|
getTrackInfos(&drivenum, (char)drive);
|
||
|
|
||
|
m_pMapDrive = new CMapDrive(TRUE);
|
||
|
int nbdrives = m_pMapDrive->GetMaxDrives();
|
||
|
if (!nbdrives) return 0;
|
||
|
|
||
|
int host = -1, id = -1, lun = -1;
|
||
|
if (getSCSIIDFromDrive((char)drive, &host, &id, &lun))
|
||
|
{
|
||
|
int found = 0;
|
||
|
for (int i = 0;i < nbdrives;i++)
|
||
|
{
|
||
|
drive_info = m_pMapDrive->GetInfo(i);
|
||
|
if (drive_info.HostAdapterNumber == host && drive_info.ID == id && drive_info.LUN == lun)
|
||
|
{
|
||
|
found = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!found)
|
||
|
{
|
||
|
s_last_error = "Drive not found";
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// can't figure out the SCSI ID, oh well, try the gay method
|
||
|
TDriveInfo *tdi = &m_pMapDrive->GetInfo(drivenum);
|
||
|
if (!tdi)
|
||
|
{
|
||
|
s_last_error = "Drive not found";
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
drive_info = *tdi;
|
||
|
}
|
||
|
|
||
|
scsi = new CSCSICD((char)drive, drive_info);
|
||
|
|
||
|
TDriveStatus status = scsi->Get_DriveStatus();
|
||
|
|
||
|
if (!status.CDPresent)
|
||
|
{
|
||
|
s_last_error = "CD not present";
|
||
|
//infos->warning("No CD present!");
|
||
|
g_drive=0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
TTrackList track_info = {0};
|
||
|
track_info.TrackNummer = track;
|
||
|
scsi->ReadTrackInfo(track_info);
|
||
|
|
||
|
if (track_info.Flags.DataTrack)
|
||
|
{
|
||
|
s_last_error = "Cannot play track";
|
||
|
//infos->warning("Can't play data tracks");
|
||
|
g_drive=0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
start_sector = track_info.StartSektor;
|
||
|
current_sector = start_sector;
|
||
|
end_sector = start_sector;
|
||
|
slength = track_info.Laenge;
|
||
|
end_sector += slength;
|
||
|
|
||
|
g_playlength = (slength / 75) * 1000;
|
||
|
|
||
|
g_nch = track_info.Flags.AudioChannels;
|
||
|
g_srate = 44100;
|
||
|
g_bps = 16;
|
||
|
|
||
|
scsi->PrepareCDDA();
|
||
|
|
||
|
if (!sbuf)
|
||
|
sbuf = (unsigned char *)malloc(2352 * buf_size);
|
||
|
bytes_in_sbuf = 0;
|
||
|
|
||
|
last_eject_scan = 0;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int WindacPlay::play(wchar_t drive, int track) //called by winamp2's normal(old) play() interface
|
||
|
{
|
||
|
if (open(drive, track)) return 1;
|
||
|
|
||
|
// do this here as it helps to prevent an audio glitch on first playback and volume is set low
|
||
|
setvolume(a_v, a_p);
|
||
|
|
||
|
int maxlat = line.outMod->Open(44100, g_nch, 16, -1, -1);
|
||
|
if (maxlat < 0)
|
||
|
{
|
||
|
g_drive=0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
line.SetInfo(1411, 44, g_nch, 1);
|
||
|
line.SAVSAInit(maxlat, 44100);
|
||
|
line.VSASetInfo(g_nch, 44100);
|
||
|
line.is_seekable = 1;
|
||
|
|
||
|
killswitch = 0;
|
||
|
DWORD thread_id;
|
||
|
hThread = CreateThread(NULL, NULL, &threadProc, (LPVOID)this, NULL, &thread_id);
|
||
|
SetThreadPriority(hThread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
|
||
|
|
||
|
//open the device thru MCI (for getfileinfo to work properly)
|
||
|
g_playtrack = track;
|
||
|
needsToClose = true;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int WindacPlay::read(char *dest, int len, int *killswitch) //called by winampGetExtendedRead_getData
|
||
|
{
|
||
|
int l = 0;
|
||
|
|
||
|
while (l < len && !*killswitch)
|
||
|
{
|
||
|
if (!*killswitch && bytes_in_sbuf <= 0 && current_sector.GetHSG() < end_sector.GetHSG())
|
||
|
{
|
||
|
//scan for ejected CD only every 2 seconds
|
||
|
if (last_eject_scan + 5000 < GetTickCount())
|
||
|
{
|
||
|
int cnt = 5;
|
||
|
while (!scsi->Get_DriveStatus().CDPresent && cnt--)
|
||
|
{
|
||
|
Sleep(100);
|
||
|
}
|
||
|
if (cnt < 0 && !scsi->Get_DriveStatus().CDPresent)
|
||
|
{
|
||
|
//infos->error("No CD present!");
|
||
|
return -1;
|
||
|
}
|
||
|
last_eject_scan = GetTickCount();
|
||
|
}
|
||
|
|
||
|
unsigned char *s = sbuf;
|
||
|
while ((bytes_in_sbuf < buf_size*2352) && (current_sector.GetHSG() < end_sector.GetHSG()))
|
||
|
{
|
||
|
int n = min((int)16, (int)(end_sector.GetHSG() - current_sector.GetHSG()));
|
||
|
memset(s, 0, n*2352);
|
||
|
scsi->ReadCDDA(current_sector, n, s);
|
||
|
while (!scsi->WaitCDDA() && !*killswitch) Sleep(66);
|
||
|
if (*killswitch) break;
|
||
|
bytes_in_sbuf += n * 2352;
|
||
|
s += n * 2352;
|
||
|
current_sector += n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bytes_in_sbuf) break;
|
||
|
|
||
|
int bytes = min(bytes_in_sbuf, len - l);
|
||
|
memcpy(dest + l, sbuf, bytes);
|
||
|
|
||
|
if (bytes_in_sbuf > bytes) memcpy(sbuf, sbuf + bytes, bytes_in_sbuf - bytes);
|
||
|
bytes_in_sbuf -= bytes;
|
||
|
|
||
|
l += bytes;
|
||
|
}
|
||
|
return l;
|
||
|
}
|
||
|
|
||
|
void WindacPlay::getTrackInfos(int *drivenum, char driveletter)
|
||
|
{
|
||
|
//finds first cdrom drive letter
|
||
|
char firstcd = 'D';
|
||
|
{
|
||
|
DWORD drives = GetLogicalDrives();
|
||
|
int nb = 0;
|
||
|
for (int drivemask = 0; (drivemask < 32) && (nb < 4); drivemask++)
|
||
|
{
|
||
|
if (drives&(1 << drivemask))
|
||
|
{
|
||
|
wchar_t tmp[16] = {0};
|
||
|
wsprintf(tmp, L"%c:\\", L'A' + drivemask);
|
||
|
if (GetDriveType(tmp) == DRIVE_CDROM)
|
||
|
{
|
||
|
firstcd = 'A' + drivemask;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*drivenum = driveletter - (unsigned char)firstcd;
|
||
|
}
|
||
|
|
||
|
WindacPlay::WindacPlay()
|
||
|
{
|
||
|
scsi = NULL;
|
||
|
sbuf = NULL;
|
||
|
m_pMapDrive = NULL;
|
||
|
buf_size = 64; //make it configitem
|
||
|
hThread = NULL;
|
||
|
decode_pos_ms = 0;
|
||
|
inited = 0;
|
||
|
need_seek = -1;
|
||
|
needsToClose = false;
|
||
|
}
|
||
|
|
||
|
WindacPlay::~WindacPlay()
|
||
|
{
|
||
|
if (scsi)
|
||
|
{
|
||
|
scsi->FinishCDDA();
|
||
|
delete(scsi);
|
||
|
}
|
||
|
delete(m_pMapDrive);
|
||
|
free(sbuf);
|
||
|
if (inited) FreeASPI();
|
||
|
|
||
|
if (needsToClose)
|
||
|
{
|
||
|
needsToClose = false;
|
||
|
}
|
||
|
}
|