xref: /haiku/src/apps/patchbay/MidiEventMeter.cpp (revision c14bca2958fb7b0c34d5464ccfdd87038f909a0c)
142b7984aSPete Goodeve /* MidiEventMeter.cpp
242b7984aSPete Goodeve  * ------------------
342b7984aSPete Goodeve  * Implements the MidiEventMeter class.
442b7984aSPete Goodeve  *
542b7984aSPete Goodeve  * Copyright 2013, Haiku, Inc. All rights reserved.
642b7984aSPete Goodeve  * Distributed under the terms of the MIT License.
742b7984aSPete Goodeve  *
842b7984aSPete Goodeve  * Revisions by Pete Goodeve
942b7984aSPete Goodeve  *
1042b7984aSPete Goodeve  * Copyright 1999, Be Incorporated.   All Rights Reserved.
1142b7984aSPete Goodeve  * This file may be used under the terms of the Be Sample Code License.
1242b7984aSPete Goodeve  */
1342b7984aSPete Goodeve 
14*82fbbe21SPete Goodeve #include "MidiEventMeter.h"
15*82fbbe21SPete Goodeve 
1642b7984aSPete Goodeve #include <stdio.h>
1742b7984aSPete Goodeve #include <MidiRoster.h>
1842b7984aSPete Goodeve #include <MidiProducer.h>
1942b7984aSPete Goodeve #include <MidiConsumer.h>
2042b7984aSPete Goodeve #include <View.h>
21*82fbbe21SPete Goodeve 
2242b7984aSPete Goodeve #include "CountEventConsumer.h"
2342b7984aSPete Goodeve 
2442b7984aSPete Goodeve static const BRect METER_BOUNDS(0, 0, 7, 31);
2542b7984aSPete Goodeve 
2642b7984aSPete Goodeve // If we get this number of events per pulse or greater, we will
2742b7984aSPete Goodeve // max out the event meter.
2842b7984aSPete Goodeve // Value was determined empirically based on my banging on a MIDI
2942b7984aSPete Goodeve // keyboard controller with a pulse of 200ms.
3042b7984aSPete Goodeve static const int32 METER_SCALE = 10;
3142b7984aSPete Goodeve 
3242b7984aSPete Goodeve 
MidiEventMeter(int32 producerID)3342b7984aSPete Goodeve MidiEventMeter::MidiEventMeter(int32 producerID)
3442b7984aSPete Goodeve 	:
3542b7984aSPete Goodeve 	fCounter(NULL),
3642b7984aSPete Goodeve 	fMeterLevel(0)
3742b7984aSPete Goodeve {
3842b7984aSPete Goodeve 	BMidiRoster* roster = BMidiRoster::MidiRoster();
39*82fbbe21SPete Goodeve 	if (roster != NULL) {
4042b7984aSPete Goodeve 		BMidiProducer* producer = roster->FindProducer(producerID);
41*82fbbe21SPete Goodeve 		if (producer != NULL) {
4242b7984aSPete Goodeve 			BString name;
4342b7984aSPete Goodeve 			name << producer->Name() << " Event Meter";
4442b7984aSPete Goodeve 			fCounter = new CountEventConsumer(name.String());
4542b7984aSPete Goodeve 			producer->Connect(fCounter);
4642b7984aSPete Goodeve 			producer->Release();
4742b7984aSPete Goodeve 		}
4842b7984aSPete Goodeve 	}
4942b7984aSPete Goodeve }
5042b7984aSPete Goodeve 
5142b7984aSPete Goodeve 
~MidiEventMeter()5242b7984aSPete Goodeve MidiEventMeter::~MidiEventMeter()
5342b7984aSPete Goodeve {
54*82fbbe21SPete Goodeve 	if (fCounter != NULL)
5542b7984aSPete Goodeve 		fCounter->Release();
5642b7984aSPete Goodeve }
5742b7984aSPete Goodeve 
5842b7984aSPete Goodeve 
5942b7984aSPete Goodeve void
Pulse(BView * view)6042b7984aSPete Goodeve MidiEventMeter::Pulse(BView* view)
6142b7984aSPete Goodeve {
6242b7984aSPete Goodeve 	int32 newLevel = fMeterLevel;
63*82fbbe21SPete Goodeve 	if (fCounter != NULL) {
6442b7984aSPete Goodeve 		newLevel = CalcMeterLevel(fCounter->CountEvents());
6542b7984aSPete Goodeve 		fCounter->Reset();
6642b7984aSPete Goodeve 	}
6742b7984aSPete Goodeve 	if (newLevel != fMeterLevel) {
6842b7984aSPete Goodeve 		fMeterLevel = newLevel;
6942b7984aSPete Goodeve 		view->Invalidate(BRect(METER_BOUNDS).InsetBySelf(1, 1));
7042b7984aSPete Goodeve 	}
7142b7984aSPete Goodeve }
7242b7984aSPete Goodeve 
7342b7984aSPete Goodeve 
7442b7984aSPete Goodeve BRect
Bounds() const7542b7984aSPete Goodeve MidiEventMeter::Bounds() const
7642b7984aSPete Goodeve {
7742b7984aSPete Goodeve 	return METER_BOUNDS;
7842b7984aSPete Goodeve }
7942b7984aSPete Goodeve 
8042b7984aSPete Goodeve 
8142b7984aSPete Goodeve void
Draw(BView * view)8242b7984aSPete Goodeve MidiEventMeter::Draw(BView* view)
8342b7984aSPete Goodeve {
8442b7984aSPete Goodeve 	const rgb_color METER_BLACK = { 0, 0, 0, 255 };
8542b7984aSPete Goodeve 	const rgb_color METER_GREY = { 180, 180, 180, 255 };
8642b7984aSPete Goodeve 	const rgb_color METER_GREEN = { 0, 255, 0, 255 };
8742b7984aSPete Goodeve 
8842b7984aSPete Goodeve 	view->PushState();
8942b7984aSPete Goodeve 
9042b7984aSPete Goodeve 	// draw the frame
9142b7984aSPete Goodeve 	BPoint lt = METER_BOUNDS.LeftTop();
9242b7984aSPete Goodeve 	BPoint rb = METER_BOUNDS.RightBottom();
9342b7984aSPete Goodeve 	view->BeginLineArray(4);
9442b7984aSPete Goodeve 	view->AddLine(BPoint(lt.x, lt.y), BPoint(rb.x - 1, lt.y), METER_BLACK);
9542b7984aSPete Goodeve 	view->AddLine(BPoint(rb.x, lt.y), BPoint(rb.x, rb.y - 1), METER_BLACK);
9642b7984aSPete Goodeve 	view->AddLine(BPoint(rb.x, rb.y), BPoint(lt.x + 1, rb.y), METER_BLACK);
9742b7984aSPete Goodeve 	view->AddLine(BPoint(lt.x, rb.y), BPoint(lt.x, lt.y + 1), METER_BLACK);
9842b7984aSPete Goodeve 	view->EndLineArray();
9942b7984aSPete Goodeve 
10042b7984aSPete Goodeve 	// draw the cells
10142b7984aSPete Goodeve 	BRect cell = METER_BOUNDS;
10242b7984aSPete Goodeve 	cell.InsetBy(1, 1);
10342b7984aSPete Goodeve 	cell.bottom = cell.top + (cell.Height() + 1) / 5;
10442b7984aSPete Goodeve 	cell.bottom--;
10542b7984aSPete Goodeve 
10642b7984aSPete Goodeve 	const float kTintArray[] =
10742b7984aSPete Goodeve 		{B_DARKEN_4_TINT,
10842b7984aSPete Goodeve 		 B_DARKEN_3_TINT,
10942b7984aSPete Goodeve 		 B_DARKEN_2_TINT,
11042b7984aSPete Goodeve 		 B_DARKEN_1_TINT,
11142b7984aSPete Goodeve 		 B_NO_TINT};
11242b7984aSPete Goodeve 
113*82fbbe21SPete Goodeve 	for (int32 i = 4; i >= 0; i--) {
11442b7984aSPete Goodeve 		rgb_color color;
11542b7984aSPete Goodeve 		if (fMeterLevel > i) {
11642b7984aSPete Goodeve 			color = tint_color(METER_GREEN, kTintArray[i]);
11742b7984aSPete Goodeve 		} else {
11842b7984aSPete Goodeve 			color = METER_GREY;
11942b7984aSPete Goodeve 		}
12042b7984aSPete Goodeve 		view->SetHighColor(color);
12142b7984aSPete Goodeve 		view->FillRect(cell);
12242b7984aSPete Goodeve 		cell.OffsetBy(0, cell.Height() + 1);
12342b7984aSPete Goodeve 	}
12442b7984aSPete Goodeve 
12542b7984aSPete Goodeve 	view->PopState();
12642b7984aSPete Goodeve }
12742b7984aSPete Goodeve 
12842b7984aSPete Goodeve 
12942b7984aSPete Goodeve int32
CalcMeterLevel(int32 eventCount) const13042b7984aSPete Goodeve MidiEventMeter::CalcMeterLevel(int32 eventCount) const
13142b7984aSPete Goodeve {
13242b7984aSPete Goodeve 	// we use an approximately logarithmic scale for determing the actual
13342b7984aSPete Goodeve 	// drawn meter level, so that low-density event streams show up well.
13442b7984aSPete Goodeve 	if (eventCount == 0)
13542b7984aSPete Goodeve 		return 0;
13642b7984aSPete Goodeve 	else if (eventCount < (int32)(0.5 * METER_SCALE))
13742b7984aSPete Goodeve 		return 1;
13842b7984aSPete Goodeve 	else if (eventCount < (int32)(0.75 * METER_SCALE))
13942b7984aSPete Goodeve 		return 2;
14042b7984aSPete Goodeve 	else if (eventCount < (int32)(0.9 * METER_SCALE))
14142b7984aSPete Goodeve 		return 3;
14242b7984aSPete Goodeve 	else if (eventCount < METER_SCALE)
14342b7984aSPete Goodeve 		return 4;
14442b7984aSPete Goodeve 	return 5;
14542b7984aSPete Goodeve }
146