diff options
Diffstat (limited to 'Src/Plugins/Input/in_cdda/WindacPlay.cpp')
-rw-r--r-- | Src/Plugins/Input/in_cdda/WindacPlay.cpp | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_cdda/WindacPlay.cpp b/Src/Plugins/Input/in_cdda/WindacPlay.cpp new file mode 100644 index 00000000..69c7a78b --- /dev/null +++ b/Src/Plugins/Input/in_cdda/WindacPlay.cpp @@ -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; + } +}
\ No newline at end of file |