123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- #pragma once
- #include <bfc/platform/types.h>
- #include "../Winamp/in2.h"
- #include "../Winamp/out.h"
- #include "SpillBuffer.h"
- #include <assert.h>
- namespace nu
- {
- template <class wait_t>
- class AudioOutput : public wait_t
- {
- public:
- AudioOutput( In_Module *plugin ) : plugin( plugin )
- {
- Init( nullptr );
- }
- ~AudioOutput()
- {
- post_buffer.reset();
- buffer576.reset();
- }
-
- void Init( Out_Module *_output )
- {
- output = _output;
- audio_opened = false;
- first_timestamp = 0;
- sample_size = 0;
- output_latency = 0;
- post_buffer.reset();
- buffer576.reset();
- cut_size = 0;
- pre_cut_size = 0;
- pre_cut = 0;
- decoder_delay = 0;
- channels = 0;
- sample_rate = 0;
- bps = 0;
- }
-
- void SetPostDelay(int postSize)
- {
- if (postSize < 0)
- {
- postSize = 0;
- }
- else if (postSize)
- {
- if (sample_size)
- post_buffer.reserve(postSize*sample_size);
- cut_size = postSize;
- }
- }
-
- void SetZeroPadding(int postSize)
- {
- postSize -= decoder_delay;
- if (postSize < 0)
- {
- postSize = 0;
- }
- SetPostDelay(postSize);
- }
-
- void SetGapless(int decoderDelaySize, int preSize, int postSize)
- {
- decoder_delay = decoderDelaySize;
- SetZeroPadding(postSize);
- pre_cut_size = preSize;
- pre_cut = pre_cut_size + decoder_delay;
- }
-
- void SetDelays(int decoderDelaySize, int preSize, int postSize)
- {
- decoder_delay = decoderDelaySize;
- SetPostDelay(postSize);
- pre_cut_size = preSize;
- pre_cut = pre_cut_size;
- }
-
- void Flush(int time_in_ms)
- {
- if (audio_opened)
- {
- pre_cut = pre_cut_size;
- output->Flush(time_in_ms);
- first_timestamp = 0;
- buffer576.clear();
- post_buffer.clear();
- }
- else
- first_timestamp = time_in_ms;
- }
- bool Opened() const
- {
- return audio_opened;
- }
- int GetLatency() const
- {
- return output_latency;
- }
- int GetFirstTimestamp() const
- {
- return first_timestamp;
- }
-
- bool Open(int timestamp, int channels, int sample_rate, int bps, int buffer_len_ms=-1, int pre_buffer_ms=-1)
- {
- if (!audio_opened)
- {
- int latency = output->Open(sample_rate, channels, bps, buffer_len_ms, pre_buffer_ms);
- if (latency < 0)
- return false;
- plugin->SAVSAInit(latency, sample_rate);
- plugin->VSASetInfo(sample_rate, channels);
- output->SetVolume(-666);
- plugin->SetInfo(-1, sample_rate / 1000, channels, 1);
- output_latency = latency;
- first_timestamp = timestamp;
- sample_size = channels*bps / 8;
- this->channels=channels;
- this->sample_rate=sample_rate;
- this->bps=bps;
- SetPostDelay((int)cut_size);
- buffer576.reserve(576*sample_size);
- audio_opened=true;
- }
- return audio_opened;
- }
- void Close()
- {
- if (audio_opened && output)
- {
- output->Close();
- plugin->SAVSADeInit();
- }
- output = 0;
- first_timestamp = 0;
- }
-
- int Write(char *out, size_t outSize)
- {
- if (!out && !outSize)
- {
-
- if (!post_buffer.empty())
- {
- void *buffer = 0;
- size_t len = 0;
- if (post_buffer.get(&buffer, &len))
- {
- int ret = Write576((char *)buffer, len);
- if (ret != 0)
- return ret;
- }
- }
-
- if (!buffer576.empty())
- {
- void *buffer = 0;
- size_t len = 0;
- if (buffer576.get(&buffer, &len))
- {
- int ret = WriteOutput((char *)buffer, len);
- if (ret != 0)
- return ret;
- }
- }
- output->Write(0, 0);
- return 0;
- }
-
- if (!sample_size)
- return 0;
- assert((outSize % sample_size) == 0);
- size_t outSamples = outSize / sample_size;
-
- size_t pre = min(pre_cut, outSamples);
- out += pre * sample_size;
- outSize -= pre * sample_size;
- pre_cut -= pre;
-
-
- if (!outSize)
- return 0;
-
- if (outSize < post_buffer.length())
- {
- size_t bytes_written = post_buffer.write(out, outSize);
- out+=bytes_written;
- outSize-=bytes_written;
- }
-
- if (!outSize)
- return 0;
-
- if (!post_buffer.empty())
- {
- void *buffer = 0;
- size_t len = 0;
- if (post_buffer.get(&buffer, &len))
- {
- int ret = Write576((char *)buffer, len);
- if (ret != 0)
- return ret;
- }
- }
-
- size_t remainingFill = post_buffer.remaining();
- int outWrite = max(0, (int)outSize - (int)remainingFill);
-
- if (outWrite)
- {
- int ret = Write576(out, outWrite);
- if (ret != 0)
- return ret;
- }
- out += outWrite;
- outSize -= outWrite;
-
- if (outSize)
- {
- post_buffer.write(out, outSize);
- }
- return 0;
- }
-
- int WaitWhilePlaying()
- {
- while (output->IsPlaying())
- {
- int ret = WaitOrAbort(10);
- if (ret != 0)
- return ret;
- output->CanWrite();
-
- }
- return 0;
- }
- private:
-
- int WaitForOutput(int write_size_bytes)
- {
- while (output->CanWrite() < write_size_bytes)
- {
- int ret = WaitOrAbort(55);
- if (ret != 0)
- return ret;
- }
- return 0;
- }
-
- int WriteOutput(char *buffer, size_t len)
- {
- int ret = WaitForOutput((int)len);
- if (ret != 0)
- return ret;
-
- if (len == 576*sample_size)
- {
- plugin->SAAddPCMData(buffer, channels, bps, output->GetWrittenTime() + first_timestamp);
- plugin->VSAAddPCMData(buffer, channels, bps, output->GetWrittenTime() + first_timestamp);
- }
- if (plugin->dsp_isactive())
- len = sample_size * plugin->dsp_dosamples((short *)buffer, (int)(len / sample_size), bps, channels, sample_rate);
- output->Write(buffer, (int)len);
- return 0;
- }
-
- int Write576(char *buffer, size_t out_size)
- {
-
- if (!buffer576.empty())
- {
- size_t bytes_written = buffer576.write(buffer, out_size);
- out_size -= bytes_written;
- buffer += bytes_written;
- }
- if (buffer576.full())
- {
- void *buffer = 0;
- size_t len = 0;
- if (buffer576.get(&buffer, &len))
- {
- int ret = WriteOutput((char *)buffer, len);
- if (ret != 0)
- return ret;
- }
- }
- while (out_size >= 576*sample_size)
- {
- int ret = WriteOutput(buffer, 576*sample_size);
- if (ret != 0)
- return ret;
- out_size -= 576*sample_size;
- buffer+=576*sample_size;
- }
- if (out_size)
- {
- assert(out_size < 576*sample_size);
- buffer576.write(buffer, out_size);
- }
- return 0;
- }
- private:
- Out_Module *output;
- In_Module *plugin;
- SpillBuffer post_buffer, buffer576;
- size_t cut_size;
- size_t pre_cut, pre_cut_size, decoder_delay;
- bool audio_opened;
- int first_timestamp;
- size_t sample_size;
- int output_latency;
- int channels, sample_rate, bps;
- };
- }
|