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
12KB

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