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