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.

496 lines
11KB

  1. /* SpiralSound
  2. * Copyleft (C) 2001 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 "MatrixPlugin.h"
  19. #include "MatrixPluginGUI.h"
  20. #include <FL/Fl_Button.h>
  21. #include "SpiralIcon.xpm"
  22. #include "../../RiffWav.h"
  23. #include "../../NoteTable.h"
  24. extern "C" {
  25. SpiralPlugin* CreateInstance()
  26. {
  27. return new MatrixPlugin;
  28. }
  29. char** GetIcon()
  30. {
  31. return SpiralIcon_xpm;
  32. }
  33. int GetID()
  34. {
  35. return 0x0012;
  36. }
  37. }
  38. ///////////////////////////////////////////////////////
  39. MatrixPlugin::MatrixPlugin() :
  40. m_TickTime(1.0f),
  41. m_StepTime(1.0f),
  42. m_Time(0.0f),
  43. m_Step(0),
  44. m_Loop(true),
  45. m_NoteCut(false),
  46. m_Current(0),
  47. m_GUICurrent(0),
  48. m_CurrentNoteCV(0),
  49. m_CurrentTriggerCV(0),
  50. m_Triggered(false),
  51. m_ClockHigh(false),
  52. m_CopyPattern(0),
  53. m_PatAdvance(false),
  54. m_PatReset(false)
  55. {
  56. m_Version=3;
  57. m_PluginInfo.Name="Matrix";
  58. m_PluginInfo.Width=560;
  59. m_PluginInfo.Height=270;
  60. m_PluginInfo.NumInputs=5;
  61. m_PluginInfo.NumOutputs=19;
  62. m_PluginInfo.PortTips.push_back("Play Trigger");
  63. m_PluginInfo.PortTips.push_back("StepTime CV");
  64. m_PluginInfo.PortTips.push_back("Input Pitch CV");
  65. m_PluginInfo.PortTips.push_back("Input Trigger CV");
  66. m_PluginInfo.PortTips.push_back("External Clock");
  67. //m_PluginInfo.PortTips.push_back("Pattern Advance");
  68. //m_PluginInfo.PortTips.push_back("Pattern Reset");
  69. m_PluginInfo.PortTips.push_back("Output Pitch");
  70. m_PluginInfo.PortTips.push_back("Output Trigger");
  71. m_PluginInfo.PortTips.push_back("Trigger 1");
  72. m_PluginInfo.PortTips.push_back("Trigger 2");
  73. m_PluginInfo.PortTips.push_back("Trigger 3");
  74. m_PluginInfo.PortTips.push_back("Trigger 4");
  75. m_PluginInfo.PortTips.push_back("Trigger 5");
  76. m_PluginInfo.PortTips.push_back("Trigger 6");
  77. m_PluginInfo.PortTips.push_back("Trigger 7");
  78. m_PluginInfo.PortTips.push_back("Trigger 8");
  79. m_PluginInfo.PortTips.push_back("Trigger 9");
  80. m_PluginInfo.PortTips.push_back("Trigger 10");
  81. m_PluginInfo.PortTips.push_back("Trigger 11");
  82. m_PluginInfo.PortTips.push_back("Trigger 12");
  83. m_PluginInfo.PortTips.push_back("Trigger 13");
  84. m_PluginInfo.PortTips.push_back("Trigger 14");
  85. m_PluginInfo.PortTips.push_back("Trigger 15");
  86. m_PluginInfo.PortTips.push_back("Trigger 16");
  87. m_PluginInfo.PortTips.push_back("Reset Trigger");
  88. for (int n=0; n<NUM_PATTERNS; n++)
  89. {
  90. m_Matrix[n].Length=64;
  91. m_Matrix[n].Speed=1.0f;
  92. m_Matrix[n].Octave=0;
  93. for (int x=0; x<MATX; x++)
  94. for (int y=0; y<MATY; y++)
  95. {
  96. m_Matrix[n].Matrix[x][y]=false;
  97. m_Matrix[n].Volume[x][y]=1;
  98. }
  99. m_TriggerLevel[n]=0;
  100. }
  101. m_AudioCH->Register("NoteCut",&m_NoteCut,ChannelHandler::INPUT);
  102. m_AudioCH->Register("Volume",&m_GUIArgs.Volume,ChannelHandler::INPUT);
  103. m_AudioCH->Register("Current",&m_GUICurrent,ChannelHandler::INPUT);
  104. m_AudioCH->Register("StepTime",&m_StepTime,ChannelHandler::INPUT);
  105. m_AudioCH->Register("Num",&m_GUIArgs.Num,ChannelHandler::INPUT);
  106. m_AudioCH->Register("Length",&m_GUIArgs.Length,ChannelHandler::INPUT);
  107. m_AudioCH->Register("Speed",&m_GUIArgs.Speed,ChannelHandler::INPUT);
  108. m_AudioCH->Register("X",&m_GUIArgs.X,ChannelHandler::INPUT);
  109. m_AudioCH->Register("Y",&m_GUIArgs.Y,ChannelHandler::INPUT);
  110. m_AudioCH->Register("Octave",&m_GUIArgs.Octave,ChannelHandler::INPUT);
  111. m_AudioCH->Register("Step",&m_Step,ChannelHandler::OUTPUT);
  112. m_AudioCH->RegisterData("Matrix",ChannelHandler::OUTPUT_REQUEST,&m_Matrix,sizeof(m_Matrix));
  113. }
  114. MatrixPlugin::~MatrixPlugin()
  115. {
  116. }
  117. PluginInfo &MatrixPlugin::Initialise(const HostInfo *Host)
  118. {
  119. PluginInfo& Info = SpiralPlugin::Initialise(Host);
  120. m_TickTime = 1.0f/(float)m_HostInfo->SAMPLERATE;
  121. return Info;
  122. }
  123. SpiralGUIType *MatrixPlugin::CreateGUI()
  124. {
  125. return new MatrixPluginGUI(m_PluginInfo.Width,
  126. m_PluginInfo.Height,
  127. this,m_AudioCH,m_HostInfo);
  128. }
  129. void MatrixPlugin::Execute()
  130. {
  131. for (int n=0; n<m_HostInfo->BUFSIZE; n++)
  132. {
  133. if (InputExists(1)) m_StepTime = GetInput(1,n);
  134. // inc time
  135. m_Time+=m_TickTime;
  136. SetOutputPitch(0,n,m_CurrentNoteCV);
  137. SetOutput(1,n,m_CurrentTriggerCV);
  138. // clear the pattern sync
  139. SetOutput(18, n, 0);
  140. bool ExternalClock = InputExists(4);
  141. bool ExternalClockTriggered=false;
  142. if (GetInputPitch(0,n)>0)
  143. {
  144. if (!m_Triggered)
  145. {
  146. float Freq=GetInputPitch(0,n);
  147. // Notes 0 to 16 trigger patterns 0 to 16
  148. // No other notes catered for
  149. for (int i=0; i<NUM_PATTERNS; i++)
  150. {
  151. if (feq(Freq,NoteTable[i],0.01f))
  152. {
  153. m_Current=i;
  154. break;
  155. }
  156. }
  157. // make it so the next note to trigger
  158. // will be the first one
  159. m_Time=m_StepTime*(1/m_Matrix[m_Current].Speed);
  160. m_Step=-1;
  161. ExternalClockTriggered=true;
  162. m_Triggered=true;
  163. }
  164. }
  165. else
  166. {
  167. m_Triggered=false;
  168. }
  169. // set the individual triggers
  170. for (int t=0; t<NUM_PATTERNS; t++) SetOutput(t+2,n,m_TriggerLevel[t]);
  171. if (ExternalClock)
  172. {
  173. if (GetInput(4,n)>0)
  174. {
  175. if(!m_ClockHigh)
  176. {
  177. m_ClockHigh=true;
  178. ExternalClockTriggered=true;
  179. }
  180. }
  181. else
  182. {
  183. if (m_ClockHigh)
  184. {
  185. m_ClockHigh=false;
  186. ExternalClockTriggered=true;
  187. }
  188. }
  189. // reset the position on a signal from input 1
  190. if (InputExists(0) && GetInput(0,n)!=0)
  191. {
  192. m_Step=-1;
  193. ExternalClockTriggered=true;
  194. }
  195. }
  196. /* not yet...
  197. // external pattern advance
  198. if (GetInput(5,n)>0)
  199. {
  200. if (!m_PatAdvance)
  201. {
  202. m_Current++;
  203. if (m_Current==16) m_Current=0;
  204. m_PatAdvance=true;
  205. m_Step=-1;
  206. ExternalClockTriggered=true;
  207. }
  208. }
  209. else
  210. {
  211. m_PatAdvance=false;
  212. }
  213. // external pattern reset
  214. if (GetInput(6,n)>0)
  215. {
  216. if (!m_PatReset)
  217. {
  218. m_Current=0;
  219. m_PatReset=true;
  220. m_Step=-1;
  221. ExternalClockTriggered=true;
  222. }
  223. }
  224. else
  225. {
  226. m_PatReset=false;
  227. }
  228. */
  229. // An external clock pulse overrides the internal timing
  230. if ((!ExternalClock && m_Time>=m_StepTime*(1/m_Matrix[m_Current].Speed)) ||
  231. (ExternalClock && ExternalClockTriggered))
  232. {
  233. m_Time=0;
  234. m_Step++;
  235. if (m_Step >= m_Matrix[m_Current].Length)
  236. {
  237. SetOutput(18, n, 1);
  238. m_Step=0;
  239. }
  240. // Reset the values
  241. m_CurrentTriggerCV=0;
  242. if (m_NoteCut) m_CurrentNoteCV=0;
  243. for (int t=0; t<NUM_PATTERNS; t++)
  244. {
  245. SetOutput(t+2,n,0);
  246. m_TriggerLevel[t]=0;
  247. }
  248. // Scan the matrix at current time
  249. for (int i=0; i<MATY; i++)
  250. {
  251. if (m_Matrix[m_Current].Matrix[m_Step][i])
  252. {
  253. m_CurrentNoteCV=NoteTable[i+m_Matrix[m_Current].Octave*12];
  254. m_CurrentTriggerCV=m_Matrix[m_Current].Volume[m_Step][i];
  255. m_TriggerLevel[i]=m_Matrix[m_Current].Volume[m_Step][i];
  256. }
  257. }
  258. // reset the triggers between steps to clear them
  259. // otherwise consecutive events wont get triggered
  260. SetOutput(1,n,0);
  261. for (int t=0; t<NUM_PATTERNS; t++) SetOutput(t+2,n,0);
  262. }
  263. }
  264. }
  265. void MatrixPlugin::ExecuteCommands()
  266. {
  267. if (m_AudioCH->IsCommandWaiting())
  268. {
  269. switch (m_AudioCH->GetCommand())
  270. {
  271. case MAT_LENGTH :
  272. m_Matrix[m_GUICurrent].Length=m_GUIArgs.Length;
  273. break;
  274. case MAT_SPEED :
  275. m_Matrix[m_GUICurrent].Speed=m_GUIArgs.Speed;
  276. break;
  277. case MAT_ACTIVATE :
  278. m_Matrix[m_GUICurrent].Matrix[m_GUIArgs.X][m_GUIArgs.Y]=true;
  279. break;
  280. case MAT_DEACTIVATE :
  281. m_Matrix[m_GUICurrent].Matrix[m_GUIArgs.X][m_GUIArgs.Y]=false;
  282. break;
  283. case MAT_OCTAVE :
  284. m_Matrix[m_GUICurrent].Octave=m_GUIArgs.Octave;
  285. break;
  286. case COPY :
  287. CopyPattern();
  288. break;
  289. case PASTE :
  290. PastePattern();
  291. break;
  292. case CLEAR :
  293. ClearPattern();
  294. break;
  295. case TUP :
  296. if (CanTransposeUp()) TransposeUp();
  297. break;
  298. case TDOWN :
  299. if (CanTransposeDown()) TransposeDown();
  300. break;
  301. case MAT_VOLUME :
  302. m_Matrix[m_GUICurrent].Volume[m_GUIArgs.X][m_GUIArgs.Y]=m_GUIArgs.Volume;
  303. break;
  304. case SET_CURRENT :
  305. m_Current=m_GUIArgs.Num;
  306. break;
  307. }
  308. }
  309. }
  310. void MatrixPlugin::PastePattern() {
  311. m_Matrix[m_GUICurrent].Length = m_Matrix[m_CopyPattern].Length;
  312. m_Matrix[m_GUICurrent].Speed = m_Matrix[m_CopyPattern].Speed;
  313. m_Matrix[m_GUICurrent].Octave = m_Matrix[m_CopyPattern].Octave;
  314. for (int y=0; y<MATY; y++) {
  315. for (int x=0; x<MATX; x++) {
  316. m_Matrix[m_Current].Matrix[x][y] = m_Matrix[m_CopyPattern].Matrix[x][y];
  317. }
  318. }
  319. }
  320. void MatrixPlugin::ClearPattern() {
  321. for (int y=0; y<MATY; y++) {
  322. for (int x=0; x<MATX; x++) {
  323. m_Matrix[m_GUICurrent].Matrix[x][y] = 0;
  324. }
  325. }
  326. }
  327. void MatrixPlugin::TransposeUp() {
  328. int x, y;
  329. for (y=MATY-1; y>=0; y--) {
  330. for (x=0; x<MATX; x++) {
  331. m_Matrix[m_GUICurrent].Matrix[x][y] = m_Matrix[m_GUICurrent].Matrix[x][y-1];
  332. }
  333. }
  334. for (x=0; x<MATX; x++) {
  335. m_Matrix[m_GUICurrent].Matrix[x][0] = 0;
  336. }
  337. }
  338. void MatrixPlugin::TransposeDown()
  339. {
  340. int x, y;
  341. for (y=0; y<MATY-1; y++)
  342. {
  343. for (x=0; x<MATX; x++)
  344. {
  345. m_Matrix[m_GUICurrent].Matrix[x][y] = m_Matrix[m_GUICurrent].Matrix[x][y+1];
  346. }
  347. }
  348. for (x=0; x<MATX; x++)
  349. {
  350. m_Matrix[m_GUICurrent].Matrix[x][MATY-1] = 0;
  351. }
  352. }
  353. bool MatrixPlugin::CanTransposeDown()
  354. {
  355. for (int x=0; x<MATX; x++) if (m_Matrix[m_GUICurrent].Matrix[x][0]) return False;
  356. return True;
  357. }
  358. bool MatrixPlugin::CanTransposeUp()
  359. {
  360. for (int x=0; x<MATX; x++) if (m_Matrix[m_Current].Matrix[x][MATY-1]) return False;
  361. return True;
  362. }
  363. void MatrixPlugin::StreamOut(ostream &s)
  364. {
  365. s<<m_Version<<" ";
  366. s<<m_Current<<" "<<m_Time<<" "<<m_Step<<" "<<m_Loop<<" "<<m_NoteCut<<" "<<endl;
  367. for (int n=0; n<NUM_PATTERNS; n++)
  368. {
  369. s<<m_Matrix[n].Length<<" "<<m_Matrix[n].Speed<<" "<<m_Matrix[n].Octave<<endl;
  370. for (int y=0; y<MATY; y++)
  371. {
  372. for (int x=0; x<MATX; x++)
  373. {
  374. if (m_Matrix[n].Matrix[x][y]) s<<x<<" "<<y<<" "<<m_Matrix[n].Volume[x][y]<<" ";
  375. }
  376. }
  377. s<<"-1 ";
  378. }
  379. }
  380. void MatrixPlugin::StreamIn(istream &s)
  381. {
  382. int version;
  383. s>>version;
  384. switch (version)
  385. {
  386. case 1:
  387. {
  388. s>>m_Current>>m_Time>>m_Step>>m_Loop>>m_NoteCut;
  389. for (int n=0; n<NUM_PATTERNS; n++)
  390. {
  391. s>>m_Matrix[n].Length>>m_Matrix[n].Speed>>m_Matrix[n].Octave;
  392. for (int y=0; y<MATY; y++)
  393. for (int x=0; x<MATX; x++)
  394. {
  395. s>>m_Matrix[n].Matrix[x][y];
  396. }
  397. }
  398. } break;
  399. case 2:
  400. {
  401. s>>m_Current>>m_Time>>m_Step>>m_Loop>>m_NoteCut;
  402. for (int n=0; n<NUM_PATTERNS; n++)
  403. {
  404. s>>m_Matrix[n].Length>>m_Matrix[n].Speed>>m_Matrix[n].Octave;
  405. int x=0,y=0;
  406. while(x!=-1)
  407. {
  408. s>>x;
  409. if (x!=-1)
  410. {
  411. s>>y;
  412. if (y!=-1) m_Matrix[n].Matrix[x][y]=true;
  413. }
  414. }
  415. }
  416. } break;
  417. case 3:
  418. {
  419. s>>m_Current>>m_Time>>m_Step>>m_Loop>>m_NoteCut;
  420. for (int n=0; n<NUM_PATTERNS; n++)
  421. {
  422. s>>m_Matrix[n].Length>>m_Matrix[n].Speed>>m_Matrix[n].Octave;
  423. int x=0,y=0;
  424. float v;
  425. while(x!=-1)
  426. {
  427. s>>x;
  428. if (x!=-1)
  429. {
  430. s>>y>>v;
  431. if (y!=-1)
  432. {
  433. m_Matrix[n].Matrix[x][y]=true;
  434. m_Matrix[n].Volume[x][y]=v;
  435. }
  436. }
  437. }
  438. }
  439. } break;
  440. }
  441. }