xref: /haiku/src/apps/cortex/addons/Flanger/FlangerNode.h (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
1 // FlangerNode.h
2 // * PURPOSE
3 // - implements a basic audio filter
4 // - eventually abstract -> 'SimpleAudioFilter'?
5 //
6 //
7 // * HISTORY
8 //   e.moon		15jun99		Begun
9 
10 #ifndef __FlangerNode_H__
11 #define __FlangerNode_H__
12 
13 #include <BufferProducer.h>
14 #include <BufferConsumer.h>
15 #include <Controllable.h>
16 #include <MediaEventLooper.h>
17 
18 // forwards
19 class BBufferGroup;
20 class BMediaAddOn;
21 
22 class AudioBuffer;
23 
24 class FlangerNode :
25 	public		BBufferConsumer,
26 	public		BBufferProducer,
27 	public		BControllable,
28 	public		BMediaEventLooper {
29 
30 public:					// *** ctor/dtor
31 	virtual ~FlangerNode();
32 	FlangerNode(BMediaAddOn* pAddOn=0);
33 
34 public:					// *** BMediaNode
35 
36 	virtual status_t HandleMessage(
37 		int32 code,
38 		const void* pData,
39 		size_t size);
40 
41 	virtual BMediaAddOn* AddOn(
42 		int32* poID) const;
43 
44 	virtual void SetRunMode(
45 		run_mode mode);
46 
47 protected:				// *** BMediaEventLooper
48 
49 	virtual void HandleEvent(
50 		const media_timed_event* pEvent,
51 		bigtime_t howLate,
52 		bool realTimeEvent=false);
53 
54 protected:
55 	// "The Media Server calls this hook function after the node has
56 	//  been registered.  This is derived from BMediaNode; BMediaEventLooper
57 	//  implements it to call Run() automatically when the node is registered;
58 	//  if you implement NodeRegistered() you should call through to
59 	//  BMediaEventLooper::NodeRegistered() after you've done your custom
60 	//  operations."
61 
62 	virtual void NodeRegistered();
63 
64 	// "Augment OfflineTime() to compute the node's current time; it's called
65 	//  by the Media Kit when it's in offline mode. Update any appropriate
66 	//  internal information as well, then call through to the BMediaEventLooper
67 	//  implementation."
68 
69 	virtual bigtime_t OfflineTime(); //nyi
70 
71 public:					// *** BBufferConsumer
72 
73 	virtual status_t AcceptFormat(
74 		const media_destination& destination,
75 		media_format* pioFormat);
76 
77 	// "If you're writing a node, and receive a buffer with the B_SMALL_BUFFER
78 	//  flag set, you must recycle the buffer before returning."
79 
80 	virtual void BufferReceived(
81 		BBuffer* pBuffer);
82 
83 	// * make sure to fill in poInput->format with the contents of
84 	//   pFormat; as of R4.5 the Media Kit passes poInput->format to
85 	//   the producer in BBufferProducer::Connect().
86 
87 	virtual status_t Connected(
88 		const media_source& source,
89 		const media_destination& destination,
90 		const media_format& format,
91 		media_input* poInput);
92 
93 	virtual void Disconnected(
94 		const media_source& source,
95 		const media_destination& destination);
96 
97 	virtual void DisposeInputCookie(
98 		int32 cookie);
99 
100 	// "You should implement this function so your node will know that the data
101 	//  format is going to change. Note that this may be called in response to
102 	//  your AcceptFormat() call, if your AcceptFormat() call alters any wildcard
103 	//  fields in the specified format.
104 	//
105 	//  Because FormatChanged() is called by the producer, you don't need to (and
106 	//  shouldn't) ask it if the new format is acceptable.
107 	//
108 	//  If the format change isn't possible, return an appropriate error from
109 	//  FormatChanged(); this error will be passed back to the producer that
110 	//  initiated the new format negotiation in the first place."
111 
112 	virtual status_t FormatChanged(
113 		const media_source& source,
114 		const media_destination& destination,
115 		int32 changeTag,
116 		const media_format& newFormat);
117 
118 	virtual status_t GetLatencyFor(
119 		const media_destination& destination,
120 		bigtime_t* poLatency,
121 		media_node_id* poTimeSource);
122 
123 	virtual status_t GetNextInput(
124 		int32* pioCookie,
125 		media_input* poInput);
126 
127 	virtual void ProducerDataStatus(
128 		const media_destination& destination,
129 		int32 status,
130 		bigtime_t tpWhen);
131 
132 	// "This function is provided to aid in supporting media formats in which the
133 	//  outer encapsulation layer doesn't supply timing information. Producers will
134 	//  tag the buffers they generate with seek tags; these tags can be used to
135 	//  locate key frames in the media data."
136 
137 	virtual status_t SeekTagRequested(
138 		const media_destination& destination,
139 		bigtime_t targetTime,
140 		uint32 flags,
141 		media_seek_tag* poSeekTag,
142 		bigtime_t* poTaggedTime,
143 		uint32* poFlags);
144 
145 public:					// *** BBufferProducer
146 
147 	// "When a consumer calls BBufferConsumer::RequestAdditionalBuffer(), this
148 	//  function is called as a result. Its job is to call SendBuffer() to
149 	//  immediately send the next buffer to the consumer. The previousBufferID,
150 	//  previousTime, and previousTag arguments identify the last buffer the
151 	//  consumer received. Your node should respond by sending the next buffer
152 	//  after the one described.
153 	//
154 	//  The previousTag may be NULL.
155 	//  Return B_OK if all is well; otherwise return an appropriate error code."
156 	virtual void AdditionalBufferRequested(
157 		const media_source& source,
158 		media_buffer_id previousBufferID,
159 		bigtime_t previousTime,
160 		const media_seek_tag* pPreviousTag); //nyi
161 
162 	virtual void Connect(
163 		status_t status,
164 		const media_source& source,
165 		const media_destination& destination,
166 		const media_format& format,
167 		char* pioName); //nyi
168 
169 	virtual void Disconnect(
170 		const media_source& source,
171 		const media_destination& destination); //nyi
172 
173 	virtual status_t DisposeOutputCookie(
174 		int32 cookie); //nyi
175 
176 	virtual void EnableOutput(
177 		const media_source& source,
178 		bool enabled,
179 		int32* _deprecated_); //nyi
180 
181 	virtual status_t FormatChangeRequested(
182 		const media_source& source,
183 		const media_destination& destination,
184 		media_format* pioFormat,
185 		int32* _deprecated_); //nyi
186 
187 	virtual status_t FormatProposal(
188 		const media_source& source,
189 		media_format* pioFormat); //nyi
190 
191 	virtual status_t FormatSuggestionRequested(
192 		media_type type,
193 		int32 quality,
194 		media_format* poFormat); //nyi
195 
196 	virtual status_t GetLatency(
197 		bigtime_t* poLatency); //nyi
198 
199 	virtual status_t GetNextOutput(
200 		int32* pioCookie,
201 		media_output* poOutput); //nyi
202 
203 	// "This hook function is called when a BBufferConsumer that's receiving data
204 	//  from you determines that its latency has changed. It will call its
205 	//  BBufferConsumer::SendLatencyChange() function, and in response, the Media
206 	//  Server will call your LatencyChanged() function.  The source argument
207 	//  indicates your output that's involved in the connection, and destination
208 	//  specifies the input on the consumer to which the connection is linked.
209 	//  newLatency is the consumer's new latency. The flags are currently unused."
210 	virtual void LatencyChanged(
211 		const media_source& source,
212 		const media_destination& destination,
213 		bigtime_t newLatency,
214 		uint32 flags); //nyi
215 
216 	virtual void LateNoticeReceived(
217 		const media_source& source,
218 		bigtime_t howLate,
219 		bigtime_t tpWhen); //nyi
220 
221 	// PrepareToConnect() is the second stage of format negotiations that happens
222 	// inside BMediaRoster::Connect().  At this point, the consumer's AcceptFormat()
223 	// method has been called, and that node has potentially changed the proposed
224 	// format.  It may also have left wildcards in the format.  PrepareToConnect()
225 	// *must* fully specialize the format before returning!
226 
227 	virtual status_t PrepareToConnect(
228 		const media_source& source,
229 		const media_destination& destination,
230 		media_format* pioFormat,
231 		media_source* poSource,
232 		char* poName); //nyi
233 
234 	virtual status_t SetBufferGroup(
235 		const media_source& source,
236 		BBufferGroup* pGroup); //nyi
237 
238 	virtual status_t SetPlayRate(
239 		int32 numerator,
240 		int32 denominator); //nyi
241 
242 	virtual status_t VideoClippingChanged(
243 		const media_source& source,
244 		int16 numShorts,
245 		int16* pClipData,
246 		const media_video_display_info& display,
247 		int32* poFromChangeTag); //nyi
248 
249 public:					// *** BControllable
250 
251 	virtual status_t GetParameterValue(
252 		int32 id,
253 		bigtime_t* poLastChangeTime,
254 		void* poValue,
255 		size_t* pioSize); //nyi
256 
257 	virtual void SetParameterValue(
258 		int32 id,
259 		bigtime_t changeTime,
260 		const void* pValue,
261 		size_t size); //nyi
262 
263 
264 protected:				// HandleEvent() impl.
265 	void handleParameterEvent(
266 		const media_timed_event* pEvent);
267 
268 	void handleStartEvent(
269 		const media_timed_event* pEvent);
270 
271 	void handleStopEvent(
272 		const media_timed_event* pEvent);
273 
274 	void ignoreEvent(
275 		const media_timed_event* pEvent);
276 
277 protected:				// *** internal operations
278 
279 	// figure the preferred format: any fields left as wildcards
280 	// are negotiable
281 	virtual void getPreferredFormat(
282 		media_format& ioFormat);
283 
284 	// test the given template format against a proposed format.
285 	// specialize wildcards for fields where the template contains
286 	// non-wildcard data; write required fields into proposed format
287 	// if they mismatch.
288 	// Returns B_OK if the proposed format doesn't conflict with the
289 	// template, or B_MEDIA_BAD_FORMAT otherwise.
290 
291 	status_t validateProposedFormat(
292 		const media_format& preferredFormat,
293 		media_format& ioProposedFormat);
294 
295 	// fill in wildcards in the given format.
296 	// (assumes the format passes validateProposedFormat().)
297 	void specializeOutputFormat(
298 		media_format& ioFormat);
299 
300 	// set parameters to their default settings
301 	virtual void initParameterValues();
302 
303 	// create and register a parameter web
304 	virtual void initParameterWeb();
305 
306 	// construct delay line if necessary, reset filter state
307 	virtual void initFilter();
308 
309 	virtual void startFilter();
310 	virtual void stopFilter();
311 
312 	// figure processing latency by doing 'dry runs' of filterBuffer()
313 	virtual bigtime_t calcProcessingLatency();
314 
315 	// filter buffer data in place
316 	virtual void filterBuffer(
317 		BBuffer* pBuffer); //nyi
318 
319 private:					// *** connection/format members
320 
321 	// The 'template' format
322 	// +++++ init in NodeRegistered()
323 	media_format			m_preferredFormat;
324 
325 	// The current input/output format (this filter doesn't do any
326 	// on-the-fly conversion.)  Any fields that are not wildcards
327 	// are mandatory; the first connection (input or output) decides
328 	// the node's format.  If both input and output are disconnected,
329 	// m_format.u.raw_audio should revert to media_raw_audio_format::wildcard.
330 	media_format			m_format;
331 
332 	// Connections & associated state variables
333 	media_input				m_input;
334 
335 	media_output			m_output;
336 	bool								m_outputEnabled;
337 
338 // [16jun99] buffers are generated by the upstream producer; this
339 //           node processes them in-place and forwards them downstream.
340 //
341 //	// The outbound buffer group
342 //	BBufferGroup*			m_pBufferGroup;
343 
344 	// Time required by downstream consumer(s) to properly deliver a buffer
345 	bigtime_t					m_downstreamLatency;
346 
347 	// Worst-case time needed to fill a buffer
348 	bigtime_t					m_processingLatency;
349 
350 private:					// *** filter state
351 
352 	// Frames sent since the filter started
353 	uint64						m_framesSent;
354 
355 	// the buffer
356 	AudioBuffer*			m_pDelayBuffer;
357 
358 	// write position (buffer offset at which the next
359 	// incoming frame will be stored)
360 	uint32						m_delayWriteFrame;
361 
362 	// radial counter (for sweep 'LFO')
363 	float							m_fTheta;
364 	float							m_fThetaInc;
365 
366 	// sweep LFO state
367 	float							m_fSweepBase;
368 	float							m_fSweepFactor;
369 
370 //	// position (relative to m_delayWriteFrame) from which
371 //	// delayed frames are read.  varies between -m_fSweepMax and
372 //	// -m_fSweepMin.
373 //	float							m_fDelayReadOffset;
374 //
375 //	// rate at which m_fDelayReadOffset currently varies.
376 //	// [16jun99: a triangle-shaped sweep for now]
377 //	float							m_fDelayReadDelta;
378 
379 	// maximum delay (buffer length) in milliseconds
380 	static const float			s_fMaxDelay;
381 
382 private:					// *** filter parameter data
383 
384 	// ratio of dry-to-processed signal
385 	float							m_fMixRatio;
386 	bigtime_t					m_tpMixRatioChanged;
387 
388 	// rate of sweep (Hz)
389 	float							m_fSweepRate;
390 	bigtime_t					m_tpSweepRateChanged;
391 
392 	// minimum delay (low bound of sweep) (ms)
393 	float							m_fDelay;
394 	bigtime_t					m_tpDelayChanged;
395 
396 	// range of sweep (ms)
397 	float							m_fDepth;
398 	bigtime_t					m_tpDepthChanged;
399 
400 	// feedback (0.0 - 1.0)
401 	float							m_fFeedback;
402 	bigtime_t					m_tpFeedbackChanged;
403 
404 private:					// *** add-on stuff
405 
406 	// host add-on
407 	BMediaAddOn*	m_pAddOn;
408 
409 	static const char* const		s_nodeName;
410 };
411 
412 #endif /*__FlangerNode_H__*/
413