foobar2000 SDK  2015-08-03
output.h
Go to the documentation of this file.
1 #ifndef _FOOBAR2000_SDK_OUTPUT_H_
2 #define _FOOBAR2000_SDK_OUTPUT_H_
3 
5 PFC_DECLARE_EXCEPTION(exception_output_module_not_found, exception_output_device_not_found, "Output module not found")
6 
7 
8 // =======================================================
9 // IDEA BIN
10 // ========
11 // Accurate timing info required! get_latency NOT safe to call from any thread while it should be
12 // There should be a legitimate way ( as in other than matching get_latency() against the amount of sent data ) to know when the output has finished prebuffering and started actual playback
13 // Outputs should be able to handle idling : idle(abort_callback&) => while(!update()) aborter.sleep(); or optimized for specific output
14 // =======================================================
15 
17 struct t_pcmspec
18 {
19  inline t_pcmspec() {reset();}
20  inline t_pcmspec(const t_pcmspec & p_source) {*this = p_source;}
21  unsigned m_sample_rate;
23  unsigned m_channels,m_channel_config;
24  bool m_float;
25 
26  inline unsigned align() const {return (m_bits_per_sample / 8) * m_channels;}
27 
28  t_size time_to_bytes(double p_time) const {return (t_size)audio_math::time_to_samples(p_time,m_sample_rate) * (m_bits_per_sample / 8) * m_channels;}
29  double bytes_to_time(t_size p_bytes) const {return (double) (p_bytes / ((m_bits_per_sample / 8) * m_channels)) / (double) m_sample_rate;}
30 
31  inline bool operator==(/*const t_pcmspec & p_spec1,*/const t_pcmspec & p_spec2) const
32  {
33  return /*p_spec1.*/m_sample_rate == p_spec2.m_sample_rate
34  && /*p_spec1.*/m_bits_per_sample == p_spec2.m_bits_per_sample
35  && /*p_spec1.*/m_channels == p_spec2.m_channels
36  && /*p_spec1.*/m_channel_config == p_spec2.m_channel_config
37  && /*p_spec1.*/m_float == p_spec2.m_float;
38  }
39 
40  inline bool operator!=(/*const t_pcmspec & p_spec1,*/const t_pcmspec & p_spec2) const
41  {
42  return !(*this == p_spec2);
43  }
44 
45  inline void reset() {m_sample_rate = 0; m_bits_per_sample = 0; m_channels = 0; m_channel_config = 0; m_float = false;}
46  inline bool is_valid() const
47  {
48  return m_sample_rate >= 1000 && m_sample_rate <= 1000000 &&
49  m_channels > 0 && m_channels <= 256 && m_channel_config != 0 &&
50  (m_bits_per_sample == 8 || m_bits_per_sample == 16 || m_bits_per_sample == 24 || m_bits_per_sample == 32);
51  }
52 };
53 
54 struct t_samplespec {
57 
58  t_size time_to_samples(double p_time) const {PFC_ASSERT(is_valid());return (t_size)audio_math::time_to_samples(p_time,m_sample_rate);}
59  double samples_to_time(t_size p_samples) const {PFC_ASSERT(is_valid()); return audio_math::samples_to_time(p_samples,m_sample_rate);}
60 
61  inline t_samplespec() {reset();}
62  inline t_samplespec(audio_chunk const & in) {fromchunk(in);}
63 
64  inline void reset() {m_sample_rate = 0; m_channels = 0; m_channel_config = 0;}
65 
66  inline bool operator==(const t_samplespec & p_spec2) const {
67  return m_sample_rate == p_spec2.m_sample_rate && m_channels == p_spec2.m_channels && m_channel_config == p_spec2.m_channel_config;
68  }
69 
70  inline bool operator!=(const t_samplespec & p_spec2) const {
71  return !(*this == p_spec2);
72  }
73 
74  inline bool is_valid() const {
75  return m_sample_rate > 0 && m_channels > 0 && audio_chunk::g_count_channels(m_channel_config) == m_channels;
76  }
77 
78  static t_samplespec g_fromchunk(const audio_chunk & p_chunk) {
79  t_samplespec temp; temp.fromchunk(p_chunk); return temp;
80  }
81 
82  void fromchunk(const audio_chunk & p_chunk) {
83  m_sample_rate = p_chunk.get_sample_rate();
84  m_channels = p_chunk.get_channels();
85  m_channel_config = p_chunk.get_channel_config();
86  }
87 };
88 
90 {
91 public:
92  virtual void on_device(const GUID & p_guid,const char * p_name,unsigned p_name_length) = 0;
93 };
94 
95 class NOVTABLE output : public service_base {
96  FB2K_MAKE_SERVICE_INTERFACE(output,service_base);
97 public:
99  virtual double get_latency() = 0;
101  virtual void process_samples(const audio_chunk & p_chunk) = 0;
104  virtual void update(bool & p_ready) = 0;
106  virtual void pause(bool p_state) = 0;
108  virtual void flush() = 0;
110  virtual void force_play() = 0;
111 
114  virtual void volume_set(double p_val) = 0;
115 
116 };
117 
118 class NOVTABLE output_v2 : public output {
119  FB2K_MAKE_SERVICE_INTERFACE(output_v2, output);
120 public:
121  virtual bool want_track_marks() {return false;}
122  virtual void on_track_mark() {}
123  virtual void enable_fading(bool state) {}
124  virtual void flush_changing_track() {flush();}
125 };
126 
127 class NOVTABLE output_entry : public service_base {
128  FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(output_entry);
129 public:
131  virtual void instantiate(service_ptr_t<output> & p_out,const GUID & p_device,double p_buffer_length,bool p_dither,t_uint32 p_bitdepth) = 0;
133  virtual void enum_devices(output_device_enum_callback & p_callback) = 0;
135  virtual GUID get_guid() = 0;
137  virtual const char * get_name() = 0;
138 
142  virtual void advanced_settings_popup(HWND p_parent,POINT p_menupoint) = 0;
143 
144  enum {
145  flag_needs_bitdepth_config = 1 << 0,
146  flag_needs_dither_config = 1 << 1,
147  flag_needs_advanced_config = 1 << 2,
148  flag_needs_device_list_prefixes = 1 << 3,
149  };
150 
151  virtual t_uint32 get_config_flags() = 0;
152 
153  pfc::string8 get_device_name( const GUID & deviceID);
154  bool get_device_name( const GUID & deviceID, pfc::string_base & out );
155 
156  static bool g_find( const GUID & outputID, output_entry::ptr & outObj );
157  static output_entry::ptr g_find(const GUID & outputID );
158 };
159 
161 template<typename T, typename E = output_entry>
162 class output_entry_impl_t : public E
163 {
164 public:
165  void instantiate(service_ptr_t<output> & p_out,const GUID & p_device,double p_buffer_length,bool p_dither,t_uint32 p_bitdepth) {
166  p_out = new service_impl_t<T>(p_device,p_buffer_length,p_dither,p_bitdepth);
167  }
168  void enum_devices(output_device_enum_callback & p_callback) {T::g_enum_devices(p_callback);}
169  GUID get_guid() {return T::g_get_guid();}
170  const char * get_name() {return T::g_get_name();}
171  void advanced_settings_popup(HWND p_parent,POINT p_menupoint) {T::g_advanced_settings_popup(p_parent,p_menupoint);}
172 
174  t_uint32 flags = 0;
175  if (T::g_advanced_settings_query()) flags |= output_entry::flag_needs_advanced_config;
176  if (T::g_needs_bitdepth_config()) flags |= output_entry::flag_needs_bitdepth_config;
177  if (T::g_needs_dither_config()) flags |= output_entry::flag_needs_dither_config;
178  if (T::g_needs_device_list_prefixes()) flags |= output_entry::flag_needs_device_list_prefixes ;
179  return flags;
180  }
181 };
182 
183 
185 template<class T>
186 class output_factory_t : public service_factory_single_t<output_entry_impl_t<T> > {};
187 
188 class output_impl : public output_v2 {
189 protected:
190  output_impl() : m_incoming_ptr(0) {}
191  virtual void on_update() = 0;
193  virtual void write(const audio_chunk & p_data) = 0;
194  virtual t_size can_write_samples() = 0;
195  virtual t_size get_latency_samples() = 0;
196  virtual void on_flush() = 0;
197  virtual void on_flush_changing_track() {on_flush();}
198  virtual void open(t_samplespec const & p_spec) = 0;
199 
200  virtual void pause(bool p_state) = 0;
201  virtual void force_play() = 0;
202  virtual void volume_set(double p_val) = 0;
203 protected:
204  void on_need_reopen() {m_active_spec = t_samplespec();}
205 private:
206  void flush();
207  void flush_changing_track();
208  void update(bool & p_ready);
209  double get_latency();
210  void process_samples(const audio_chunk & p_chunk);
211 
215 };
216 
217 
218 class NOVTABLE volume_callback {
219 public:
220  virtual void on_volume_scale(float v) = 0;
221  virtual void on_volume_arbitrary(int v) = 0;
222 };
223 
224 class NOVTABLE volume_control : public service_base {
225  FB2K_MAKE_SERVICE_INTERFACE(volume_control, service_base)
226 public:
227  virtual void add_callback(volume_callback * ptr) = 0;
228  virtual void remove_callback(volume_callback * ptr) = 0;
229 
230  enum style_t {
232  styleArbitrary
233  };
234 
235  virtual style_t getStyle() = 0;
236 
237  virtual float scaleGet() = 0;
238  virtual void scaleSet(float v) = 0;
239 
240  virtual void arbitrarySet(int val) = 0;
241  virtual int arbitraryGet() = 0;
242  virtual int arbitraryGetMin() = 0;
243  virtual int arbitraryGetMax() = 0;
244  virtual bool arbitraryGetMute() = 0;
245  virtual void arbitrarySetMute(bool val) = 0;
246 };
247 
248 
249 class NOVTABLE output_entry_v2 : public output_entry {
250  FB2K_MAKE_SERVICE_INTERFACE(output_entry_v2, output_entry)
251 public:
252  virtual bool get_volume_control(const GUID & id, volume_control::ptr & out) = 0;
253  virtual bool hasVisualisation() = 0;
254 };
255 
256 #pragma pack(push, 1)
257 struct outputCoreConfig_t {
259 
260  static outputCoreConfig_t defaults();
261 
265  uint32_t m_flags;
266  uint32_t m_bitDepth;
267  enum { flagUseDither = 1 << 0 };
268 };
269 #pragma pack(pop)
270 
273 class NOVTABLE output_manager : public service_base {
274  FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(output_manager);
275 public:
279  virtual output::ptr instantiateCoreDefault(double overrideBufferLength = 0) = 0;
280  virtual void getCoreConfig( void * out, size_t outSize ) = 0;
281 
282  void getCoreConfig(outputCoreConfig_t & out ) { getCoreConfig(&out, sizeof(out) ); }
283 };
284 
285 
286 extern const GUID output_id_null;
287 extern const GUID output_id_default;
288 
289 #endif //_FOOBAR2000_SDK_OUTPUT_H_
t_size m_incoming_ptr
Definition: output.h:213
bool operator==(const t_samplespec &p_spec2) const
Definition: output.h:66
bool is_valid() const
Definition: output.h:74
Template implementing reference-counting features of service_base. Intended for dynamic instantiation...
Definition: service_impl.h:4
bool m_float
Definition: output.h:24
t_samplespec m_incoming_spec
Definition: output.h:214
double bytes_to_time(t_size p_bytes) const
Definition: output.h:29
Definition: pfc.h:71
t_uint32 m_channels
Definition: output.h:56
t_size time_to_bytes(double p_time) const
Definition: output.h:28
unsigned get_sample_rate() const
Helper, same as get_srate().
Definition: audio_chunk.h:103
Interface to container of a chunk of audio data. See audio_chunk_impl for an implementation.
Definition: audio_chunk.h:5
void reset()
Definition: output.h:64
void enum_devices(output_device_enum_callback &p_callback)
Definition: output.h:168
Definition: output.h:147
unsigned m_sample_rate
Definition: output.h:21
exception_output_device_not_found
Definition: output.h:5
virtual unsigned get_channels() const =0
Retrieves channel count of contained audio data.
bool operator!=(const t_samplespec &p_spec2) const
Definition: output.h:70
unsigned m_channels
Definition: output.h:23
t_samplespec()
Definition: output.h:61
void fromchunk(const audio_chunk &p_chunk)
Definition: output.h:82
unsigned m_bits_per_sample
Definition: output.h:22
void advanced_settings_popup(HWND p_parent, POINT p_menupoint)
Definition: output.h:171
t_size time_to_samples(double p_time) const
Definition: output.h:58
t_pcmspec()
Definition: output.h:19
const char * get_name()
Definition: output.h:170
t_uint32 m_sample_rate
Definition: output.h:55
virtual unsigned get_channel_config() const =0
Retrieves channel map of contained audio data. Conditions where number of channels specified by chann...
virtual void enable_fading(bool state)
Definition: output.h:123
Structure describing PCM audio data format, with basic helper functions.
Definition: output.h:17
static unsigned g_count_channels(unsigned p_config)
Counts channels specified by channel map.
size_t t_size
Definition: int_types.h:48
double m_buffer_length
Definition: output.h:264
Use this to register your output implementation.
Definition: output.h:186
Helper; implements output_entry for specific output class implementation. output_entry methods are fo...
Definition: output.h:162
void instantiate(service_ptr_t< output > &p_out, const GUID &p_device, double p_buffer_length, bool p_dither, t_uint32 p_bitdepth)
Definition: output.h:165
GUID get_guid()
Definition: output.h:169
t_uint32 m_channel_config
Definition: output.h:56
Base class for all service classes. Provides interfaces for reference counter and querying for differ...
Definition: service.h:333
Definition: output.h:148
bool operator==(const t_pcmspec &p_spec2) const
Definition: output.h:31
void write(const service_ptr_t< file > &p_file, abort_callback &p_abort, const char *p_string, bool is_utf8)
uint32_t m_bitDepth
Definition: output.h:266
unsigned align() const
Definition: output.h:26
PFC_DECLARE_EXCEPTION(exception_output_device_not_found, pfc::exception,"Audio device not found") PFC_DECLARE_EXCEPTION(exception_output_module_not_found
static t_samplespec g_fromchunk(const audio_chunk &p_chunk)
Definition: output.h:78
virtual void on_track_mark()
Definition: output.h:122
void on_need_reopen()
Definition: output.h:204
bool is_valid() const
Definition: output.h:46
const GUID output_id_null
Definition: output.cpp:105
const GUID output_id_default
Definition: output.cpp:109
void getCoreConfig(outputCoreConfig_t &out)
Definition: output.h:282
std::exception exception
Definition: primitives.h:193
unsigned m_channel_config
Definition: output.h:23
Definition: output.h:146
Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes.
Definition: service.h:55
void reset()
Definition: output.h:45
Definition: output.h:127
virtual bool want_track_marks()
Definition: output.h:121
virtual void on_flush_changing_track()
Definition: output.h:197
output_impl()
Definition: output.h:190
t_pcmspec(const t_pcmspec &p_source)
Definition: output.h:20
uint32_t m_flags
Definition: output.h:265
bool operator!=(const t_pcmspec &p_spec2) const
Definition: output.h:40
t_uint32 get_config_flags()
Definition: output.h:173
Definition: output.h:145
virtual void flush_changing_track()
Definition: output.h:124
uint32_t t_uint32
Definition: int_types.h:5
Definition: output.h:95
Definition: output.h:249
t_samplespec(audio_chunk const &in)
Definition: output.h:62
double samples_to_time(t_size p_samples) const
Definition: output.h:59
pfc::array_t< audio_sample, pfc::alloc_fast_aggressive > m_incoming
Definition: output.h:212