1 /* 2 * Copyright (c) 2004 Matthijs Hollemans 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <Synth.h> 24 #include <Window.h> 25 26 #include "ScopeView.h" 27 28 //------------------------------------------------------------------------------ 29 30 ScopeView::ScopeView() 31 : BView(BRect(0, 0, 180, 63), NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, 32 B_WILL_DRAW) 33 { 34 SetViewColor(0, 0, 0); 35 36 playing = false; 37 enabled = true; 38 haveFile = false; 39 loading = false; 40 liveInput = false; 41 42 sampleCount = (int32) Bounds().Width(); 43 leftSamples = new int16[sampleCount]; 44 rightSamples = new int16[sampleCount]; 45 } 46 47 //------------------------------------------------------------------------------ 48 49 ScopeView::~ScopeView() 50 { 51 delete[] leftSamples; 52 delete[] rightSamples; 53 } 54 55 //------------------------------------------------------------------------------ 56 57 void ScopeView::AttachedToWindow() 58 { 59 finished = false; 60 threadId = spawn_thread(_Thread, "ScopeThread", B_NORMAL_PRIORITY, this); 61 if (threadId >= B_OK) 62 { 63 resume_thread(threadId); 64 } 65 } 66 67 //------------------------------------------------------------------------------ 68 69 void ScopeView::DetachedFromWindow() 70 { 71 if (threadId >= B_OK) 72 { 73 finished = true; 74 status_t exitValue; 75 wait_for_thread(threadId, &exitValue); 76 } 77 } 78 79 //------------------------------------------------------------------------------ 80 81 void ScopeView::Draw(BRect updateRect) 82 { 83 super::Draw(updateRect); 84 85 if (loading) 86 { 87 DrawLoading(); 88 } 89 else if (!haveFile && !liveInput) 90 { 91 DrawNoFile(); 92 } 93 else if (!enabled) 94 { 95 DrawDisabled(); 96 } 97 else if (playing || liveInput) 98 { 99 DrawPlaying(); 100 } 101 else 102 { 103 DrawStopped(); 104 } 105 } 106 107 //------------------------------------------------------------------------------ 108 109 void ScopeView::SetPlaying(bool flag) 110 { 111 playing = flag; 112 } 113 114 //------------------------------------------------------------------------------ 115 116 void ScopeView::SetEnabled(bool flag) 117 { 118 enabled = flag; 119 } 120 121 //------------------------------------------------------------------------------ 122 123 void ScopeView::SetHaveFile(bool flag) 124 { 125 haveFile = flag; 126 } 127 128 //------------------------------------------------------------------------------ 129 130 void ScopeView::SetLoading(bool flag) 131 { 132 loading = flag; 133 } 134 135 //------------------------------------------------------------------------------ 136 137 void ScopeView::SetLiveInput(bool flag) 138 { 139 liveInput = flag; 140 } 141 142 //------------------------------------------------------------------------------ 143 144 int32 ScopeView::_Thread(void* data) 145 { 146 return ((ScopeView*) data)->Thread(); 147 } 148 149 //------------------------------------------------------------------------------ 150 151 int32 ScopeView::Thread() 152 { 153 // Because Pulse() was too slow, I created a thread that tells the 154 // ScopeView to repaint itself. Note that we need to call LockLooper 155 // with a timeout, otherwise we'll deadlock in DetachedFromWindow(). 156 157 while (!finished) 158 { 159 if (enabled && (playing || liveInput)) 160 { 161 if (LockLooperWithTimeout(50000) == B_OK) 162 { 163 Invalidate(); 164 UnlockLooper(); 165 } 166 } 167 snooze(50000); 168 } 169 return 0; 170 } 171 172 //------------------------------------------------------------------------------ 173 174 void ScopeView::DrawLoading() 175 { 176 DrawText("Loading instruments" B_UTF8_ELLIPSIS); 177 } 178 179 //------------------------------------------------------------------------------ 180 181 void ScopeView::DrawNoFile() 182 { 183 DrawText("Drop MIDI file here"); 184 } 185 186 //------------------------------------------------------------------------------ 187 188 void ScopeView::DrawDisabled() 189 { 190 SetHighColor(64, 64, 64); 191 192 StrokeLine( 193 BPoint(0, Bounds().Height() / 2), 194 BPoint(Bounds().Width(), Bounds().Height() / 2)); 195 } 196 197 //------------------------------------------------------------------------------ 198 199 void ScopeView::DrawStopped() 200 { 201 SetHighColor(0, 130, 0); 202 203 StrokeLine( 204 BPoint(0, Bounds().Height() / 2), 205 BPoint(Bounds().Width(), Bounds().Height() / 2)); 206 } 207 208 //------------------------------------------------------------------------------ 209 210 void ScopeView::DrawPlaying() 211 { 212 int32 width = (int32) Bounds().Width(); 213 int32 height = (int32) Bounds().Height(); 214 215 // Scope drawing magic based on code by Michael Pfeiffer. 216 217 int32 size = be_synth->GetAudio(leftSamples, rightSamples, sampleCount); 218 if (size > 0) 219 { 220 SetHighColor(255, 0, 130); 221 SetLowColor(0, 130, 0); 222 #define N 16 223 int32 x, y, sx = 0, f = (height << N) / 65535, dy = height / 2 + 1; 224 for (int32 i = 0; i < width; i++) 225 { 226 x = sx / width; 227 y = ((leftSamples[x] * f) >> N) + dy; 228 FillRect(BRect(i, y, i, y)); 229 y = ((rightSamples[x] * f) >> N) + dy; 230 FillRect(BRect(i, y, i, y), B_SOLID_LOW); 231 sx += size; 232 } 233 } 234 } 235 236 //------------------------------------------------------------------------------ 237 238 void ScopeView::DrawText(const char* text) 239 { 240 font_height height; 241 GetFontHeight(&height); 242 243 float strWidth = StringWidth(text); 244 float strHeight = height.ascent + height.descent; 245 246 float x = (Bounds().Width() - strWidth)/2; 247 float y = height.ascent + (Bounds().Height() - strHeight)/2; 248 249 SetHighColor(255, 255, 255); 250 SetLowColor(ViewColor()); 251 SetDrawingMode(B_OP_OVER); 252 253 DrawString(text, BPoint(x, y)); 254 } 255 256 //------------------------------------------------------------------------------ 257