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