diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/audio | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/audio')
-rw-r--r-- | Src/replicant/audio/ifc_audio_decoder_callback.h | 57 | ||||
-rw-r--r-- | Src/replicant/audio/ifc_audio_decoder_packet.h | 23 | ||||
-rw-r--r-- | Src/replicant/audio/ifc_audio_decoder_pull.h | 34 | ||||
-rw-r--r-- | Src/replicant/audio/ifc_audioout.h | 76 | ||||
-rw-r--r-- | Src/replicant/audio/ifc_equalizer.h | 27 | ||||
-rw-r--r-- | Src/replicant/audio/parameters.h | 47 | ||||
-rw-r--r-- | Src/replicant/audio/types.h | 44 |
7 files changed, 308 insertions, 0 deletions
diff --git a/Src/replicant/audio/ifc_audio_decoder_callback.h b/Src/replicant/audio/ifc_audio_decoder_callback.h new file mode 100644 index 00000000..2db3fa1d --- /dev/null +++ b/Src/replicant/audio/ifc_audio_decoder_callback.h @@ -0,0 +1,57 @@ +#pragma once +#include "foundation/dispatch.h" +#include "nx/nxuri.h" +#include "metadata/ifc_metadata.h" + +/* this is the class you actually use */ +class ifc_audio_decoder_callback : public Wasabi2::Dispatchable +{ +protected: + ifc_audio_decoder_callback() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_audio_decoder_callback() {} +public: + /* you must implement this class to use the decoder */ + class callback : public Wasabi2::Dispatchable + { + protected: + callback() : Dispatchable(DISPATCHABLE_VERSION) {} + ~callback() {} + public: + /* frames is defined as all channels, e.g. 16bit stereo is 4 bytes per frame (2 bytes per sample) + return NErr_Success to continue receiving callbacks + */ + int OnAudio(const void *buffer, size_t buffer_frames) { return AudioDecoderCallback_OnAudio(buffer, buffer_frames); } + + enum + { + DISPATCHABLE_VERSION=0, + }; + private: + virtual int WASABICALL AudioDecoderCallback_OnAudio(const void *buffer, size_t buffer_frames)=0; + }; + + /* if possible, returns an upper bound on the number of frames used internally. this would be the maximum buffer_frames value you receive in a callback */ + int GetFrameSize(size_t *frame_size) { return AudioDecoderCallback_GetFrameSize(frame_size); } + int GetMetadata(ifc_metadata **metadata) { return AudioDecoderCallback_GetMetadata(metadata); } + + /* returns + * NErr_Success on a successfully completed decode + * NErr_Interrupted if the callback function aborted decoding + * anything else indicates a decoding error + */ + int Decode(ifc_audio_decoder_callback::callback *callback) { return AudioDecoderCallback_Decode(callback); } + + /* Like decode, but only processes one frame. + returns NErr_EndOfFile on the last frame */ + int DecodeStep(ifc_audio_decoder_callback::callback *callback) { return AudioDecoderCallback_DecodeStep(callback); } + + enum + { + DISPATCHABLE_VERSION=0, + }; +private: + virtual int WASABICALL AudioDecoderCallback_Decode(ifc_audio_decoder_callback::callback *callback)=0; + virtual int WASABICALL AudioDecoderCallback_DecodeStep(ifc_audio_decoder_callback::callback *callback)=0; + virtual int WASABICALL AudioDecoderCallback_GetFrameSize(size_t *frame_size)=0; + virtual int WASABICALL AudioDecoderCallback_GetMetadata(ifc_metadata **metadata)=0; +}; diff --git a/Src/replicant/audio/ifc_audio_decoder_packet.h b/Src/replicant/audio/ifc_audio_decoder_packet.h new file mode 100644 index 00000000..cd929899 --- /dev/null +++ b/Src/replicant/audio/ifc_audio_decoder_packet.h @@ -0,0 +1,23 @@ +#pragma once +#include "foundation/dispatch.h" +#include "nx/nxuri.h" +#include "metadata/ifc_metadata.h" + +class ifc_audio_decoder_packet : public Wasabi2::Dispatchable +{ +protected: + ifc_audio_decoder_packet() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_audio_decoder_packet() {} +public: + + int GetMetadata(ifc_metadata **metadata) { return AudioDecoderPacket_GetMetadata(metadata); } + int Decode(void **out_packet, size_t *frames_available) { return AudioDecoderPacket_Decode(out_packet, frames_available); } + + enum + { + DISPATCHABLE_VERSION=0, + }; +private: + virtual int WASABICALL AudioDecoderPacket_GetMetadata(ifc_metadata **metadata)=0; + virtual int WASABICALL AudioDecoderPacket_Decode(void **out_packet, size_t *frames_available)=0; +}; diff --git a/Src/replicant/audio/ifc_audio_decoder_pull.h b/Src/replicant/audio/ifc_audio_decoder_pull.h new file mode 100644 index 00000000..9be97987 --- /dev/null +++ b/Src/replicant/audio/ifc_audio_decoder_pull.h @@ -0,0 +1,34 @@ +#pragma once +#include "foundation/dispatch.h" +#include "nx/nxuri.h" +#include "metadata/ifc_metadata.h" + +class ifc_audio_decoder_pull : public Wasabi2::Dispatchable +{ +protected: + ifc_audio_decoder_pull() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_audio_decoder_pull() {} +public: + + /* if possible, returns an upper bound on the number of frames used internally. pull decoders are most optimal if you use this to malloc your buffer */ + int GetFrameSize(size_t *frame_size) { return AudioDecoderPull_GetFrameSize(frame_size); } + int GetMetadata(ifc_metadata **metadata) { return AudioDecoderPull_GetMetadata(metadata); } + + /* returns + * NErr_EndOfFile when decode is done (frames_written will be valid, but probably 0) + * NErr_Success on successful decode, but not end-of-file (frames_written will be valid) + * anything else indicates a decode error */ + int Decode(void *buffer, size_t buffer_frames, size_t *frames_written) { return AudioDecoderPull_Decode(buffer, buffer_frames, frames_written); } + /* You need to call Close() when you are done (even if you Release) because some implementations might have ifc_metadata being the same object */ + void Close() { AudioDecoderPull_Close(); } + + enum + { + DISPATCHABLE_VERSION=0, + }; +private: + virtual int WASABICALL AudioDecoderPull_GetFrameSize(size_t *frame_size)=0; + virtual int WASABICALL AudioDecoderPull_GetMetadata(ifc_metadata **metadata)=0; + virtual int WASABICALL AudioDecoderPull_Decode(void *buffer, size_t buffer_frames, size_t *frames_written)=0; + virtual void WASABICALL AudioDecoderPull_Close()=0; +}; diff --git a/Src/replicant/audio/ifc_audioout.h b/Src/replicant/audio/ifc_audioout.h new file mode 100644 index 00000000..1ebd9e19 --- /dev/null +++ b/Src/replicant/audio/ifc_audioout.h @@ -0,0 +1,76 @@ +#pragma once +#include "foundation/dispatch.h" +#include "foundation/error.h" +#include "audio/parameters.h" + + +class NOVTABLE ifc_audioout : public Wasabi2::Dispatchable +{ +protected: + ifc_audioout() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_audioout() {} + +public: + enum + { + CHANNEL_LAYOUT_MICROSOFT = 0x0, // microsoft channel order - http://www.microsoft.com/whdc/device/audio/multichaud.mspx#E4C + CHANNEL_LAYOUT_MPEG = 0x1, + }; + + + enum + { + EXTENDED_FLAG_APPLY_GAIN=0x1, /* apply the gain value specified in Parameters::gain */ + EXTENDED_FLAG_REPLAYGAIN=0x2, /* pass if you tried to figure out ReplayGain on your own. otherwise the Audio Output object will apply the default gain */ + EXTENDED_FLAG_GAIN_MASK=EXTENDED_FLAG_APPLY_GAIN|EXTENDED_FLAG_REPLAYGAIN, /* a mask to check whether or not the gain value is valid */ + /* so that you can check if a flag was set that you don't understand */ + EXTENDED_FLAG_VALID_MASK=EXTENDED_FLAG_APPLY_GAIN|EXTENDED_FLAG_REPLAYGAIN, + }; + + struct Parameters + { + size_t sizeof_parameters; + nsaudio::Parameters audio; + /* anything after this needs sizeof_parameters to be large enough + AND a flag set in extended_fields_flags + if there's no flag for the field, it's because a default value of 0 can be assumed */ + unsigned int extended_fields_flags; // set these if you use any of the following fields. see comment above + double gain; // additional gain specified by client. usually used for replaygain (so it can be combined with EQ pre-amp or float/pcm conversion) + size_t frames_trim_start; // number of frames to trim from the start + size_t frames_trim_end; // number of frames to trim from the start + }; + + int Output(const void *data, size_t data_size) { return AudioOutput_Output(data, data_size); } + // returns number of bytes that you can write + size_t CanWrite() { return AudioOutput_CanWrite(); } + void Flush(double seconds) { AudioOutput_Flush(seconds); } + void Pause(int state) { AudioOutput_Pause(state); } + + /* called by the input plugin when no more output will be sent */ + void Done() { AudioOutput_Done(); } + /* called by the input plugin when playback was forcefully stopped */ + void Stop() { AudioOutput_Stop(); } + + /* returns the latency in seconds (how many seconds until samples you're about to write show up at the audio output */ + double Latency() { return AudioOutput_Latency(); } + + /* only valid after a call to Done(). Returns NErr_True if there is still data in the buffer, NErr_False otherwise */ + int Playing() { return AudioOutput_Playing(); } + +protected: + virtual int WASABICALL AudioOutput_Output(const void *data, size_t data_size)=0; + virtual size_t WASABICALL AudioOutput_CanWrite()=0; // returns number of bytes that you can write + virtual void WASABICALL AudioOutput_Flush(double seconds)=0; + virtual void WASABICALL AudioOutput_Pause(int state)=0; + + /* called by the input plugin when no more output will be sent */ + virtual void WASABICALL AudioOutput_Done()=0; + /* called by the input plugin when playback was forcefully stopped */ + virtual void WASABICALL AudioOutput_Stop()=0; + virtual double WASABICALL AudioOutput_Latency()=0; + virtual int WASABICALL AudioOutput_Playing()=0; + enum + { + DISPATCHABLE_VERSION, + }; +}; diff --git a/Src/replicant/audio/ifc_equalizer.h b/Src/replicant/audio/ifc_equalizer.h new file mode 100644 index 00000000..aabe4822 --- /dev/null +++ b/Src/replicant/audio/ifc_equalizer.h @@ -0,0 +1,27 @@ +#pragma once +#include "foundation/dispatch.h" + +class ifc_equalizer : public Wasabi2::Dispatchable +{ +protected: + ifc_equalizer() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_equalizer() {} + +public: + + int SetPreamp(double dB) { return Equalizer_SetPreamp(dB); } + int SetBand(unsigned int band, double dB) { return Equalizer_SetBand(band, dB); } + int Enable() { return Equalizer_Enable(); } + int Disable() { return Equalizer_Disable(); } +private: + virtual int WASABICALL Equalizer_SetPreamp(double dB)=0; + virtual int WASABICALL Equalizer_SetBand(unsigned int band, double dB)=0; + virtual int WASABICALL Equalizer_Enable()=0; + virtual int WASABICALL Equalizer_Disable()=0; + + enum + { + DISPATCHABLE_VERSION, + }; + +}; diff --git a/Src/replicant/audio/parameters.h b/Src/replicant/audio/parameters.h new file mode 100644 index 00000000..0e3cad17 --- /dev/null +++ b/Src/replicant/audio/parameters.h @@ -0,0 +1,47 @@ +#pragma once +#include "foundation/types.h" +#include "foundation/guid.h" + + +namespace nsaudio +{ + enum + { + /* when this is set, the const void * passed to AudioOutput_Output is assumed to be an array of channels, + e.g. (format_type == nsaudio_type_float && (format_flags & FORMAT_FLAG_NONINTERLEAVED) && number_of_channels == 2) + means that you pass a float *[2] to AudioOutput_Output + */ + FORMAT_FLAG_INTERLEAVED=0x1, + FORMAT_FLAG_NONINTERLEAVED=0x2, + FORMAT_FLAG_NATIVE_ENDIAN=0x4, + FORMAT_FLAG_LITTLE_ENDIAN=0x8, /* audio is SPECIFICALLY little endian (as opposed to native endian on little-endian machines) */ + FORMAT_FLAG_BIG_ENDIAN=0x10, /* audio is SPECIFICALLY big endian (as opposed to native endian on big-endian machines) */ + FORMAT_FLAG_SIGNED=0x20, /* e.g. 8 bit PCM is typically unsigned (0-255) */ + FORMAT_FLAG_UNSIGNED=0x40, /* e.g. 8 bit PCM is typically unsigned (0-255) */ + + /* so that you can check if a flag was set that you don't understand */ + FORMAT_FLAG_VALID_INTERLEAVE = FORMAT_FLAG_INTERLEAVED|FORMAT_FLAG_NONINTERLEAVED, + FORMAT_FLAG_VALID_ENDIAN = FORMAT_FLAG_NATIVE_ENDIAN|FORMAT_FLAG_LITTLE_ENDIAN|FORMAT_FLAG_BIG_ENDIAN, + FORMAT_FLAG_VALID_SIGNED=FORMAT_FLAG_SIGNED|FORMAT_FLAG_UNSIGNED, + FORMAT_FLAG_VALID_MASK=FORMAT_FLAG_VALID_INTERLEAVE|FORMAT_FLAG_VALID_ENDIAN|FORMAT_FLAG_VALID_SIGNED, + }; + + // {4B80932C-E55F-4969-91EA-772584ABEDC2} + static const GUID format_type_pcm = + { 0x4b80932c, 0xe55f, 0x4969, { 0x91, 0xea, 0x77, 0x25, 0x84, 0xab, 0xed, 0xc2 } }; + + // {6D47717F-A383-4CF8-BB1E-72254BE3F9DC} + static const GUID format_type_float = + { 0x6d47717f, 0xa383, 0x4cf8, { 0xbb, 0x1e, 0x72, 0x25, 0x4b, 0xe3, 0xf9, 0xdc } }; + + struct Parameters + { + double sample_rate; + GUID format_type; // PCM, floating point, SPDIF pass-thru, etc. + unsigned int format_flags; // endian, interleaved, signed + unsigned int bytes_per_sample; // e.g. 4 for 20bit in a 32bit container + unsigned int bits_per_sample; // number of valid bits within the sample + unsigned int number_of_channels; + unsigned int channel_layout; + }; +}; diff --git a/Src/replicant/audio/types.h b/Src/replicant/audio/types.h new file mode 100644 index 00000000..62a07104 --- /dev/null +++ b/Src/replicant/audio/types.h @@ -0,0 +1,44 @@ +#pragma once +#include "foundation/types.h" + +enum Agave_PositionType +{ + AGAVE_PLAYPOSITION_100NANOECONDS = 0, + AGAVE_PLAYPOSITION_MILLISECONDS = 1, + AGAVE_PLAYPOSITION_SECONDS = 2, + AGAVE_PLAYPOSITION_HMSF= 3, + AGAVE_PLAYPOSITION_SAMPLE_FRAMES = 4, + AGAVE_PLAYPOSITION_BYTES = 5, + AGAVE_PLAYPOSITION_PACKETS = 6, +}; + +struct Agave_HMSF +{ + uint8_t hours; + uint8_t minutes; + uint8_t seconds; + uint8_t frames; +}; + +union Agave_Position +{ + uint64_t nanoseconds100; // in increments of 100 nanoseconds (microsoft style) + uint64_t milliseconds; + double seconds; + Agave_HMSF hmsf; + uint64_t sample_frames; + uint64_t bytes; + uint64_t packets; +}; + +struct Agave_Seek +{ + Agave_PositionType position_type; + Agave_Position position; +}; + +static void Agave_Seek_SetBytes(Agave_Seek *seek, uint64_t bytes) +{ + seek->position_type=AGAVE_PLAYPOSITION_BYTES; + seek->position.bytes = bytes; +} |