123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- #include "Main.h"
- #include <windows.h>
- #include "VeritasPlay.h"
- #include "CDDB.h"
- #include "workorder.h"
- #include "api.h"
- VeritasPlay::VeritasPlay(bool _ripping)
- : opened(false), ripping(_ripping),
- primo(0), padStart(false), padEnd(false)
- {
- submitHandle=0;
- hThread = NULL;
- overflowBuffer = NULL;
- overflow = 0;
- buffers = NULL;
- currentBuffer = 0;
- }
- VeritasPlay::~VeritasPlay()
- {
- if (opened)
- Abort();
- Close();
- DestroyBuffers();
- if (primo)
- {
- waServiceFactory *sf = (line.service ? line.service->service_getServiceByGuid(obj_primo::getServiceGuid()) : NULL);
- if (sf) sf->releaseInterface(primo);
- }
-
- primo = 0;
- if (submitHandle)
- {
- int x = workorder->CloseSig(submitHandle);
- submitHandle=0;
- }
- }
- void VeritasPlay::CreateBuffers()
- {
- if (buffers)
- return;
- if (ripping)
- {
- buf_size = config_rip_buffersize;
- nb_veritas_buf = config_rip_buffers;
- }
- else
- {
- buf_size = config_play_buffersize;
- nb_veritas_buf = config_play_buffers;
- }
- overflowBuffer = new BYTE[2352 * buf_size];
- overflow = 0;
- buffers = new VeritasBuffer[nb_veritas_buf];
- for (int i = 0;i < nb_veritas_buf;i++)
- {
- buffers[i].Create(buf_size);
- }
- }
- void VeritasPlay::DestroyBuffers()
- {
- if (buffers)
- {
- for (int i = 0;i < nb_veritas_buf;i++)
- {
- buffers[i].Destroy();
- }
- delete [] buffers;
- }
- buffers = 0;
- delete overflowBuffer;
- overflowBuffer = 0;
- }
- void VeritasPlay::setvolume(int a_v, int a_p)
- {
- line.outMod->SetVolume(a_v);
- line.outMod->SetPan(a_p);
- }
- void VeritasPlay::setoutputtime(int time_in_ms)
- {
- need_seek = time_in_ms;
- }
- void VeritasPlay::stop()
- {
- killswitch = 1;
- Close();
- if (hThread)
- {
- WaitForEvent(hThread, INFINITE);
- hThread=0;
- }
- line.outMod->Close();
- }
- void VeritasPlay::SeekAndFlush()
- {
- int destsector = start_sector + ((need_seek * 75) / 1000);
- Abort();
- openVeritasTrack(destsector, end_sector - destsector);
- decode_pos_ms = need_seek;
- // wait for a buffer before we flush
- DWORD cursec = 0, totsec = 0;
- while (true)
- {
- if (primo->RunningStatus(PRIMOSDK_GETSTATUS, &cursec, &totsec) != PRIMOSDK_RUNNING
- && primo->UnitStatus(&unit, NULL, NULL, NULL, NULL) == PRIMOSDK_UNITERROR)
- return;
- // check how far we've gone
- if (cursec < buffers[currentBuffer].sector)
- Sleep(1);
- else
- break;
- }
- overflow = 0;
- lastseek = destsector;
- line.outMod->Flush(need_seek);
- need_seek = -1;
- }
- void VeritasPlay::Seek()
- {
- int destsector = start_sector + ((need_seek * 75) / 1000);
- Abort();
- openVeritasTrack(destsector, end_sector - destsector);
- overflow = 0;
- decode_pos_ms = need_seek;
- need_seek = -1;
- lastseek = destsector;
- }
- void VeritasPlay::Abort()
- {
- AbortAsync();
- WaitForAbort(66);
- }
- void VeritasPlay::AbortAsync()
- {
- primo->RunningStatus(PRIMOSDK_ABORT, NULL, NULL);
- }
- void VeritasPlay::WaitForAbort(int time)
- {
- while (primo->RunningStatus(PRIMOSDK_GETSTATUS, NULL, NULL) == PRIMOSDK_RUNNING)
- Sleep(time);
- opened=false;
- }
- int VeritasPlay::openVeritasTrack(DWORD start, DWORD length)
- {
- int speedChoice = config_maxextractspeed;
- DWORD speed;
- if (ripping)
- {
- switch (speedChoice)
- {
- case 0: // 0.5x
- case 1: // 1x
- speed = 1; // can't do 0.5x in the SDK
- break;
- case 2: // 2x
- speed = 2;
- break;
- case 3: // 4x
- speed = 4;
- break;
- case 4: // 8x
- speed = 8;
- break;
- case 5: // 16x
- if (getRegVer() <= 0)
- speed = 8;
- else
- speed = 16;
- break;
- default:
- if (speedChoice < 0)
- speed = PRIMOSDK_MIN;
- else
- {
- if (getRegVer() <= 0)
- speed = 8;
- else
- speed = PRIMOSDK_MAX;
- }
- break;
- }
- }
- else
- speed = 4;//PRIMOSDK_MAX;
- if (primo->ExtractAudioToBuffer(&unit, start, length, speed, 0, 0, 0) != PRIMOSDK_OK)
- return 0;
- for (int i = 0;i < nb_veritas_buf;i++)
- {
- buffers[i].internal = buffers[i].buffer;
- if (i==0 && padStart)
- {
- buffers[i].offset = buf_size*2352 + config_offset*4;
- buffers[i].readSize = buf_size*2352;
- memset((char *)(buffers[i].internal)+buffers[i].offset, 0, buffers[i].readSize);
- buffers[i].sector=0;
- continue;
- }
- if (i==0 && ripping)
- buffers[i].offset = ((2352 + config_offset*4) % 2352);
- if (primo->NextExtractAudioBuffer(buffers[i].buffer, buf_size*2352, &buffers[i].readSize, &buffers[i].sector) != PRIMOSDK_OK)
- return 0;
- }
- currentBuffer = 0;
- opened = true;
- return 1;
- }
- int VeritasPlay::CopyOverflow(char *sample_buffer, int len)
- {
- if (overflow)
- {
- len = min(len, overflow);
- memset(sample_buffer, 0, len);
- memcpy(sample_buffer, overflowBuffer, len);
- overflow -= len;
- return len;
- }
- return 0;
- }
- void VeritasPlay::OutputOverflow()
- {
- while (overflow)
- {
- char sample_buffer[576*4*2] = {0};
- int bytes = 576 * 4;
- int len = min(bytes, overflow);
- memset(sample_buffer, 0, bytes);
- memcpy(sample_buffer, overflowBuffer, len);
- Output(sample_buffer, bytes);
- overflow -= len;
- }
- }
- #include <assert.h>
- void VeritasPlay::OutputBuffer(VeritasBuffer &buffer)
- {
- char sample_buffer[576*4*2] = {0};
- size_t bytes = 576 * 4;
- char *bufferPosition = sample_buffer;
- if (overflow)
- {
- assert(overflow < (long)bytes);
- memcpy(bufferPosition, overflowBuffer, overflow);
- bytes -= overflow;
- bufferPosition += overflow;
- overflow = 0;
- }
- BYTE *bufferInput = buffer.buffer;
- while (buffer.readSize)
- {
- if (buffer.readSize < bytes) // if we don't have enough left, save it to overflow
- {
- // if there was overflow last time, and the passed buffer didn't fill us up
- // then we'll have to save both
- BYTE *temp = overflowBuffer;
- int samplesLeft = 576 * 4 - bytes;
- if (samplesLeft)
- {
- memcpy(temp, sample_buffer, samplesLeft);
- temp += samplesLeft;
- overflow += samplesLeft;
- }
- // copy any leftovers of the passed buffer
- memcpy(temp, bufferInput, buffer.readSize);
- bufferInput += buffer.readSize;
- overflow += buffer.readSize;
- buffer.readSize = 0;
- return ;
- }
- else
- {
- memcpy(bufferPosition, bufferInput, bytes);
- bufferPosition = sample_buffer;
- bufferInput += bytes;
- buffer.readSize -= bytes;
- bytes = 576 * 4;
- Output(sample_buffer, 576*4);
- }
- }
- }
- size_t VeritasPlay::CopyBuffer(VeritasBuffer &buffer, char *&sample_buffer, int &bytes)
- {
- // since a buffer is only copied once, this is safe
- buffer.readSize -= buffer.offset;
- buffer.internal += buffer.offset;
- buffer.offset=0;
- size_t len = min((size_t)bytes, buffer.readSize);
- memcpy(sample_buffer, buffer.internal, len);
- buffer.internal += len;
- buffer.readSize -= len;
- sample_buffer += len;
- bytes -= len;
- return len;
- }
- void VeritasPlay::Output(char *buffer, int len)
- {
- line.VSAAddPCMData(buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/);
- line.SAAddPCMData(buffer, g_nch, 16, line.outMod->GetWrittenTime() /*decode_pos_ms*/);
- int bytes = len;
- if (line.dsp_isactive())
- bytes = line.dsp_dosamples((short *)buffer, len / g_nch / 2, 16, g_nch, 44100) * (g_nch * 2);
- while (line.outMod->CanWrite() < bytes && !killswitch) Sleep(10);
- line.outMod->Write(buffer, bytes);
- decode_pos_ms += ((len / g_nch / 2) * 1000) / 44100;
- }
- int VeritasPlay::read(char *dest, int len, int *killswitch) //called by winampGetExtendedRead_getData
- {
- bool noAbort=false;
- int bytesCopied = 0;
- speedLimiter.Limit(killswitch);
- while (!*killswitch)
- {
- DWORD cursec = 0, totsec = 0;
- int r = primo->RunningStatus(PRIMOSDK_GETSTATUS, &cursec, &totsec);
- switch(r)
- {
- case PRIMOSDK_RUNNING:
- break;
- case PRIMOSDK_OK:
- noAbort=true;
- break;
- default:
- goto readabort; // benski> Mr. Faulkner's high school BASIC class prepared me for the real world!
- }
- int a = primo->UnitStatus(&unit, NULL, NULL, NULL, NULL);
- switch(a)
- {
- case PRIMOSDK_OK:
- break;
- default: // todo is everything else really an error? maybe message box for testing purposes
- goto readabort;
- }
- // check how far we've gone
- if (cursec >= buffers[currentBuffer].sector)
- {
- char *olddest=dest;
- int bytes = CopyBuffer(buffers[currentBuffer], dest, len);
- if (submitHandle && bytes)
- {
- int res = workorder->WriteSigData(submitHandle, olddest, bytes);
- switch(res)
- {
- case S_OK:
- break;
- case SG_SignatureAcquired:
- default:
- workorder->CloseSig(submitHandle);
- submitHandle=0;
- break;
- }
- }
- speedLimiter.MoreBytesRead(bytes);
- bytesCopied += bytes;
- if (!len || end == 1)
- {
- return bytesCopied;
- }
- if ((buffers[currentBuffer].sector + lastseek) == end_sector) // are we done?
- {
- bytesCopied -= ((2352 - config_offset*4) % 2352);
- end = 1;
- return bytesCopied;
- }
- buffers[currentBuffer].internal = buffers[currentBuffer].buffer;
- buffers[currentBuffer].offset = 0;
- if (!noAbort)
- if (primo) primo->NextExtractAudioBuffer(buffers[currentBuffer].buffer, buf_size*2352, &buffers[currentBuffer].readSize, &buffers[currentBuffer].sector);
- currentBuffer = (currentBuffer + 1) % nb_veritas_buf;
-
- }
- else if (bytesCopied != 0)
- return bytesCopied;
- else
- Sleep(13*buf_size);
- }
- // TODO: we can only get here if killswitch got set or if there was an error
- readabort:
- if (submitHandle)
- {
- workorder->AbortSig(submitHandle);
- submitHandle=0;
- }
- AbortAsync();
- return -1;
- }
- int VeritasPlay::threadProc2()
- {
- bool noAbort=false;
- while (!killswitch)
- {
- if (need_seek != -1)
- SeekAndFlush();
- DWORD cursec = 0, totsec = 0;
- int r = primo->RunningStatus(PRIMOSDK_GETSTATUS, &cursec, &totsec);
- switch(r)
- {
- case PRIMOSDK_RUNNING:
- break;
- case PRIMOSDK_OK:
- noAbort=true;
- break;
- default:
- Abort();
- if (!killswitch) Sleep(200);
- if (!killswitch) PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- return 0;
- }
- int a = primo->UnitStatus(&unit, NULL, NULL, NULL, NULL);
- switch(a)
- {
- case PRIMOSDK_OK:
- break;
- default: // todo is everything else really an error? maybe message box for testing purposes
- Abort();
- if (!killswitch) Sleep(200);
- if (!killswitch) PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- return 0;
- }
- // check how far we've gone
- if (cursec >= buffers[currentBuffer].sector)
- {
- OutputBuffer(buffers[currentBuffer]);
- if ((buffers[currentBuffer].sector+lastseek)==end_sector) // are we done?
- break;
- buffers[currentBuffer].internal = buffers[currentBuffer].buffer;
- if (!noAbort)
- primo->NextExtractAudioBuffer(buffers[currentBuffer].buffer, buf_size*2352, &buffers[currentBuffer].readSize, &buffers[currentBuffer].sector);
- currentBuffer = (currentBuffer + 1) % nb_veritas_buf;
- }
- else
- Sleep(13*buf_size);
- }
- if (killswitch)
- {
- Abort();
- return 0;
- }
- if (!noAbort)
- AbortAsync();
- OutputOverflow();
- //wait for output to be finished
- line.outMod->Write(NULL, 0);
- if (!noAbort)
- WaitForAbort(10);
- while (!killswitch && line.outMod->IsPlaying()) Sleep(10);
- if (!killswitch)
- PostMessage(line.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- return 0;
- }
- #define VERITASPLAY_OPEN_FAIL 1
- #define VERITASPLAY_OPEN_NOPRIMO 2
- int VeritasPlay::open(char drive, int track) //called by winampGetExtendedRead
- {
- if ((ripping && !config_rip_veritas))
- return VERITASPLAY_OPEN_FAIL;
- need_seek = -1;
- driveLetter = drive;
- unit = drive;
- hThread = NULL;
- if (!primo)
- {
- waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
- if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
- }
- if (!primo)
- return VERITASPLAY_OPEN_NOPRIMO;
- end = 0;
- speedLimiter.Reset();
- if (getRegVer() <= 0)
- speedLimiter.SetLimit(5);
- else
- speedLimiter.NoLimit();
- if (primo->DiscInfoEx(&unit,0, NULL, NULL, NULL, NULL, NULL, NULL) == PRIMOSDK_OK)
- {
- DWORD sesnum, tracktype, pregap;
- if (primo->TrackInfo(track, &sesnum, &tracktype, &pregap, &start_sector, &sec_length) == PRIMOSDK_OK)
- {
- if (ripping)
- {
- if (config_offset != 0)
- sec_length++; // TODO: some sort of logic for the last track
- if (config_offset<0)
- {
- if (track != 1 || config_read_leadin)
- start_sector--;
- else
- {
- sec_length--;
- padStart=true;
- }
- }
-
- }
- end_sector = start_sector + sec_length;
- #if 0 // TODO: add a config option to skip pregap (maybe separate config for burning and playback)
- start_sector+=pregap;
- sec_length-=pregap;
- #endif
- CreateBuffers();
- if (openVeritasTrack(start_sector, sec_length))
- {
- g_nch = 2; // TODO: maybe we should handle red book 4 channel audio?
- g_playlength = (sec_length / 75) * 1000;
- decode_pos_ms = 0;
- lastseek = start_sector;
- need_seek = -1;
- return 0;
- }
- }
- }
- Close();
- return VERITASPLAY_OPEN_FAIL;
- }
- int VeritasPlay::play(char drive, int track) //called by winamp2
- {
- if (!config_use_dae2 || !config_use_veritas)
- return 1;
- hThread=NULL;
- {
- g_playtrack = track;
- }
- switch(open(drive, track))
- {
- case VERITASPLAY_OPEN_FAIL:
- Sleep(200);
- // fall through
- case VERITASPLAY_OPEN_NOPRIMO:
- Close();
- return 1;
- }
- DWORD thread_id;
- hThread = CreateThread(NULL, NULL, &threadProc, (LPVOID)this, CREATE_SUSPENDED, &thread_id);
- SetThreadPriority(hThread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
- int maxlat = line.outMod->Open(44100, g_nch, 16, -1, -1);
- if (maxlat < 0)
- {
- Sleep(200);
- Close();
- CloseHandle(hThread);
- return 1;
- }
- killswitch = 0;
- line.SetInfo(1411, 44, g_nch, 1);
- line.SAVSAInit(maxlat, 44100);
- line.VSASetInfo(g_nch, 44100);
- line.is_seekable = 1;
- ResumeThread(hThread);
- return 0;
- }
- void VeritasPlay::Close()
- {
- driveLetter=0;
- }
|