2 * Copyright 2005, Jérôme Duval. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Inspired by SoundCapture from Be newsletter (Media Kit Basics:
6 * Consumers and Producers)
12 #include <MediaDefs.h>
14 #include <StackOrHeapArray.h>
17 #include "DrawingTidbits.h"
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};
24 VUView::VUView(BRect rect
, uint32 resizeFlags
)
25 : BView(rect
, "vumeter", resizeFlags
, B_WILL_DRAW
),
30 rect
.OffsetTo(B_ORIGIN
);
31 fLevelCount
= int(rect
.Height()) / 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);
39 memset(fBitmap
->Bits(), 0, fBitmap
->BitsLength());
41 fBitmapView
= new BView(rect
, "bitmapView", B_FOLLOW_LEFT
|B_FOLLOW_TOP
,
43 fBitmap
->AddChild(fBitmapView
);
54 VUView::AttachedToWindow()
56 SetViewColor(B_TRANSPARENT_COLOR
);
62 VUView::DetachedFromWindow()
69 VUView::Draw(BRect updateRect
)
80 fThreadId
= spawn_thread(_RenderLaunch
, "VU view", B_NORMAL_PRIORITY
,
84 resume_thread(fThreadId
);
92 kill_thread(fThreadId
);
98 VUView::_RenderLaunch(void *data
)
100 VUView
*vu
= (VUView
*) data
;
106 #define SHIFT_UNTIL(value,shift,min) \
107 value = (value - shift > min) ? (value - shift) : min
110 VUView::_RenderLoop()
112 BStackOrHeapArray
<rgb_color
[2], 64> levels(fLevelCount
);
114 for (int32 i
= 0; i
< fLevelCount
; i
++) {
115 levels
[i
][0] = levels
[i
][1] = back_color
;
121 for (int32 channel
= 0; channel
< 2; channel
++) {
122 int32 level
= fCurrentLevels
[channel
];
123 for (int32 i
= 0; i
< level
; i
++) {
124 if (levels
[i
][channel
].red
>= 90) {
125 SHIFT_UNTIL(levels
[i
][channel
].red
, 15, low_color
.red
);
126 SHIFT_UNTIL(levels
[i
][channel
].blue
, 15, low_color
.blue
);
128 SHIFT_UNTIL(levels
[i
][channel
].red
, 7, low_color
.red
);
129 SHIFT_UNTIL(levels
[i
][channel
].blue
, 7, low_color
.blue
);
130 SHIFT_UNTIL(levels
[i
][channel
].green
, 14, low_color
.green
);
134 levels
[level
][channel
] = high_color
;
136 for (int32 i
= level
+ 1; i
< fLevelCount
; i
++) {
137 if (levels
[i
][channel
].red
>= 85) {
138 SHIFT_UNTIL(levels
[i
][channel
].red
, 15, back_color
.red
);
139 SHIFT_UNTIL(levels
[i
][channel
].blue
, 15, back_color
.blue
);
141 SHIFT_UNTIL(levels
[i
][channel
].red
, 7, back_color
.red
);
142 SHIFT_UNTIL(levels
[i
][channel
].blue
, 7, back_color
.blue
);
143 SHIFT_UNTIL(levels
[i
][channel
].green
, 14,
151 fBitmapView
->BeginLineArray(fLevelCount
* 2);
152 BPoint start1
, end1
, start2
, end2
;
157 start1
.y
= end1
.y
= start2
.y
= end2
.y
= 2;
158 for (int32 i
= fLevelCount
- 1; i
>= 0; i
--) {
159 fBitmapView
->AddLine(start1
, end1
, levels
[i
][0]);
160 fBitmapView
->AddLine(start2
, end2
, levels
[i
][1]);
161 start1
.y
= end1
.y
= start2
.y
= end2
.y
= end2
.y
+ 2;
163 fBitmapView
->EndLineArray();
168 if (Window()->LockWithTimeout(5000) == B_OK
) {
179 VUView::_ComputeNextLevel(const void *data
, size_t size
, uint32 format
,
182 const T
* samp
= (const T
*)data
;
184 // get the min and max values in the nibbling interval
185 // and set max to be the greater of the absolute value
189 for (uint32 i
= channel
; i
< size
/sizeof(T
); i
+= fChannels
) {
192 else if (max
< samp
[i
])
195 if (-max
> (min
+ 1))
203 VUView::ComputeLevels(const void* data
, size_t size
, uint32 format
)
205 for (int32 channel
= 0; channel
< fChannels
; channel
++) {
207 case media_raw_audio_format::B_AUDIO_FLOAT
:
209 float max
= _ComputeNextLevel
<float>(data
, size
, format
,
211 fCurrentLevels
[channel
] = (uint8
)(max
* 127);
214 case media_raw_audio_format::B_AUDIO_INT
:
216 int32 max
= _ComputeNextLevel
<int32
>(data
, size
, format
,
218 fCurrentLevels
[channel
] = max
/ (2 << (32-7));
221 case media_raw_audio_format::B_AUDIO_SHORT
:
223 int16 max
= _ComputeNextLevel
<int16
>(data
, size
, format
,
225 fCurrentLevels
[channel
] = max
/ (2 << (16-7));
228 case media_raw_audio_format::B_AUDIO_UCHAR
:
230 uchar max
= _ComputeNextLevel
<uchar
>(data
, size
, format
,
232 fCurrentLevels
[channel
] = max
/ 2 - 127;
235 case media_raw_audio_format::B_AUDIO_CHAR
:
237 char max
= _ComputeNextLevel
<char>(data
, size
, format
,
239 fCurrentLevels
[channel
] = max
/ 2;
243 if (fCurrentLevels
[channel
] < 0)
244 fCurrentLevels
[channel
] = 0;