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