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: 6 * Consumers and Producers) 7 */ 8 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <MediaDefs.h> 13 #include <Screen.h> 14 #include <Window.h> 15 16 #include "DrawingTidbits.h" 17 #include "VUView.h" 18 19 const rgb_color back_color = {12, 36, 12}; 20 const rgb_color low_color = {40, 120, 40}; 21 const rgb_color high_color = {240, 255, 240}; 22 23 VUView::VUView(BRect rect, uint32 resizeFlags) 24 : BView(rect, "vumeter", resizeFlags, B_WILL_DRAW), 25 fThreadId(-1), 26 fBitmap(NULL), 27 fQuitting(false) 28 { 29 rect.OffsetTo(B_ORIGIN); 30 fLevelCount = int(rect.Height()) / 2; 31 fChannels = 2; 32 fCurrentLevels = new int32[fChannels]; 33 for (int channel = 0; channel < fChannels; channel++) 34 fCurrentLevels[channel] = 0; 35 fBitmap = new BBitmap(rect, BScreen().ColorSpace(), true); 36 37 38 memset(fBitmap->Bits(), 0, fBitmap->BitsLength()); 39 40 fBitmapView = new BView(rect, "bitmapView", B_FOLLOW_LEFT|B_FOLLOW_TOP, 41 B_WILL_DRAW); 42 fBitmap->AddChild(fBitmapView); 43 } 44 45 46 VUView::~VUView() 47 { 48 delete fBitmap; 49 } 50 51 52 void 53 VUView::AttachedToWindow() 54 { 55 SetViewColor(B_TRANSPARENT_COLOR); 56 _Run(); 57 } 58 59 60 void 61 VUView::DetachedFromWindow() 62 { 63 _Quit(); 64 } 65 66 67 void 68 VUView::Draw(BRect updateRect) 69 { 70 DrawBitmap(fBitmap); 71 72 Sync(); 73 } 74 75 76 void 77 VUView::_Run() 78 { 79 fThreadId = spawn_thread(_RenderLaunch, "VU view", B_NORMAL_PRIORITY, this); 80 if (fThreadId < 0) 81 return; 82 resume_thread(fThreadId); 83 } 84 85 void 86 VUView::_Quit() 87 { 88 fQuitting = true; 89 snooze(10000); 90 kill_thread(fThreadId); 91 } 92 93 94 95 int32 96 VUView::_RenderLaunch(void *data) 97 { 98 VUView *vu = (VUView*) data; 99 vu->_RenderLoop(); 100 return B_OK; 101 } 102 103 104 #define SHIFT_UNTIL(value,shift,min) \ 105 value = (value - shift > min) ? (value - shift) : min 106 107 void 108 VUView::_RenderLoop() 109 { 110 rgb_color levels[fLevelCount][2]; 111 112 for (int32 i = 0; i < fLevelCount; i++) { 113 levels[i][0] = levels[i][1] = back_color; 114 } 115 116 while (!fQuitting) { 117 118 /* computing */ 119 for (int32 channel = 0; channel < 2; channel++) { 120 int32 level = fCurrentLevels[channel]; 121 for (int32 i = 0; i < level; i++) { 122 if (levels[i][channel].red >= 90) { 123 SHIFT_UNTIL(levels[i][channel].red, 15, low_color.red); 124 SHIFT_UNTIL(levels[i][channel].blue, 15, low_color.blue); 125 } else { 126 SHIFT_UNTIL(levels[i][channel].red, 7, low_color.red); 127 SHIFT_UNTIL(levels[i][channel].blue, 7, low_color.blue); 128 SHIFT_UNTIL(levels[i][channel].green, 14, low_color.green); 129 } 130 } 131 132 levels[level][channel] = high_color; 133 134 for (int32 i = level + 1; i < fLevelCount; i++) { 135 if (levels[i][channel].red >= 85) { 136 SHIFT_UNTIL(levels[i][channel].red, 15, back_color.red); 137 SHIFT_UNTIL(levels[i][channel].blue, 15, back_color.blue); 138 } else { 139 SHIFT_UNTIL(levels[i][channel].red, 7, back_color.red); 140 SHIFT_UNTIL(levels[i][channel].blue, 7, back_color.blue); 141 SHIFT_UNTIL(levels[i][channel].green, 14, back_color.green); 142 } 143 } 144 } 145 146 /* rendering */ 147 fBitmap->Lock(); 148 fBitmapView->BeginLineArray(fLevelCount * 2); 149 BPoint start1, end1, start2, end2; 150 start1.x = 3; 151 start2.x = 22; 152 end1.x = 16; 153 end2.x = 35; 154 start1.y = end1.y = start2.y = end2.y = 2; 155 for (int32 i = fLevelCount - 1; i >= 0; i--) { 156 fBitmapView->AddLine(start1, end1, levels[i][0]); 157 fBitmapView->AddLine(start2, end2, levels[i][1]); 158 start1.y = end1.y = start2.y = end2.y = end2.y + 2; 159 } 160 fBitmapView->EndLineArray(); 161 fBitmap->Unlock(); 162 163 /* ask drawing */ 164 165 if (Window()->LockWithTimeout(5000) == B_OK) { 166 Invalidate(); 167 Window()->Unlock(); 168 snooze(50000); 169 } 170 } 171 } 172 173 174 template<typename T> 175 T 176 VUView::_ComputeNextLevel(void *data, size_t size, uint32 format, int32 channel) 177 { 178 T* samp = (T*)data; 179 180 // get the min and max values in the nibbling interval 181 // and set max to be the greater of the absolute value 182 // of these. 183 184 T min = 0, max = 0; 185 for (uint32 i = channel; i < size/sizeof(T); i += fChannels) { 186 if (min > samp[i]) 187 min = samp[i]; 188 else if (max < samp[i]) 189 max = samp[i]; 190 } 191 if (-max > (min + 1)) 192 max = -min; 193 194 return max; 195 } 196 197 198 void 199 VUView::ComputeLevels(void* data, size_t size, uint32 format) 200 { 201 for (int32 channel = 0; channel < fChannels; channel++) { 202 switch (format) { 203 case media_raw_audio_format::B_AUDIO_FLOAT: 204 { 205 float max = _ComputeNextLevel<float>(data, size, format, 206 channel); 207 fCurrentLevels[channel] = (uint8)(max * 127); 208 break; 209 } 210 case media_raw_audio_format::B_AUDIO_INT: 211 { 212 int32 max = _ComputeNextLevel<int32>(data, size, format, 213 channel); 214 fCurrentLevels[channel] = max / (2 << (32-7)); 215 break; 216 } 217 case media_raw_audio_format::B_AUDIO_SHORT: 218 { 219 int16 max = _ComputeNextLevel<int16>(data, size, format, 220 channel); 221 fCurrentLevels[channel] = max / (2 << (16-7)); 222 break; 223 } 224 case media_raw_audio_format::B_AUDIO_UCHAR: 225 { 226 uchar max = _ComputeNextLevel<uchar>(data, size, format, 227 channel); 228 fCurrentLevels[channel] = max / 2 - 127; 229 break; 230 } 231 case media_raw_audio_format::B_AUDIO_CHAR: 232 { 233 char max = _ComputeNextLevel<char>(data, size, format, 234 channel); 235 fCurrentLevels[channel] = max / 2; 236 break; 237 } 238 } 239 if (fCurrentLevels[channel] < 0) 240 fCurrentLevels[channel] = 0; 241 } 242 } 243