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.

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