/* * Copyright (c) 1999-2000, Eric Moon. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions, and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // FlangerNode.h // * PURPOSE // - implements a basic audio filter // - eventually abstract -> 'SimpleAudioFilter'? // // // * HISTORY // e.moon 15jun99 Begun #ifndef __FlangerNode_H__ #define __FlangerNode_H__ #include #include #include #include // forwards class BBufferGroup; class BMediaAddOn; class AudioBuffer; class FlangerNode : public BBufferConsumer, public BBufferProducer, public BControllable, public BMediaEventLooper { public: // *** ctor/dtor virtual ~FlangerNode(); FlangerNode(BMediaAddOn* pAddOn=0); public: // *** BMediaNode virtual status_t HandleMessage( int32 code, const void* pData, size_t size); virtual BMediaAddOn* AddOn( int32* poID) const; virtual void SetRunMode( run_mode mode); protected: // *** BMediaEventLooper virtual void HandleEvent( const media_timed_event* pEvent, bigtime_t howLate, bool realTimeEvent=false); protected: // "The Media Server calls this hook function after the node has // been registered. This is derived from BMediaNode; BMediaEventLooper // implements it to call Run() automatically when the node is registered; // if you implement NodeRegistered() you should call through to // BMediaEventLooper::NodeRegistered() after you've done your custom // operations." virtual void NodeRegistered(); // "Augment OfflineTime() to compute the node's current time; it's called // by the Media Kit when it's in offline mode. Update any appropriate // internal information as well, then call through to the BMediaEventLooper // implementation." virtual bigtime_t OfflineTime(); //nyi public: // *** BBufferConsumer virtual status_t AcceptFormat( const media_destination& destination, media_format* pioFormat); // "If you're writing a node, and receive a buffer with the B_SMALL_BUFFER // flag set, you must recycle the buffer before returning." virtual void BufferReceived( BBuffer* pBuffer); // * make sure to fill in poInput->format with the contents of // pFormat; as of R4.5 the Media Kit passes poInput->format to // the producer in BBufferProducer::Connect(). virtual status_t Connected( const media_source& source, const media_destination& destination, const media_format& format, media_input* poInput); virtual void Disconnected( const media_source& source, const media_destination& destination); virtual void DisposeInputCookie( int32 cookie); // "You should implement this function so your node will know that the data // format is going to change. Note that this may be called in response to // your AcceptFormat() call, if your AcceptFormat() call alters any wildcard // fields in the specified format. // // Because FormatChanged() is called by the producer, you don't need to (and // shouldn't) ask it if the new format is acceptable. // // If the format change isn't possible, return an appropriate error from // FormatChanged(); this error will be passed back to the producer that // initiated the new format negotiation in the first place." virtual status_t FormatChanged( const media_source& source, const media_destination& destination, int32 changeTag, const media_format& newFormat); virtual status_t GetLatencyFor( const media_destination& destination, bigtime_t* poLatency, media_node_id* poTimeSource); virtual status_t GetNextInput( int32* pioCookie, media_input* poInput); virtual void ProducerDataStatus( const media_destination& destination, int32 status, bigtime_t tpWhen); // "This function is provided to aid in supporting media formats in which the // outer encapsulation layer doesn't supply timing information. Producers will // tag the buffers they generate with seek tags; these tags can be used to // locate key frames in the media data." virtual status_t SeekTagRequested( const media_destination& destination, bigtime_t targetTime, uint32 flags, media_seek_tag* poSeekTag, bigtime_t* poTaggedTime, uint32* poFlags); public: // *** BBufferProducer // "When a consumer calls BBufferConsumer::RequestAdditionalBuffer(), this // function is called as a result. Its job is to call SendBuffer() to // immediately send the next buffer to the consumer. The previousBufferID, // previousTime, and previousTag arguments identify the last buffer the // consumer received. Your node should respond by sending the next buffer // after the one described. // // The previousTag may be NULL. // Return B_OK if all is well; otherwise return an appropriate error code." virtual void AdditionalBufferRequested( const media_source& source, media_buffer_id previousBufferID, bigtime_t previousTime, const media_seek_tag* pPreviousTag); //nyi virtual void Connect( status_t status, const media_source& source, const media_destination& destination, const media_format& format, char* pioName); //nyi virtual void Disconnect( const media_source& source, const media_destination& destination); //nyi virtual status_t DisposeOutputCookie( int32 cookie); //nyi virtual void EnableOutput( const media_source& source, bool enabled, int32* _deprecated_); //nyi virtual status_t FormatChangeRequested( const media_source& source, const media_destination& destination, media_format* pioFormat, int32* _deprecated_); //nyi virtual status_t FormatProposal( const media_source& source, media_format* pioFormat); //nyi virtual status_t FormatSuggestionRequested( media_type type, int32 quality, media_format* poFormat); //nyi virtual status_t GetLatency( bigtime_t* poLatency); //nyi virtual status_t GetNextOutput( int32* pioCookie, media_output* poOutput); //nyi // "This hook function is called when a BBufferConsumer that's receiving data // from you determines that its latency has changed. It will call its // BBufferConsumer::SendLatencyChange() function, and in response, the Media // Server will call your LatencyChanged() function. The source argument // indicates your output that's involved in the connection, and destination // specifies the input on the consumer to which the connection is linked. // newLatency is the consumer's new latency. The flags are currently unused." virtual void LatencyChanged( const media_source& source, const media_destination& destination, bigtime_t newLatency, uint32 flags); //nyi virtual void LateNoticeReceived( const media_source& source, bigtime_t howLate, bigtime_t tpWhen); //nyi // PrepareToConnect() is the second stage of format negotiations that happens // inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat() // method has been called, and that node has potentially changed the proposed // format. It may also have left wildcards in the format. PrepareToConnect() // *must* fully specialize the format before returning! virtual status_t PrepareToConnect( const media_source& source, const media_destination& destination, media_format* pioFormat, media_source* poSource, char* poName); //nyi virtual status_t SetBufferGroup( const media_source& source, BBufferGroup* pGroup); //nyi virtual status_t SetPlayRate( int32 numerator, int32 denominator); //nyi virtual status_t VideoClippingChanged( const media_source& source, int16 numShorts, int16* pClipData, const media_video_display_info& display, int32* poFromChangeTag); //nyi public: // *** BControllable virtual status_t GetParameterValue( int32 id, bigtime_t* poLastChangeTime, void* poValue, size_t* pioSize); //nyi virtual void SetParameterValue( int32 id, bigtime_t changeTime, const void* pValue, size_t size); //nyi protected: // HandleEvent() impl. void handleParameterEvent( const media_timed_event* pEvent); void handleStartEvent( const media_timed_event* pEvent); void handleStopEvent( const media_timed_event* pEvent); void ignoreEvent( const media_timed_event* pEvent); protected: // *** internal operations // figure the preferred format: any fields left as wildcards // are negotiable virtual void getPreferredFormat( media_format& ioFormat); // test the given template format against a proposed format. // specialize wildcards for fields where the template contains // non-wildcard data; write required fields into proposed format // if they mismatch. // Returns B_OK if the proposed format doesn't conflict with the // template, or B_MEDIA_BAD_FORMAT otherwise. status_t validateProposedFormat( const media_format& preferredFormat, media_format& ioProposedFormat); // fill in wildcards in the given format. // (assumes the format passes validateProposedFormat().) void specializeOutputFormat( media_format& ioFormat); // set parameters to their default settings virtual void initParameterValues(); // create and register a parameter web virtual void initParameterWeb(); // construct delay line if necessary, reset filter state virtual void initFilter(); virtual void startFilter(); virtual void stopFilter(); // figure processing latency by doing 'dry runs' of filterBuffer() virtual bigtime_t calcProcessingLatency(); // filter buffer data in place virtual void filterBuffer( BBuffer* pBuffer); //nyi private: // *** connection/format members // The 'template' format // +++++ init in NodeRegistered() media_format m_preferredFormat; // The current input/output format (this filter doesn't do any // on-the-fly conversion.) Any fields that are not wildcards // are mandatory; the first connection (input or output) decides // the node's format. If both input and output are disconnected, // m_format.u.raw_audio should revert to media_raw_audio_format::wildcard. media_format m_format; // Connections & associated state variables media_input m_input; media_output m_output; bool m_outputEnabled; // [16jun99] buffers are generated by the upstream producer; this // node processes them in-place and forwards them downstream. // // // The outbound buffer group // BBufferGroup* m_pBufferGroup; // Time required by downstream consumer(s) to properly deliver a buffer bigtime_t m_downstreamLatency; // Worst-case time needed to fill a buffer bigtime_t m_processingLatency; private: // *** filter state // Frames sent since the filter started uint64 m_framesSent; // the buffer AudioBuffer* m_pDelayBuffer; // write position (buffer offset at which the next // incoming frame will be stored) uint32 m_delayWriteFrame; // radial counter (for sweep 'LFO') float m_fTheta; float m_fThetaInc; // sweep LFO state float m_fSweepBase; float m_fSweepFactor; // // position (relative to m_delayWriteFrame) from which // // delayed frames are read. varies between -m_fSweepMax and // // -m_fSweepMin. // float m_fDelayReadOffset; // // // rate at which m_fDelayReadOffset currently varies. // // [16jun99: a triangle-shaped sweep for now] // float m_fDelayReadDelta; // maximum delay (buffer length) in milliseconds static const float s_fMaxDelay; private: // *** filter parameter data // ratio of dry-to-processed signal float m_fMixRatio; bigtime_t m_tpMixRatioChanged; // rate of sweep (Hz) float m_fSweepRate; bigtime_t m_tpSweepRateChanged; // minimum delay (low bound of sweep) (ms) float m_fDelay; bigtime_t m_tpDelayChanged; // range of sweep (ms) float m_fDepth; bigtime_t m_tpDepthChanged; // feedback (0.0 - 1.0) float m_fFeedback; bigtime_t m_tpFeedbackChanged; private: // *** add-on stuff // host add-on BMediaAddOn* m_pAddOn; static const char* const s_nodeName; }; #endif /*__FlangerNode_H__*/