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