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