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.

378 lines
8.2KB

  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. #include <string.h>
  24. /////////////////////////////////////////////////////////////////////////////
  25. static const int REZ = 1000;
  26. static const float RADCONV = 0.017453292;
  27. static const int INDW = 3; // indicator width
  28. static const int UPDATECYCLES = 4;
  29. static const int POSMARKER_MAX = 50;
  30. Fl_Loop::Fl_Loop(int x, int y, int w, int h, const char* label) :
  31. Fl_Group(x,y,w,h,label),
  32. m_data(NULL),
  33. m_MainWin(NULL),
  34. m_Length(1000),
  35. m_InnerRad((int)(w/2*0.75f)),
  36. m_OuterRad((int)(w/2*0.95f)),
  37. m_BorderRad(w/2),
  38. m_IndSX(0),
  39. m_IndSY(0),
  40. m_IndEX(0),
  41. m_IndEY(0),
  42. m_StartAngle(0),
  43. m_EndAngle(1),
  44. m_MoveAngle(0.0f),
  45. m_RangeStart(0),
  46. m_RangeEnd(0),
  47. m_Angle(0),
  48. m_Pos(0),
  49. m_Update(true),
  50. m_StopUpdate(false),
  51. m_WaveSize(1.0f),
  52. m_Move(0),
  53. m_LastMove(0),
  54. m_Snap(false),
  55. m_SnapDegrees(45),
  56. m_PosMarkerCount(0),
  57. cb_Move(NULL),
  58. m_BGColour (FL_BLACK),
  59. m_WaveColour (FL_GREEN),
  60. m_SelColour (FL_WHITE),
  61. m_IndColour (FL_BLUE),
  62. m_MrkColour (FL_YELLOW)
  63. {
  64. box(FL_NO_BOX);
  65. m_MidX=(w/2)+x;
  66. m_MidY=(h/2)+y-20;
  67. }
  68. void Fl_Loop::SetData(float const *set, const int Len)
  69. {
  70. if (m_data!=NULL) delete[] m_data;
  71. m_data = new float[Len];
  72. memcpy((void*)m_data,(void*)set,Len*sizeof(float));
  73. SetLength(Len);
  74. }
  75. void Fl_Loop::SetLength(const int Len)
  76. {
  77. m_Length=Len;
  78. // recalc start and end points
  79. m_RangeStart=(long)(m_StartAngle*(m_Length/360.0f));
  80. while (m_RangeStart < 0) m_RangeStart += m_Length;
  81. while (m_RangeStart > m_Length) m_RangeStart -= m_Length;
  82. m_RangeEnd=(long)(m_EndAngle*(m_Length/360.0f));
  83. while (m_RangeEnd < 0) m_RangeEnd += m_Length;
  84. while (m_RangeEnd > m_Length) m_RangeEnd -= m_Length;
  85. }
  86. void Fl_Loop::SelectAll()
  87. {
  88. m_RangeStart=0;
  89. m_RangeEnd=m_Length;
  90. }
  91. void Fl_Loop::DrawWav()
  92. {
  93. int Thickness=(m_OuterRad-m_InnerRad)/2;
  94. int n=0,X=0,Y=0,ox=0,oy=0, c=0;
  95. bool FirstTime=true, DrawnSnap=false;
  96. float Angle=0;
  97. float Sample=0;
  98. float SampleAngle=360.0f/(float)(REZ);
  99. fl_color (m_WaveColour);
  100. while(m_Length>0 && n<m_Length)
  101. {
  102. n=(int)((Angle/360.0f)*m_Length);
  103. if (m_data)
  104. {
  105. Sample=m_data[n]*m_WaveSize;
  106. if (Sample>1) Sample=1;
  107. if (Sample<-1) Sample=-1;
  108. }
  109. Angle=c*SampleAngle;
  110. ox=X;
  111. oy=Y;
  112. float pos=Sample*Thickness+m_InnerRad+Thickness;
  113. X=(int)(m_MidX+x()+sin(Angle*RADCONV)*pos);
  114. Y=(int)(m_MidY+y()+cos(Angle*RADCONV)*pos);
  115. if (Angle>m_StartAngle && Angle<m_EndAngle)
  116. {
  117. // draw the selection indicator
  118. fl_color (m_SelColour);
  119. }
  120. else
  121. {
  122. fl_color (m_WaveColour);
  123. }
  124. if (!FirstTime) fl_line(X,Y,ox,oy);
  125. // draw the snap points
  126. if(m_SnapDegrees && (int)Angle%m_SnapDegrees==0)
  127. {
  128. if (!DrawnSnap)
  129. {
  130. fl_color (m_MrkColour);
  131. fl_line((int)(m_MidX+x()+sin(Angle*RADCONV)*m_InnerRad),
  132. (int)(m_MidY+y()+cos(Angle*RADCONV)*m_InnerRad),
  133. (int)(m_MidX+x()+sin(Angle*RADCONV)*m_OuterRad),
  134. (int)(m_MidY+y()+cos(Angle*RADCONV)*m_OuterRad));
  135. DrawnSnap=true;
  136. }
  137. }
  138. else
  139. {
  140. DrawnSnap=false;
  141. }
  142. c++;
  143. FirstTime=false;
  144. }
  145. /*XSetFunction(fl_display,fl_gc,GXxor);
  146. fl_line_style(FL_SOLID, 3, NULL);
  147. fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
  148. fl_line_style(FL_SOLID, 1, NULL);
  149. XSetFunction(fl_display,fl_gc,GXcopy); */
  150. }
  151. void Fl_Loop::DrawPosMarker()
  152. {
  153. if (!m_Update) return;
  154. //Fl_Window* Last = current();
  155. //if (Last!=this && Last!=m_MainWin) return;
  156. //if (Last==m_MainWin) return;
  157. if (!visible() || !window()->visible() || !parent()->visible()) return;
  158. window()->make_current();
  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 (m_IndColour);
  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. if (m_PosMarkerCount>POSMARKER_MAX)
  176. {
  177. redraw();
  178. m_PosMarkerCount=0;
  179. }
  180. m_PosMarkerCount++;
  181. //Last->make_current();
  182. }
  183. void Fl_Loop::DrawWidgets()
  184. {
  185. Fl_Group::draw();
  186. }
  187. void Fl_Loop::DrawEveryThing()
  188. {
  189. if (damage() & (FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL))
  190. {
  191. if (m_PosMarkerCount>POSMARKER_MAX)
  192. {
  193. m_PosMarkerCount=0;
  194. }
  195. //fl_color(color());
  196. //fl_rectf(x(),y(),w(),h());
  197. m_InnerRad-=5;
  198. m_OuterRad+=5;
  199. fl_color (m_BGColour);
  200. fl_pie(m_MidX+x()-m_OuterRad, m_MidY+y()-m_OuterRad, m_OuterRad*2, m_OuterRad*2, 0, 360);
  201. fl_color (color());
  202. fl_pie(m_MidX+x()-m_InnerRad, m_MidY+y()-m_InnerRad, m_InnerRad*2, m_InnerRad*2, 0, 360);
  203. m_OuterRad-=5;
  204. m_InnerRad+=5;
  205. DrawWav();
  206. }
  207. DrawWidgets();
  208. }
  209. void Fl_Loop::draw()
  210. {
  211. DrawEveryThing();
  212. }
  213. int Fl_Loop::handle(int event)
  214. {
  215. static int LastButtonPushed=0;
  216. // call base
  217. if (!Fl_Group::handle(event))
  218. {
  219. switch (event)
  220. {
  221. case FL_PUSH:
  222. LastButtonPushed=Fl::event_button();
  223. // fall through
  224. case FL_DRAG:
  225. {
  226. int mx = Fl::event_x()-(m_MidX+x());
  227. int my = Fl::event_y()-(m_MidY+y());
  228. if (!mx && !my) break;
  229. double angle = 90+atan2((float)-my, (float)mx)*180/M_PI;
  230. while (angle < m_Angle-180) angle += 360;
  231. while (angle > m_Angle+180) angle -= 360;
  232. while (angle < 0) angle += 360;
  233. while (angle > 360) angle -= 360;
  234. m_Angle=angle;
  235. // snap
  236. if (m_Snap)
  237. {
  238. m_Angle-=(int)m_Angle%m_SnapDegrees;
  239. }
  240. if (LastButtonPushed==2)
  241. {
  242. m_Pos=m_Angle*(m_Length/360.0f);
  243. while (m_Pos < 0) m_Pos += m_Length;
  244. while (m_Pos > m_Length) m_Pos -= m_Length;
  245. }
  246. else if (LastButtonPushed==1)
  247. {
  248. switch (event)
  249. {
  250. case FL_PUSH:
  251. {
  252. m_StartAngle=m_Angle;
  253. m_EndAngle=m_Angle;
  254. redraw();
  255. }
  256. break;
  257. case FL_DRAG:
  258. {
  259. if (m_Angle>m_StartAngle)
  260. {
  261. m_EndAngle=m_Angle;
  262. }
  263. else
  264. {
  265. m_StartAngle=m_Angle;
  266. }
  267. redraw();
  268. }
  269. break;
  270. }
  271. // convert angle to sample data
  272. m_RangeStart=(long)(m_StartAngle*(m_Length/360.0f));
  273. while (m_RangeStart < 0) m_RangeStart += m_Length;
  274. while (m_RangeStart > m_Length) m_RangeStart -= m_Length;
  275. m_RangeEnd=(long)(m_EndAngle*(m_Length/360.0f));
  276. while (m_RangeEnd < 0) m_RangeEnd += m_Length;
  277. while (m_RangeEnd > m_Length) m_RangeEnd -= m_Length;
  278. }else if (LastButtonPushed==3)
  279. {
  280. switch (event)
  281. {
  282. case FL_PUSH:
  283. {
  284. m_MoveAngle=m_Angle;
  285. // reset the last
  286. // convert angle to sample data
  287. m_LastMove=(int)(m_MoveAngle*(m_Length/360.0f));
  288. while (m_LastMove < 0) m_LastMove += m_Length;
  289. while (m_LastMove > m_Length) m_Move -= m_Length;
  290. }
  291. break;
  292. case FL_DRAG:
  293. {
  294. m_MoveAngle=m_Angle;
  295. redraw();
  296. }
  297. break;
  298. }
  299. // convert angle to sample data
  300. m_Move=(int)(m_MoveAngle*(m_Length/360.0f));
  301. while (m_Move < 0) m_Move += m_Length;
  302. while (m_Move > m_Length) m_Move -= m_Length;
  303. // do the move
  304. if (cb_Move) cb_Move(this,m_LastMove-m_Move);
  305. m_LastMove=m_Move;
  306. }
  307. }
  308. break;
  309. case FL_RELEASE:
  310. break;
  311. default:
  312. return 0;
  313. }
  314. }
  315. return 1;
  316. }