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 <Catalog.h> 24 #include <Locale.h> 25 #include <Synth.h> 26 #include <Window.h> 27 28 #include "ScopeView.h" 29 30 #undef B_TRANSLATION_CONTEXT 31 #define B_TRANSLATION_CONTEXT "Scope View" 32 33 34 //------------------------------------------------------------------------------ 35 36 ScopeView::ScopeView() 37 : BView(BRect(0, 0, 180, 63), NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, 38 B_WILL_DRAW) 39 { 40 SetViewColor(0, 0, 0); 41 42 playing = false; 43 enabled = true; 44 haveFile = false; 45 loading = false; 46 liveInput = false; 47 48 sampleCount = (int32) Bounds().Width(); 49 leftSamples = new int16[sampleCount]; 50 rightSamples = new int16[sampleCount]; 51 } 52 53 //------------------------------------------------------------------------------ 54 55 ScopeView::~ScopeView() 56 { 57 delete[] leftSamples; 58 delete[] rightSamples; 59 } 60 61 //------------------------------------------------------------------------------ 62 63 void ScopeView::AttachedToWindow() 64 { 65 finished = false; 66 threadId = spawn_thread(_Thread, "ScopeThread", B_NORMAL_PRIORITY, this); 67 if (threadId >= B_OK) 68 { 69 resume_thread(threadId); 70 } 71 } 72 73 //------------------------------------------------------------------------------ 74 75 void ScopeView::DetachedFromWindow() 76 { 77 if (threadId >= B_OK) 78 { 79 finished = true; 80 status_t exitValue; 81 wait_for_thread(threadId, &exitValue); 82 } 83 } 84 85 //------------------------------------------------------------------------------ 86 87 void ScopeView::Draw(BRect updateRect) 88 { 89 super::Draw(updateRect); 90 91 if (loading) 92 { 93 DrawLoading(); 94 } 95 else if (!haveFile && !liveInput) 96 { 97 DrawNoFile(); 98 } 99 else if (!enabled) 100 { 101 DrawDisabled(); 102 } 103 else if (playing || liveInput) 104 { 105 DrawPlaying(); 106 } 107 else 108 { 109 DrawStopped(); 110 } 111 } 112 113 //------------------------------------------------------------------------------ 114 115 void ScopeView::SetPlaying(bool flag) 116 { 117 playing = flag; 118 } 119 120 //------------------------------------------------------------------------------ 121 122 void ScopeView::SetEnabled(bool flag) 123 { 124 enabled = flag; 125 } 126 127 //------------------------------------------------------------------------------ 128 129 void ScopeView::SetHaveFile(bool flag) 130 { 131 haveFile = flag; 132 } 133 134 //------------------------------------------------------------------------------ 135 136 void ScopeView::SetLoading(bool flag) 137 { 138 loading = flag; 139 } 140 141 //------------------------------------------------------------------------------ 142 143 void ScopeView::SetLiveInput(bool flag) 144 { 145 liveInput = flag; 146 } 147 148 //------------------------------------------------------------------------------ 149 150 int32 ScopeView::_Thread(void* data) 151 { 152 return ((ScopeView*) data)->Thread(); 153 } 154 155 //------------------------------------------------------------------------------ 156 157 int32 ScopeView::Thread() 158 { 159 // Because Pulse() was too slow, I created a thread that tells the 160 // ScopeView to repaint itself. Note that we need to call LockLooper 161 // with a timeout, otherwise we'll deadlock in DetachedFromWindow(). 162 163 while (!finished) 164 { 165 if (enabled && (playing || liveInput)) 166 { 167 if (LockLooperWithTimeout(50000) == B_OK) 168 { 169 Invalidate(); 170 UnlockLooper(); 171 } 172 } 173 snooze(50000); 174 } 175 return 0; 176 } 177 178 //------------------------------------------------------------------------------ 179 180 void ScopeView::DrawLoading() 181 { 182 DrawText("Loading instruments" B_UTF8_ELLIPSIS); 183 } 184 185 //------------------------------------------------------------------------------ 186 187 void ScopeView::DrawNoFile() 188 { 189 DrawText(B_TRANSLATE("Drop MIDI file here")); 190 } 191 192 //------------------------------------------------------------------------------ 193 194 void ScopeView::DrawDisabled() 195 { 196 SetHighColor(64, 64, 64); 197 198 StrokeLine( 199 BPoint(0, Bounds().Height() / 2), 200 BPoint(Bounds().Width(), Bounds().Height() / 2)); 201 } 202 203 //------------------------------------------------------------------------------ 204 205 void ScopeView::DrawStopped() 206 { 207 SetHighColor(0, 130, 0); 208 209 StrokeLine( 210 BPoint(0, Bounds().Height() / 2), 211 BPoint(Bounds().Width(), Bounds().Height() / 2)); 212 } 213 214 //------------------------------------------------------------------------------ 215 216 void ScopeView::DrawPlaying() 217 { 218 int32 width = (int32) Bounds().Width(); 219 int32 height = (int32) Bounds().Height(); 220 221 // Scope drawing magic based on code by Michael Pfeiffer. 222 223 int32 size = be_synth->GetAudio(leftSamples, rightSamples, sampleCount); 224 if (size > 0) 225 { 226 SetHighColor(255, 0, 130); 227 SetLowColor(0, 130, 0); 228 #define N 16 229 int32 x, y, sx = 0, f = (height << N) / 65535, dy = height / 2 + 1; 230 for (int32 i = 0; i < width; i++) 231 { 232 x = sx / width; 233 y = ((leftSamples[x] * f) >> N) + dy; 234 FillRect(BRect(i, y, i, y)); 235 y = ((rightSamples[x] * f) >> N) + dy; 236 FillRect(BRect(i, y, i, y), B_SOLID_LOW); 237 sx += size; 238 } 239 } 240 } 241 242 //------------------------------------------------------------------------------ 243 244 void ScopeView::DrawText(const char* text) 245 { 246 font_height height; 247 GetFontHeight(&height); 248 249 float strWidth = StringWidth(text); 250 float strHeight = height.ascent + height.descent; 251 252 float x = (Bounds().Width() - strWidth)/2; 253 float y = height.ascent + (Bounds().Height() - strHeight)/2; 254 255 SetHighColor(255, 255, 255); 256 SetLowColor(ViewColor()); 257 SetDrawingMode(B_OP_OVER); 258 259 DrawString(text, BPoint(x, y)); 260 } 261 262 //------------------------------------------------------------------------------ 263