winamp/Src/Plugins/Input/in_cdda/WindacPlay.cpp
2024-09-24 14:54:57 +02:00

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;
}
}