You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

411 lines
9.1KB

  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. #include "Fl_Loop.h"
  19. #include <iostream>
  20. #include <FL/fl_draw.H>
  21. #include <FL/x.H>
  22. #include <math.h>
  23. /////////////////////////////////////////////////////////////////////////////
  24. static const int REZ = 1000;
  25. static const float RADCONV = 0.017453292;
  26. static const int INDW = 3; // indicator width
  27. static const int UPDATECYCLES = 4;
  28. static const int POSMARKER_MAX = 50;
  29. Fl_Loop::Fl_Loop(int x, int y, int w, int h, const char* label) :
  30. Fl_Group(x,y,w,h,label),
  31. m_data(NULL),
  32. m_MainWin(NULL),
  33. m_Length(1000),
  34. m_InnerRad((int)(w/2*0.75f)),
  35. m_OuterRad((int)(w/2*0.95f)),
  36. m_BorderRad(w/2),
  37. m_IndSX(0),
  38. m_IndSY(0),
  39. m_IndEX(0),
  40. m_IndEY(0),
  41. m_StartAngle(0),
  42. m_EndAngle(1),
  43. m_MoveAngle(0.0f),
  44. m_RangeStart(0),
  45. m_RangeEnd(0),
  46. m_Angle(0),
  47. m_Pos(NULL),
  48. m_Update(false),
  49. m_StopUpdate(false),
  50. m_WaveSize(1.0f),
  51. m_Move(0),
  52. m_LastMove(0),
  53. m_Snap(false),
  54. m_SnapDegrees(45),
  55. m_PosMarkerCount(0)
  56. {
  57. m_MidX=(w/2)+x;
  58. m_MidY=(h/2)+y-20;
  59. }
  60. void Fl_Loop::SetupCopyBufFuncs(cb_CopyBuf1 *Cut,
  61. cb_CopyBuf1 *Copy,
  62. cb_CopyBuf2 *Paste,
  63. cb_CopyBuf2 *PasteMix,
  64. cb_CopyBuf1 *ZeroRange,
  65. cb_CopyBuf1 *ReverseRange,
  66. cb_CopyBuf1 *Halve,
  67. cb_CopyBuf1 *Hold,
  68. cb_CopyBuf1 *SelectAll,
  69. cb_CopyBuf1 *NewTrigger,
  70. cb_CopyBuf1 *Move)
  71. {
  72. cb_Cut = Cut;
  73. cb_Copy = Copy;
  74. cb_Paste = Paste;
  75. cb_PasteMix = PasteMix;
  76. cb_ZeroRange = ZeroRange;
  77. cb_ReverseRange = ReverseRange;
  78. cb_Halve = Halve;
  79. cb_Hold = Hold;
  80. cb_SelectAll = SelectAll;
  81. cb_NewTrigger = NewTrigger;
  82. cb_Move = Move;
  83. }
  84. void Fl_Loop::SetLength(const int Len)
  85. {
  86. m_Length=Len;
  87. // recalc start and end points
  88. m_RangeStart=(int)(m_StartAngle*(m_Length/360.0f));
  89. while (m_RangeStart < 0) m_RangeStart += m_Length;
  90. while (m_RangeStart > m_Length) m_RangeStart -= m_Length;
  91. m_RangeEnd=(int)(m_EndAngle*(m_Length/360.0f));
  92. while (m_RangeEnd < 0) m_RangeEnd += m_Length;
  93. while (m_RangeEnd > m_Length) m_RangeEnd -= m_Length;
  94. }
  95. void Fl_Loop::DrawWav()
  96. {
  97. int Thickness=(m_OuterRad-m_InnerRad)/2;
  98. int n=0,X=0,Y=0,ox=0,oy=0, c=0, skip=0;
  99. bool FirstTime=true;
  100. float Angle=0;
  101. float Sample=0;
  102. float SampleAngle=360.0f/(float)(REZ);
  103. skip=m_Length/REZ;
  104. if (skip<1) skip=1;
  105. fl_color(100,155,100);
  106. while(m_Length>0 && n<m_Length)
  107. {
  108. if (m_data)
  109. {
  110. Sample=m_data[n]*m_WaveSize;
  111. if (Sample>1) Sample=1;
  112. if (Sample<-1) Sample=-1;
  113. }
  114. Angle=c*SampleAngle;
  115. ox=X;
  116. oy=Y;
  117. float pos=Sample*Thickness+m_InnerRad+Thickness;
  118. X=(int)(m_MidX+x()+sin(Angle*RADCONV)*pos);
  119. Y=(int)(m_MidY+y()+cos(Angle*RADCONV)*pos);
  120. if (Angle>m_StartAngle && Angle<m_EndAngle)
  121. {
  122. // draw the selection indicator
  123. fl_color(255,255,255);
  124. }
  125. else
  126. {
  127. fl_color(100,155,100);
  128. }
  129. if (!FirstTime) fl_line(X,Y,ox,oy);
  130. // draw the snap points
  131. if(m_SnapDegrees && (int)Angle%m_SnapDegrees==0)
  132. {
  133. fl_color(155,155,50);
  134. fl_line((int)(m_MidX+x()+sin(Angle*RADCONV)*m_InnerRad),
  135. (int)(m_MidY+y()+cos(Angle*RADCONV)*m_InnerRad),
  136. (int)(m_MidX+x()+sin(Angle*RADCONV)*m_OuterRad),
  137. (int)(m_MidY+y()+cos(Angle*RADCONV)*m_OuterRad));
  138. }
  139. n+=skip;
  140. c++;
  141. FirstTime=false;
  142. }
  143. /*XSetFunction(fl_display,fl_gc,GXxor);
  144. fl_line_style(FL_SOLID, 3, NULL);
  145. fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
  146. fl_line_style(FL_SOLID, 1, NULL);
  147. XSetFunction(fl_display,fl_gc,GXcopy); */
  148. }
  149. void Fl_Loop::DrawPosMarker()
  150. {
  151. if (!m_Update) return;
  152. //Fl_Window* Last = current();
  153. //if (Last!=this && Last!=m_MainWin) return;
  154. //if (Last==m_MainWin) return;
  155. if (!visible() || !window()->visible() || !parent()->visible()) return;
  156. window()->make_current();
  157. if (m_Pos)
  158. {
  159. float Angle=(*m_Pos/m_Length)*360.0;
  160. fl_line_style(FL_SOLID, 3, NULL);
  161. #if !__APPLE__
  162. XSetFunction(fl_display,fl_gc,GXxor);
  163. #endif
  164. fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
  165. fl_color(FL_BLUE);
  166. m_IndSX=(int)(m_MidX+x()+sin(Angle*RADCONV)*m_InnerRad);
  167. m_IndSY=(int)(m_MidY+y()+cos(Angle*RADCONV)*m_InnerRad);
  168. m_IndEX=(int)(m_MidX+x()+sin(Angle*RADCONV)*m_OuterRad);
  169. m_IndEY=(int)(m_MidY+y()+cos(Angle*RADCONV)*m_OuterRad);
  170. fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
  171. fl_line_style(FL_SOLID, 1, NULL);
  172. #if !__APPLE__
  173. XSetFunction(fl_display,fl_gc,GXcopy);
  174. #endif
  175. }
  176. if (m_PosMarkerCount>POSMARKER_MAX)
  177. {
  178. redraw();
  179. m_PosMarkerCount=0;
  180. }
  181. m_PosMarkerCount++;
  182. //Last->make_current();
  183. }
  184. void Fl_Loop::DrawWidgets()
  185. {
  186. Fl_Group::draw();
  187. }
  188. void Fl_Loop::DrawEveryThing()
  189. {
  190. if (damage() & (FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL))
  191. {
  192. if (m_PosMarkerCount>POSMARKER_MAX)
  193. {
  194. m_PosMarkerCount=0;
  195. }
  196. fl_color(color());
  197. fl_rectf(x(),y(),w(),h());
  198. m_InnerRad-=5;
  199. m_OuterRad+=5;
  200. fl_color(20,60,20);
  201. fl_pie(m_MidX+x()-m_OuterRad, m_MidY+y()-m_OuterRad, m_OuterRad*2, m_OuterRad*2, 0, 360);
  202. fl_color(color());
  203. fl_pie(m_MidX+x()-m_InnerRad, m_MidY+y()-m_InnerRad, m_InnerRad*2, m_InnerRad*2, 0, 360);
  204. m_OuterRad-=5;
  205. m_InnerRad+=5;
  206. DrawWav();
  207. }
  208. DrawWidgets();
  209. }
  210. void Fl_Loop::draw()
  211. {
  212. DrawEveryThing();
  213. }
  214. int Fl_Loop::handle(int event)
  215. {
  216. static int LastButtonPushed=0;
  217. // call base
  218. if (!Fl_Group::handle(event))
  219. {
  220. switch (event)
  221. {
  222. case FL_PUSH:
  223. LastButtonPushed=Fl::event_button();
  224. // fall through
  225. case FL_DRAG:
  226. {
  227. int mx = Fl::event_x()-(m_MidX+x());
  228. int my = Fl::event_y()-(m_MidY+y());
  229. if (!mx && !my) break;
  230. double angle = 90+atan2((float)-my, (float)mx)*180/M_PI;
  231. while (angle < m_Angle-180) angle += 360;
  232. while (angle > m_Angle+180) angle -= 360;
  233. while (angle < 0) angle += 360;
  234. while (angle > 360) angle -= 360;
  235. m_Angle=angle;
  236. // snap
  237. if (m_Snap)
  238. {
  239. m_Angle-=(int)m_Angle%m_SnapDegrees;
  240. }
  241. if (LastButtonPushed==2)
  242. {
  243. if (m_Pos)
  244. {
  245. *m_Pos=m_Angle*(m_Length/360.0f);
  246. while (*m_Pos < 0) *m_Pos += m_Length;
  247. while (*m_Pos > m_Length) *m_Pos -= m_Length;
  248. }
  249. }
  250. else if (LastButtonPushed==1)
  251. {
  252. switch (event)
  253. {
  254. case FL_PUSH:
  255. {
  256. m_StartAngle=m_Angle;
  257. m_EndAngle=m_Angle;
  258. redraw();
  259. }
  260. break;
  261. case FL_DRAG:
  262. {
  263. if (m_Angle>m_StartAngle)
  264. {
  265. m_EndAngle=m_Angle;
  266. }
  267. else
  268. {
  269. m_StartAngle=m_Angle;
  270. }
  271. redraw();
  272. }
  273. break;
  274. }
  275. // convert angle to sample data
  276. m_RangeStart=(int)(m_StartAngle*(m_Length/360.0f));
  277. while (m_RangeStart < 0) m_RangeStart += m_Length;
  278. while (m_RangeStart > m_Length) m_RangeStart -= m_Length;
  279. m_RangeEnd=(int)(m_EndAngle*(m_Length/360.0f));
  280. while (m_RangeEnd < 0) m_RangeEnd += m_Length;
  281. while (m_RangeEnd > m_Length) m_RangeEnd -= m_Length;
  282. }else if (LastButtonPushed==3)
  283. {
  284. switch (event)
  285. {
  286. case FL_PUSH:
  287. {
  288. m_MoveAngle=m_Angle;
  289. // reset the last
  290. // convert angle to sample data
  291. m_LastMove=(int)(m_MoveAngle*(m_Length/360.0f));
  292. while (m_LastMove < 0) m_LastMove += m_Length;
  293. while (m_LastMove > m_Length) m_Move -= m_Length;
  294. }
  295. break;
  296. case FL_DRAG:
  297. {
  298. m_MoveAngle=m_Angle;
  299. redraw();
  300. }
  301. break;
  302. }
  303. // convert angle to sample data
  304. m_Move=(int)(m_MoveAngle*(m_Length/360.0f));
  305. while (m_Move < 0) m_Move += m_Length;
  306. while (m_Move > m_Length) m_Move -= m_Length;
  307. // do the move
  308. cb_Move(this,m_LastMove-m_Move,0);
  309. m_LastMove=m_Move;
  310. }
  311. }
  312. break;
  313. case FL_RELEASE:
  314. break;
  315. case FL_KEYBOARD:
  316. case FL_SHORTCUT:
  317. {
  318. if (Fl::event_key(FL_Control_L) || Fl::event_key(FL_Control_R))
  319. {
  320. if (Fl::event_key('c')) cb_Copy(this,m_RangeStart,m_RangeEnd);
  321. if (Fl::event_key('v')) cb_Paste(this,m_RangeStart);
  322. if (Fl::event_key('x')) cb_Cut(this,m_RangeStart,m_RangeEnd);
  323. if (Fl::event_key('b')) cb_PasteMix(this,m_RangeStart);
  324. if (Fl::event_key('z')) cb_ZeroRange(this,m_RangeStart,m_RangeEnd);
  325. if (Fl::event_key('r')) cb_ReverseRange(this,m_RangeStart,m_RangeEnd);
  326. if (Fl::event_key('h')) cb_Halve(this,0,0);
  327. if (Fl::event_key('s')) cb_Hold(this,0,0);
  328. if (Fl::event_key('a'))
  329. {
  330. m_StartAngle=0.0f;
  331. m_RangeStart=0;
  332. m_EndAngle=360.0f;
  333. m_RangeEnd=m_Length;
  334. redraw();
  335. }
  336. if (Fl::event_key('t')) cb_NewTrigger(this,0,0);
  337. // move?
  338. }
  339. }
  340. break;
  341. default:
  342. return 0;
  343. }
  344. }
  345. return 1;
  346. }