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