xref: /haiku/src/add-ons/media/media-add-ons/equalizer/EqualizerNode.cpp (revision 71c77851c93a10711107777f0325db11f1845923)
1*71c77851Sthreedeyes /*
2*71c77851Sthreedeyes  * Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com. All rights reserved.
3*71c77851Sthreedeyes  * Distributed under the terms of the MIT License.
4*71c77851Sthreedeyes  */
5*71c77851Sthreedeyes 
6*71c77851Sthreedeyes #include <ByteOrder.h>
7*71c77851Sthreedeyes #include <Buffer.h>
8*71c77851Sthreedeyes #include <BufferGroup.h>
9*71c77851Sthreedeyes #include <TimeSource.h>
10*71c77851Sthreedeyes #include <ParameterWeb.h>
11*71c77851Sthreedeyes #include <String.h>
12*71c77851Sthreedeyes 
13*71c77851Sthreedeyes #include <stdio.h>
14*71c77851Sthreedeyes #include <string.h>
15*71c77851Sthreedeyes 
16*71c77851Sthreedeyes #include "EqualizerNode.h"
17*71c77851Sthreedeyes 
18*71c77851Sthreedeyes //EqualizerNode
19*71c77851Sthreedeyes EqualizerNode::~EqualizerNode() {
20*71c77851Sthreedeyes 	Quit();
21*71c77851Sthreedeyes }
22*71c77851Sthreedeyes 
23*71c77851Sthreedeyes EqualizerNode::EqualizerNode(BMediaAddOn* addon) :
24*71c77851Sthreedeyes 	BMediaNode("10 Band Equalizer"),
25*71c77851Sthreedeyes 	BBufferConsumer(B_MEDIA_RAW_AUDIO),
26*71c77851Sthreedeyes 	BBufferProducer(B_MEDIA_RAW_AUDIO),
27*71c77851Sthreedeyes 	BControllable(),
28*71c77851Sthreedeyes 	BMediaEventLooper(),
29*71c77851Sthreedeyes 	fAddOn(addon),
30*71c77851Sthreedeyes 	fProcessLatency(0),
31*71c77851Sthreedeyes 	fDownstreamLatency(0),
32*71c77851Sthreedeyes 	fOutputMediaEnabled(true)
33*71c77851Sthreedeyes {
34*71c77851Sthreedeyes }
35*71c77851Sthreedeyes 
36*71c77851Sthreedeyes //BMediaNode
37*71c77851Sthreedeyes BMediaAddOn*
38*71c77851Sthreedeyes EqualizerNode::AddOn(int32 *id) const
39*71c77851Sthreedeyes {
40*71c77851Sthreedeyes 	if(fAddOn)
41*71c77851Sthreedeyes 		*id = 0;
42*71c77851Sthreedeyes 	return fAddOn;
43*71c77851Sthreedeyes }
44*71c77851Sthreedeyes 
45*71c77851Sthreedeyes status_t
46*71c77851Sthreedeyes EqualizerNode::HandleMessage(int32 message, const void *data, size_t size)
47*71c77851Sthreedeyes {
48*71c77851Sthreedeyes 	if((BControllable::HandleMessage(message, data, size)!=B_OK) &&
49*71c77851Sthreedeyes 		(BBufferConsumer::HandleMessage(message, data, size) != B_OK) &&
50*71c77851Sthreedeyes 		(BBufferProducer::HandleMessage(message, data, size) != B_OK) &&
51*71c77851Sthreedeyes 		(BControllable::HandleMessage(message, data, size) != B_OK) ) {
52*71c77851Sthreedeyes    			BMediaNode::HandleMessage(message, data, size);
53*71c77851Sthreedeyes 		return B_OK;
54*71c77851Sthreedeyes 	} else {
55*71c77851Sthreedeyes 		BMediaNode::HandleBadMessage(message, data, size);
56*71c77851Sthreedeyes 		return B_ERROR;
57*71c77851Sthreedeyes 	}
58*71c77851Sthreedeyes }
59*71c77851Sthreedeyes 
60*71c77851Sthreedeyes void
61*71c77851Sthreedeyes EqualizerNode::NodeRegistered()
62*71c77851Sthreedeyes {
63*71c77851Sthreedeyes 	SetPriority(B_REAL_TIME_PRIORITY);
64*71c77851Sthreedeyes 	Run();
65*71c77851Sthreedeyes 
66*71c77851Sthreedeyes 	fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
67*71c77851Sthreedeyes 	fPreferredFormat.u.raw_audio.buffer_size = BUFF_SIZE;
68*71c77851Sthreedeyes 	fPreferredFormat.u.raw_audio = media_raw_audio_format::wildcard;
69*71c77851Sthreedeyes 	fPreferredFormat.u.raw_audio.channel_count = media_raw_audio_format::wildcard.channel_count;
70*71c77851Sthreedeyes 	fPreferredFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
71*71c77851Sthreedeyes 
72*71c77851Sthreedeyes 	fFormat.type = B_MEDIA_RAW_AUDIO;
73*71c77851Sthreedeyes 	fFormat.u.raw_audio = media_raw_audio_format::wildcard;
74*71c77851Sthreedeyes 
75*71c77851Sthreedeyes 	fInputMedia.destination.port = ControlPort();
76*71c77851Sthreedeyes 	fInputMedia.destination.id = ID_AUDIO_INPUT;
77*71c77851Sthreedeyes 	fInputMedia.node = Node();
78*71c77851Sthreedeyes 	fInputMedia.source = media_source::null;
79*71c77851Sthreedeyes 	fInputMedia.format = fFormat;
80*71c77851Sthreedeyes 	strncpy(fInputMedia.name, "Audio Input", B_MEDIA_NAME_LENGTH);
81*71c77851Sthreedeyes 
82*71c77851Sthreedeyes 	fOutputMedia.source.port = ControlPort();
83*71c77851Sthreedeyes 	fOutputMedia.source.id = ID_AUDIO_OUTPUT;
84*71c77851Sthreedeyes 	fOutputMedia.node = Node();
85*71c77851Sthreedeyes 	fOutputMedia.destination = media_destination::null;
86*71c77851Sthreedeyes 	fOutputMedia.format = fFormat;
87*71c77851Sthreedeyes 	strncpy(fOutputMedia.name, "Audio Output", B_MEDIA_NAME_LENGTH);
88*71c77851Sthreedeyes 
89*71c77851Sthreedeyes 	InitParameterValues();
90*71c77851Sthreedeyes 	InitParameterWeb();
91*71c77851Sthreedeyes }
92*71c77851Sthreedeyes 
93*71c77851Sthreedeyes //BControllable
94*71c77851Sthreedeyes status_t
95*71c77851Sthreedeyes EqualizerNode::GetParameterValue(int32 id, bigtime_t *lastChangeTime, void *value, size_t *size)
96*71c77851Sthreedeyes {
97*71c77851Sthreedeyes 	if(*size < sizeof(float)) {
98*71c77851Sthreedeyes 		return B_NO_MEMORY;
99*71c77851Sthreedeyes 	}
100*71c77851Sthreedeyes 
101*71c77851Sthreedeyes 	if(id == P_MUTE) {
102*71c77851Sthreedeyes 		*(int32*)value = fMute;
103*71c77851Sthreedeyes 		*lastChangeTime = fMuteLastChanged;
104*71c77851Sthreedeyes 		*size = sizeof(int32);
105*71c77851Sthreedeyes 		return B_OK;
106*71c77851Sthreedeyes 	} else if(id == P_BYPASS) {
107*71c77851Sthreedeyes 		*(int32*)value = fByPass;
108*71c77851Sthreedeyes 		*lastChangeTime = fByPassLastChanged;
109*71c77851Sthreedeyes 		*size = sizeof(int32);
110*71c77851Sthreedeyes 		return B_OK;
111*71c77851Sthreedeyes 	} else if(id == P_PREAMP) {
112*71c77851Sthreedeyes 		*(float*)value = (float)fEqualizer.PreAmp();
113*71c77851Sthreedeyes 		*lastChangeTime = fPreAmpLastChanged;
114*71c77851Sthreedeyes 		*size = sizeof(float);
115*71c77851Sthreedeyes 		return B_OK;
116*71c77851Sthreedeyes 	} else if(id >= P_BANDS && id < P_BANDS + fEqualizer.BandCount()) {
117*71c77851Sthreedeyes 		int band = id - P_BANDS;
118*71c77851Sthreedeyes 		*(float*)value = (float)fEqualizer.Band(band);
119*71c77851Sthreedeyes 		*lastChangeTime = fBandsLastChanged[band];
120*71c77851Sthreedeyes 		*size = sizeof(float);
121*71c77851Sthreedeyes 		return B_OK;
122*71c77851Sthreedeyes 	}
123*71c77851Sthreedeyes 
124*71c77851Sthreedeyes 	return B_ERROR;
125*71c77851Sthreedeyes }
126*71c77851Sthreedeyes 
127*71c77851Sthreedeyes void
128*71c77851Sthreedeyes EqualizerNode::SetParameterValue(int32 id, bigtime_t time, const void *value, size_t size)
129*71c77851Sthreedeyes {
130*71c77851Sthreedeyes 	if(id == P_PREAMP || id == P_BYPASS || id == P_MUTE ||
131*71c77851Sthreedeyes 		(id >= P_BANDS && id < P_BANDS + fEqualizer.BandCount())) {
132*71c77851Sthreedeyes 		media_timed_event ev(time, BTimedEventQueue::B_PARAMETER, (void*)value,
133*71c77851Sthreedeyes 							BTimedEventQueue::B_NO_CLEANUP, size, id, "EQ");
134*71c77851Sthreedeyes 		ParameterEventProcessing(&ev);	//dirty hack for parameter processing (mediakit bug????)
135*71c77851Sthreedeyes 		EventQueue()->AddEvent(ev);
136*71c77851Sthreedeyes 	}
137*71c77851Sthreedeyes }
138*71c77851Sthreedeyes 
139*71c77851Sthreedeyes //BBufferConsumer
140*71c77851Sthreedeyes void
141*71c77851Sthreedeyes EqualizerNode::BufferReceived(BBuffer *buffer)
142*71c77851Sthreedeyes {
143*71c77851Sthreedeyes 	if(buffer->Header()->destination != fInputMedia.destination.id) {
144*71c77851Sthreedeyes 		buffer->Recycle();
145*71c77851Sthreedeyes 		return;
146*71c77851Sthreedeyes 	}
147*71c77851Sthreedeyes 
148*71c77851Sthreedeyes 	if(fOutputMedia.destination == media_destination::null || !fOutputMediaEnabled) {
149*71c77851Sthreedeyes 		buffer->Recycle();
150*71c77851Sthreedeyes 		return;
151*71c77851Sthreedeyes 	}
152*71c77851Sthreedeyes 
153*71c77851Sthreedeyes 	FilterBuffer(buffer);
154*71c77851Sthreedeyes 
155*71c77851Sthreedeyes 	status_t err = SendBuffer(buffer, fOutputMedia.source, fOutputMedia.destination);
156*71c77851Sthreedeyes 	if (err < B_OK) {
157*71c77851Sthreedeyes 		buffer->Recycle();
158*71c77851Sthreedeyes 	}
159*71c77851Sthreedeyes }
160*71c77851Sthreedeyes 
161*71c77851Sthreedeyes status_t
162*71c77851Sthreedeyes EqualizerNode::AcceptFormat(const media_destination &dst, media_format *format)
163*71c77851Sthreedeyes {
164*71c77851Sthreedeyes 	if(dst != fInputMedia.destination) {
165*71c77851Sthreedeyes 		return B_MEDIA_BAD_DESTINATION;
166*71c77851Sthreedeyes 	}
167*71c77851Sthreedeyes 	if(format->type != B_MEDIA_RAW_AUDIO) {
168*71c77851Sthreedeyes 		return B_MEDIA_BAD_FORMAT;
169*71c77851Sthreedeyes 	}
170*71c77851Sthreedeyes 
171*71c77851Sthreedeyes 	ValidateFormat((fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
172*71c77851Sthreedeyes 			fFormat : fPreferredFormat, *format);
173*71c77851Sthreedeyes 
174*71c77851Sthreedeyes 	return B_OK;
175*71c77851Sthreedeyes }
176*71c77851Sthreedeyes 
177*71c77851Sthreedeyes status_t
178*71c77851Sthreedeyes EqualizerNode::GetNextInput(int32* cookie, media_input* input)
179*71c77851Sthreedeyes {
180*71c77851Sthreedeyes 	if(*cookie) {
181*71c77851Sthreedeyes 		return B_BAD_INDEX;
182*71c77851Sthreedeyes 	}
183*71c77851Sthreedeyes 	++*cookie;
184*71c77851Sthreedeyes 	*input = fInputMedia;
185*71c77851Sthreedeyes 	return B_OK;
186*71c77851Sthreedeyes }
187*71c77851Sthreedeyes 
188*71c77851Sthreedeyes void
189*71c77851Sthreedeyes EqualizerNode::DisposeInputCookie(int32 cookie)
190*71c77851Sthreedeyes {
191*71c77851Sthreedeyes }
192*71c77851Sthreedeyes 
193*71c77851Sthreedeyes status_t
194*71c77851Sthreedeyes EqualizerNode::FormatChanged(const media_source &src, const media_destination &dst,
195*71c77851Sthreedeyes 							int32 changeTag, const media_format &format)
196*71c77851Sthreedeyes {
197*71c77851Sthreedeyes 	return B_MEDIA_BAD_FORMAT;
198*71c77851Sthreedeyes }
199*71c77851Sthreedeyes 
200*71c77851Sthreedeyes void
201*71c77851Sthreedeyes EqualizerNode::ProducerDataStatus(const media_destination &dst, int32 status, bigtime_t when)
202*71c77851Sthreedeyes {
203*71c77851Sthreedeyes 	if(fOutputMedia.destination != media_destination::null) {
204*71c77851Sthreedeyes 		SendDataStatus(status, fOutputMedia.destination, when);
205*71c77851Sthreedeyes 	}
206*71c77851Sthreedeyes }
207*71c77851Sthreedeyes 
208*71c77851Sthreedeyes status_t
209*71c77851Sthreedeyes EqualizerNode::GetLatencyFor( const media_destination &dst, bigtime_t *latency,
210*71c77851Sthreedeyes 							media_node_id* outTimeSource)
211*71c77851Sthreedeyes {
212*71c77851Sthreedeyes 
213*71c77851Sthreedeyes 	if(dst != fInputMedia.destination) {
214*71c77851Sthreedeyes 		return B_MEDIA_BAD_DESTINATION;
215*71c77851Sthreedeyes 	}
216*71c77851Sthreedeyes 
217*71c77851Sthreedeyes 	*latency = fDownstreamLatency + fProcessLatency;
218*71c77851Sthreedeyes 	*outTimeSource = TimeSource()->ID();
219*71c77851Sthreedeyes 	return B_OK;
220*71c77851Sthreedeyes }
221*71c77851Sthreedeyes 
222*71c77851Sthreedeyes status_t
223*71c77851Sthreedeyes EqualizerNode::Connected(const media_source& source,
224*71c77851Sthreedeyes 	const media_destination& destination, const media_format& format,
225*71c77851Sthreedeyes 	media_input* poInput)
226*71c77851Sthreedeyes {
227*71c77851Sthreedeyes 	if(destination != fInputMedia.destination) {
228*71c77851Sthreedeyes 		return B_MEDIA_BAD_DESTINATION;
229*71c77851Sthreedeyes 	}
230*71c77851Sthreedeyes 	if(fInputMedia.source != media_source::null) {
231*71c77851Sthreedeyes 		return B_MEDIA_ALREADY_CONNECTED;
232*71c77851Sthreedeyes 	}
233*71c77851Sthreedeyes 
234*71c77851Sthreedeyes 	fInputMedia.source = source;
235*71c77851Sthreedeyes 	fInputMedia.format = format;
236*71c77851Sthreedeyes 	*poInput = fInputMedia;
237*71c77851Sthreedeyes 	fFormat = format;
238*71c77851Sthreedeyes 
239*71c77851Sthreedeyes 	return B_OK;
240*71c77851Sthreedeyes }
241*71c77851Sthreedeyes 
242*71c77851Sthreedeyes void
243*71c77851Sthreedeyes EqualizerNode::Disconnected(const media_source &src, const media_destination &dst)
244*71c77851Sthreedeyes {
245*71c77851Sthreedeyes 	if(fInputMedia.source != src || dst != fInputMedia.destination) {
246*71c77851Sthreedeyes 		return;
247*71c77851Sthreedeyes 	}
248*71c77851Sthreedeyes 	fInputMedia.source = media_source::null;
249*71c77851Sthreedeyes 
250*71c77851Sthreedeyes 	if(fOutputMedia.destination == media_destination::null) {
251*71c77851Sthreedeyes 		fFormat.u.raw_audio = media_raw_audio_format::wildcard;
252*71c77851Sthreedeyes 	}
253*71c77851Sthreedeyes 	fInputMedia.format = fFormat;
254*71c77851Sthreedeyes }
255*71c77851Sthreedeyes 
256*71c77851Sthreedeyes //BBufferProducer
257*71c77851Sthreedeyes status_t
258*71c77851Sthreedeyes EqualizerNode::FormatSuggestionRequested(media_type type, int32 quality, media_format *format)
259*71c77851Sthreedeyes {
260*71c77851Sthreedeyes 	if(type != B_MEDIA_RAW_AUDIO) {
261*71c77851Sthreedeyes 		return B_MEDIA_BAD_FORMAT;
262*71c77851Sthreedeyes 	}
263*71c77851Sthreedeyes 
264*71c77851Sthreedeyes 	if(fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) {
265*71c77851Sthreedeyes 		*format = fFormat;
266*71c77851Sthreedeyes 	} else {
267*71c77851Sthreedeyes 		*format = fPreferredFormat;
268*71c77851Sthreedeyes 	}
269*71c77851Sthreedeyes 	return B_OK;
270*71c77851Sthreedeyes }
271*71c77851Sthreedeyes 
272*71c77851Sthreedeyes status_t
273*71c77851Sthreedeyes EqualizerNode::FormatProposal(const media_source &src, media_format* format)
274*71c77851Sthreedeyes {
275*71c77851Sthreedeyes 	if(src != fOutputMedia.source) {
276*71c77851Sthreedeyes 		return B_MEDIA_BAD_SOURCE;
277*71c77851Sthreedeyes 	}
278*71c77851Sthreedeyes 
279*71c77851Sthreedeyes 	if(format->type != B_MEDIA_RAW_AUDIO) {
280*71c77851Sthreedeyes 		return B_MEDIA_BAD_FORMAT;
281*71c77851Sthreedeyes 	}
282*71c77851Sthreedeyes 
283*71c77851Sthreedeyes 	ValidateFormat((fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
284*71c77851Sthreedeyes 			fFormat:fPreferredFormat,*format);
285*71c77851Sthreedeyes 
286*71c77851Sthreedeyes 	return B_OK;
287*71c77851Sthreedeyes }
288*71c77851Sthreedeyes 
289*71c77851Sthreedeyes status_t
290*71c77851Sthreedeyes EqualizerNode::FormatChangeRequested(const media_source &src, const media_destination &dst,
291*71c77851Sthreedeyes 						media_format* format, int32* _deprecated_)
292*71c77851Sthreedeyes {
293*71c77851Sthreedeyes 	return B_MEDIA_BAD_FORMAT;
294*71c77851Sthreedeyes }
295*71c77851Sthreedeyes 
296*71c77851Sthreedeyes void
297*71c77851Sthreedeyes EqualizerNode::LateNoticeReceived(const media_source &src, bigtime_t late, bigtime_t when)
298*71c77851Sthreedeyes {
299*71c77851Sthreedeyes 	if(src != fOutputMedia.source || fInputMedia.source == media_source::null) {
300*71c77851Sthreedeyes 		return;
301*71c77851Sthreedeyes 	}
302*71c77851Sthreedeyes 	NotifyLateProducer(fInputMedia.source, late, when);
303*71c77851Sthreedeyes }
304*71c77851Sthreedeyes 
305*71c77851Sthreedeyes status_t
306*71c77851Sthreedeyes EqualizerNode::GetNextOutput(int32 *cookie, media_output* output)
307*71c77851Sthreedeyes {
308*71c77851Sthreedeyes 	if(*cookie) {
309*71c77851Sthreedeyes 		return B_BAD_INDEX;
310*71c77851Sthreedeyes 	}
311*71c77851Sthreedeyes 	++*cookie;
312*71c77851Sthreedeyes 	*output = fOutputMedia;
313*71c77851Sthreedeyes 	return B_OK;
314*71c77851Sthreedeyes }
315*71c77851Sthreedeyes 
316*71c77851Sthreedeyes status_t
317*71c77851Sthreedeyes EqualizerNode::DisposeOutputCookie(int32 cookie)
318*71c77851Sthreedeyes {
319*71c77851Sthreedeyes 	return B_OK;
320*71c77851Sthreedeyes }
321*71c77851Sthreedeyes 
322*71c77851Sthreedeyes status_t
323*71c77851Sthreedeyes EqualizerNode::SetBufferGroup(const media_source &src, BBufferGroup *group)
324*71c77851Sthreedeyes {
325*71c77851Sthreedeyes 	int32 changeTag;
326*71c77851Sthreedeyes 	status_t ret = B_OK;
327*71c77851Sthreedeyes 
328*71c77851Sthreedeyes 	if(src != fOutputMedia.source) {
329*71c77851Sthreedeyes 		return B_MEDIA_BAD_SOURCE;
330*71c77851Sthreedeyes 	}
331*71c77851Sthreedeyes 	if(fInputMedia.source == media_source::null) {
332*71c77851Sthreedeyes 		return B_ERROR;
333*71c77851Sthreedeyes 	}
334*71c77851Sthreedeyes 
335*71c77851Sthreedeyes 	ret = SetOutputBuffersFor(fInputMedia.source, fInputMedia.destination, group, 0, &changeTag);
336*71c77851Sthreedeyes 	return ret;
337*71c77851Sthreedeyes }
338*71c77851Sthreedeyes 
339*71c77851Sthreedeyes status_t
340*71c77851Sthreedeyes EqualizerNode::PrepareToConnect( const media_source &src, const media_destination &dst,
341*71c77851Sthreedeyes 							media_format* format, media_source* outSource, char* outName)
342*71c77851Sthreedeyes {
343*71c77851Sthreedeyes 	if(src != fOutputMedia.source) {
344*71c77851Sthreedeyes 		return B_MEDIA_BAD_SOURCE;
345*71c77851Sthreedeyes 	}
346*71c77851Sthreedeyes 
347*71c77851Sthreedeyes 	if(format->type != B_MEDIA_RAW_AUDIO) {
348*71c77851Sthreedeyes 		return B_MEDIA_BAD_FORMAT;
349*71c77851Sthreedeyes 	}
350*71c77851Sthreedeyes 
351*71c77851Sthreedeyes 	if(fOutputMedia.destination != media_destination::null) {
352*71c77851Sthreedeyes 		return B_MEDIA_ALREADY_CONNECTED;
353*71c77851Sthreedeyes 	}
354*71c77851Sthreedeyes 
355*71c77851Sthreedeyes 	status_t err = ValidateFormat((fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
356*71c77851Sthreedeyes 		fFormat : fPreferredFormat, *format);
357*71c77851Sthreedeyes 
358*71c77851Sthreedeyes 	if(err < B_OK) {
359*71c77851Sthreedeyes 		return err;
360*71c77851Sthreedeyes 	}
361*71c77851Sthreedeyes 
362*71c77851Sthreedeyes 	SetOutputFormat(*format);
363*71c77851Sthreedeyes 
364*71c77851Sthreedeyes 	fOutputMedia.destination = dst;
365*71c77851Sthreedeyes 	fOutputMedia.format = *format;
366*71c77851Sthreedeyes 
367*71c77851Sthreedeyes 	*outSource = fOutputMedia.source;
368*71c77851Sthreedeyes 	strncpy(outName, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
369*71c77851Sthreedeyes 
370*71c77851Sthreedeyes 	return B_OK;
371*71c77851Sthreedeyes }
372*71c77851Sthreedeyes 
373*71c77851Sthreedeyes void
374*71c77851Sthreedeyes EqualizerNode::Connect(status_t status, const media_source &src, const media_destination &dst,
375*71c77851Sthreedeyes 						const media_format &format, char *outName)
376*71c77851Sthreedeyes {
377*71c77851Sthreedeyes 	status_t err;
378*71c77851Sthreedeyes 	if(status < B_OK) {
379*71c77851Sthreedeyes 		fOutputMedia.destination = media_destination::null;
380*71c77851Sthreedeyes 		return;
381*71c77851Sthreedeyes 	}
382*71c77851Sthreedeyes 
383*71c77851Sthreedeyes 	strncpy(outName, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
384*71c77851Sthreedeyes 	fOutputMedia.destination = dst;
385*71c77851Sthreedeyes 	fFormat = format;
386*71c77851Sthreedeyes 
387*71c77851Sthreedeyes 	media_node_id timeSource;
388*71c77851Sthreedeyes 	err = FindLatencyFor(fOutputMedia.destination, &fDownstreamLatency, &timeSource);
389*71c77851Sthreedeyes 
390*71c77851Sthreedeyes 	InitFilter();
391*71c77851Sthreedeyes 
392*71c77851Sthreedeyes 	fProcessLatency = GetFilterLatency();
393*71c77851Sthreedeyes 	SetEventLatency(fDownstreamLatency + fProcessLatency);
394*71c77851Sthreedeyes 
395*71c77851Sthreedeyes 	if(fInputMedia.source != media_source::null) {
396*71c77851Sthreedeyes 		SendLatencyChange(fInputMedia.source, fInputMedia.destination,
397*71c77851Sthreedeyes 						EventLatency() + SchedulingLatency());
398*71c77851Sthreedeyes 	}
399*71c77851Sthreedeyes 
400*71c77851Sthreedeyes 	bigtime_t duration = 0;
401*71c77851Sthreedeyes 
402*71c77851Sthreedeyes 	int sample_size = (fFormat.u.raw_audio.format & 0xf) *
403*71c77851Sthreedeyes 						fFormat.u.raw_audio.channel_count;
404*71c77851Sthreedeyes 
405*71c77851Sthreedeyes 	if (fFormat.u.raw_audio.buffer_size > 0 &&
406*71c77851Sthreedeyes 		fFormat.u.raw_audio.frame_rate > 0 &&
407*71c77851Sthreedeyes 		sample_size > 0) {
408*71c77851Sthreedeyes 			duration = (bigtime_t)(((fFormat.u.raw_audio.buffer_size / sample_size) /
409*71c77851Sthreedeyes 									fFormat.u.raw_audio.frame_rate) * 1000000.0);
410*71c77851Sthreedeyes 	}
411*71c77851Sthreedeyes 
412*71c77851Sthreedeyes 	SetBufferDuration(duration);
413*71c77851Sthreedeyes }
414*71c77851Sthreedeyes 
415*71c77851Sthreedeyes void
416*71c77851Sthreedeyes EqualizerNode::Disconnect(const media_source &src, const media_destination &dst)
417*71c77851Sthreedeyes {
418*71c77851Sthreedeyes 	if(src != fOutputMedia.source) {
419*71c77851Sthreedeyes 		return;
420*71c77851Sthreedeyes 	}
421*71c77851Sthreedeyes 
422*71c77851Sthreedeyes 	if(dst != fOutputMedia.destination) {
423*71c77851Sthreedeyes 		return;
424*71c77851Sthreedeyes 	}
425*71c77851Sthreedeyes 
426*71c77851Sthreedeyes 	fOutputMedia.destination = media_destination::null;
427*71c77851Sthreedeyes 
428*71c77851Sthreedeyes 	if(fInputMedia.source == media_source::null) {
429*71c77851Sthreedeyes 		fFormat.u.raw_audio = media_raw_audio_format::wildcard;
430*71c77851Sthreedeyes 	}
431*71c77851Sthreedeyes 
432*71c77851Sthreedeyes 	fOutputMedia.format = fFormat;
433*71c77851Sthreedeyes }
434*71c77851Sthreedeyes 
435*71c77851Sthreedeyes void
436*71c77851Sthreedeyes EqualizerNode::EnableOutput(const media_source &src, bool enabled, int32* _deprecated_)
437*71c77851Sthreedeyes {
438*71c77851Sthreedeyes 	if(src != fOutputMedia.source) {
439*71c77851Sthreedeyes 		return;
440*71c77851Sthreedeyes 	}
441*71c77851Sthreedeyes 	fOutputMediaEnabled = enabled;
442*71c77851Sthreedeyes }
443*71c77851Sthreedeyes 
444*71c77851Sthreedeyes status_t
445*71c77851Sthreedeyes EqualizerNode::GetLatency(bigtime_t *latency)
446*71c77851Sthreedeyes {
447*71c77851Sthreedeyes 	*latency = EventLatency() + SchedulingLatency();
448*71c77851Sthreedeyes 	return B_OK;
449*71c77851Sthreedeyes }
450*71c77851Sthreedeyes 
451*71c77851Sthreedeyes void
452*71c77851Sthreedeyes EqualizerNode::LatencyChanged(const media_source &src, const media_destination &dst,
453*71c77851Sthreedeyes 						bigtime_t latency, uint32 flags)
454*71c77851Sthreedeyes {
455*71c77851Sthreedeyes 	if(src != fOutputMedia.source || dst != fOutputMedia.destination) {
456*71c77851Sthreedeyes 		return;
457*71c77851Sthreedeyes 	}
458*71c77851Sthreedeyes 
459*71c77851Sthreedeyes 	fDownstreamLatency = latency;
460*71c77851Sthreedeyes 	SetEventLatency(fDownstreamLatency + fProcessLatency);
461*71c77851Sthreedeyes 
462*71c77851Sthreedeyes 	if(fInputMedia.source != media_source::null) {
463*71c77851Sthreedeyes 		SendLatencyChange(fInputMedia.source,
464*71c77851Sthreedeyes 					fInputMedia.destination,EventLatency() + SchedulingLatency());
465*71c77851Sthreedeyes 	}
466*71c77851Sthreedeyes }
467*71c77851Sthreedeyes 
468*71c77851Sthreedeyes //BMediaEventLooper
469*71c77851Sthreedeyes bigtime_t
470*71c77851Sthreedeyes EqualizerNode::OfflineTime()
471*71c77851Sthreedeyes {
472*71c77851Sthreedeyes 	return 0LL;
473*71c77851Sthreedeyes }
474*71c77851Sthreedeyes 
475*71c77851Sthreedeyes //EqualizerNode
476*71c77851Sthreedeyes void
477*71c77851Sthreedeyes EqualizerNode::HandleEvent(const media_timed_event *event, bigtime_t late, bool realTime)
478*71c77851Sthreedeyes {
479*71c77851Sthreedeyes 	if(event->type == BTimedEventQueue::B_PARAMETER) {
480*71c77851Sthreedeyes 		ParameterEventProcessing(event);
481*71c77851Sthreedeyes 	}
482*71c77851Sthreedeyes }
483*71c77851Sthreedeyes 
484*71c77851Sthreedeyes 
485*71c77851Sthreedeyes 
486*71c77851Sthreedeyes void
487*71c77851Sthreedeyes EqualizerNode::ParameterEventProcessing(const media_timed_event* event)
488*71c77851Sthreedeyes {
489*71c77851Sthreedeyes 	float value = 0.0;
490*71c77851Sthreedeyes 	int32 value32 = 0;
491*71c77851Sthreedeyes 
492*71c77851Sthreedeyes 	int32 id = event->bigdata;
493*71c77851Sthreedeyes 	size_t size = event->data;
494*71c77851Sthreedeyes 	bigtime_t now = TimeSource()->Now();
495*71c77851Sthreedeyes 
496*71c77851Sthreedeyes 	type_code v_type = B_FLOAT_TYPE;
497*71c77851Sthreedeyes 
498*71c77851Sthreedeyes 	BParameter *web_param;
499*71c77851Sthreedeyes 
500*71c77851Sthreedeyes 	for(int i=0; i<fWeb->CountParameters(); i++) {
501*71c77851Sthreedeyes 		web_param = fWeb->ParameterAt(i);
502*71c77851Sthreedeyes 		if(web_param->ID() == id) {
503*71c77851Sthreedeyes 			v_type=web_param->ValueType();
504*71c77851Sthreedeyes 			break;
505*71c77851Sthreedeyes 		}
506*71c77851Sthreedeyes 	}
507*71c77851Sthreedeyes 
508*71c77851Sthreedeyes 	if(v_type == B_FLOAT_TYPE)
509*71c77851Sthreedeyes 		value = *((float*)event->pointer);
510*71c77851Sthreedeyes 	if(v_type == B_INT32_TYPE) {
511*71c77851Sthreedeyes 		value32 = *((int32*)event->pointer);
512*71c77851Sthreedeyes 		value = (float)value32;
513*71c77851Sthreedeyes 	}
514*71c77851Sthreedeyes 
515*71c77851Sthreedeyes 	if(id == P_MUTE) {
516*71c77851Sthreedeyes 		fMute = value32;
517*71c77851Sthreedeyes 		fMuteLastChanged = now;
518*71c77851Sthreedeyes 		BroadcastNewParameterValue(now,	id,	event->pointer, size);
519*71c77851Sthreedeyes 	} else if(id == P_BYPASS) {
520*71c77851Sthreedeyes 		fByPass = value32;
521*71c77851Sthreedeyes 		fByPassLastChanged = now;
522*71c77851Sthreedeyes 		BroadcastNewParameterValue(now,	id,	event->pointer, size);
523*71c77851Sthreedeyes 	} else if(id == P_PREAMP) {
524*71c77851Sthreedeyes 		if(value != fEqualizer.PreAmp()) {
525*71c77851Sthreedeyes 			fEqualizer.SetPreAmp(value);
526*71c77851Sthreedeyes 			fPreAmpLastChanged = now;
527*71c77851Sthreedeyes 			BroadcastNewParameterValue(now,	id,	&value,	size);
528*71c77851Sthreedeyes 		}
529*71c77851Sthreedeyes 	} else if(id >= P_BANDS && id < P_BANDS + fEqualizer.BandCount()) {
530*71c77851Sthreedeyes 		int band = id - P_BANDS;
531*71c77851Sthreedeyes 		if(value != fEqualizer.Band(band)) {
532*71c77851Sthreedeyes 			fEqualizer.SetBand(band, value);
533*71c77851Sthreedeyes 			fBandsLastChanged[band] = now;
534*71c77851Sthreedeyes 			BroadcastNewParameterValue(now,	id,	&value,	size);
535*71c77851Sthreedeyes 		}
536*71c77851Sthreedeyes 	}
537*71c77851Sthreedeyes }
538*71c77851Sthreedeyes 
539*71c77851Sthreedeyes status_t
540*71c77851Sthreedeyes EqualizerNode::ValidateFormat(const media_format &preferredFormat,
541*71c77851Sthreedeyes 							media_format &format)
542*71c77851Sthreedeyes {
543*71c77851Sthreedeyes 	status_t ret = B_OK;
544*71c77851Sthreedeyes 
545*71c77851Sthreedeyes 	if(format.type != B_MEDIA_RAW_AUDIO) {
546*71c77851Sthreedeyes 		format = preferredFormat;
547*71c77851Sthreedeyes 		return B_MEDIA_BAD_FORMAT;
548*71c77851Sthreedeyes 	}
549*71c77851Sthreedeyes 
550*71c77851Sthreedeyes 	media_raw_audio_format &wild = media_raw_audio_format::wildcard;
551*71c77851Sthreedeyes 	media_raw_audio_format &f = format.u.raw_audio;
552*71c77851Sthreedeyes 	const media_raw_audio_format &pref = format.u.raw_audio;
553*71c77851Sthreedeyes 
554*71c77851Sthreedeyes 	if(pref.frame_rate != wild.frame_rate && f.frame_rate != pref.frame_rate) {
555*71c77851Sthreedeyes 		if(f.frame_rate != wild.frame_rate) {
556*71c77851Sthreedeyes 			ret = B_MEDIA_BAD_FORMAT;
557*71c77851Sthreedeyes 		}
558*71c77851Sthreedeyes 		f.frame_rate = pref.frame_rate;
559*71c77851Sthreedeyes 	}
560*71c77851Sthreedeyes 
561*71c77851Sthreedeyes 	if(pref.channel_count != wild.channel_count && f.channel_count != pref.channel_count) {
562*71c77851Sthreedeyes 		if(f.channel_count != wild.channel_count) {
563*71c77851Sthreedeyes 			ret = B_MEDIA_BAD_FORMAT;
564*71c77851Sthreedeyes 		}
565*71c77851Sthreedeyes 		f.channel_count = pref.channel_count;
566*71c77851Sthreedeyes 	}
567*71c77851Sthreedeyes 
568*71c77851Sthreedeyes 	if(pref.byte_order != wild.byte_order &&  f.byte_order != pref.byte_order) {
569*71c77851Sthreedeyes 		if(f.byte_order != wild.byte_order) {
570*71c77851Sthreedeyes 			ret = B_MEDIA_BAD_FORMAT;
571*71c77851Sthreedeyes 		}
572*71c77851Sthreedeyes 		f.byte_order = pref.byte_order;
573*71c77851Sthreedeyes 	}
574*71c77851Sthreedeyes 
575*71c77851Sthreedeyes 	if(pref.format != wild.format &&  f.format != pref.format) {
576*71c77851Sthreedeyes 		if(f.format != wild.format) {
577*71c77851Sthreedeyes 			ret = B_MEDIA_BAD_FORMAT;
578*71c77851Sthreedeyes 		}
579*71c77851Sthreedeyes 		f.format = pref.format;
580*71c77851Sthreedeyes 	}
581*71c77851Sthreedeyes 
582*71c77851Sthreedeyes 	if(pref.buffer_size != wild.buffer_size && f.buffer_size != pref.buffer_size) {
583*71c77851Sthreedeyes 		if(f.buffer_size != wild.buffer_size) {
584*71c77851Sthreedeyes 			ret = B_MEDIA_BAD_FORMAT;
585*71c77851Sthreedeyes 		}
586*71c77851Sthreedeyes 		f.buffer_size = pref.buffer_size;
587*71c77851Sthreedeyes 	}
588*71c77851Sthreedeyes 
589*71c77851Sthreedeyes 	return ret;
590*71c77851Sthreedeyes }
591*71c77851Sthreedeyes 
592*71c77851Sthreedeyes void
593*71c77851Sthreedeyes EqualizerNode::SetOutputFormat(media_format &format)
594*71c77851Sthreedeyes {
595*71c77851Sthreedeyes 	media_raw_audio_format &f = format.u.raw_audio;
596*71c77851Sthreedeyes 	media_raw_audio_format &w = media_raw_audio_format::wildcard;
597*71c77851Sthreedeyes 
598*71c77851Sthreedeyes 	if(f.frame_rate == w.frame_rate) {
599*71c77851Sthreedeyes 		f.frame_rate = 44100.0;
600*71c77851Sthreedeyes 	}
601*71c77851Sthreedeyes 
602*71c77851Sthreedeyes 	if(f.channel_count == w.channel_count) {
603*71c77851Sthreedeyes 		if(fInputMedia.source != media_source::null) {
604*71c77851Sthreedeyes 			f.channel_count = fInputMedia.format.u.raw_audio.channel_count;
605*71c77851Sthreedeyes 		} else {
606*71c77851Sthreedeyes 			f.channel_count = 2;
607*71c77851Sthreedeyes 		}
608*71c77851Sthreedeyes 	}
609*71c77851Sthreedeyes 
610*71c77851Sthreedeyes 	if(f.format == w.format) {
611*71c77851Sthreedeyes 		f.format = media_raw_audio_format::B_AUDIO_FLOAT;
612*71c77851Sthreedeyes 	}
613*71c77851Sthreedeyes 
614*71c77851Sthreedeyes 	if(f.byte_order == w.format) {
615*71c77851Sthreedeyes 		f.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
616*71c77851Sthreedeyes 	}
617*71c77851Sthreedeyes 
618*71c77851Sthreedeyes 	if(f.buffer_size == w.buffer_size) {
619*71c77851Sthreedeyes 		f.buffer_size = BUFF_SIZE;
620*71c77851Sthreedeyes 	}
621*71c77851Sthreedeyes }
622*71c77851Sthreedeyes 
623*71c77851Sthreedeyes void
624*71c77851Sthreedeyes EqualizerNode::InitParameterValues()
625*71c77851Sthreedeyes {
626*71c77851Sthreedeyes 	fMute = 0;
627*71c77851Sthreedeyes 	fByPass = 0;
628*71c77851Sthreedeyes 	fMuteLastChanged = 0LL;
629*71c77851Sthreedeyes 	fByPassLastChanged = 0LL;
630*71c77851Sthreedeyes 	fPreAmpLastChanged = 0LL;
631*71c77851Sthreedeyes 
632*71c77851Sthreedeyes 	for(int i=0;i<EQ_BANDS;i++) {
633*71c77851Sthreedeyes 		fBandsLastChanged[i] = 0LL;
634*71c77851Sthreedeyes 	}
635*71c77851Sthreedeyes 
636*71c77851Sthreedeyes 	fEqualizer.CleanUp();
637*71c77851Sthreedeyes }
638*71c77851Sthreedeyes 
639*71c77851Sthreedeyes void
640*71c77851Sthreedeyes EqualizerNode::InitParameterWeb(void)
641*71c77851Sthreedeyes {
642*71c77851Sthreedeyes 	fWeb = new BParameterWeb();
643*71c77851Sthreedeyes 
644*71c77851Sthreedeyes 	BParameterGroup *fParamGroup = fWeb->MakeGroup("EqualizerNode Parameters");
645*71c77851Sthreedeyes 	BParameterGroup *fFControlGroup = fParamGroup->MakeGroup("FilterControl");
646*71c77851Sthreedeyes 
647*71c77851Sthreedeyes 	fFControlGroup->MakeDiscreteParameter(P_MUTE,B_MEDIA_NO_TYPE,"Mute", B_ENABLE);
648*71c77851Sthreedeyes 	fFControlGroup->MakeDiscreteParameter(P_BYPASS,B_MEDIA_NO_TYPE,"ByPass", B_ENABLE);
649*71c77851Sthreedeyes 
650*71c77851Sthreedeyes 	BNullParameter *label;
651*71c77851Sthreedeyes 	BParameterGroup *group;
652*71c77851Sthreedeyes 	BContinuousParameter *value;
653*71c77851Sthreedeyes 
654*71c77851Sthreedeyes 	group = fParamGroup->MakeGroup("Pre Amp");
655*71c77851Sthreedeyes 	label = group->MakeNullParameter(P_PREAMP_LABEL, B_MEDIA_NO_TYPE,
656*71c77851Sthreedeyes 									 "Pre Amp", B_GENERIC);
657*71c77851Sthreedeyes 	value = group->MakeContinuousParameter(P_PREAMP, B_MEDIA_NO_TYPE,
658*71c77851Sthreedeyes 									 "", B_GAIN, "dB", -8.0, 8.0, 0.1);
659*71c77851Sthreedeyes 	label->AddOutput(value);
660*71c77851Sthreedeyes 	value->AddInput(label);
661*71c77851Sthreedeyes 
662*71c77851Sthreedeyes 	for(int i=0; i<fEqualizer.BandCount(); i++) {
663*71c77851Sthreedeyes 		char freq[32];
664*71c77851Sthreedeyes 		sprintf(freq,"%gHz",fEqualizer.BandFrequency(i));
665*71c77851Sthreedeyes 		group = fParamGroup->MakeGroup(freq);
666*71c77851Sthreedeyes 		label = group->MakeNullParameter(P_BAND_LABELS + i, B_MEDIA_NO_TYPE,
667*71c77851Sthreedeyes 										freq, B_GENERIC);
668*71c77851Sthreedeyes 		value = group->MakeContinuousParameter(P_BANDS + i, B_MEDIA_NO_TYPE,
669*71c77851Sthreedeyes 										"", B_GAIN, "dB", -16.0, 16.0, 0.1);
670*71c77851Sthreedeyes 		label->AddOutput(value);
671*71c77851Sthreedeyes 		value->AddInput(label);
672*71c77851Sthreedeyes 	}
673*71c77851Sthreedeyes 
674*71c77851Sthreedeyes 	SetParameterWeb(fWeb);
675*71c77851Sthreedeyes }
676*71c77851Sthreedeyes 
677*71c77851Sthreedeyes void
678*71c77851Sthreedeyes EqualizerNode::InitFilter(void)
679*71c77851Sthreedeyes {
680*71c77851Sthreedeyes 	fEqualizer.SetFormat(fFormat.u.raw_audio.channel_count, fFormat.u.raw_audio.frame_rate);
681*71c77851Sthreedeyes }
682*71c77851Sthreedeyes 
683*71c77851Sthreedeyes bigtime_t
684*71c77851Sthreedeyes EqualizerNode::GetFilterLatency(void)
685*71c77851Sthreedeyes {
686*71c77851Sthreedeyes 	if(fOutputMedia.destination == media_destination::null) {
687*71c77851Sthreedeyes 		return 0LL;
688*71c77851Sthreedeyes 	}
689*71c77851Sthreedeyes 
690*71c77851Sthreedeyes 	BBufferGroup *test_group = new BBufferGroup(fOutputMedia.format.u.raw_audio.buffer_size, 1);
691*71c77851Sthreedeyes 
692*71c77851Sthreedeyes 	BBuffer *buffer = test_group->RequestBuffer(fOutputMedia.format.u.raw_audio.buffer_size);
693*71c77851Sthreedeyes 	buffer->Header()->type = B_MEDIA_RAW_AUDIO;
694*71c77851Sthreedeyes 	buffer->Header()->size_used = fOutputMedia.format.u.raw_audio.buffer_size;
695*71c77851Sthreedeyes 
696*71c77851Sthreedeyes 	bigtime_t begin = system_time();
697*71c77851Sthreedeyes 	FilterBuffer(buffer);
698*71c77851Sthreedeyes 	bigtime_t latency = system_time() - begin;
699*71c77851Sthreedeyes 
700*71c77851Sthreedeyes 	buffer->Recycle();
701*71c77851Sthreedeyes 	delete test_group;
702*71c77851Sthreedeyes 
703*71c77851Sthreedeyes 	InitFilter();
704*71c77851Sthreedeyes 
705*71c77851Sthreedeyes 	return latency;
706*71c77851Sthreedeyes }
707*71c77851Sthreedeyes 
708*71c77851Sthreedeyes void
709*71c77851Sthreedeyes EqualizerNode::FilterBuffer(BBuffer* buffer)
710*71c77851Sthreedeyes {
711*71c77851Sthreedeyes 	uint32 m_frameSize = (fFormat.u.raw_audio.format & 0x0f) * fFormat.u.raw_audio.channel_count;
712*71c77851Sthreedeyes 	uint32 samples = buffer->Header()->size_used / m_frameSize;
713*71c77851Sthreedeyes 	uint32 channels = fFormat.u.raw_audio.channel_count;
714*71c77851Sthreedeyes 	if(fMute !=0 ) {
715*71c77851Sthreedeyes 		memset(buffer->Data(), 0, buffer->Header()->size_used);
716*71c77851Sthreedeyes 	} else {
717*71c77851Sthreedeyes 		if(fByPass == 0) {
718*71c77851Sthreedeyes 			fEqualizer.ProcessBuffer((float*)buffer->Data(), samples*channels);
719*71c77851Sthreedeyes 		}
720*71c77851Sthreedeyes 	}
721*71c77851Sthreedeyes }
722