1 /*  LoopWidget
2  *  Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include "Fl_Loop.h"
20 #include <iostream>
21 #include <FL/fl_draw.H>
22 #include <FL/x.H>
23 #include <math.h>
24 
25 /////////////////////////////////////////////////////////////////////////////
26 
27 static const float NORM  = ((1.0f)/(32767.0f));
28 static const int   REZ   = 1000;
29 static const float RADCONV = 0.017453292;
30 static const int   INDW = 3; // indicator width
31 static const int   UPDATECYCLES = 4;
32 
Fl_Loop(int x,int y,int w,int h,const char * label)33 Fl_Loop::Fl_Loop(int x, int y, int w, int h, const char* label) :
34 Fl_Double_Window(x,y,w,h,label),
35 m_data(NULL),
36 m_MainWin(NULL),
37 m_Length(1000),
38 m_InnerRad((int)(w/2*0.75f)),
39 m_OuterRad((int)(w/2*0.95f)),
40 m_BorderRad(w/2),
41 m_IndSX(0),
42 m_IndSY(0),
43 m_IndEX(0),
44 m_IndEY(0),
45 m_StartAngle(0),
46 m_EndAngle(1),
47 m_MoveAngle(0.0f),
48 m_RangeStart(0),
49 m_RangeEnd(0),
50 m_Angle(0),
51 m_Pos(NULL),
52 m_Update(false),
53 m_StopUpdate(false),
54 m_WaveSize(1.0f),
55 m_Move(0),
56 m_LastMove(0),
57 m_Snap(false),
58 m_SnapDegrees(45)
59 {
60 	SetIdle();
61 	m_MidX=(w/2);
62 	m_MidY=(h/2);
63 }
64 
SetIdle()65 void Fl_Loop::SetIdle()
66 {
67 	//Fl::add_idle(&Fl_Loop::cb_Idle,this);
68 }
UnsetIdle()69 void Fl_Loop::UnsetIdle()
70 {
71 	Fl::remove_idle(&Fl_Loop::cb_Idle,this);
72 }
73 
SetupCopyBufFuncs(cb_CopyBuf1 * Cut,cb_CopyBuf1 * Copy,cb_CopyBuf2 * Paste,cb_CopyBuf2 * PasteMix,cb_CopyBuf1 * ZeroRange,cb_CopyBuf1 * ReverseRange,cb_CopyBuf1 * Halve,cb_CopyBuf1 * Hold,cb_CopyBuf1 * SelectAll,cb_CopyBuf1 * NewTrigger,cb_CopyBuf1 * Move)74 void Fl_Loop::SetupCopyBufFuncs(cb_CopyBuf1 *Cut,
75 					   cb_CopyBuf1 *Copy,
76 					   cb_CopyBuf2 *Paste,
77 					   cb_CopyBuf2 *PasteMix,
78 					   cb_CopyBuf1 *ZeroRange,
79 					   cb_CopyBuf1 *ReverseRange,
80 					   cb_CopyBuf1 *Halve,
81 					   cb_CopyBuf1 *Hold,
82 					   cb_CopyBuf1 *SelectAll,
83 					   cb_CopyBuf1 *NewTrigger,
84 					   cb_CopyBuf1 *Move)
85 
86 {
87 	cb_Cut = Cut;
88 	cb_Copy = Copy;
89 	cb_Paste = Paste;
90 	cb_PasteMix = PasteMix;
91 	cb_ZeroRange = ZeroRange;
92 	cb_ReverseRange = ReverseRange;
93 	cb_Halve = Halve;
94 	cb_Hold = Hold;
95 	cb_SelectAll = SelectAll;
96 	cb_NewTrigger = NewTrigger;
97 	cb_Move = Move;
98 }
99 
100 
101 
SetLength(const int Len)102 void Fl_Loop::SetLength(const int Len)
103 {
104 	m_Length=Len;
105 
106 	// recalc start and end points
107 	m_RangeStart=(int)(m_StartAngle*(m_Length/360.0f));
108 	while (m_RangeStart < 0) m_RangeStart += m_Length;
109 	while (m_RangeStart > m_Length) m_RangeStart -= m_Length;
110 
111 	m_RangeEnd=(int)(m_EndAngle*(m_Length/360.0f));
112 	while (m_RangeEnd < 0) m_RangeEnd += m_Length;
113 	while (m_RangeEnd > m_Length) m_RangeEnd -= m_Length;
114 }
115 
DrawWav()116 void Fl_Loop::DrawWav()
117 {
118 	int Thickness=(m_OuterRad-m_InnerRad)/2;
119 	int n=0,x=0,y=0,ox=0,oy=0, c=0, skip=0;
120 	bool FirstTime=true;
121 	float Angle=0;
122 	float Sample=0;
123 	float SampleAngle=360.0f/(float)(REZ);
124 
125 	skip=m_Length/REZ;
126 	if (skip<1) skip=1;
127 
128 	fl_color(100,155,100);
129 
130 	while(m_Length>0 && n<m_Length)
131 	{
132 		if (m_data)
133 		{
134 			Sample=m_data[n]*NORM*m_WaveSize;
135 			if (Sample>1) Sample=1;
136 			if (Sample<-1) Sample=-1;
137 		}
138 
139 		Angle=c*SampleAngle;
140 
141 		ox=x;
142 		oy=y;
143 
144 		float pos=Sample*Thickness+m_InnerRad+Thickness;
145 
146 		x=(int)(m_MidX+sin(Angle*RADCONV)*pos);
147 		y=(int)(m_MidY+cos(Angle*RADCONV)*pos);
148 
149 		if (Angle>m_StartAngle && Angle<m_EndAngle)
150 		{
151 			// draw the selection indicator
152 			fl_color(255,255,255);
153 		}
154 		else
155 		{
156 			fl_color(100,155,100);
157 		}
158 
159 		if (!FirstTime) fl_line(x,y,ox,oy);
160 
161 		// draw the snap points
162 		if(m_SnapDegrees && (int)Angle%m_SnapDegrees==0)
163 		{
164 			fl_color(155,155,50);
165 			fl_line((int)(m_MidX+sin(Angle*RADCONV)*m_InnerRad),
166 					(int)(m_MidY+cos(Angle*RADCONV)*m_InnerRad),
167 					(int)(m_MidX+sin(Angle*RADCONV)*m_OuterRad),
168 					(int)(m_MidY+cos(Angle*RADCONV)*m_OuterRad));
169 		}
170 
171 		n+=skip;
172 		c++;
173 		FirstTime=false;
174 	}
175 
176 	XSetFunction(fl_display,fl_gc,GXxor);
177 	fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
178 	XSetFunction(fl_display,fl_gc,GXcopy);
179 }
180 
DrawPosMarker()181 void Fl_Loop::DrawPosMarker()
182 {
183 	if (!m_Update) return;
184 	Fl_Window* Last = current();
185 
186 	//if (Last!=this && Last!=m_MainWin) return;
187 	if (Last==m_MainWin) return;
188 	if (!visible()) return;
189 
190 	make_current();
191 
192 	if (m_Pos)
193 	{
194 		float Angle=(*m_Pos/m_Length)*360.0;
195 
196     	XSetFunction(fl_display,fl_gc,GXxor);
197 		fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
198 
199 		m_IndSX=(int)(m_MidX+sin(Angle*RADCONV)*m_InnerRad);
200 		m_IndSY=(int)(m_MidY+cos(Angle*RADCONV)*m_InnerRad);
201 		m_IndEX=(int)(m_MidX+sin(Angle*RADCONV)*m_OuterRad);
202 		m_IndEY=(int)(m_MidY+cos(Angle*RADCONV)*m_OuterRad);
203 
204 		fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
205 
206 		XSetFunction(fl_display,fl_gc,GXcopy);
207 	}
208 
209 	//Last->make_current();
210 }
211 
DrawWidgets()212 void Fl_Loop::DrawWidgets()
213 {
214 	Fl_Double_Window::draw();
215 }
216 
DrawEveryThing()217 void Fl_Loop::DrawEveryThing()
218 {
219 	if (damage() & (FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL))
220 	{
221 
222 		fl_color(color());
223 		fl_rectf(0,0,w(),h());
224 
225 		m_InnerRad-=5;
226 		m_OuterRad+=5;
227 		fl_color(20,60,20);
228 		fl_pie(m_MidX-m_OuterRad, m_MidY-m_OuterRad, m_OuterRad*2, m_OuterRad*2, 0, 360);
229 		fl_color(color());
230 		fl_pie(m_MidX-m_InnerRad, m_MidY-m_InnerRad, m_InnerRad*2, m_InnerRad*2, 0, 360);
231 		m_OuterRad-=5;
232 		m_InnerRad+=5;
233 
234 		DrawWav();
235 	}
236 
237 	DrawWidgets();
238 }
239 
draw()240 void Fl_Loop::draw()
241 {
242 	DrawEveryThing();
243 }
244 
handle(int event)245 int Fl_Loop::handle(int event)
246 {
247 	static int LastButtonPushed=0;
248 
249 	// call base
250 	if (!Fl_Double_Window::handle(event))
251 	{
252 
253 	switch (event)
254 	{
255   		case FL_PUSH:
256 			LastButtonPushed=Fl::event_button();
257 			// fall through
258 		case FL_DRAG:
259     		{
260 				int mx = Fl::event_x()-m_MidX;
261 				int my = Fl::event_y()-m_MidY;
262 				if (!mx && !my) break;
263 
264 				double angle = 90+atan2((float)-my, (float)mx)*180/M_PI;
265 				while (angle < m_Angle-180) angle += 360;
266 				while (angle > m_Angle+180) angle -= 360;
267 
268 				while (angle < 0) angle += 360;
269 				while (angle > 360) angle -= 360;
270 
271 				m_Angle=angle;
272 
273 				// snap
274 				if (m_Snap)
275 				{
276 					m_Angle-=(int)m_Angle%m_SnapDegrees;
277 				}
278 
279 				if (LastButtonPushed==2)
280 				{
281 					if (m_Pos)
282 					{
283 						*m_Pos=m_Angle*(m_Length/360.0f);
284 
285 						while (*m_Pos < 0) *m_Pos += m_Length;
286 						while (*m_Pos > m_Length) *m_Pos -= m_Length;
287 					}
288 				}
289 				else if (LastButtonPushed==1)
290 				{
291 					switch (event)
292 					{
293   						case FL_PUSH:
294 						{
295 							m_StartAngle=m_Angle;
296 							m_EndAngle=m_Angle;
297 							redraw();
298 						}
299 						break;
300 
301 						case FL_DRAG:
302 						{
303 							if (m_Angle>m_StartAngle)
304 							{
305 								m_EndAngle=m_Angle;
306 							}
307 							else
308 							{
309 								m_StartAngle=m_Angle;
310 							}
311 							redraw();
312 						}
313 						break;
314 					}
315 
316 					// convert angle to sample data
317 					m_RangeStart=(int)(m_StartAngle*(m_Length/360.0f));
318 					while (m_RangeStart < 0) m_RangeStart += m_Length;
319 					while (m_RangeStart > m_Length) m_RangeStart -= m_Length;
320 
321 					m_RangeEnd=(int)(m_EndAngle*(m_Length/360.0f));
322 					while (m_RangeEnd < 0) m_RangeEnd += m_Length;
323 					while (m_RangeEnd > m_Length) m_RangeEnd -= m_Length;
324 
325 				}else if (LastButtonPushed==3)
326 				{
327 				switch (event)
328 					{
329 						case FL_PUSH:
330 						{
331 							m_MoveAngle=m_Angle;
332 
333 							// reset the last
334 							// convert angle to sample data
335 							m_LastMove=(int)(m_MoveAngle*(m_Length/360.0f));
336 							while (m_LastMove < 0) m_LastMove += m_Length;
337 							while (m_LastMove > m_Length) m_Move -= m_Length;
338 						}
339 						break;
340 
341 						case FL_DRAG:
342 						{
343 							m_MoveAngle=m_Angle;
344 							redraw();
345 						}
346 						break;
347 					}
348 
349 					// convert angle to sample data
350 					m_Move=(int)(m_MoveAngle*(m_Length/360.0f));
351 					while (m_Move < 0) m_Move += m_Length;
352 					while (m_Move > m_Length) m_Move -= m_Length;
353 
354 					// do the move
355 					cb_Move(this,m_LastMove-m_Move,0);
356 
357 					m_LastMove=m_Move;
358 				}
359 			}
360 			break;
361 
362 		case FL_RELEASE:
363 			break;
364 
365 		case FL_KEYBOARD:
366 		{
367 			if (Fl::event_key(FL_Control_L) || Fl::event_key(FL_Control_R))
368 			{
369 			if (Fl::event_key('c'))	cb_Copy(this,m_RangeStart,m_RangeEnd);
370 			if (Fl::event_key('v'))	cb_Paste(this,m_RangeStart);
371 			if (Fl::event_key('x'))	cb_Cut(this,m_RangeStart,m_RangeEnd);
372 			if (Fl::event_key('b')) cb_PasteMix(this,m_RangeStart);
373 			if (Fl::event_key('z'))	cb_ZeroRange(this,m_RangeStart,m_RangeEnd);
374 			if (Fl::event_key('r'))	cb_ReverseRange(this,m_RangeStart,m_RangeEnd);
375 			if (Fl::event_key('h'))	cb_Halve(this,0,0);
376 			if (Fl::event_key('s'))	cb_Hold(this,0,0);
377 			if (Fl::event_key('a'))
378 			{
379 				m_StartAngle=0.0f;
380 				m_RangeStart=0;
381 				m_EndAngle=360.0f;
382 				m_RangeEnd=m_Length;
383 				redraw();
384 			}
385 			if (Fl::event_key('t'))	cb_NewTrigger(this,0,0);
386 			// move?
387 			}
388 		}
389 		break;
390 
391 		default:
392 			return 0;
393   		}
394 
395 	}
396 	return 1;
397 }
398 
cb_Idle(void * o)399 void Fl_Loop::cb_Idle(void* o)
400 {
401 	((Fl_Loop*)(o))->DrawPosMarker();
402 }
403