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.

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