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.

428 lines
10KB

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