Initial community commit
This commit is contained in:
321
Src/Plugins/Input/in_cdda/WindacPlay.cpp
Normal file
321
Src/Plugins/Input/in_cdda/WindacPlay.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user