123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810 |
- #include "DecodeThread.h"
- #include "giofile.h"
- #include "main.h"
- #include "pdtimer.h"
- #include "mpegutil.h"
- #include "../Winamp/wa_ipc.h"
- #include "config.h"
- #include <shlwapi.h>
- #include "adts.h"
- #include "adts_vlb.h"
- #include <foundation/error.h>
- // {19450308-90D7-4E45-8A9D-DC71E67123E2}
- static const GUID adts_aac_guid =
- { 0x19450308, 0x90d7, 0x4e45, { 0x8a, 0x9d, 0xdc, 0x71, 0xe6, 0x71, 0x23, 0xe2 } };
- // {4192FE3F-E843-445c-8D62-51BE5EE5E68C}
- static const GUID adts_mp2_guid =
- { 0x4192fe3f, 0xe843, 0x445c, { 0x8d, 0x62, 0x51, 0xbe, 0x5e, 0xe5, 0xe6, 0x8c } };
- extern int m_is_stream;
- extern bool m_is_stream_seekable;
- // post this to the main window at end of file (after playback as stopped)
- #define WM_WA_MPEG_EOF WM_USER+2
- /* public data */
- int last_decode_pos_ms;
- int decode_pos_ms; // current decoding position, in milliseconds.
- volatile int seek_needed; // if != -1, it is the point that the decode
- // thread should seek to, in ms.
- int g_ds;
- size_t g_bits;
- int g_sndopened;
- int g_bufferstat;
- int g_length = -1000;
- int g_vis_enabled;
- volatile int g_closeaudio = 0;
- CGioFile *g_playing_file=0;
- /* private data */
- static size_t g_samplebuf_used;
- static int need_prebuffer;
- static int g_srate, g_nch, g_br_add, g_br_div, g_avg_vbr_br;
- int g_br;
- class EndCutter
- {
- public:
- EndCutter() : buffer(0), cutSize(0), filledSize(0), preCutSize(0), preCut(0), decoderDelay(0)
- {}
- ~EndCutter()
- {
- free(buffer);
- }
- void SetEndSize(int postSize)
- {
- postSize -= decoderDelay;
- if (postSize < 0)
- postSize = 0;
- else if (postSize)
- {
- free(buffer);
- buffer = (char *)calloc(postSize, sizeof(char));
- cutSize = postSize;
- }
- }
- void SetSize(int decoderDelaySize, int preSize, int postSize)
- {
- decoderDelay = decoderDelaySize;
- SetEndSize(postSize);
- preCutSize = preSize;
- preCut = preCutSize + decoderDelay;
- }
- void Flush(int time_in_ms)
- {
- if (time_in_ms == 0) // TODO: calculate actual delay if we seek within the encoder delay area
- preCut = preCutSize; // reset precut size if we seek to the start
- filledSize = 0;
- mod.outMod->Flush(time_in_ms);
- }
- void Write(char *out, int outSize)
- {
- if (!out && (!outSize))
- {
- mod.outMod->Write(0, 0);
- return ;
- }
- // cut pre samples, if necessary
- int pre = min(preCut, outSize);
- out += pre;
- outSize -= pre;
- preCut -= pre;
- if (!outSize)
- return ;
- int remainingFill = cutSize - filledSize;
- int fillWrite = min(outSize - remainingFill, filledSize); // only write fill buffer if we've got enough left to fill it up
- if (fillWrite > 0)
- {
- mod.outMod->Write((char *)buffer, fillWrite);
- if (cutSize - fillWrite)
- memmove(buffer, buffer + fillWrite, cutSize - fillWrite);
- filledSize -= fillWrite;
- }
- remainingFill = cutSize - filledSize;
- int outWrite = max(0, outSize - remainingFill);
- if (outWrite)
- mod.outMod->Write((char *)out, outWrite);
- out += outWrite;
- outSize -= outWrite;
- if (outSize)
- {
- memcpy(buffer + filledSize, out, outSize);
- filledSize += outSize;
- }
- }
- char *buffer;
- int cutSize;
- int filledSize;
- int preCut, preCutSize, decoderDelay;
- };
- class DecodeLoop
- {
- public:
- DecodeLoop() : decoder(0)
- {
- isAac = 0;
- isEAAC = 0;
- last_bpos = -1;
- need_synclight = true;
- done = 0;
- br = 0;
- g_framesize = 0;
- maxlatency = 0;
- sampleFrameSize = 0;
- memset(&g_samplebuf, 0, sizeof(g_samplebuf));
- }
- ~DecodeLoop()
- {
- if (decoder)
- {
- decoder->Close();
- decoder->Release();
- }
- decoder=0;
- }
- DWORD Loop();
- DWORD OpenDecoder();
- void Seek(int seekPosition);
- void PreBuffer();
- void Decode();
- void Viz();
- void CalculateCodecDelay();
- DWORD OpenOutput(int numChannels, int sampleRate, int bitsPerSample);
- void SetupStream();
- BYTE g_samplebuf[6*3*2*2*1152];
- int g_framesize;
- int isAac;
- int isEAAC;
- CGioFile file;
- int maxlatency;
- int last_bpos;
- bool need_synclight;
- int done; // set to TRUE if decoding has finished, 2 if all has been written
- size_t br;
- EndCutter endCutter;
- int sampleFrameSize;
- adts *decoder;
- };
- static int CalcPreBuffer(int buffer_setting, int bitrate)
- {
- if (bitrate < 8)
- bitrate = 8;
- else if (bitrate > 320)
- bitrate = 320;
- int prebuffer = (buffer_setting * bitrate) / 128;
- if (prebuffer > 100)
- prebuffer=100;
- return prebuffer;
- }
- void DecodeLoop::SetupStream()
- {
- char buf[1024] = {0};
- int len;
- m_is_stream = file.IsStream();
- //Wait until we have data...
- while (!killDecodeThread && file.Peek(buf, 1024, &len) == NErr_Success && !len)
- Sleep(50);
- m_is_stream_seekable = file.IsStreamSeekable();
- char *content_type = file.m_content_type;
- if (content_type)
- {
- if (!_strnicmp(content_type, "misc/ultravox", 13))
- {
- switch (file.uvox_last_message)
- {
- case 0x8001:
- case 0x8003:
- isEAAC = 1;
- isAac = 1;
- break;
- case 0x8000:
- isAac = 1;
- break;
- }
- }
- else if (!_strnicmp(content_type, "audio/aac", 9))
- {
- isEAAC = 1;
- isAac = 1;
- }
- else if (!_strnicmp(content_type, "audio/aacp", 10))
- {
- isEAAC = 1;
- isAac = 1;
- }
- else if (!_strnicmp(content_type, "audio/apl", 10))
- {
- isEAAC = 1;
- isAac = 1;
- }
- }
- // todo: poll until connected to see if we get aac uvox frames or a content-type:aac header
- }
- DWORD DecodeLoop::OpenOutput(int numChannels, int sampleRate, int bitsPerSample)
- {
- maxlatency = mod.outMod->Open(sampleRate, numChannels, bitsPerSample, -1, -1);
- // maxlatency is the maxium latency between a outMod->Write() call and
- // when you hear those samples. In ms. Used primarily by the visualization
- // system.
- if (maxlatency < 0) // error opening device
- {
- PostMessage(mod.hMainWindow, WM_COMMAND, 40047, 0);
- return 0;
- }
- g_sndopened = 1;
- if (maxlatency == 0 && file.IsStream() == 2) // can't use with disk writer
- {
- if (!killDecodeThread)
- {
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_CANNOT_WRITE_STREAMS_TO_DISK,lastfn_status,256);
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- if (!killDecodeThread) Sleep(200);
- if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- g_bufferstat = 0;
- g_closeaudio = 1;
- return 0;
- }
- if (paused) mod.outMod->Pause(1);
- // set the output plug-ins default volume.
- // volume is 0-255, -666 is a token for
- // current volume.
- mod.outMod->SetVolume(-666);
- return 1;
- }
- void DecodeLoop::CalculateCodecDelay()
- {
- int decoderDelaySamples = (int)decoder->GetDecoderDelay();
- endCutter.SetSize(decoderDelaySamples*sampleFrameSize,
- file.prepad*sampleFrameSize,
- file.postpad*sampleFrameSize);
- }
- void DecodeLoop::Viz()
- {
- if (!config_fastvis || (decoder->GetLayer() != 3 || g_ds))
- {
- int vis_waveNch;
- int vis_specNch;
- int csa = mod.SAGetMode();
- int is_vis_running = mod.VSAGetMode(&vis_specNch, &vis_waveNch);
- if (csa || is_vis_running)
- {
- int l = 576 * sampleFrameSize;
- int ti = decode_pos_ms;
- {
- if (g_ds == 2)
- {
- memcpy(g_samplebuf + g_samplebuf_used, g_samplebuf, g_samplebuf_used);
- }
- size_t pos = 0;
- while (pos < g_samplebuf_used)
- {
- int a, b;
- if (mod.SAGetMode()) mod.SAAddPCMData((char *)g_samplebuf + pos, g_nch, (int)g_bits, ti);
- if (mod.VSAGetMode(&a, &b)) mod.VSAAddPCMData((char *)g_samplebuf + pos, g_nch, (int)g_bits, ti);
- ti += ((l / sampleFrameSize * 1000) / g_srate);
- pos += l >> g_ds;
- }
- }
- }
- }
- else
- {
- int l = (576 * (int)g_bits * g_nch);
- int ti = decode_pos_ms;
- size_t pos = 0;
- int x = 0;
- while (pos < g_samplebuf_used)
- {
- do_layer3_vis((short*)(g_samplebuf + pos), &g_vis_table[x++][0][0][0], g_nch, ti);
- ti += (l / g_nch / 2 * 1000) / g_srate;
- pos += l;
- }
- }
- }
- void DecodeLoop::Decode()
- {
- while (g_samplebuf_used < (size_t)g_framesize && !killDecodeThread && seek_needed == -1)
- {
- size_t newl = 0;
- size_t br=0;
- size_t endCut=0;
- int res = decoder->Decode(&file, g_samplebuf + g_samplebuf_used, sizeof(g_samplebuf) / 2 - g_samplebuf_used, &newl, &br, &endCut);
- if (config_gapless && endCut)
- endCutter.SetEndSize((int)endCut* sampleFrameSize);
- // we're not using switch here because we sometimes need to break out of the while loop
- if (res == adts::SUCCESS)
- {
- if (!file.m_vbr_frames)
- {
- if (br) {
- bool do_real_br=false;
- if (!(config_miscopts&2) && br != decoder->GetCurrentBitrate())
- {
- do_real_br=true;
- }
- int r = (int)br;
- g_br_add += r;
- g_br_div++;
- r = (g_br_add + g_br_div / 2) / g_br_div;
- if (g_br != r)
- {
- need_synclight = false;
- g_br = r;
- if (!file.m_vbr_frames && file.IsSeekable()) g_length = MulDiv(file.GetContentLength(), 8, g_br);
- if (!do_real_br)
- mod.SetInfo(g_br, -1, -1, 1);
- }
- if (do_real_br)
- mod.SetInfo((int)br, -1, -1, 1);
- }
- }
- else
- {
- if (br) {
- int r;
- if (!(config_miscopts&2) || !g_avg_vbr_br)
- r = (int)br;
- else r = g_avg_vbr_br;
- if (g_br != r)
- {
- need_synclight = false;
- g_br = r;
- mod.SetInfo(g_br, -1, -1, 1);
- }
- }
- }
- if (need_synclight)
- {
- need_synclight = false;
- mod.SetInfo(-1, -1, -1, 1);
- }
- g_samplebuf_used += newl;
- }
- else if (res == adts::ENDOFFILE)
- {
- done = 1;
- break;
- }
- else if (res == adts::NEEDMOREDATA)
- {
- if (file.IsStream() && !need_synclight)
- {
- need_synclight = true; mod.SetInfo(-1, -1, -1, 0);
- }
- if (file.IsStream() && !mod.outMod->IsPlaying())
- {
- need_prebuffer = CalcPreBuffer(config_http_prebuffer_underrun, (int)br);
- }
- break;
- }
- else
- {
- if (!need_synclight) mod.SetInfo(-1, -1, -1, 0);
- need_synclight = true;
- break;
- }
- }
- }
- void DecodeLoop::PreBuffer()
- {
- int p = file.RunStream();
- int pa = file.PercentAvailable();
- if (pa >= need_prebuffer || p == 2)
- {
- EnterCriticalSection(&g_lfnscs);
- lastfn_status[0] = 0;
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- need_prebuffer = 0;
- g_bufferstat = 0;
- last_bpos = -1;
- }
- else
- {
- int bpos = pa * 100 / need_prebuffer;
- if (!g_bufferstat) g_bufferstat = decode_pos_ms;
- if (bpos != last_bpos)
- {
- last_bpos = bpos;
- EnterCriticalSection(&g_lfnscs);
- if (stricmp(lastfn_status, "stream temporarily interrupted"))
- {
- char langbuf[512] = {0};
- wsprintfA(lastfn_status, WASABI_API_LNGSTRING_BUF(IDS_BUFFER_X,langbuf,512), bpos);
- }
- LeaveCriticalSection(&g_lfnscs);
- int csa = mod.SAGetMode();
- char tempdata[75*2] = {0, };
- int x;
- if (csa&1)
- {
- for (x = 0; x < bpos*75 / 100; x ++)
- {
- tempdata[x] = x * 16 / 75;
- }
- }
- if (csa&2)
- {
- int offs = (csa & 1) ? 75 : 0;
- x = 0;
- while (x < bpos*75 / 100)
- {
- tempdata[offs + x++] = -6 + x * 14 / 75;
- }
- while (x < 75)
- {
- tempdata[offs + x++] = 0;
- }
- }
- if (csa == 4)
- {
- tempdata[0] = tempdata[1] = (bpos * 127 / 100);
- }
- if (csa) mod.SAAdd(tempdata, ++g_bufferstat, (csa == 3) ? 0x80000003 : csa);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- }
- }
- void DecodeLoop::Seek(int seekPosition)
- {
- if (done == 3)
- return;
- done=0;
- int br = (int)decoder->GetCurrentBitrate();
- need_prebuffer = CalcPreBuffer(config_http_prebuffer_underrun, br);
- if (need_prebuffer < 1) need_prebuffer = 5;
- last_decode_pos_ms = decode_pos_ms = seekPosition;
- seek_needed = -1;
- endCutter.Flush(decode_pos_ms);
- decoder->Flush(&file);
- done = 0;
- g_samplebuf_used = 0;
- int r = g_br;
- if (g_br_div) r = (g_br_add + g_br_div / 2) / g_br_div;
- file.Seek(decode_pos_ms, r);
- // need_prebuffer=config_http_prebuffer/8;
- // g_br_add=g_br_div=0;
- }
- DWORD DecodeLoop::OpenDecoder()
- {
- mod.UsesOutputPlug &= ~8;
- if (isAac)
- {
- if (isEAAC)
- {
- waServiceFactory *factory = mod.service->service_getServiceByGuid(adts_aac_guid);
- if (factory)
- decoder = (adts *)factory->getInterface();
- mod.UsesOutputPlug|=8;
- }
- if (!decoder)
- {
- decoder = new ADTS_VLB;
- mod.UsesOutputPlug &= ~8;
- }
- }
- else
- {
- waServiceFactory *factory = mod.service->service_getServiceByGuid(adts_mp2_guid);
- if (factory)
- decoder = (adts *)factory->getInterface();
- mod.UsesOutputPlug|=8;
- }
- if (decoder) {
- decoder->SetDecoderHooks(mp3GiveVisData, mp2Equalize, mp3Equalize);
- }
- if (decoder
- && decoder->Initialize(AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false),
- config_downmix == 2,
- AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true),
- (int)AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16), true, false,
- (config_miscopts&1)/*crc*/) == adts::SUCCESS
- && decoder->Open(&file))
- {
- // sync to stream
- while (1)
- {
- switch (decoder->Sync(&file, g_samplebuf, sizeof(g_samplebuf), &g_samplebuf_used, &br))
- {
- case adts::SUCCESS:
- return 1;
- case adts::FAILURE:
- case adts::ENDOFFILE:
- if (!killDecodeThread)
- {
- if (!lastfn_status_err)
- {
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_ERROR_SYNCING_TO_STREAM,lastfn_status,256);
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- }
- if (!killDecodeThread) Sleep(200);
- if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- return 0;
- case adts::NEEDMOREDATA:
- if (!killDecodeThread && file.IsStream()) Sleep(25);
- if (killDecodeThread) return 0;
- }
- }
- }
- return 0;
- }
- DWORD DecodeLoop::Loop()
- {
- last_decode_pos_ms = 0;
- if (file.Open(lastfn, config_max_bufsize_k) != NErr_Success)
- {
- if (!killDecodeThread) Sleep(200);
- if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- return 0;
- }
- if (file.IsSeekable()) mod.is_seekable = 1;
- wchar_t *ext = PathFindExtension(lastfn);
- if (!_wcsicmp(ext, L".aac")
- || !_wcsicmp(ext, L".vlb")
- || !_wcsicmp(ext, L".apl"))
- {
- if (file.IsStream())
- SetupStream();
- else
- {
- isAac = 1;
- if (!_wcsicmp(ext, L".aac") || !_wcsicmp(ext, L".apl")) isEAAC = 1;
- }
- }
- else if (file.IsStream())
- SetupStream();
- if (OpenDecoder() == 0)
- return 0;
- EnterCriticalSection(&streamInfoLock);
- g_playing_file = &file;
- if (file.uvox_3901)
- {
- PostMessage(mod.hMainWindow, WM_WA_IPC, (WPARAM) "0x3901", IPC_METADATA_CHANGED);
- PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
- }
- LeaveCriticalSection(&streamInfoLock);
-
- EnterCriticalSection(&g_lfnscs);
- lastfn_status[0] = 0;
- LeaveCriticalSection(&g_lfnscs);
- lastfn_data_ready = 1;
- // TODO? if (decoder != &aacp) // hack because aac+ bitrate isn't accurate at this point
- br = decoder->GetCurrentBitrate();
- need_prebuffer = CalcPreBuffer(config_http_prebuffer, (int)br);
- if (((!(config_eqmode&4) && decoder->GetLayer() == 3) ||
- ((config_eqmode&8) && decoder->GetLayer() < 3)))
- {
- mod.UsesOutputPlug |= 2;
- }
- else
- mod.UsesOutputPlug &= ~2;
- decoder->CalculateFrameSize(&g_framesize);
- decoder->GetOutputParameters(&g_bits, &g_nch, &g_srate);
- if (!killDecodeThread && file.IsStream() == 1)
- {
- DWORD_PTR dw;
- if (!killDecodeThread) SendMessageTimeout(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE, SMTO_BLOCK, 100, &dw);
- if (!killDecodeThread) SendMessageTimeout(mod.hMainWindow, WM_TIMER, 38, 0, SMTO_BLOCK, 100, &dw);
- }
- sampleFrameSize = g_nch * ((int)g_bits/8);
- if (config_gapless)
- CalculateCodecDelay();
- if (OpenOutput(g_nch, g_srate, (int)g_bits) == 0)
- return 0;
- /* ----- send info to winamp and vis: bitrate, etc ----- */
- g_br = (int)decoder->GetCurrentBitrate();
- g_br_add = g_br;
- g_br_div = 1;
- g_avg_vbr_br = file.GetAvgVBRBitrate();
- mod.SetInfo(g_br, g_srate / 1000, g_nch, 0);
- // initialize visualization stuff
- mod.SAVSAInit((maxlatency << g_ds), g_srate);
- mod.VSASetInfo(g_srate, g_nch);
- /* ----- end send info to winamp and vis ----- */
- if (file.IsSeekable() && g_br)
- {
- mod.is_seekable = 1;
- if (!file.m_vbr_frames) g_length = MulDiv(file.GetContentLength(), 8, g_br);
- else g_length = file.m_vbr_ms;
- }
- if (file.IsStream())
- {
- if (need_prebuffer < config_http_prebuffer / 2)
- need_prebuffer = config_http_prebuffer / 2;
- }
- while (!killDecodeThread)
- {
- if (seek_needed != -1)
- Seek(seek_needed);
- if (need_prebuffer && file.IsStream() && maxlatency && !file.EndOf())
- PreBuffer();
- int needsleep = 1;
- if (done == 2) // done was set to TRUE during decoding, signaling eof
- {
- mod.outMod->CanWrite(); // some output drivers need CanWrite
- // to be called on a regular basis.
- if (!mod.outMod->IsPlaying())
- {
- // we're done playing, so tell Winamp and quit the thread.
- if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- done=3;
- break;
- }
- }
- else
- {
- int fs = (g_framesize * ((mod.dsp_isactive() == 1) ? 2 : 1));
- // TODO: we should really support partial writes, there's no gaurantee that CanWrite() will EVER get big enough
- if (mod.outMod->CanWrite() >= fs && (!need_prebuffer || !file.IsStream() || !maxlatency))
- // CanWrite() returns the number of bytes you can write, so we check that
- // to the block size. the reason we multiply the block size by two if
- // mod.dsp_isactive() is that DSP plug-ins can change it by up to a
- // factor of two (for tempo adjustment).
- {
- int p = mod.SAGetMode();
- g_vis_enabled = ((p & 1) || p == 4);
- if (!g_vis_enabled)
- {
- int s, a;
- mod.VSAGetMode(&s, &a);
- if (s) g_vis_enabled = 1;
- }
- Decode();
- if ((g_samplebuf_used >= (size_t)g_framesize || (done && g_samplebuf_used > 0)) && seek_needed == -1)
- {
- // adjust decode position variable
- if (file.isSeekReset())
- last_decode_pos_ms = decode_pos_ms = 0;
- else
- decode_pos_ms += ((int)g_samplebuf_used / sampleFrameSize * 1000) / g_srate;
- // if we have a DSP plug-in, then call it on our samples
- if (mod.dsp_isactive())
- {
- g_samplebuf_used = mod.dsp_dosamples((short *)g_samplebuf, (int)g_samplebuf_used / sampleFrameSize, (int)g_bits, g_nch, g_srate) * sampleFrameSize;
- }
- Viz();
- endCutter.Write((char *)g_samplebuf, (int)g_samplebuf_used);
- g_samplebuf_used = 0;
- needsleep = 0;
- //memcpy(g_samplebuf,g_samplebuf+r,g_samplebuf_used);
- }
- if (done)
- {
- endCutter.Write(0, 0);
- done = 2;
- }
- }
- }
- if (decode_pos_ms > last_decode_pos_ms + 1000)
- {
- last_decode_pos_ms = decode_pos_ms;
- }
- if (needsleep) Sleep(10);
- // if we can't write data, wait a little bit. Otherwise, continue
- // through the loop writing more data (without sleeping)
- }
- /* ---- change some globals to let everyone know we're done */
- EnterCriticalSection(&g_lfnscs);
- lastfn_status[0] = 0;
- LeaveCriticalSection(&g_lfnscs);
- g_bufferstat = 0;
- g_closeaudio = 1;
- /* ---- */
- return 0;
- }
- DWORD WINAPI DecodeThread(LPVOID b)
- {
- DecodeLoop loop;
-
- DWORD ret = loop.Loop();
- EnterCriticalSection(&streamInfoLock);
- g_playing_file = 0;
- LeaveCriticalSection(&streamInfoLock);
- return ret;
- }
|