| 
							- /*  SpiralSound
 -  *  Copyleft (C) 2001 David Griffiths <dave@pawfal.org>
 -  *
 -  *  This program is free software; you can redistribute it and/or modify
 -  *  it under the terms of the GNU General Public License as published by
 -  *  the Free Software Foundation; either version 2 of the License, or
 -  *  (at your option) any later version.
 -  *
 -  *  This program is distributed in the hope that it will be useful,
 -  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -  *  GNU General Public License for more details.
 -  *
 -  *  You should have received a copy of the GNU General Public License
 -  *  along with this program; if not, write to the Free Software
 -  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 - */
 - #include "SpiralLoopPlugin.h"
 - #include "SpiralLoopPluginGUI.h"
 - #include <FL/Fl_Button.h>
 - #include "SpiralIcon.xpm"
 - #include "../../NoteTable.h"
 - 
 - #include "../../RiffWav.h"
 - 
 - using namespace std;
 - 
 - static const float TRIG_THRESH = 0.1;
 - static const int   RECBUFFERSIZE = 16384;
 - static const float RECORD_GAIN = 1.0f;
 - 
 - extern "C" {
 - SpiralPlugin* SpiralPlugin_CreateInstance()
 - {
 - 	return new SpiralLoopPlugin;
 - }
 - 
 - char** SpiralPlugin_GetIcon()
 - {
 - 	return SpiralIcon_xpm;
 - }
 - 
 - int SpiralPlugin_GetID()
 - {
 - 	return 0x001a;
 - }
 - 
 - string SpiralPlugin_GetGroupName()
 - {
 - 	return "Delay/Sampling";
 - }
 - }
 - 
 - ///////////////////////////////////////////////////////
 - 
 - SpiralLoopPlugin::SpiralLoopPlugin() : 
 - m_Id(0),
 - m_Pos(0),
 - m_IntPos(0),
 - m_PlayBufPos(0),
 - m_Playing(true),
 - m_Recording(false),
 - m_DelMe(false),
 - m_LoopPoint(0),
 - m_Speed(1.0f),
 - m_Volume(1.0f),
 - m_RecordingSource(NULL),
 - m_FirstRecord(true),
 - m_FixedRecord(false),
 - m_RecLength(0),
 - m_TickTime(0),
 - m_TickCurrent(0),
 - m_TicksPerLoop(64),
 - m_TickOutput(1.0f),
 - m_Triggered(false)
 - {
 - 	m_PluginInfo.Name="SpiralLoop";
 - 	m_PluginInfo.Width=300;
 - 	m_PluginInfo.Height=320;
 - 	m_PluginInfo.NumInputs=2;
 - 	m_PluginInfo.NumOutputs=10;		
 - 	m_PluginInfo.PortTips.push_back("Input");
 - 	m_PluginInfo.PortTips.push_back("Play Trigger");	
 - 	m_PluginInfo.PortTips.push_back("Output");
 - 	m_PluginInfo.PortTips.push_back("Clock");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 0");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 1");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 2");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 3");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 4");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 5");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 6");
 - 	m_PluginInfo.PortTips.push_back("LoopTrigger 7");			
 - 	
 - 	m_AudioCH->Register("TicksPerLoop",&m_TicksPerLoop);
 - 	m_AudioCH->Register("Volume",&m_Volume);
 - 	m_AudioCH->Register("Speed",&m_Speed);
 - 	m_AudioCH->Register("Length",&m_GUIArgs.Length);
 - 	m_AudioCH->Register("Start",&m_GUIArgs.Start);
 - 	m_AudioCH->Register("End",&m_GUIArgs.End);
 - 	m_AudioCH->Register("Pos",&m_Pos,ChannelHandler::OUTPUT);
 - 	m_AudioCH->RegisterData("Name",ChannelHandler::INPUT,&m_GUIArgs.Name,sizeof(m_GUIArgs.Name));
 - 	m_AudioCH->RegisterData("SampleBuffer",ChannelHandler::OUTPUT_REQUEST,&m_SampleBuffer,TRANSBUF_SIZE);
 - 	m_AudioCH->Register("SampleSize",&m_SampleSize,ChannelHandler::OUTPUT_REQUEST);
 - 
 - 	m_Version=2;
 - }
 - 
 - SpiralLoopPlugin::~SpiralLoopPlugin()
 - {
 - }
 - 
 - PluginInfo &SpiralLoopPlugin::Initialise(const HostInfo *Host)
 - {	
 - 	return SpiralPlugin::Initialise(Host);
 - }
 - 
 - SpiralGUIType *SpiralLoopPlugin::CreateGUI()
 - {
 - 	return new SpiralLoopPluginGUI(m_PluginInfo.Width,
 - 								  	    m_PluginInfo.Height,
 - 										this,m_AudioCH,m_HostInfo);
 - }
 - 
 - void SpiralLoopPlugin::Execute()
 - {
 - 	if (InputExists(0)) SetRecordingSource(GetInput(0)->GetBuffer());
 - 	else SetRecordingSource(NULL);
 - 
 - 	for (int n=0; n<8; n++) GetOutputBuf(n+1)->Zero();
 - 
 - 	// get the triggers active this frame
 - 	for (vector<TriggerInfo>::iterator i=m_TriggerVec.begin();
 - 		 i!=m_TriggerVec.end(); i++)
 - 	{
 - 		if (m_Pos > i->Time*m_StoreBuffer.GetLength() &&
 - 			!i->Triggered)
 - 		{
 - 			GetOutputBuf(i->Channel+2)->Set(1);
 - 			i->Triggered=true;
 - 		}
 - 	}
 - 
 - 	if (GetOutput(*GetOutputBuf(0)))
 - 	{
 - 		// if it's looped - reset the triggers
 - 		for (vector<TriggerInfo>::iterator i=m_TriggerVec.begin();
 - 		 i!=m_TriggerVec.end(); i++)
 - 		{
 - 			i->Triggered=false;
 - 		}
 - 		
 - 		m_TickCurrent=m_TickTime;
 - 	}	
 - 
 - 	if (GetInput(1,0)>TRIG_THRESH) 
 - 	{
 - 		if (!m_Triggered)
 - 		{
 - 			Trigger();		
 - 			m_Triggered=true;
 - 		}
 - 	}
 - 	else m_Triggered=false;
 - 	
 - 	m_TickCurrent+=m_HostInfo->BUFSIZE;
 - 	if (m_TickCurrent>=m_TickTime)
 - 	{
 - 		m_TickOutput=-m_TickOutput;
 - 		m_TickTime=m_StoreBuffer.GetLength()/m_TicksPerLoop;
 - 		m_TickCurrent=0;
 - 	}
 - 	
 - 	GetOutputBuf(1)->Set(m_TickOutput);
 - }
 - 
 - void SpiralLoopPlugin::ExecuteCommands()
 - {
 - 	if (m_AudioCH->IsCommandWaiting())
 - 	{
 - 		switch(m_AudioCH->GetCommand())
 - 		{
 - 		case START			: SetPlaying(true); break;
 - 		case STOP			: SetPlaying(false); break;
 - 		case RECORD			: Clear(); Record(true); break;
 - 		case OVERDUB		: Record(true); break;
 - 		case ENDRECORD		: Record(false); break;		
 - 		case LOAD			: LoadWav(m_GUIArgs.Name); break;
 - 		case SAVE			: SaveWav(m_GUIArgs.Name); break;
 - 		case CUT			: Cut(m_GUIArgs.Start, m_GUIArgs.End); break;
 - 		case COPY			: Copy(m_GUIArgs.Start, m_GUIArgs.End); break;
 - 		case PASTE			: Paste(m_GUIArgs.Start); break;
 - 		case PASTEMIX		: PasteMix(m_GUIArgs.Start); break;
 - 		case ZERO_RANGE		: ZeroRange(m_GUIArgs.Start, m_GUIArgs.End); break;
 - 		case REVERSE_RANGE	: ReverseRange(m_GUIArgs.Start, m_GUIArgs.End); break;
 - 		case SELECT_ALL		: SelectAll(); break;
 - 		case DOUBLE			: Double(); break;
 - 		case HALF			: Halve(); break;
 - 		case MOVE			: Move(m_GUIArgs.Start); break;
 - 		case CROP			: Crop(); break;
 - 		case KEEPDUB		: MixDub(); break;
 - 		case UNDODUB		: ClearDub(); break;
 - 		case CHANGE_LENGTH	: m_LoopPoint=(int)(m_StoreBuffer.GetLength()*m_GUIArgs.Length); break;
 - 		case NEW_TRIGGER	: 
 - 			{
 - 				TriggerInfo NewTrigger;
 - 				NewTrigger.Channel = m_GUIArgs.End;
 - 				NewTrigger.Time    = m_GUIArgs.Length;
 - 				if ((int)m_TriggerVec.size()!=m_GUIArgs.Start) cerr<<"no of triggers error!"<<endl;
 - 				m_TriggerVec.push_back(NewTrigger); break;
 - 			}
 - 		case UPDATE_TRIGGER	: 
 - 			{
 - 				m_TriggerVec[m_GUIArgs.Start].Channel = m_GUIArgs.End;
 - 				m_TriggerVec[m_GUIArgs.Start].Time    = m_GUIArgs.Length;			
 - 			}
 - 		case GETSAMPLE    	: 
 - 			{
 - 				m_AudioCH->SetupBulkTransfer((void*)m_StoreBuffer.GetBuffer());
 - 				m_SampleSize=m_StoreBuffer.GetLength();
 - 			} break;
 - 		}
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::StreamOut(ostream &s)
 - {
 - 	s<<m_Version<<" "; 
 - 	s<<m_LoopPoint<<" "<<m_Speed<<" "<<m_Volume<<" "<<m_TicksPerLoop<<" ";
 - 	s<<m_TriggerVec.size()<<" ";
 - 	for (vector<TriggerInfo>::iterator i=m_TriggerVec.begin();
 - 		 i!=m_TriggerVec.end(); i++)
 - 	{
 - 		s<<i->Channel<<" "<<i->Time<<" ";
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::StreamIn(istream &s)
 - {
 - 	int version;
 - 	s>>version;
 - 	s>>m_LoopPoint>>m_Speed>>m_Volume>>m_TicksPerLoop;
 - 	int size;
 - 	s>>size;
 - 	
 - 	for (int n=0; n<size; n++)
 - 	{
 - 		TriggerInfo t;
 - 		s>>t.Channel>>t.Time;
 - 		m_TriggerVec.push_back(t);
 - 	}
 - }
 - 	
 - bool SpiralLoopPlugin::SaveExternalFiles(const string &Dir)
 - {
 - 	char temp[256];
 - 	sprintf(temp,"%sSpiralLoopSample%d.wav",Dir.c_str(),SpiralPlugin_GetID());	
 - 	SaveWav(temp);
 - 	return true;
 - }
 - 
 - void SpiralLoopPlugin::LoadExternalFiles(const string &Dir)
 - {
 - 	char temp[256];
 - 	sprintf(temp,"%sSpiralLoopSample%d.wav",Dir.c_str(),SpiralPlugin_GetID());	
 - 	LoadWav(temp);
 - }
 - 
 - 
 - void SpiralLoopPlugin::LoadWav(const char *Filename)
 - {
 - 	WavFile wav;
 - 	if (wav.Open(Filename, WavFile::READ))
 - 	{
 - 		//Clear();
 - 		AllocateMem(wav.GetSize());		
 - 		wav.Load(m_StoreBuffer);	
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::SaveWav(const char *Filename)
 - {
 - 	WavFile wav;
 - 	if (wav.Open(Filename, WavFile::WRITE, WavFile::MONO))
 - 	{
 - 		wav.Save(m_StoreBuffer);
 - 	}
 - 	
 - 	m_Sample=Filename;
 - }
 - 
 - bool SpiralLoopPlugin::GetOutput(Sample &data)
 - {
 - 	if (!m_Recording && !m_Playing)
 - 	{
 - 		return false;
 - 	}
 - 	
 - 	if (!m_Recording && m_StoreBuffer.GetLength()==0)
 - 	{
 - 		return false;
 - 	}
 - 	
 - 	if (m_FixedRecord && m_DubBuffer.GetLength()!=m_StoreBuffer.GetLength())
 - 	{
 - 		cerr<<"eek! dub and store buffers don't match!"<<endl;
 - 	}
 - 	
 - 	if (m_Recording)
 - 	{	
 - 		RecordBuf(m_Pos, data.GetLength());
 - 			
 - 		if (!m_StoreBuffer.GetLength())
 - 		{
 - 			return false;
 - 		}	
 - 	}
 - 
 - 	int Pos;
 - 	bool ret=false;
 - 	
 - 	for (int n=0; n<data.GetLength(); n++)
 - 	{		
 - 		Pos=static_cast<int>(m_Pos);
 - 				
 - 		// brute force fix
 - 		if (Pos>0 && Pos<m_LoopPoint)
 - 		{
 - 			data.Set(n,(m_StoreBuffer[m_Pos]+m_DubBuffer[m_Pos])*m_Volume);
 - 		}
 - 		else data.Set(n,0);
 - 		
 - 		m_Pos+=m_Speed;
 - 		
 - 		if (static_cast<int>(m_Pos)>=m_LoopPoint)
 - 		{
 - 			ret=true;
 - 			m_Pos=0;
 - 		}
 - 	}
 - 	
 - 	m_IntPos=static_cast<int>(m_Pos);
 - 	
 - 	return ret;
 - }
 - 
 - void SpiralLoopPlugin::AllocateMem(int Length)
 - {		
 - 	// We might need to keep these values (if loading workspace)
 - 	if (m_LoopPoint>Length) m_LoopPoint=Length;
 - 	if (m_Pos>Length) m_Pos=0;
 - 	
 - 	if (m_LoopPoint==0) m_LoopPoint=Length;
 - 	
 - 	if (!m_StoreBuffer.Allocate(Length) || 
 - 	    !m_DubBuffer.Allocate(Length))
 - 	{
 - 		cerr<<"AllocateMem can't allocate any more memory!"<<endl;
 - 		Clear();
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::Clear()
 - {
 - 	m_StoreBuffer.Clear();
 - 	m_DubBuffer.Clear();
 - 	m_FixedRecord=false;
 - 	m_FirstRecord=true;
 - 	m_LoopPoint=0;
 - }
 - 
 - void SpiralLoopPlugin::RecordBuf(float Pos, int Length)
 - {
 - 	if (!m_RecordingSource) return;
 - 
 - 	static float OldPos=Pos;
 - 
 - 	if (m_FirstRecord)
 - 	{
 - 		// Find out if we want a fixed length record
 - 		// based on the last sample length, or not
 - 		if (m_StoreBuffer.GetLength())
 - 		{
 - 			m_FixedRecord=true;
 - 		}
 - 		else
 - 		{
 - 			m_FixedRecord=false;
 - 			m_RecBuffer.Allocate(RECBUFFERSIZE);
 - 			m_StoreBuffer.Clear();
 - 			m_RecPos=0;
 - 		}
 - 
 - 		m_FirstRecord=false;
 - 		m_RecLength=0;
 - 		OldPos=Pos;
 - 	}
 - 	
 - 	if (m_FixedRecord)
 - 	{
 - 		m_RecLength=m_LoopPoint;
 - 				
 - 		if (Pos>=m_StoreBuffer.GetLength())
 - 		{
 - 			Pos=0;
 - 		}
 - 			
 - 		for (int n=0; n<Length; n++)
 - 		{			
 - 			// just add directly to the old buffer
 - 			float temp=m_DubBuffer[static_cast<int>(Pos)]+m_RecordingSource[n]*RECORD_GAIN;
 - 			
 - 			// fill in all the samples between the speed jump with the same value
 - 			m_DubBuffer.Set((int)Pos,temp);
 - 			
 - 			for (int i=static_cast<int>(OldPos); i<=static_cast<int>(Pos); i++)
 - 			{
 - 				m_DubBuffer.Set(i,temp);
 - 			}
 - 						
 - 			OldPos=Pos;
 - 			Pos+=m_Speed;
 - 			
 - 			if (Pos>=m_StoreBuffer.GetLength())
 - 			{
 - 				Pos-=m_StoreBuffer.GetLength();				
 - 				
 - 				// remember to fill up to the end of the last buffer
 - 				for (int i=static_cast<int>(OldPos); i<m_StoreBuffer.GetLength(); i++)
 - 				{
 - 					m_DubBuffer.Set(i,temp);
 - 				}
 - 				
 - 				// and the beggining of this one
 - 				for (int i=0; i<Pos; i++)
 - 				{
 - 					m_DubBuffer.Set(i,temp);
 - 				}
 - 				
 - 				OldPos=0;	
 - 			}
 - 			
 - 		}
 - 	}
 - 	else
 - 	{
 - 		for (int n=0; n<Length; n++)
 - 		{							
 - 			// see if we need a new buffer
 - 			if (m_RecPos>=RECBUFFERSIZE)
 - 			{
 - 				// put the two buffers together
 - 				m_StoreBuffer.Add(m_RecBuffer);				
 - 				m_RecPos=0;
 - 			}
 - 				
 - 			m_RecBuffer.Set(m_RecPos,m_RecordingSource[n]*RECORD_GAIN);
 - 			
 - 			m_RecLength++;
 - 			m_RecPos++;
 - 		}
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::EndRecordBuf()
 - {
 - 	m_FirstRecord=true;	
 - 	m_LoopPoint=m_StoreBuffer.GetLength();
 - 	
 - 	if (!m_FixedRecord)
 - 	{
 - 		// reallocate the hold buffer for the new size
 - 		// (if the size has changed)
 - 		m_DubBuffer.Allocate(m_LoopPoint);			
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::Crop()
 - {
 - 	if (m_LoopPoint<m_StoreBuffer.GetLength())
 - 	{
 - 		m_StoreBuffer.CropTo(m_LoopPoint);		
 - 		m_DubBuffer.CropTo(m_LoopPoint); 
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::Double()
 - {
 - 	Crop();
 - 	
 - 	m_StoreBuffer.Add(m_StoreBuffer);
 - 	m_DubBuffer.Add(m_DubBuffer);
 - 	m_LoopPoint=m_StoreBuffer.GetLength();
 - }
 - 
 - void SpiralLoopPlugin::MatchLength(int Len)
 - {
 - 	// set the length, and make sure enough data is allocated
 - 	if (m_StoreBuffer.GetLength()>Len)
 - 	{
 - 		SetLength(Len);
 - 		return;
 - 	}
 - 	else
 - 	{
 - 		// if it's empty
 - 		if (!m_StoreBuffer.GetLength())
 - 		{			
 - 			AllocateMem(Len);
 - 			m_StoreBuffer.Zero();
 - 		}
 - 		else 
 - 		// there is something in the buffer already, but we need to
 - 		// add on some extra data to make the length the same
 - 		{
 - 			int ExtraLen=Len-m_StoreBuffer.GetLength();
 - 			m_StoreBuffer.Expand(ExtraLen);
 - 			m_DubBuffer.Expand(ExtraLen);		
 - 		}
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::Cut(int Start, int End)
 - { 
 - 	m_StoreBuffer.GetRegion(m_CopyBuffer,Start,End);
 - 	m_StoreBuffer.Remove(Start,End);
 - 	
 - 	if (m_StoreBuffer.GetLength()<m_LoopPoint)
 - 	{
 - 		m_LoopPoint=m_StoreBuffer.GetLength();
 - 	}
 - 	if (m_Pos>m_LoopPoint)
 - 	{
 - 		m_Pos=0;
 - 	}
 - 	
 - 	m_DubBuffer.Allocate(m_StoreBuffer.GetLength());
 - }
 - 
 - void SpiralLoopPlugin::Copy(int Start, int End)
 - { 
 - 	m_StoreBuffer.GetRegion(m_CopyBuffer,Start,End); 
 - }
 - 
 - void SpiralLoopPlugin::Paste(int Start)
 - { 
 - 	m_StoreBuffer.Insert(m_CopyBuffer,Start); 
 - 	
 - 	if (m_StoreBuffer.GetLength()<m_LoopPoint)
 - 	{
 - 		m_LoopPoint=m_StoreBuffer.GetLength();
 - 	}
 - 	if (m_Pos>m_LoopPoint)
 - 	{
 - 		m_Pos=0;
 - 	}
 - 	
 - 	m_DubBuffer.Allocate(m_StoreBuffer.GetLength());
 - }
 - 
 - void SpiralLoopPlugin::PasteMix(int Start)
 - { 
 - 	m_StoreBuffer.Mix(m_CopyBuffer,Start); 
 - }
 - 
 - void SpiralLoopPlugin::ZeroRange(int Start, int End)
 - {
 - 	for (int n=Start; n<End; n++)
 - 	{
 - 		m_StoreBuffer.Set(n,0);
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::ReverseRange(int Start, int End)
 - {
 - 	m_StoreBuffer.Reverse(Start,End);
 - }
 - 
 - void SpiralLoopPlugin::Halve()
 - {
 - 	m_StoreBuffer.Shrink(m_StoreBuffer.GetLength()/2);
 - 	m_DubBuffer.Shrink(m_DubBuffer.GetLength()/2);
 - 
 - 	if (m_StoreBuffer.GetLength()<m_LoopPoint)
 - 	{
 - 		m_LoopPoint=m_StoreBuffer.GetLength();
 - 	}
 - 	if (m_Pos>m_LoopPoint)
 - 	{
 - 		m_Pos=0;
 - 	}
 - }
 - 
 - void SpiralLoopPlugin::SelectAll()
 - {
 - }
 - 
 - void SpiralLoopPlugin::Move(int Start)
 - {
 - 	m_StoreBuffer.Move(Start);
 - }
 
 
  |