xref: /haiku/src/apps/midiplayer/ScopeView.cpp (revision e221c09e508ffc3c62738140c9b6fc4fa211662a)
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, 127, 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