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.

375 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 "StreamPlugin.h"
  19. #include "StreamPluginGUI.h"
  20. #include <FL/Fl_Button.h>
  21. #include "SpiralIcon.xpm"
  22. #include "../../NoteTable.h"
  23. #include <stdio.h>
  24. #include "../../../config.h"
  25. #ifdef USE_LIBSNDFILE
  26. #include <sndfile.h>
  27. #endif
  28. #include "../../RiffWav.h"
  29. using namespace std;
  30. static const float TRIG_THRESH = 0.1;
  31. static const float BUFSECONDS = 1.0f;
  32. extern "C" {
  33. SpiralPlugin* SpiralPlugin_CreateInstance()
  34. {
  35. return new StreamPlugin;
  36. }
  37. char** SpiralPlugin_GetIcon()
  38. {
  39. return SpiralIcon_xpm;
  40. }
  41. int SpiralPlugin_GetID()
  42. {
  43. return 0x0119;
  44. }
  45. string SpiralPlugin_GetGroupName()
  46. {
  47. return "Delay/Sampling";
  48. }
  49. }
  50. ///////////////////////////////////////////////////////
  51. StreamPlugin::StreamPlugin() :
  52. #ifdef USE_LIBSNDFILE
  53. m_File (NULL),
  54. #endif
  55. m_SampleRate (44100),
  56. m_SampleSize (256),
  57. m_StreamPos (0),
  58. m_GlobalPos (0),
  59. m_Pitch (1.0f),
  60. m_SamplePos (-1),
  61. m_Pos (0),
  62. m_Mode(STOPM)
  63. {
  64. m_PluginInfo.Name = "Stream";
  65. m_PluginInfo.Width = 245;
  66. m_PluginInfo.Height = 165;
  67. m_PluginInfo.NumInputs = 3;
  68. m_PluginInfo.NumOutputs = 3;
  69. m_PluginInfo.PortTips.push_back ("Pitch CV");
  70. m_PluginInfo.PortTips.push_back ("Play Trigger");
  71. m_PluginInfo.PortTips.push_back ("Stop Trigger");
  72. m_PluginInfo.PortTips.push_back ("Left Out");
  73. m_PluginInfo.PortTips.push_back ("Right Out");
  74. m_PluginInfo.PortTips.push_back ("Finish Trigger");
  75. m_GUIArgs.Volume = 1.0f;
  76. m_GUIArgs.PitchMod = 1.0f;
  77. m_GUIArgs.PlayOut = false;
  78. m_AudioCH->Register ("Volume", &m_GUIArgs.Volume);
  79. m_AudioCH->Register ("Pitch", &m_GUIArgs.PitchMod, ChannelHandler::INPUT);
  80. m_AudioCH->RegisterData ("FileName", ChannelHandler::INPUT,
  81. &m_GUIArgs.FileName, sizeof (m_GUIArgs.FileName));
  82. m_AudioCH->Register ("Time", &m_GUIArgs.Time);
  83. m_AudioCH->Register ("TimeOut", &m_GUIArgs.TimeOut, ChannelHandler::OUTPUT);
  84. m_AudioCH->Register ("MaxTime", &m_GUIArgs.MaxTime, ChannelHandler::OUTPUT);
  85. m_AudioCH->Register ("Playing", &m_GUIArgs.PlayOut, ChannelHandler::OUTPUT);
  86. }
  87. StreamPlugin::~StreamPlugin()
  88. {
  89. #ifdef USE_LIBSNDFILE
  90. if (m_File)
  91. sf_close(m_File);
  92. m_File = NULL;
  93. #endif
  94. }
  95. PluginInfo &StreamPlugin::Initialise(const HostInfo *Host)
  96. {
  97. PluginInfo& Info = SpiralPlugin::Initialise(Host);
  98. return Info;
  99. }
  100. SpiralGUIType *StreamPlugin::CreateGUI() {
  101. return new StreamPluginGUI(m_PluginInfo.Width, m_PluginInfo.Height, this, m_AudioCH, m_HostInfo);
  102. }
  103. void StreamPlugin::Execute() {
  104. #ifdef USE_LIBSNDFILE
  105. if (m_File) {
  106. for (int n=0; n<m_HostInfo->BUFSIZE; n++) {
  107. bool FinTrig = false;
  108. float CVPitch = GetInput(0, n)*10.0f;
  109. if (GetInput (1, n) > 0) m_Mode = PLAYM;
  110. if (GetInput (2, n) > 0) {
  111. m_Mode = STOPM;
  112. m_Pos = 0;
  113. m_GlobalPos = 0;
  114. m_StreamPos = 0;
  115. }
  116. bool DoLoadChunk = false;
  117. if (m_Pos<0) {
  118. m_Pos = m_SampleSize - 1;
  119. m_StreamPos -= m_SampleSize;
  120. FinTrig = m_StreamPos < 0;
  121. if (FinTrig) {
  122. m_StreamPos = m_FileInfo.frames - m_SampleSize;
  123. m_GlobalPos = m_StreamPos;
  124. }
  125. DoLoadChunk = true;
  126. }
  127. else if (m_Pos >= m_SampleSize) {
  128. m_Pos = 0;
  129. m_StreamPos += m_SampleSize;
  130. FinTrig = m_StreamPos >= m_FileInfo.frames;
  131. if (FinTrig) {
  132. m_StreamPos = 0;
  133. m_GlobalPos = 0;
  134. }
  135. DoLoadChunk = true;
  136. }
  137. if (DoLoadChunk) {
  138. if ((m_FileInfo.frames - m_StreamPos) < 256)
  139. m_SampleSize = m_FileInfo.frames - m_StreamPos;
  140. else
  141. m_SampleSize = 256;
  142. if (sf_seek(m_File, m_StreamPos, SEEK_SET)==-1)
  143. {
  144. cerr<<"StreamPlugin: File ["<<m_GUIArgs.FileName<<"] Seek error"<<endl;
  145. }
  146. float *TempBuf = new float[m_SampleSize * m_FileInfo.channels];
  147. int ChunkSize = 0;
  148. ChunkSize = (int)sf_read_float(m_File, TempBuf, m_SampleSize*m_FileInfo.channels);
  149. if ((m_SampleSize*m_FileInfo.channels)!=ChunkSize)
  150. {
  151. cerr<<"StreamPlugin: Only recieved "<<ChunkSize<<" of "<<m_SampleSize<<": Read chunk error"<<endl;
  152. } else {
  153. // Extract and scale samples to float range +/-1.0
  154. for (int n=0; n<m_SampleSize; n++)
  155. {
  156. m_SampleL.Set(n,TempBuf[n*m_FileInfo.channels]);
  157. if (m_FileInfo.channels>1)
  158. m_SampleR.Set(n,TempBuf[n*m_FileInfo.channels+1]);
  159. }
  160. }
  161. delete[] TempBuf;
  162. }
  163. if (FinTrig) SetOutput (2, n, 1);
  164. else SetOutput (2, n, 0);
  165. if (m_Mode==PLAYM) {
  166. SetOutput (0, n, m_SampleL[m_Pos] * m_GUIArgs.Volume);
  167. SetOutput (1, n, m_SampleR[m_Pos] * m_GUIArgs.Volume);
  168. m_Pos += m_GUIArgs.PitchMod + CVPitch;
  169. m_GlobalPos += m_GUIArgs.PitchMod + CVPitch;
  170. }
  171. else {
  172. SetOutput (0, n, 0);
  173. SetOutput (1, n, 0);
  174. }
  175. }
  176. m_GUIArgs.TimeOut = m_GlobalPos / (float)m_SampleRate;
  177. m_GUIArgs.PlayOut = m_Mode==PLAYM;
  178. }
  179. #else
  180. if (m_File.IsOpen()) {
  181. for (int n=0; n<m_HostInfo->BUFSIZE; n++) {
  182. bool FinTrig = false;
  183. float CVPitch = GetInput(0, n)*10.0f;
  184. if (GetInput (1, n) > 0) m_Mode = PLAYM;
  185. if (GetInput (2, n) > 0) {
  186. m_Mode = STOPM;
  187. m_Pos = 0;
  188. m_GlobalPos = 0;
  189. m_StreamPos = 0;
  190. }
  191. if (m_Pos<0) {
  192. m_Pos = m_SampleSize - 1;
  193. m_StreamPos -= m_SampleSize;
  194. FinTrig = m_StreamPos < 0;
  195. if (FinTrig) {
  196. m_StreamPos = m_File.GetSize() - m_SampleSize;
  197. m_GlobalPos = m_StreamPos;
  198. }
  199. m_File.SeekToChunk (m_StreamPos);
  200. m_File.LoadChunk (m_SampleSize, m_SampleL, m_SampleR);
  201. }
  202. else if (m_Pos >= m_SampleSize) {
  203. m_Pos = 0;
  204. m_StreamPos += m_SampleSize;
  205. FinTrig = m_StreamPos >= m_File.GetSize();
  206. if (FinTrig) {
  207. m_StreamPos = 0;
  208. m_GlobalPos = 0;
  209. }
  210. m_File.SeekToChunk (m_StreamPos);
  211. m_File.LoadChunk (m_SampleSize, m_SampleL, m_SampleR);
  212. }
  213. if (FinTrig) SetOutput (2, n, 1);
  214. else SetOutput (2, n, 0);
  215. if (m_Mode==PLAYM) {
  216. SetOutput (0, n, m_SampleL[m_Pos] * m_GUIArgs.Volume);
  217. SetOutput (1, n, m_SampleR[m_Pos] * m_GUIArgs.Volume);
  218. m_Pos += m_GUIArgs.PitchMod + CVPitch;
  219. m_GlobalPos += m_GUIArgs.PitchMod + CVPitch;
  220. }
  221. else {
  222. SetOutput (0, n, 0);
  223. SetOutput (1, n, 0);
  224. }
  225. }
  226. m_GUIArgs.TimeOut = m_GlobalPos / (float)m_SampleRate;
  227. m_GUIArgs.PlayOut = m_Mode==PLAYM;
  228. }
  229. #endif
  230. }
  231. void StreamPlugin::ExecuteCommands() {
  232. if (m_AudioCH->IsCommandWaiting()) {
  233. switch (m_AudioCH->GetCommand()) {
  234. case SET_TIME:
  235. SetTime();
  236. break;
  237. case LOAD:
  238. OpenStream();
  239. break;
  240. case RESTART:
  241. m_StreamPos = 0;
  242. m_GlobalPos = 0;
  243. break;
  244. case STOP:
  245. m_Mode = STOPM;
  246. break;
  247. case PLAY:
  248. m_Mode = PLAYM;
  249. break;
  250. }
  251. }
  252. }
  253. void StreamPlugin::SetTime (void) {
  254. m_GlobalPos = m_SampleRate * m_GUIArgs.Time;
  255. m_StreamPos = (int)(m_SampleRate * m_GUIArgs.Time);
  256. m_Pos = m_SampleSize;
  257. }
  258. void StreamPlugin::OpenStream (void) {
  259. m_StreamPos = 0;
  260. m_GlobalPos = 0;
  261. #ifdef USE_LIBSNDFILE
  262. m_FileInfo.format = 0;
  263. if (m_File != NULL)
  264. {
  265. sf_close(m_File);
  266. m_File = NULL;
  267. }
  268. m_File = sf_open (m_GUIArgs.FileName, SFM_READ, &m_FileInfo);
  269. if (m_File == NULL)
  270. {
  271. cerr<<"StreamPlugin: File ["<<m_GUIArgs.FileName<<"] does not exist"<<endl;
  272. return;
  273. }
  274. if (m_FileInfo.frames < 256)
  275. m_SampleSize = m_FileInfo.frames;
  276. else
  277. m_SampleSize = 256;
  278. m_SampleL.Allocate (m_SampleSize);
  279. m_SampleR.Allocate (m_SampleSize);
  280. m_Pitch = m_FileInfo.samplerate / (float)m_HostInfo->SAMPLERATE;
  281. if (m_FileInfo.channels>1) {
  282. m_Pitch *= 2;
  283. m_GUIArgs.MaxTime = GetLength();
  284. }
  285. else m_GUIArgs.MaxTime = GetLength() / 2;
  286. #else
  287. if (m_File.IsOpen ()) m_File.Close ();
  288. m_File.Open (m_GUIArgs.FileName, WavFile::READ);
  289. m_SampleL.Allocate (m_SampleSize);
  290. m_SampleR.Allocate (m_SampleSize);
  291. m_Pitch = m_SampleRate / (float)m_HostInfo->SAMPLERATE;
  292. if (m_File.IsStereo ()) {
  293. m_Pitch *= 2;
  294. m_GUIArgs.MaxTime = GetLength();
  295. }
  296. else m_GUIArgs.MaxTime = GetLength() / 2;
  297. #endif
  298. }
  299. float StreamPlugin::GetLength (void) {
  300. #ifdef USE_LIBSNDFILE
  301. if (m_FileInfo.channels>1) return m_FileInfo.frames / (float)m_FileInfo.samplerate;
  302. else return m_FileInfo.frames / (float)m_FileInfo.samplerate * 2;
  303. #else
  304. if (m_File.IsStereo()) return m_File.GetSize() / (float)m_File.GetSamplerate ();
  305. else return m_File.GetSize() / (float)m_File.GetSamplerate () * 2;
  306. #endif
  307. }
  308. void StreamPlugin::StreamOut (ostream &s) {
  309. s << m_Version << " "
  310. << m_GUIArgs.Volume << " "
  311. << m_GUIArgs.PitchMod << " "
  312. << strlen (m_GUIArgs.FileName) << " "
  313. << m_GUIArgs.FileName << " "
  314. // is it really necessary to save this lot??
  315. << m_Pos << " "
  316. << m_StreamPos << " "
  317. << m_GlobalPos << " "
  318. << m_Pitch << " " << endl;
  319. }
  320. void StreamPlugin::StreamIn(istream &s) {
  321. int version;
  322. s >> version;
  323. s >> m_GUIArgs.Volume >> m_GUIArgs.PitchMod;
  324. int size;
  325. s >> size;
  326. if (size > 255) size = 255;
  327. s.ignore (1);
  328. s.get (m_GUIArgs.FileName, size+1);
  329. if (m_GUIArgs.FileName != "None") OpenStream ();
  330. // is it really necessary to load this lot??
  331. s >> m_Pos;
  332. s >> m_StreamPos;
  333. s >> m_GlobalPos;
  334. s >> m_Pitch;
  335. }