xref: /haiku/src/apps/soundrecorder/ScopeView.cpp (revision 0b2dbe7d46ee888392907c60131b7f7652314175)
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 "ScopeView.h"
14 
15 
16 ScopeView::ScopeView(BRect rect, uint32 resizeFlags)
17 	: BView(rect, "vumeter", resizeFlags, B_WILL_DRAW | B_FRAME_EVENTS),
18 	fThreadId(-1),
19 	fBitmap(NULL),
20 	fIsRendering(false),
21 	fMediaTrack(NULL),
22 	fQuitting(false),
23 	fMainTime(0),
24 	fRightTime(1000000),
25 	fLeftTime(0),
26 	fTotalTime(1000000)
27 {
28 	fBitmap = new BBitmap(rect, BScreen().ColorSpace(), true);
29 	memset(fBitmap->Bits(), 0, fBitmap->BitsLength());
30 
31 	rect.OffsetToSelf(B_ORIGIN);
32 	rect.right -= 2;
33 	fBitmapView = new BView(rect.OffsetToSelf(B_ORIGIN), "bitmapView", B_FOLLOW_LEFT|B_FOLLOW_TOP, B_WILL_DRAW);
34 	fBitmap->AddChild(fBitmapView);
35 
36 	fRenderSem = create_sem(0, "scope rendering");
37 	fHeight = Bounds().Height();
38 }
39 
40 
41 ScopeView::~ScopeView()
42 {
43 	delete_sem(fRenderSem);
44 }
45 
46 
47 void
48 ScopeView::AttachedToWindow()
49 {
50 	SetViewColor(B_TRANSPARENT_COLOR);
51 	Run();
52 }
53 
54 
55 void
56 ScopeView::DetachedFromWindow()
57 {
58 	Quit();
59 }
60 
61 
62 void
63 ScopeView::Draw(BRect updateRect)
64 {
65 	BRect bounds = Bounds();
66 	if (!fIsRendering)
67 		DrawBitmapAsync(fBitmap, BPoint(2,0));
68 
69 	float x = 2;
70 	if (fTotalTime !=0)
71 		x = 2 + (fMainTime - fLeftTime) * (bounds.right - 2) / (fRightTime - fLeftTime);
72 	SetHighColor(60,255,40);
73 	StrokeLine(BPoint(x, bounds.top), BPoint(x, bounds.bottom));
74 
75 	Sync();
76 }
77 
78 
79 void
80 ScopeView::Run()
81 {
82 	fThreadId = spawn_thread(&RenderLaunch, "Scope view", B_NORMAL_PRIORITY, this);
83 	if (fThreadId < 0)
84 		return;
85 	resume_thread(fThreadId);
86 }
87 
88 void
89 ScopeView::Quit()
90 {
91 	delete_sem(fRenderSem);
92 	fQuitting = true;
93 	snooze(10000);
94 	kill_thread(fThreadId);
95 }
96 
97 
98 
99 int32
100 ScopeView::RenderLaunch(void *data)
101 {
102 	ScopeView *scope = (ScopeView*) data;
103 	scope->RenderLoop();
104 	return B_OK;
105 }
106 
107 
108 void
109 ScopeView::RenderLoop()
110 {
111 
112 	while (!fQuitting) {
113 
114 		if (acquire_sem(fRenderSem)!=B_OK)
115 			continue;
116 
117 		fIsRendering = true;
118 
119 		int32 frame_size = (fPlayFormat.u.raw_audio.format & 0xf) * fPlayFormat.u.raw_audio.channel_count;
120 		int64 totalFrames = fMediaTrack->CountFrames();
121 		int16 samples[fPlayFormat.u.raw_audio.buffer_size / (fPlayFormat.u.raw_audio.format & 0xf)];
122 		int64 frames = 0;
123 		int64 sum = 0;
124 		int64 framesIndex = 0;
125 		int32 sumCount = 0;
126 		fMediaTrack->SeekToFrame(&frames);
127 
128 		printf("begin computing\n");
129 
130 		int32 previewIndex = 0;
131 
132 		while (fMediaTrack->ReadFrames(samples, &frames) == B_OK) {
133 			//printf("reading block\n");
134 			framesIndex = 0;
135 
136 			while (framesIndex < frames) {
137 
138 				for (; framesIndex < frames && sumCount < totalFrames/20000; framesIndex++, sumCount++) {
139 					sum += samples[2*framesIndex];
140 					sum += samples[2*framesIndex+1];
141 				}
142 
143 				if (previewIndex >= 20000) {
144 					break;
145 				}
146 
147 				if (sumCount >= totalFrames/20000) {
148 					//printf("computing block %ld, sumCount %ld\n", previewIndex, sumCount);
149 					fPreview[previewIndex++] = (int32)(sum / 2 /(totalFrames/20000) / 32767.0 * fHeight / 2 + fHeight / 2);
150 					sumCount = 0;
151 					sum = 0;
152 				}
153 			}
154 
155 
156 		}
157 
158 		printf("finished computing\n");
159 
160 		/* rendering */
161 		RenderBitmap();
162 
163 		/* ask drawing */
164 
165 		fIsRendering = false;
166 
167 		if (Window()->LockWithTimeout(5000) == B_OK) {
168 			Invalidate();
169 			Window()->Unlock();
170 		}
171 	}
172 }
173 
174 
175 void
176 ScopeView::SetMainTime(bigtime_t timestamp)
177 {
178 	fMainTime = timestamp;
179 	Invalidate();
180 }
181 
182 
183 void
184 ScopeView::SetTotalTime(bigtime_t timestamp)
185 {
186 	fTotalTime = timestamp;
187 	Invalidate();
188 }
189 
190 void
191 ScopeView::SetLeftTime(bigtime_t timestamp)
192 {
193 	fLeftTime = timestamp;
194 	RenderBitmap();
195 	Invalidate();
196 }
197 
198 void
199 ScopeView::SetRightTime(bigtime_t timestamp)
200 {
201 	fRightTime = timestamp;
202 	RenderBitmap();
203 	Invalidate();
204 }
205 
206 
207 void
208 ScopeView::RenderTrack(BMediaTrack *track, media_format format)
209 {
210 	fMediaTrack = track;
211 	fPlayFormat = format;
212 	release_sem(fRenderSem);
213 }
214 
215 
216 void
217 ScopeView::FrameResized(float width, float height)
218 {
219 	InitBitmap();
220 	RenderBitmap();
221 	Invalidate();
222 }
223 
224 
225 void
226 ScopeView::InitBitmap()
227 {
228 	if (fBitmapView) {
229 		fBitmap->RemoveChild(fBitmapView);
230 		delete fBitmapView;
231 	}
232 	if (fBitmap)
233 		delete fBitmap;
234 
235 	BRect rect = Bounds();
236 
237 	fBitmap = new BBitmap(rect, BScreen().ColorSpace(), true);
238 	memset(fBitmap->Bits(), 0, fBitmap->BitsLength());
239 
240 	rect.OffsetToSelf(B_ORIGIN);
241 	rect.right -= 2;
242 	fBitmapView = new BView(rect.OffsetToSelf(B_ORIGIN), "bitmapView", B_FOLLOW_LEFT|B_FOLLOW_TOP, B_WILL_DRAW);
243 	fBitmap->AddChild(fBitmapView);
244 }
245 
246 
247 void
248 ScopeView::RenderBitmap()
249 {
250 	if (!fMediaTrack)
251 		return;
252 
253 	/* rendering */
254 	fBitmap->Lock();
255 	memset(fBitmap->Bits(), 0, fBitmap->BitsLength());
256 	float width = fBitmapView->Bounds().Width();
257 
258 	fBitmapView->SetDrawingMode(B_OP_ADD);
259 	fBitmapView->SetHighColor(15,60,15);
260 	int32 leftIndex = (fTotalTime != 0) ? fLeftTime * 20000 / fTotalTime : 0;
261 	int32 rightIndex = (fTotalTime != 0) ? fRightTime * 20000 / fTotalTime : 20000;
262 
263 	for (int32 i = leftIndex; i<rightIndex; i++) {
264 		BPoint point((i - leftIndex) * width / (rightIndex - leftIndex), fPreview[i]);
265 		//printf("point x %f y %f\n", point.x, point.y);
266 		fBitmapView->StrokeLine(point, point);
267 	}
268 
269 	fBitmap->Unlock();
270 }
271 
272