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