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 "PoshSamplerPlugin.h"
19 #include "PoshSamplerPluginGUI.h"
20 #include <FL/Fl_Button.H>
21 #include "SpiralIcon.xpm"
22 #include "../../NoteTable.h"
23 #include <stdio.h>
24
25 #include "../../RiffWav.h"
26
27 using namespace std;
28
29 static const int NOTETRIG = NUM_SAMPLES*2+1;
30 static const int REC_INPUT = 16;
31
32 static const int S1_INPUT = 18;
33 static const int S2_INPUT = 19;
34 static const int S3_INPUT = 20;
35
36 extern "C" {
SpiralPlugin_CreateInstance()37 SpiralPlugin* SpiralPlugin_CreateInstance()
38 {
39 return new PoshSamplerPlugin;
40 }
41
SpiralPlugin_GetIcon()42 char** SpiralPlugin_GetIcon()
43 {
44 return SpiralIcon_xpm;
45 }
46
SpiralPlugin_GetID()47 int SpiralPlugin_GetID()
48 {
49 return 32;
50 }
51
SpiralPlugin_GetGroupName()52 string SpiralPlugin_GetGroupName()
53 {
54 return "Delay/Sampling";
55 }
56 }
57
58 ///////////////////////////////////////////////////////
59
60 static void
InitializeSampleDescription(SampleDesc * NewDesc,const string & Pathname,int Note)61 InitializeSampleDescription(SampleDesc* NewDesc, const string &Pathname, int Note)
62 {
63 if (NewDesc) {
64 NewDesc->Pathname = Pathname;
65 NewDesc->Volume = 1.0f;
66 NewDesc->Velocity = 1.0f;
67 NewDesc->Pitch = 1.0f;
68 NewDesc->PitchMod = 1.0f;
69 NewDesc->SamplePos = -1;
70 NewDesc->Loop = false;
71 NewDesc->PingPong = false;
72 NewDesc->Note = Note;
73 NewDesc->Octave = 0;
74 NewDesc->TriggerUp = true;
75 NewDesc->SamplePos = -1;
76 NewDesc->SampleRate = 44100;
77 NewDesc->Stereo = false;
78 NewDesc->PlayStart = 0;
79 NewDesc->LoopStart = 0;
80 NewDesc->LoopEnd = INT_MAX;
81 }
82 }
83
PoshSamplerPlugin()84 PoshSamplerPlugin::PoshSamplerPlugin() :
85 m_Recording(false)
86 {
87 m_PluginInfo.Name="PoshSampler";
88 m_PluginInfo.Width=400;
89 m_PluginInfo.Height=215;
90 m_PluginInfo.NumInputs=21;
91 m_PluginInfo.NumOutputs=9;
92 m_PluginInfo.PortTips.push_back("Sample 1 Pitch");
93 m_PluginInfo.PortTips.push_back("Sample 1 Trigger");
94 m_PluginInfo.PortTips.push_back("Sample 2 Pitch");
95 m_PluginInfo.PortTips.push_back("Sample 2 Trigger");
96 m_PluginInfo.PortTips.push_back("Sample 3 Pitch");
97 m_PluginInfo.PortTips.push_back("Sample 3 Trigger");
98 m_PluginInfo.PortTips.push_back("Sample 4 Pitch");
99 m_PluginInfo.PortTips.push_back("Sample 4 Trigger");
100 m_PluginInfo.PortTips.push_back("Sample 5 Pitch");
101 m_PluginInfo.PortTips.push_back("Sample 5 Trigger");
102 m_PluginInfo.PortTips.push_back("Sample 6 Pitch");
103 m_PluginInfo.PortTips.push_back("Sample 6 Trigger");
104 m_PluginInfo.PortTips.push_back("Sample 7 Pitch");
105 m_PluginInfo.PortTips.push_back("Sample 7 Trigger");
106 m_PluginInfo.PortTips.push_back("Sample 8 Pitch");
107 m_PluginInfo.PortTips.push_back("Sample 8 Trigger");
108 m_PluginInfo.PortTips.push_back("Input");
109 m_PluginInfo.PortTips.push_back("Sample trigger pitch");
110 m_PluginInfo.PortTips.push_back("Sample 1 Start Pos");
111 m_PluginInfo.PortTips.push_back("Sample 2 Start Pos");
112 m_PluginInfo.PortTips.push_back("Sample 3 Start Pos");
113 m_PluginInfo.PortTips.push_back("Mixed Output");
114 m_PluginInfo.PortTips.push_back("Sample 1 Output");
115 m_PluginInfo.PortTips.push_back("Sample 2 Output");
116 m_PluginInfo.PortTips.push_back("Sample 3 Output");
117 m_PluginInfo.PortTips.push_back("Sample 4 Output");
118 m_PluginInfo.PortTips.push_back("Sample 5 Output");
119 m_PluginInfo.PortTips.push_back("Sample 6 Output");
120 m_PluginInfo.PortTips.push_back("Sample 7 Output");
121 m_PluginInfo.PortTips.push_back("Sample 8 Output");
122
123 for (int n=0; n<NUM_SAMPLES; n++)
124 {
125 Sample* NewSample = new Sample;
126 m_SampleVec.push_back(NewSample);
127
128 SampleDesc* NewDesc = new SampleDesc;
129 char temp[256];
130 sprintf (temp, "PoshSampler%d_%d", GetID(), n);
131 InitializeSampleDescription(NewDesc, temp, n);
132 m_SampleDescVec.push_back(NewDesc);
133 }
134
135 m_Version=3;
136 m_Current = 0;
137
138 m_AudioCH->Register("Num",&m_GUIArgs.Num);
139 m_AudioCH->Register("Value",&m_GUIArgs.Value);
140 m_AudioCH->Register("Bool",&m_GUIArgs.Boole);
141 m_AudioCH->Register("Int",&m_GUIArgs.Int);
142 m_AudioCH->Register("Start",&m_GUIArgs.Start);
143 m_AudioCH->Register("End",&m_GUIArgs.End);
144 m_AudioCH->Register("LoopStart",&m_GUIArgs.LoopStart);
145 m_AudioCH->RegisterData("Name",ChannelHandler::INPUT,&m_GUIArgs.Name,sizeof(m_GUIArgs.Name));
146 m_AudioCH->Register("PlayPos",&m_CurrentPlayPos,ChannelHandler::OUTPUT);
147 m_AudioCH->RegisterData("SampleBuffer",ChannelHandler::OUTPUT_REQUEST,&m_SampleBuffer,TRANSBUF_SIZE);
148 m_AudioCH->Register("SampleSize",&m_SampleSize,ChannelHandler::OUTPUT_REQUEST);
149
150 }
151
~PoshSamplerPlugin()152 PoshSamplerPlugin::~PoshSamplerPlugin()
153 {
154 for (vector<Sample*>::iterator i=m_SampleVec.begin();
155 i!=m_SampleVec.end(); i++)
156 {
157 delete(*i);
158 }
159
160 for (vector<SampleDesc*>::iterator i=m_SampleDescVec.begin();
161 i!=m_SampleDescVec.end(); i++)
162 {
163 delete(*i);
164 }
165 }
166
Initialise(const HostInfo * Host)167 PluginInfo &PoshSamplerPlugin::Initialise(const HostInfo *Host)
168 {
169 return SpiralPlugin::Initialise(Host);;
170 }
171
CreateGUI()172 SpiralGUIType *PoshSamplerPlugin::CreateGUI()
173 {
174 return new PoshSamplerPluginGUI(m_PluginInfo.Width,
175 m_PluginInfo.Height,
176 this,m_AudioCH,m_HostInfo);
177 }
178
Execute()179 void PoshSamplerPlugin::Execute()
180 {
181 static bool Pong=false;
182
183 for (int s=0; s<NUM_SAMPLES+1; s++)
184 {
185 GetOutputBuf(s)->Zero();
186 }
187
188 float Freq=0;
189
190 for (int n=0; n<m_HostInfo->BUFSIZE; n++)
191 {
192 Freq=GetInputPitch(NOTETRIG,n);
193
194 for (int s=0; s<NUM_SAMPLES; s++)
195 {
196 SampleDesc* S=m_SampleDescVec[s];
197
198 // if we have a sample here
199 if (m_SampleVec[s]->GetLength())
200 {
201 // Convert the CV input into a useable trigger
202
203 if (GetInput(s*2+1,n)>0 || feq(Freq,NoteTable[S->Note],0.01f))
204 {
205 if (S->TriggerUp)
206 {
207 if (s==0 && InputExists(S1_INPUT))
208 S->PlayStart=(long int)((GetInput(S1_INPUT,n)*0.5+0.5f)*(S->LoopEnd-S->LoopStart))+S->LoopStart;
209 if (s==1 && InputExists(S2_INPUT))
210 S->PlayStart=(long int)((GetInput(S2_INPUT,n)*0.5+0.5f)*(S->LoopEnd-S->LoopStart))+S->LoopStart;
211 if (s==2 && InputExists(S3_INPUT))
212 S->PlayStart=(long int)((GetInput(S3_INPUT,n)*0.5+0.5f)*(S->LoopEnd-S->LoopStart))+S->LoopStart;
213
214 if (S->PlayStart<0) S->PlayStart=0;
215
216 S->SamplePos=S->PlayStart;
217 S->TriggerUp=false;
218 S->Velocity=GetInput(s*2+1,n);
219 }
220 }
221 else
222 {
223 S->TriggerUp=true;
224
225 // end it if it's looping
226 if (S->Loop)
227 {
228 S->SamplePos=-1;
229 }
230 }
231
232 // if the sample has ended
233 if (S->SamplePos>=S->LoopEnd || S->SamplePos>=m_SampleVec[s]->GetLength())
234 {
235 if (S->Loop)
236 {
237 if (S->PingPong) Pong=true;
238 else S->SamplePos=S->LoopStart;
239 }
240 else
241 {
242 S->SamplePos=-1;
243 }
244 }
245
246 // if the sample has ended ponging
247 if (Pong && S->SamplePos<=S->LoopStart)
248 {
249 Pong=false;
250 }
251
252 if (S->SamplePos!=-1)
253 {
254 if (InputExists(s*2))
255 {
256 // Get the pitch from the CV
257 float PlayFreq=GetInputPitch(s*2,n);
258
259 // assumtion: base frequency = 440 (middle A)
260 S->Pitch = PlayFreq/440;
261 S->Pitch *= S->SampleRate/(float)m_HostInfo->SAMPLERATE;
262 }
263
264 // mix the sample to the output.
265 MixOutput(0,n,(*m_SampleVec[s])[S->SamplePos]*S->Volume*S->Velocity);
266 // copy the sample to it's individual output.
267 SetOutput(s+1,n,((*m_SampleVec[s])[S->SamplePos]*S->Volume));
268
269 float Freq=S->Pitch;
270 if (S->Octave>0) Freq*=1<<(S->Octave);
271 if (S->Octave<0) Freq/=1<<(-S->Octave);
272
273 if (Pong) S->SamplePos-=Freq*S->PitchMod;
274 else S->SamplePos+=Freq*S->PitchMod;
275 }
276 }
277 }
278 }
279
280 // record
281 static int LastRecording=false;
282 if(m_Recording && InputExists(REC_INPUT))
283 {
284 int s=0;//GUI->GetCurrentSample();
285
286 if (!LastRecording) m_SampleVec[s]->Clear();
287
288 // new sample
289 if (m_SampleVec[s]->GetLength()==0)
290 {
291 *m_SampleVec[s]=*GetInput(REC_INPUT);
292
293 m_SampleDescVec[s]->SampleRate=m_HostInfo->SAMPLERATE;
294 m_SampleDescVec[s]->Stereo=false;
295 m_SampleDescVec[s]->Pitch *= 1.0f;
296 m_SampleDescVec[s]->LoopEnd=m_SampleVec[s]->GetLength();
297
298 }
299 else
300 {
301 m_SampleVec[s]->Add(*GetInput(REC_INPUT));
302 m_SampleDescVec[s]->LoopEnd=m_SampleVec[s]->GetLength();
303 }
304 }
305 LastRecording=m_Recording;
306
307 if (m_SampleDescVec[m_Current]->SamplePos>0)
308 {
309 m_CurrentPlayPos=(long)m_SampleDescVec[m_Current]->SamplePos;
310 }
311 }
312
ExecuteCommands()313 void PoshSamplerPlugin::ExecuteCommands()
314 {
315 if (m_AudioCH->IsCommandWaiting())
316 {
317 switch(m_AudioCH->GetCommand())
318 {
319 case (LOAD) : LoadSample(m_GUIArgs.Num,m_GUIArgs.Name); break;
320 case (SAVE) : SaveSample(m_GUIArgs.Num,m_GUIArgs.Name); break;
321 case (SETVOL) : SetVolume(m_GUIArgs.Num,m_GUIArgs.Value); break;
322 case (SETPITCH) : SetPitch(m_GUIArgs.Num,m_GUIArgs.Value); break;
323 case (SETLOOP) : SetLoop(m_GUIArgs.Num,m_GUIArgs.Boole); break;
324 case (SETPING) : SetPingPong(m_GUIArgs.Num,m_GUIArgs.Boole); break;
325 case (SETNOTE) : SetNote(m_GUIArgs.Num,m_GUIArgs.Int); break;
326 case (SETOCT) : SetOctave(m_GUIArgs.Num,m_GUIArgs.Int); break;
327 case (SETPLAYPOINTS):
328 {
329 SetPlayStart(m_GUIArgs.Num,m_GUIArgs.Start);
330 SetLoopStart(m_GUIArgs.Num,m_GUIArgs.LoopStart);
331 SetLoopEnd(m_GUIArgs.Num,m_GUIArgs.End);
332 } break;
333 case (SETREC) : SetRecord(m_GUIArgs.Boole); break;
334 case (CUT) : Cut(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
335 case (COPY) : Copy(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
336 case (PASTE) : Paste(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
337 case (MIX) : Mix(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
338 case (CROP) : Crop(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
339 case (REV) : Reverse(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
340 case (AMP) : Amp(m_GUIArgs.Num,m_GUIArgs.Start,m_GUIArgs.End); break;
341 case (SETCURRENT) : m_Current = m_GUIArgs.Num; break;
342 case (GETSAMPLE) :
343 {
344 m_AudioCH->SetupBulkTransfer((void*)m_SampleVec[m_Current]->GetBuffer());
345 m_SampleSize=m_SampleVec[m_Current]->GetLengthInBytes();
346 } break;
347 };
348 }
349 }
350
StreamOut(ostream & s)351 void PoshSamplerPlugin::StreamOut(ostream &s)
352 {
353 s<<m_Version<<" ";
354 for (int n=0; n<NUM_SAMPLES; n++)
355 {
356 s<<m_SampleDescVec[n]->Volume<<" "<<
357 m_SampleDescVec[n]->PitchMod<<" "<<
358 m_SampleDescVec[n]->Loop<<" "<<
359 m_SampleDescVec[n]->PingPong<<" "<<
360 m_SampleDescVec[n]->Note<<" "<<
361 m_SampleDescVec[n]->Octave<<" "<<
362 m_SampleDescVec[n]->SamplePos<<" "<<
363 m_SampleDescVec[n]->PlayStart<<" "<<
364 m_SampleDescVec[n]->LoopStart<<" "<<
365 m_SampleDescVec[n]->LoopEnd<<" "<<
366 m_SampleDescVec[n]->Note<<" ";
367 }
368 }
369
StreamIn(istream & s)370 void PoshSamplerPlugin::StreamIn(istream &s)
371 {
372 int version;
373 s>>version;
374
375 for (int n=0; n<NUM_SAMPLES; n++)
376 {
377 s>>m_SampleDescVec[n]->Volume>>
378 m_SampleDescVec[n]->PitchMod>>
379 m_SampleDescVec[n]->Loop>>
380 m_SampleDescVec[n]->PingPong>>
381 m_SampleDescVec[n]->Note>>
382 m_SampleDescVec[n]->Octave>>
383 m_SampleDescVec[n]->SamplePos>>
384 m_SampleDescVec[n]->PlayStart>>
385 m_SampleDescVec[n]->LoopStart>>
386 m_SampleDescVec[n]->LoopEnd>>
387 m_SampleDescVec[n]->Note;
388
389 if (version<3)
390 {
391 int size;
392 s>>size;
393 s.ignore(1);
394 char Buf[4096];
395 s.get(Buf,size+1);
396 }
397 }
398 }
399
LoadSample(int n,const string & Name)400 void PoshSamplerPlugin::LoadSample(int n, const string &Name)
401 {
402 WavFile Wav;
403 if (Wav.Open(Name,WavFile::READ))
404 {
405 m_SampleVec[n]->Allocate(Wav.GetSize());
406 Wav.Load(*m_SampleVec[n]);
407 InitializeSampleDescription(m_SampleDescVec[n], Name, n);
408 m_SampleDescVec[n]->SampleRate=Wav.GetSamplerate();
409 m_SampleDescVec[n]->Stereo=Wav.IsStereo();
410 m_SampleDescVec[n]->Pitch *= m_SampleDescVec[n]->SampleRate/(float)m_HostInfo->SAMPLERATE;
411 m_SampleDescVec[n]->LoopEnd=m_SampleVec[n]->GetLength()-1;
412 }
413 }
414
SaveSample(int n,const string & Name)415 void PoshSamplerPlugin::SaveSample(int n, const string &Name)
416 {
417 if (m_SampleVec[n]->GetLength()==0) return;
418
419 WavFile Wav;
420 Wav.Open(Name,WavFile::WRITE,WavFile::MONO);
421 Wav.Save(*m_SampleVec[n]);
422 }
423
Cut(int n,long s,long e)424 void PoshSamplerPlugin::Cut(int n, long s, long e)
425 {
426 if (m_SampleVec[n]->GetLength()==0) return;
427 m_SampleVec[n]->GetRegion(m_CopyBuffer, s, e);
428 m_SampleVec[n]->Remove(s, e);
429 }
430
Copy(int n,long s,long e)431 void PoshSamplerPlugin::Copy(int n, long s, long e)
432 {
433 if (m_SampleVec[n]->GetLength()==0) return;
434 m_SampleVec[n]->GetRegion(m_CopyBuffer, s, e);
435 }
436
Paste(int n,long s,long e)437 void PoshSamplerPlugin::Paste(int n, long s, long e)
438 {
439 if (m_SampleVec[n]->GetLength()==0) return;
440 m_SampleVec[n]->Insert(m_CopyBuffer, s);
441 }
442
Mix(int n,long s,long e)443 void PoshSamplerPlugin::Mix(int n, long s, long e)
444 {
445 if (m_SampleVec[n]->GetLength()==0) return;
446 m_SampleVec[n]->Mix(m_CopyBuffer, s);
447 }
448
Crop(int n,long s,long e)449 void PoshSamplerPlugin::Crop(int n, long s, long e)
450 {
451 if (m_SampleVec[n]->GetLength()==0) return;
452 m_SampleVec[n]->Remove(0, s);
453 m_SampleVec[n]->Remove(e, m_SampleVec[n]->GetLength()-1);
454 }
455
Reverse(int n,long s,long e)456 void PoshSamplerPlugin::Reverse(int n, long s, long e)
457 {
458 if (m_SampleVec[n]->GetLength()==0) return;
459 m_SampleVec[n]->Reverse(s, e);
460 }
461
Amp(int n,long s,long e)462 void PoshSamplerPlugin::Amp(int n, long s, long e)
463 {
464 if (m_SampleVec[n]->GetLength()==0) return;
465 for (int m=0; m<m_SampleVec[n]->GetLength(); m++)
466 {
467 m_SampleVec[n]->Set(m,(*m_SampleVec[n])[m]*m_SampleDescVec[n]->Volume);
468 }
469 }
470
471
SaveExternalFiles(const string & Dir)472 bool PoshSamplerPlugin::SaveExternalFiles(const string &Dir)
473 {
474 for (int n=0; n<NUM_SAMPLES; n++)
475 {
476 char temp[256];
477 // Andy's fix for bug 766594
478 // sprintf (temp, "PoshSampler%d_%d.wav", SpiralPlugin_GetID(), n);
479 sprintf (temp, "PoshSampler%d_%d.wav", GetID(), n);
480 m_SampleDescVec[n]->Pathname = temp;
481 }
482
483 for (int n=0; n<NUM_SAMPLES; n++)
484 {
485 // if it's not empty
486 if (m_SampleVec[n]->GetLength()!=0)
487 {
488 SaveSample(n,Dir+m_SampleDescVec[n]->Pathname);
489 }
490 }
491 return true;
492 }
493
LoadExternalFiles(const string & Dir)494 void PoshSamplerPlugin::LoadExternalFiles(const string &Dir)
495 {
496 for (int n=0; n<NUM_SAMPLES; n++)
497 {
498 char temp[256];
499 // Andy's fix for bug 766594
500 // sprintf (temp, "PoshSampler%d_%d.wav", SpiralPlugin_GetID(), n);
501 sprintf (temp, "PoshSampler%d_%d.wav", GetID(), n);
502 m_SampleDescVec[n]->Pathname = temp;
503 }
504
505 for (int n=0; n<NUM_SAMPLES; n++)
506 {
507 LoadSample(n,Dir+m_SampleDescVec[n]->Pathname);
508 }
509 }
510