root/src/add-ons/media/media-add-ons/vst_host/VSTNode.cpp
/*
 * Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com.
 * All rights reserved.
 * Distributed under the terms of the MIT License.
 */ 

#include <ByteOrder.h>
#include <Buffer.h>
#include <BufferGroup.h>
#include <TimeSource.h>
#include <ParameterWeb.h>
#include <String.h>

#include <stdio.h>
#include <string.h>

#include "VSTNode.h"

//VSTNode
VSTNode::~VSTNode()
{
        Quit();
}

VSTNode::VSTNode(BMediaAddOn* addon, const char* name, const char* path)
                                :
                                BMediaNode(name),
                                BBufferConsumer(B_MEDIA_RAW_AUDIO),
                                BBufferProducer(B_MEDIA_RAW_AUDIO),
                                BControllable(),
                                BMediaEventLooper(),
                                fAddOn(addon),
                                fOutputMediaEnabled(true),
                                fDownstreamLatency(0),
                                fProcessLatency(0)
{
        fPlugin = new VSTPlugin();
        fPlugin->LoadModule(path);
}

//BMediaNode
BMediaAddOn* 
VSTNode::AddOn(int32* id) const 
{
        if(fAddOn)
                *id = 0;
        return fAddOn;
}

status_t 
VSTNode::HandleMessage(int32 message, const void* data, size_t size)
{
        if((BControllable::HandleMessage(message, data, size) != B_OK) &&
                (BBufferConsumer::HandleMessage(message, data, size) != B_OK) &&
                (BBufferProducer::HandleMessage(message, data, size) != B_OK) &&
                (BControllable::HandleMessage(message, data, size) != B_OK) ) {
                        BMediaNode::HandleMessage(message, data, size);
                return B_OK;
        }
        BMediaNode::HandleBadMessage(message, data, size);
        return B_ERROR;         
}

void
VSTNode::NodeRegistered()
{
        fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
        fPreferredFormat.u.raw_audio.buffer_size = BUFF_SIZE;
        fPreferredFormat.u.raw_audio = media_raw_audio_format::wildcard;
        fPreferredFormat.u.raw_audio.channel_count =
                media_raw_audio_format::wildcard.channel_count;
        fPreferredFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
                
        fFormat.type = B_MEDIA_RAW_AUDIO;
        fFormat.u.raw_audio = media_raw_audio_format::wildcard;
        
        fInputMedia.destination.port = ControlPort();
        fInputMedia.destination.id = ID_AUDIO_INPUT;
        fInputMedia.node = Node();
        fInputMedia.source = media_source::null;
        fInputMedia.format = fFormat;
        strncpy(fInputMedia.name, "Audio Input", B_MEDIA_NAME_LENGTH);

        fOutputMedia.source.port = ControlPort();
        fOutputMedia.source.id = ID_AUDIO_OUTPUT;
        fOutputMedia.node = Node();
        fOutputMedia.destination = media_destination::null;
        fOutputMedia.format = fFormat;
        strncpy(fOutputMedia.name, "Audio Output", B_MEDIA_NAME_LENGTH);

        InitParameterValues();
        InitParameterWeb();

        SetPriority(B_REAL_TIME_PRIORITY);
        Run();
}

//BControllable
status_t 
VSTNode::GetParameterValue(int32 id, bigtime_t* lastChangeTime, void* value,
        size_t *size)
{
        if (*size < sizeof(float) || *size < sizeof(int32))
                return B_NO_MEMORY;

        type_code v_type = B_FLOAT_TYPE;
        
        BParameter *param;      
        for(int i = 0; i < fWeb->CountParameters(); i++) {
                param = fWeb->ParameterAt(i);
                if(param->ID() == id) {
                        v_type = param->ValueType();
                        break;
                }
        }       

        *size = sizeof(float);

        if (id == P_MUTE) {
                *(int32*)value = fMute;
                *lastChangeTime = fMuteLastChanged;
                return B_OK;
        } else if (id == P_BYPASS) {
                *(int32*)value = fByPass;
                *lastChangeTime = fByPassLastChanged;
                return B_OK;
        } else {
                int32 idx = id - P_PARAM;
                if (idx >= 0 && idx < fPlugin->ParametersCount()) {
                        VSTParameter *param = fPlugin->Parameter(idx);

                        if (v_type == B_FLOAT_TYPE)
                                *(float*)value = param->Value();

                        if (v_type == B_INT32_TYPE)
                                *(int32*)value = (int32)ceil(param->Value());

                        *lastChangeTime = param->LastChangeTime();
                        return B_OK;
                }
        }               
        return B_ERROR;
}

void
VSTNode::SetParameterValue(int32 id, bigtime_t time, const void* value,
        size_t size)
{               
        int32 idx = id - P_PARAM;
        if ((idx >= 0 && idx < fPlugin->ParametersCount()) || id == P_MUTE ||
                id == P_BYPASS) {
                media_timed_event ev(time, BTimedEventQueue::B_PARAMETER, (void*)value,
                        BTimedEventQueue::B_NO_CLEANUP, size, id, "VSTParam");
                //dirty hack for parameter processing (mediakit bug????)
                ParameterEventProcessing(&ev);
                EventQueue()->AddEvent(ev);             
        }
}

//BBufferConsumer
void
VSTNode::BufferReceived(BBuffer* buffer)
{
        if (buffer->Header()->destination != fInputMedia.destination.id) {
                buffer->Recycle();
                return;
        }

        if (fOutputMedia.destination == media_destination::null ||
                !fOutputMediaEnabled) {
                buffer->Recycle();
                return;
        }

        FilterBuffer(buffer);

        status_t err = SendBuffer(buffer, fOutputMedia.source,
                fOutputMedia.destination);
                
        if (err < B_OK)
                buffer->Recycle();
}

status_t 
VSTNode::AcceptFormat(const media_destination &dst, media_format* format)
{
        if (dst != fInputMedia.destination)
                return B_MEDIA_BAD_DESTINATION;

        if (format->type != B_MEDIA_RAW_AUDIO)
                return B_MEDIA_BAD_FORMAT;

        ValidateFormat(
                (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
                fFormat : fPreferredFormat, *format);
                        
        return B_OK;
}

status_t 
VSTNode::GetNextInput(int32* cookie, media_input* input)
{
        if (*cookie)
                return B_BAD_INDEX;

        ++*cookie;
        *input = fInputMedia;
        return B_OK;
}

void 
VSTNode::DisposeInputCookie(int32 cookie)
{
}

status_t 
VSTNode::FormatChanged(const media_source &src, const media_destination &dst,
                                                        int32 changeTag, const media_format &format)
{
        return B_MEDIA_BAD_FORMAT;
}

void 
VSTNode::ProducerDataStatus(const media_destination &dst, int32 status,
        bigtime_t when)
{
        if (fOutputMedia.destination != media_destination::null)
                SendDataStatus(status, fOutputMedia.destination, when);
}

status_t 
VSTNode::GetLatencyFor( const media_destination &dst, bigtime_t* latency,
        media_node_id* outTimeSource)
{
        if (dst != fInputMedia.destination)
                return B_MEDIA_BAD_DESTINATION;

        *latency = fDownstreamLatency + fProcessLatency;
        *outTimeSource = TimeSource()->ID();
        return B_OK;
}

status_t
VSTNode::Connected(const media_source& source,
        const media_destination& destination, const media_format& format,
        media_input* input)
{
        if (destination != fInputMedia.destination)
                return B_MEDIA_BAD_DESTINATION;

        if (fInputMedia.source != media_source::null)
                return B_MEDIA_ALREADY_CONNECTED;

        fInputMedia.source = source;
        fInputMedia.format = format;
        *input = fInputMedia;
        fFormat = format;

        return B_OK;
}

void 
VSTNode::Disconnected(const media_source &src, const media_destination &dst)
{
        if(fInputMedia.source!=src || dst!=fInputMedia.destination)
                return;
        
        fInputMedia.source = media_source::null;
        
        if(fOutputMedia.destination == media_destination::null)
                fFormat.u.raw_audio = media_raw_audio_format::wildcard;
                
        fInputMedia.format = fFormat;
}

//BBufferProducer
status_t 
VSTNode::FormatSuggestionRequested(media_type type, int32 quality,
        media_format* format)
{
        if (type != B_MEDIA_RAW_AUDIO)
                return B_MEDIA_BAD_FORMAT;

        if (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format)
                *format = fFormat;      
        else
                *format = fPreferredFormat;
                
        return B_OK;
}

status_t 
VSTNode::FormatProposal(const media_source &src, media_format* format)
{
        if (src != fOutputMedia.source)
                return B_MEDIA_BAD_SOURCE;

        if (format->type != B_MEDIA_RAW_AUDIO)
                return B_MEDIA_BAD_FORMAT;

        ValidateFormat(
                (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
                fFormat : fPreferredFormat, *format);

        return B_OK;
}

status_t 
VSTNode::FormatChangeRequested(const media_source &src,
        const media_destination &dst, media_format* format, int32* _deprecated_)
{
        return B_MEDIA_BAD_FORMAT;
}

void 
VSTNode::LateNoticeReceived(const media_source &src, 
        bigtime_t late, bigtime_t when)
{
        if (src != fOutputMedia.source || fInputMedia.source == media_source::null)
                return;

        NotifyLateProducer(fInputMedia.source, late, when);
}

status_t
VSTNode::GetNextOutput(int32 *cookie, media_output* output)
{
        if (*cookie)
                return B_BAD_INDEX;

        ++*cookie;
        *output = fOutputMedia;
        return B_OK;
}

status_t 
VSTNode::DisposeOutputCookie(int32 cookie) 
{
        return B_OK;
}

status_t
VSTNode::SetBufferGroup(const media_source &src, BBufferGroup* group)
{
        status_t ret;
        int32 changeTag;

        if (src != fOutputMedia.source)
                return B_MEDIA_BAD_SOURCE;

        if (fInputMedia.source == media_source::null)
                return B_ERROR;

        ret = SetOutputBuffersFor(fInputMedia.source, fInputMedia.destination,
                group, 0, &changeTag);
                
        return ret;
}

status_t
VSTNode::PrepareToConnect( const media_source &src, const media_destination &dst,
        media_format* format, media_source* out_source, char* name)
{
        status_t ret = B_OK;
        
        if (src != fOutputMedia.source)
                return B_MEDIA_BAD_SOURCE;

        if (format->type != B_MEDIA_RAW_AUDIO)
                return B_MEDIA_BAD_FORMAT;
        
        if (fOutputMedia.destination != media_destination::null)
                return B_MEDIA_ALREADY_CONNECTED;

        ret = ValidateFormat(
                (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
                fFormat : fPreferredFormat, *format);
        
        if (ret < B_OK)
                return ret;

        SetOutputFormat(*format);

        fOutputMedia.destination = dst;
        fOutputMedia.format = *format;

        *out_source = fOutputMedia.source;
        strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH);

        return B_OK;
}

void
VSTNode::Connect(status_t status, const media_source &src,
        const media_destination &dst, const media_format &format, char* name)
{
        if (status < B_OK) {
                fOutputMedia.destination = media_destination::null;
                return;
        }

        strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
        fOutputMedia.destination = dst;
        fFormat = format;

        media_node_id timeSource;
        FindLatencyFor(fOutputMedia.destination, &fDownstreamLatency, &timeSource);
        
        InitFilter();

        fProcessLatency = GetFilterLatency();
        SetEventLatency(fDownstreamLatency + fProcessLatency);

        if (fInputMedia.source != media_source::null) {
                SendLatencyChange(fInputMedia.source, fInputMedia.destination, 
                                                        EventLatency()+SchedulingLatency());
        }

        bigtime_t duration = 0;
        
        int sample_size = (fFormat.u.raw_audio.format & 0xf)*
                                                fFormat.u.raw_audio.channel_count;
        if (fFormat.u.raw_audio.buffer_size > 0 &&
                fFormat.u.raw_audio.frame_rate > 0 &&
                sample_size > 0) {
                duration = (bigtime_t)(((fFormat.u.raw_audio.buffer_size / sample_size) /
                        fFormat.u.raw_audio.frame_rate) * 1000000.0);
        }
                        
        SetBufferDuration(duration);
}

void 
VSTNode::Disconnect(const media_source &src, const media_destination &dst) 
{
        if (src != fOutputMedia.source)
                return;

        if (dst != fOutputMedia.destination)
                return;

        fOutputMedia.destination = media_destination::null;

        if (fInputMedia.source == media_source::null)
                fFormat.u.raw_audio = media_raw_audio_format::wildcard;

        fOutputMedia.format = fFormat;
}

void 
VSTNode::EnableOutput(const media_source &src, bool enabled, int32* _deprecated_)
{
        if (src != fOutputMedia.source)
                return;
                
        fOutputMediaEnabled = enabled;
}

status_t 
VSTNode::GetLatency(bigtime_t* latency)
{
        *latency = EventLatency() + SchedulingLatency();
        return B_OK;
}

void 
VSTNode::LatencyChanged(const media_source &src, const media_destination &dst,
        bigtime_t latency, uint32 flags)
{
        if (src != fOutputMedia.source || dst != fOutputMedia.destination)
                return;

        fDownstreamLatency = latency;
        SetEventLatency(fDownstreamLatency + fProcessLatency);

        if (fInputMedia.source != media_source::null) {
                SendLatencyChange(fInputMedia.source, 
                        fInputMedia.destination,EventLatency() + SchedulingLatency());
        }
}

//BMediaEventLooper
bigtime_t 
VSTNode::OfflineTime()
{
        return 0LL;
}

//VSTNode
void
VSTNode::HandleEvent(const media_timed_event *event, bigtime_t late,
        bool realTime)
{       
        if(event->type == BTimedEventQueue::B_PARAMETER)
                ParameterEventProcessing(event);
}

void 
VSTNode::ParameterEventProcessing(const media_timed_event* event)
{
        float value = 0.0;
        int32 value32 = 0;
        
        int32 id = event->bigdata;
        size_t size = event->data;
        bigtime_t now = TimeSource()->Now();
        
        type_code v_type = B_FLOAT_TYPE;
        
        BParameter* web_param;  
        for(int i = 0; i < fWeb->CountParameters(); i++) {
                web_param = fWeb->ParameterAt(i);
                if(web_param->ID() == id) {
                        v_type = web_param->ValueType();
                        break;
                }
        }
        
        if (v_type == B_FLOAT_TYPE)
                value = *((float*)event->pointer);
        if (v_type == B_INT32_TYPE) {
                value32 = *((int32*)event->pointer);
                value = (float)value32;
        }

        if (id == P_MUTE) {
                fMute = value32;
                fMuteLastChanged = now;
                BroadcastNewParameterValue(now, id,     event->pointer, size);
        } else if (id == P_BYPASS) {
                fByPass = value32;
                fByPassLastChanged = now;
                BroadcastNewParameterValue(now, id,     event->pointer, size);
        } else {
                int32 idx = id - P_PARAM;
                if (idx >= 0 && idx < fPlugin->ParametersCount()) {
                        VSTParameter *param = fPlugin->Parameter(idx);
                        param->SetValue(value);
                        BroadcastNewParameterValue(now, id,     &value, size);
                }
        }
}

status_t
VSTNode::ValidateFormat(const media_format &preferredFormat,
                                                        media_format &proposedFormat)
{
        status_t ret = B_OK;
                
        if (proposedFormat.type != B_MEDIA_RAW_AUDIO) {
                proposedFormat = preferredFormat;
                return B_MEDIA_BAD_FORMAT;
        }

        const media_raw_audio_format &wild = media_raw_audio_format::wildcard;
        media_raw_audio_format &f = proposedFormat.u.raw_audio;
        const media_raw_audio_format &pref = preferredFormat.u.raw_audio;

        if(pref.frame_rate != wild.frame_rate && f.frame_rate != pref.frame_rate) {
                if(f.frame_rate != wild.frame_rate)
                        ret = B_MEDIA_BAD_FORMAT;
                f.frame_rate = pref.frame_rate;
        }

        if(pref.channel_count != wild.channel_count &&
                f.channel_count != pref.channel_count) {
                if(f.channel_count != wild.channel_count)
                        ret = B_MEDIA_BAD_FORMAT;
                f.channel_count = pref.channel_count;
        }

        if(pref.format != wild.format && f.format != pref.format) {
                if(f.format != wild.format)
                        ret = B_MEDIA_BAD_FORMAT;
                f.format = pref.format;
        }

        if(pref.byte_order != wild.byte_order &&
                f.byte_order != pref.byte_order) {
                if(f.byte_order != wild.byte_order)
                        ret = B_MEDIA_BAD_FORMAT;
                f.byte_order = pref.byte_order;
        }

        if(pref.buffer_size != wild.buffer_size &&
                f.buffer_size != pref.buffer_size) {
                if(f.buffer_size != wild.buffer_size)
                        ret = B_MEDIA_BAD_FORMAT;
                f.buffer_size = pref.buffer_size;
        }
        
        return ret;
}


void
VSTNode::SetOutputFormat(media_format &format)
{
        media_raw_audio_format &f = format.u.raw_audio;
        const media_raw_audio_format &w = media_raw_audio_format::wildcard;

        if (f.frame_rate == w.frame_rate)
                f.frame_rate = 44100.0;
                
        if (f.channel_count == w.channel_count) {
                if(fInputMedia.source != media_source::null)
                        f.channel_count = fInputMedia.format.u.raw_audio.channel_count;
                else
                        f.channel_count = fPlugin->Channels(VST_OUTPUT_CHANNELS);
        }

        if (f.format == w.format)
                f.format = media_raw_audio_format::B_AUDIO_FLOAT;

        if (f.byte_order == w.format) {
                f.byte_order = (B_HOST_IS_BENDIAN) ?
                        B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
        }
        
        if (f.buffer_size == w.buffer_size)
                f.buffer_size = BUFF_SIZE;
}

void 
VSTNode::InitParameterValues()
{       
        fMute = 0;
        fByPass = 0;
        fMuteLastChanged = 0LL;
        fByPassLastChanged = 0LL;
}

void 
VSTNode::InitParameterWeb()
{
        fWeb = new BParameterWeb();

        bool switch_group_needed = false;
        for(int i = 0; i < fPlugin->ParametersCount(); i++) {
                VSTParameter* param = fPlugin->Parameter(i);
                if (param->Type() == VST_PARAM_CHECKBOX ||
                   param->Type() == VST_PARAM_DROPLIST) {
                   switch_group_needed = true;
                   break;
                }
        }

        BParameterGroup* fParamGroup = fWeb->MakeGroup("Parameters");   
        BParameterGroup* fSwitchesGroup = switch_group_needed ?
                fWeb->MakeGroup("Switches") : NULL;
        BParameterGroup* fAboutGroup = fWeb->MakeGroup("About");

        BParameter* value;
        BNullParameter* label;
        BParameterGroup* group;

        BParameterGroup* fFControlGroup = fParamGroup->MakeGroup("FilterControl");
        BParameterGroup* fCheckBoxGroup = switch_group_needed ?
                fSwitchesGroup->MakeGroup("CheckBoxes") : NULL;
        BParameterGroup* fSelectorsGroup = switch_group_needed ?
                fSwitchesGroup->MakeGroup("Selectors") : NULL;
        
        fFControlGroup->MakeDiscreteParameter(P_MUTE, 
                B_MEDIA_NO_TYPE,"Mute", B_ENABLE);
        fFControlGroup->MakeDiscreteParameter(P_BYPASS,
                B_MEDIA_NO_TYPE,"ByPass", B_ENABLE);
        
        for(int i = 0; i < fPlugin->ParametersCount(); i++) {
                VSTParameter *param = fPlugin->Parameter(i);
                switch(param->Type()) {
                        case VST_PARAM_CHECKBOX:
                        {
                                BString str;
                                str << param->Name() << " (" << param->MinimumValue()
                                        << "/" << param->MaximumValue() << ")";
                                value = fCheckBoxGroup->MakeDiscreteParameter(
                                        P_PARAM + param->Index(), B_MEDIA_NO_TYPE,
                                        str.String(), B_ENABLE);
                                break;
                        }
                        case VST_PARAM_DROPLIST:
                        {
                                BDiscreteParameter *dvalue =
                                        fSelectorsGroup->MakeDiscreteParameter(P_PARAM + param->Index(),
                                                B_MEDIA_NO_TYPE, param->Name(), B_OUTPUT_MUX);
                                for(int j = 0; j < param->ListCount(); j++) {
                                        dvalue->AddItem( param->ListItemAt(j)->Index,
                                                param->ListItemAt(j)->Name.String());
                                }
                                break;
                        }
                        //sliders
                        default:
                        {
                                BString str;
                                group = fParamGroup->MakeGroup(param->Name());
                                label = group->MakeNullParameter(P_LABEL + param->Index(), 
                                                                B_MEDIA_NO_TYPE, param->Name(), B_GENERIC);
                        
                                str.SetTo(param->MaximumValue());
                                str << " " << param->Unit();
                                
                                group->MakeNullParameter(P_LABEL2 + param->Index(), 
                                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);                      
                                value = group->MakeContinuousParameter(P_PARAM + param->Index(), 
                                                                B_MEDIA_NO_TYPE, "", B_GAIN, "", 0.0, 1.0, 0.01);
                                label->AddOutput(value);
                                value->AddInput(label);
                        
                                str.SetTo(param->MinimumValue());
                                str << " " << param->Unit();
                                
                                group->MakeNullParameter(P_LABEL3 + param->Index(), 
                                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
                                break;
                        }
                }               
        }
        
        BString str("About plugin");
        label = fAboutGroup->MakeNullParameter(P_ABOUT + 0, 
                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);      

        str.SetTo("Effect name: ");
        if (strlen(fPlugin->EffectName()) != 0)
                str.Append(fPlugin->EffectName());
        else
                str.Append("not specified");

        label = fAboutGroup->MakeNullParameter(P_ABOUT + 1, 
                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
        
        str.SetTo("Vendor: ");
        if (strlen(fPlugin->Vendor()) != 0)
                str.Append(fPlugin->Vendor());
        else
                str.Append("not specified");
                
        label = fAboutGroup->MakeNullParameter(P_ABOUT + 2, 
                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
        
        str.SetTo("Product: ");
        if (strlen(fPlugin->Product()) != 0)
                str.Append(fPlugin->Product());
        else
                str.Append("not specified");

        label = fAboutGroup->MakeNullParameter(P_ABOUT + 3,
                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);

        str.SetTo("Input Channels: ");
        str<<fPlugin->Channels(VST_INPUT_CHANNELS);
        label = fAboutGroup->MakeNullParameter(P_ABOUT + 4,
                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);

        str.SetTo("Output Channels: ");
        str<<fPlugin->Channels(VST_OUTPUT_CHANNELS);
        label = fAboutGroup->MakeNullParameter(P_ABOUT + 5,
                                                B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
                
        SetParameterWeb(fWeb);
}

void 
VSTNode::InitFilter()
{       
        fBlockSize = fFormat.u.raw_audio.buffer_size / 
                                (fFormat.u.raw_audio.channel_count * sizeof(float));

        fPlugin->SetBlockSize(fBlockSize);
        fPlugin->SetSampleRate(fFormat.u.raw_audio.frame_rate);
}

bigtime_t 
VSTNode::GetFilterLatency()
{
        if (fOutputMedia.destination == media_destination::null)
                return 0LL;

        BBufferGroup* temp_group =
                new BBufferGroup(fOutputMedia.format.u.raw_audio.buffer_size, 1);

        BBuffer *buffer =
                temp_group->RequestBuffer(fOutputMedia.format.u.raw_audio.buffer_size);
        buffer->Header()->type = B_MEDIA_RAW_AUDIO;
        buffer->Header()->size_used = fOutputMedia.format.u.raw_audio.buffer_size;

        bigtime_t begin = system_time();
        FilterBuffer(buffer);
        bigtime_t latency = system_time()-begin;

        InitFilter();

        buffer->Recycle();
        delete temp_group;
        
        return latency;
}

void 
VSTNode::FilterBuffer(BBuffer* buffer)
{
        uint32 m_frameSize = (fFormat.u.raw_audio.format & 0x0f)*
                                 fFormat.u.raw_audio.channel_count;
        uint32 samples = buffer->Header()->size_used / m_frameSize;             
        uint32 channels = fFormat.u.raw_audio.channel_count;
        
        if (fMute != 0) {               
                memset(buffer->Data(), 0, buffer->Header()->size_used);
        } else {
                if (fByPass == 0) {
                        fPlugin->Process((float*)buffer->Data(), samples, channels);
                }
        }
}