1// MidiEventMeter.cpp 2// ------------------ 3// Implements the MidiEventMeter class. 4// 5// Copyright 1999, Be Incorporated. All Rights Reserved. 6// This file may be used under the terms of the Be Sample Code License. 7 8#include <stdio.h> 9#include <MidiRoster.h> 10#include <MidiProducer.h> 11#include <MidiConsumer.h> 12#include <View.h> 13#include "CountEventConsumer.h" 14#include "MidiEventMeter.h" 15 16static const BRect METER_BOUNDS(0,0,7,31); 17 18// If we get this number of events per pulse or greater, we will 19// max out the event meter. 20// Value was determined empirically based on my banging on a MIDI 21// keyboard controller with a pulse of 200ms. 22static const int32 METER_SCALE = 10; 23 24MidiEventMeter::MidiEventMeter(int32 producerID) 25 : m_counter(NULL), m_meterLevel(0) 26{ 27 BMidiRoster* roster = BMidiRoster::MidiRoster(); 28 if (roster) { 29 BMidiProducer* producer = roster->FindProducer(producerID); 30 if (producer) { 31 BString name; 32 name << producer->Name() << " Event Meter"; 33 m_counter = new CountEventConsumer(name.String()); 34 producer->Connect(m_counter); 35 producer->Release(); 36 } 37 } 38} 39 40MidiEventMeter::~MidiEventMeter() 41{ 42 if (m_counter) m_counter->Release(); 43} 44 45void MidiEventMeter::Pulse(BView* view) 46{ 47 int32 newLevel = m_meterLevel; 48 if (m_counter) { 49 newLevel = CalcMeterLevel(m_counter->CountEvents()); 50 m_counter->Reset(); 51 } 52 if (newLevel != m_meterLevel) { 53 m_meterLevel = newLevel; 54 view->Invalidate(BRect(METER_BOUNDS).InsetBySelf(1,1)); 55 } 56} 57 58BRect MidiEventMeter::Bounds() const 59{ 60 return METER_BOUNDS; 61} 62 63void MidiEventMeter::Draw(BView* view) 64{ 65 const rgb_color METER_BLACK = { 0, 0, 0, 255 }; 66 const rgb_color METER_GREY = { 180, 180, 180, 255 }; 67 const rgb_color METER_GREEN = { 0, 255, 0, 255 }; 68 69 view->PushState(); 70 71 // draw the frame 72 BPoint lt = METER_BOUNDS.LeftTop(); 73 BPoint rb = METER_BOUNDS.RightBottom(); 74 view->BeginLineArray(4); 75 view->AddLine(BPoint(lt.x, lt.y), BPoint(rb.x - 1, lt.y), METER_BLACK); 76 view->AddLine(BPoint(rb.x, lt.y), BPoint(rb.x, rb.y - 1), METER_BLACK); 77 view->AddLine(BPoint(rb.x, rb.y), BPoint(lt.x + 1, rb.y), METER_BLACK); 78 view->AddLine(BPoint(lt.x, rb.y), BPoint(lt.x, lt.y + 1), METER_BLACK); 79 view->EndLineArray(); 80 81 // draw the cells 82 BRect cell = METER_BOUNDS; 83 cell.InsetBy(1,1); 84 cell.bottom = cell.top + (cell.Height() + 1) / 5; 85 cell.bottom--; 86 87 const float kTintArray[] = { B_DARKEN_4_TINT, B_DARKEN_3_TINT, B_DARKEN_2_TINT, B_DARKEN_1_TINT, B_NO_TINT }; 88 89 for (int32 i=4; i>=0; i--) 90 { 91 rgb_color color; 92 if (m_meterLevel > i) { 93 color = tint_color(METER_GREEN, kTintArray[i]); 94 } else { 95 color = METER_GREY; 96 } 97 view->SetHighColor(color); 98 view->FillRect(cell); 99 cell.OffsetBy(0, cell.Height() + 1); 100 } 101 102 view->PopState(); 103} 104 105int32 MidiEventMeter::CalcMeterLevel(int32 eventCount) const 106{ 107 // we use an approximately logarithmic scale for determing the actual 108 // drawn meter level, so that low-density event streams show up well. 109 if (eventCount == 0) { 110 return 0; 111 } else if (eventCount < (int32)(.5*METER_SCALE)) { 112 return 1; 113 } else if (eventCount < (int32)(.75*METER_SCALE)) { 114 return 2; 115 } else if (eventCount < (int32)(.9*METER_SCALE)) { 116 return 3; 117 } else if (eventCount < METER_SCALE) { 118 return 4; 119 } else { 120 return 5; 121 } 122} 123