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