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 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 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 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 7542b7984aSPete Goodeve MidiEventMeter::Bounds() const 7642b7984aSPete Goodeve { 7742b7984aSPete Goodeve return METER_BOUNDS; 7842b7984aSPete Goodeve } 7942b7984aSPete Goodeve 8042b7984aSPete Goodeve 8142b7984aSPete Goodeve void 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 13042b7984aSPete 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