/*
 * 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;
	}
 
	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;
	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);
		}
	}
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fWeb, fBlockSize, fMute, fByPass, fMuteLastChanged, fByPassLastChanged.