xref: /haiku/src/apps/soundrecorder/VUView.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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