1 /* 2 * Copyright 2005, Jérôme Duval. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Inspired by SoundCapture from Be newsletter (Media Kit Basics: Consumers and Producers) 6 */ 7 8 #include <stdio.h> 9 #include <string.h> 10 #include <Screen.h> 11 #include <Window.h> 12 #include "DrawingTidbits.h" 13 #include "VUView.h" 14 15 const rgb_color back_color = {12, 36, 12}; 16 const rgb_color low_color = {40, 120, 40}; 17 const rgb_color high_color = {240, 255, 240}; 18 19 VUView::VUView(BRect rect, uint32 resizeFlags) 20 : BView(rect, "vumeter", resizeFlags, B_WILL_DRAW), 21 fThreadId(-1), 22 fBitmap(NULL), 23 fQuitting(false) 24 { 25 rect.OffsetTo(B_ORIGIN); 26 fLevelCount = int(rect.Height()) / 2; 27 fChannels = 2; 28 fCurrentLevels = new int32[fChannels]; 29 for (int channel=0; channel < fChannels; channel++) 30 fCurrentLevels[channel] = 0; 31 fBitmap = new BBitmap(rect, BScreen().ColorSpace(), true); 32 33 34 memset(fBitmap->Bits(), 0, fBitmap->BitsLength()); 35 36 fBitmapView = new BView(rect, "bitmapView", B_FOLLOW_LEFT|B_FOLLOW_TOP, B_WILL_DRAW); 37 fBitmap->AddChild(fBitmapView); 38 } 39 40 41 VUView::~VUView() 42 { 43 44 } 45 46 47 void 48 VUView::AttachedToWindow() 49 { 50 SetViewColor(B_TRANSPARENT_COLOR); 51 Run(); 52 } 53 54 55 void 56 VUView::DetachedFromWindow() 57 { 58 Quit(); 59 } 60 61 62 void 63 VUView::Draw(BRect updateRect) 64 { 65 DrawBitmap(fBitmap); 66 67 Sync(); 68 } 69 70 71 void 72 VUView::Run() 73 { 74 fThreadId = spawn_thread(&RenderLaunch, "VU view", B_NORMAL_PRIORITY, this); 75 if (fThreadId < 0) 76 return; 77 resume_thread(fThreadId); 78 } 79 80 void 81 VUView::Quit() 82 { 83 fQuitting = true; 84 snooze(10000); 85 kill_thread(fThreadId); 86 } 87 88 89 90 int32 91 VUView::RenderLaunch(void *data) 92 { 93 VUView *vu = (VUView*) data; 94 vu->RenderLoop(); 95 return B_OK; 96 } 97 98 99 #define SHIFT_UNTIL(value,shift,min) value = (value - shift > min) ? (value - shift) : min 100 101 void 102 VUView::RenderLoop() 103 { 104 rgb_color levels[fLevelCount][2]; 105 106 for (int32 i=0; i<fLevelCount; i++) { 107 levels[i][0] = levels[i][1] = back_color; 108 } 109 110 int32 level = 0; 111 112 while (!fQuitting) { 113 114 /* computing */ 115 for (int32 channel = 0; channel < 2; channel++) { 116 level = fCurrentLevels[channel]; 117 for (int32 i=0; i<level; i++) { 118 if (levels[i][channel].red >= 90) { 119 SHIFT_UNTIL(levels[i][channel].red, 15, low_color.red); 120 SHIFT_UNTIL(levels[i][channel].blue, 15, low_color.blue); 121 } else { 122 SHIFT_UNTIL(levels[i][channel].red, 7, low_color.red); 123 SHIFT_UNTIL(levels[i][channel].blue, 7, low_color.blue); 124 SHIFT_UNTIL(levels[i][channel].green, 14, low_color.green); 125 } 126 } 127 128 levels[level][channel] = high_color; 129 130 for (int32 i=level+1; i<fLevelCount; i++) { 131 if (levels[i][channel].red >= 85) { 132 SHIFT_UNTIL(levels[i][channel].red, 15, back_color.red); 133 SHIFT_UNTIL(levels[i][channel].blue, 15, back_color.blue); 134 } else { 135 SHIFT_UNTIL(levels[i][channel].red, 7, back_color.red); 136 SHIFT_UNTIL(levels[i][channel].blue, 7, back_color.blue); 137 SHIFT_UNTIL(levels[i][channel].green, 14, back_color.green); 138 } 139 } 140 } 141 142 /* rendering */ 143 fBitmap->Lock(); 144 fBitmapView->BeginLineArray(fLevelCount * 2); 145 BPoint start1, end1, start2, end2; 146 start1.x = 3; 147 start2.x = 22; 148 end1.x = 16; 149 end2.x = 35; 150 start1.y = end1.y = start2.y = end2.y = 2; 151 for (int32 i=fLevelCount-1; i>=0; i--) { 152 fBitmapView->AddLine(start1, end1, levels[i][0]); 153 fBitmapView->AddLine(start2, end2, levels[i][1]); 154 start1.y = end1.y = start2.y = end2.y = end2.y + 2; 155 } 156 fBitmapView->EndLineArray(); 157 fBitmap->Unlock(); 158 159 /* ask drawing */ 160 161 if (Window()->LockWithTimeout(5000) == B_OK) { 162 Invalidate(); 163 Window()->Unlock(); 164 snooze(50000); 165 } 166 } 167 } 168 169 170 void 171 VUView::ComputeNextLevel(void *data, size_t size) 172 { 173 int16* samp = (int16*)data; 174 175 for (int32 channel = 0; channel < fChannels; channel++) { 176 177 // get the min and max values in the nibbling interval 178 // and set max to be the greater of the absolute value 179 // of these. 180 181 int mi = 0, ma = 0; 182 for (uint32 ix=channel; ix<size/sizeof(uint16); ix += fChannels) { 183 if (mi > samp[ix]) mi = samp[ix]; 184 else if (ma < samp[ix]) ma = samp[ix]; 185 } 186 if (-ma > mi) ma = (mi == -32768) ? 32767 : -mi; 187 188 uint8 n = ma / (2 << (16-7)); 189 190 fCurrentLevels[channel] = n; 191 if (fCurrentLevels[channel] < 0) 192 fCurrentLevels[channel] = 0; 193 } 194 195 } 196