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