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