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.

407 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. XSetFunction(fl_display,fl_gc,GXxor);
  162. fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
  163. fl_color(FL_BLUE);
  164. m_IndSX=(int)(m_MidX+x()+sin(Angle*RADCONV)*m_InnerRad);
  165. m_IndSY=(int)(m_MidY+y()+cos(Angle*RADCONV)*m_InnerRad);
  166. m_IndEX=(int)(m_MidX+x()+sin(Angle*RADCONV)*m_OuterRad);
  167. m_IndEY=(int)(m_MidY+y()+cos(Angle*RADCONV)*m_OuterRad);
  168. fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY);
  169. fl_line_style(FL_SOLID, 1, NULL);
  170. XSetFunction(fl_display,fl_gc,GXcopy);
  171. }
  172. if (m_PosMarkerCount>POSMARKER_MAX)
  173. {
  174. redraw();
  175. m_PosMarkerCount=0;
  176. }
  177. m_PosMarkerCount++;
  178. //Last->make_current();
  179. }
  180. void Fl_Loop::DrawWidgets()
  181. {
  182. Fl_Group::draw();
  183. }
  184. void Fl_Loop::DrawEveryThing()
  185. {
  186. if (damage() & (FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL))
  187. {
  188. if (m_PosMarkerCount>POSMARKER_MAX)
  189. {
  190. m_PosMarkerCount=0;
  191. }
  192. fl_color(color());
  193. fl_rectf(x(),y(),w(),h());
  194. m_InnerRad-=5;
  195. m_OuterRad+=5;
  196. fl_color(20,60,20);
  197. fl_pie(m_MidX+x()-m_OuterRad, m_MidY+y()-m_OuterRad, m_OuterRad*2, m_OuterRad*2, 0, 360);
  198. fl_color(color());
  199. fl_pie(m_MidX+x()-m_InnerRad, m_MidY+y()-m_InnerRad, m_InnerRad*2, m_InnerRad*2, 0, 360);
  200. m_OuterRad-=5;
  201. m_InnerRad+=5;
  202. DrawWav();
  203. }
  204. DrawWidgets();
  205. }
  206. void Fl_Loop::draw()
  207. {
  208. DrawEveryThing();
  209. }
  210. int Fl_Loop::handle(int event)
  211. {
  212. static int LastButtonPushed=0;
  213. // call base
  214. if (!Fl_Group::handle(event))
  215. {
  216. switch (event)
  217. {
  218. case FL_PUSH:
  219. LastButtonPushed=Fl::event_button();
  220. // fall through
  221. case FL_DRAG:
  222. {
  223. int mx = Fl::event_x()-(m_MidX+x());
  224. int my = Fl::event_y()-(m_MidY+y());
  225. if (!mx && !my) break;
  226. double angle = 90+atan2((float)-my, (float)mx)*180/M_PI;
  227. while (angle < m_Angle-180) angle += 360;
  228. while (angle > m_Angle+180) angle -= 360;
  229. while (angle < 0) angle += 360;
  230. while (angle > 360) angle -= 360;
  231. m_Angle=angle;
  232. // snap
  233. if (m_Snap)
  234. {
  235. m_Angle-=(int)m_Angle%m_SnapDegrees;
  236. }
  237. if (LastButtonPushed==2)
  238. {
  239. if (m_Pos)
  240. {
  241. *m_Pos=m_Angle*(m_Length/360.0f);
  242. while (*m_Pos < 0) *m_Pos += m_Length;
  243. while (*m_Pos > m_Length) *m_Pos -= m_Length;
  244. }
  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=(int)(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=(int)(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. cb_Move(this,m_LastMove-m_Move,0);
  305. m_LastMove=m_Move;
  306. }
  307. }
  308. break;
  309. case FL_RELEASE:
  310. break;
  311. case FL_KEYBOARD:
  312. case FL_SHORTCUT:
  313. {
  314. if (Fl::event_key(FL_Control_L) || Fl::event_key(FL_Control_R))
  315. {
  316. if (Fl::event_key('c')) cb_Copy(this,m_RangeStart,m_RangeEnd);
  317. if (Fl::event_key('v')) cb_Paste(this,m_RangeStart);
  318. if (Fl::event_key('x')) cb_Cut(this,m_RangeStart,m_RangeEnd);
  319. if (Fl::event_key('b')) cb_PasteMix(this,m_RangeStart);
  320. if (Fl::event_key('z')) cb_ZeroRange(this,m_RangeStart,m_RangeEnd);
  321. if (Fl::event_key('r')) cb_ReverseRange(this,m_RangeStart,m_RangeEnd);
  322. if (Fl::event_key('h')) cb_Halve(this,0,0);
  323. if (Fl::event_key('s')) cb_Hold(this,0,0);
  324. if (Fl::event_key('a'))
  325. {
  326. m_StartAngle=0.0f;
  327. m_RangeStart=0;
  328. m_EndAngle=360.0f;
  329. m_RangeEnd=m_Length;
  330. redraw();
  331. }
  332. if (Fl::event_key('t')) cb_NewTrigger(this,0,0);
  333. // move?
  334. }
  335. }
  336. break;
  337. default:
  338. return 0;
  339. }
  340. }
  341. return 1;
  342. }