1 /*  SpiralLoops
2  *  Copyleft (C) 2000 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 
19 #include "Loop.h"
20 #include "SpiralSound/RiffWav.h"
21 #include "SpiralLoopsInfo.h"
22 
23 static const int   RECBUFFERSIZE = 16384;
24 static const float RECORD_GAIN = 1.0f;
25 
Loop(Loops * s)26 Loop::Loop(Loops *s) :
27 m_Id(0),
28 m_Pos(0),
29 m_IntPos(0),
30 m_PlayBufPos(0),
31 m_Playing(true),
32 m_Recording(false),
33 m_Master(false),
34 m_DelMe(false),
35 m_LoopPoint(0),
36 m_Speed(1.0f),
37 m_Volume(1.0f),
38 m_RecordingSource(NULL),
39 m_Balance(1.0f),
40 m_LeftVol(1.0f),
41 m_RightVol(1.0f),
42 m_FirstRecord(true),
43 m_FixedRecord(false),
44 m_RecLength(0),
45 m_EffectsOn(false),
46 m_Parent(s)
47 {
48 	m_Delay.SetNumChannels(1);
49 	m_Reverb.SetNumChannels(1);
50 }
51 
~Loop()52 Loop::~Loop()
53 {
54 }
55 
LoadWav(char * Filename)56 void Loop::LoadWav(char *Filename)
57 {
58 	WavFile wav;
59 	if (wav.Open(Filename, WavFile::READ))
60 	{
61 		Clear();
62 		AllocateMem(wav.GetSize());
63 		wav.Load(m_StoreBuffer);
64 	}
65 }
66 
SaveWav(char * Filename)67 void Loop::SaveWav(char *Filename)
68 {
69 	WavFile wav;
70 	if (wav.Open(Filename, WavFile::WRITE, WavFile::MONO))
71 	{
72 		wav.Save(m_StoreBuffer);
73 	}
74 }
75 
GetOutput(Sample & data)76 bool Loop::GetOutput(Sample &data)
77 {
78 	if (!m_Recording && !m_Playing)
79 	{
80 		return false;
81 	}
82 
83 	if (!m_Recording && m_StoreBuffer.GetLength()==0)
84 	{
85 		return false;
86 	}
87 
88 	if (m_Recording)
89 	{
90 		RecordBuf(m_Pos);
91 
92 		if (!m_StoreBuffer.GetLength())
93 		{
94 			return false;
95 		}
96 	}
97 
98 	int Pos;
99 
100 	for (int n=0; n<SpiralLoopsInfo::BUFSIZE; n++)
101 	{
102 		Pos=static_cast<int>(m_Pos);
103 
104 		// brute force fix
105 		if (Pos>0 && Pos<m_LoopPoint)
106 		{
107 			data[n]=static_cast<int>(m_StoreBuffer[Pos]*m_Volume);
108 		}
109 		else data[n]=0;
110 
111 		m_Pos+=m_Speed;
112 
113 		if (static_cast<int>(m_Pos)>=m_LoopPoint)
114 		{
115 			m_Pos=0;
116 		}
117 	}
118 
119 	m_Filter.GetOutput(0,data);
120 
121 	// causes problems if we save to a hold buffer
122 	// while we're recording, as we might not know
123 	// the size of the final buffer
124 	if (!m_Recording)
125 	{
126 		for (int n=0; n<SpiralLoopsInfo::BUFSIZE; n++)
127 		{
128 			if (m_PlayBufPos>=m_LoopPoint)
129 			{
130 				m_PlayBufPos=0;
131 			}
132 
133 			m_HoldBuffer[m_PlayBufPos]=data[n];
134 			m_PlayBufPos++;
135 		}
136 	}
137 
138 	// Run the effects
139 	if (m_EffectsOn)
140 	{
141 		m_Delay.GetOutput(data);
142 		m_Reverb.GetOutput(data);
143 	}
144 
145 	m_IntPos=static_cast<int>(m_Pos);
146 
147 	m_GUI->UpdatePos();
148 
149 	return true;
150 }
151 
AllocateMem(int Length)152 void Loop::AllocateMem(int Length)
153 {
154 	// We might need to keep these values (if loading workspace)
155 	if (m_LoopPoint>Length) m_LoopPoint=Length;
156 	if (m_Pos>Length) m_Pos=0;
157 
158 	if (m_LoopPoint==0) m_LoopPoint=Length;
159 
160 	if (!m_StoreBuffer.Allocate(Length) ||
161 	    !m_HoldBuffer.Allocate(Length))
162 	{
163 		cerr<<"AllocateMem can't allocate any more memory!"<<endl;
164 		Clear();
165 	}
166 }
167 
Clear()168 void Loop::Clear()
169 {
170 	m_StoreBuffer.Clear();
171 	m_HoldBuffer.Clear();
172 
173 	//m_LoopPoint=0;
174 }
175 
GetMagic()176 const float Loop::GetMagic()
177 {
178 	if (m_Speed)
179 	{
180 		if (float temp=m_LoopPoint/m_Speed)
181 		{
182 			return GetMasterMagic()/temp;
183 		}
184 	}
185 	return 1.0f;
186 }
187 
RecordBuf(float Pos)188 void Loop::RecordBuf(float Pos)
189 {
190 	if (!m_RecordingSource) return;
191 
192 	if (m_FirstRecord)
193 	{
194 		// Find out if we want a fixed length record
195 		// based on the last sample length, or not
196 		if (m_StoreBuffer.GetLength())
197 		{
198 			m_FixedRecord=true;
199 		}
200 		else
201 		{
202 			m_FixedRecord=false;
203 			m_RecBuffer.Allocate(RECBUFFERSIZE);
204 			m_StoreBuffer.Clear();
205 			m_RecPos=0;
206 		}
207 
208 		m_FirstRecord=false;
209 		m_RecLength=0;
210 	}
211 	if (m_FixedRecord)
212 	{
213 		m_RecLength=m_LoopPoint;
214 		float NextPos=0;
215 
216 		if (Pos>=m_StoreBuffer.GetLength())
217 		{
218 			Pos=0;
219 		}
220 
221 		float OldPos=Pos;
222 
223 		for (int n=0; n<SpiralLoopsInfo::BUFSIZE; n++)
224 		{
225 			// just add directly to the old buffer
226 			long temp=(long)(m_StoreBuffer[static_cast<int>(Pos)]+m_RecordingSource[n]*RECORD_GAIN);
227 
228 
229 			// todo: fill in all the samples between the
230 			// speed jump with the same value
231 
232 			for (int i=static_cast<int>(OldPos); i<=static_cast<int>(Pos); i++)
233 			{
234 				m_StoreBuffer.Set(i,temp);
235 			}
236 			OldPos=Pos;
237 			Pos+=m_Speed;
238 			if (Pos>=m_StoreBuffer.GetLength())
239 			{
240 				Pos=OldPos=0;
241 			}
242 
243 		}
244 	}
245 	else
246 	{
247 		for (int n=0; n<SpiralLoopsInfo::BUFSIZE; n++)
248 		{
249 			// see if we need a new buffer
250 			if (m_RecPos>=RECBUFFERSIZE)
251 			{
252 				// put the two buffers together
253 				m_StoreBuffer.Add(m_RecBuffer);
254 				m_RecPos=0;
255 			}
256 
257 			long temp=(long)(m_RecordingSource[n]*RECORD_GAIN);
258 			m_RecBuffer.Set(m_RecPos,temp);
259 
260 			m_RecLength++;
261 			m_RecPos++;
262 		}
263 	}
264 }
265 
EndRecordBuf()266 void Loop::EndRecordBuf()
267 {
268 	m_FirstRecord=true;
269 	m_LoopPoint=m_StoreBuffer.GetLength();
270 
271 	if (!m_FixedRecord)
272 	{
273 		// reallocate the hold buffer for the new size
274 		// (if the size has changed)
275 		m_HoldBuffer.Allocate(m_LoopPoint);
276 	}
277 }
278 
Crop()279 void Loop::Crop()
280 {
281 	if (m_LoopPoint<m_StoreBuffer.GetLength())
282 	{
283 		m_StoreBuffer.CropTo(m_LoopPoint);
284 		m_HoldBuffer.CropTo(m_LoopPoint);
285 	}
286 }
287 
Double()288 void Loop::Double()
289 {
290 	Crop();
291 
292 	m_StoreBuffer.Add(m_StoreBuffer);
293 	m_HoldBuffer.Add(m_HoldBuffer);
294 	m_LoopPoint=m_StoreBuffer.GetLength();
295 }
296 
MatchLength(int Len)297 void Loop::MatchLength(int Len)
298 {
299 	// set the length, and make sure enough data is allocated
300 	if (m_StoreBuffer.GetLength()>Len)
301 	{
302 		SetLength(Len);
303 		return;
304 	}
305 	else
306 	{
307 		// if it's empty
308 		if (!m_StoreBuffer.GetLength())
309 		{
310 			AllocateMem(Len);
311 			m_StoreBuffer.Zero();
312 		}
313 		else
314 		// there is something in the buffer already, but we need to
315 		// add on some extra data to make the length the same
316 		{
317 			int ExtraLen=Len-m_StoreBuffer.GetLength();
318 			m_StoreBuffer.Expand(ExtraLen);
319 			m_HoldBuffer.Expand(ExtraLen);
320 		}
321 	}
322 }
323 
Cut(int Start,int End)324 void Loop::Cut(int Start, int End)
325 {
326 	m_Parent->Cut(m_StoreBuffer,Start,End);
327 	if (m_StoreBuffer.GetLength()<m_LoopPoint)
328 	{
329 		m_LoopPoint=m_StoreBuffer.GetLength();
330 	}
331 	if (m_Pos>m_LoopPoint)
332 	{
333 		m_Pos=0;
334 	}
335 
336 	m_HoldBuffer.Allocate(m_StoreBuffer.GetLength());
337 }
338 
Copy(int Start,int End)339 void Loop::Copy(int Start, int End)
340 {
341 	m_Parent->Copy(m_StoreBuffer,Start,End);
342 }
343 
Paste(int Start)344 void Loop::Paste(int Start)
345 {
346 	m_Parent->Paste(m_StoreBuffer,Start);
347 	if (m_StoreBuffer.GetLength()<m_LoopPoint)
348 	{
349 		m_LoopPoint=m_StoreBuffer.GetLength();
350 	}
351 	if (m_Pos>m_LoopPoint)
352 	{
353 		m_Pos=0;
354 	}
355 
356 	m_HoldBuffer.Allocate(m_StoreBuffer.GetLength());
357 }
358 
PasteMix(int Start)359 void Loop::PasteMix(int Start)
360 {
361 	m_Parent->PasteMix(m_StoreBuffer,Start);
362 }
363 
ZeroRange(int Start,int End)364 void Loop::ZeroRange(int Start, int End)
365 {
366 	for (int n=Start; n<End; n++)
367 	{
368 		m_StoreBuffer[n]=0;
369 	}
370 }
371 
ReverseRange(int Start,int End)372 void Loop::ReverseRange(int Start, int End)
373 {
374 	m_StoreBuffer.Reverse(Start,End);
375 }
376 
Halve()377 void Loop::Halve()
378 {
379 	m_StoreBuffer.Shrink(m_StoreBuffer.GetLength()/2);
380 	m_HoldBuffer.Shrink(m_HoldBuffer.GetLength()/2);
381 
382 	if (m_StoreBuffer.GetLength()<m_LoopPoint)
383 	{
384 		m_LoopPoint=m_StoreBuffer.GetLength();
385 	}
386 	if (m_Pos>m_LoopPoint)
387 	{
388 		m_Pos=0;
389 	}
390 }
391 
SelectAll()392 void Loop::SelectAll()
393 {
394 }
395 
Move(int Start)396 void Loop::Move(int Start)
397 {
398 	m_StoreBuffer.Move(Start);
399 }
400 
401 istream &operator>>(istream &s, Loop &o)
402 {
403 	s>>o.m_Id>>o.m_Pos>>o.m_IntPos>>o.m_PlayBufPos>>o.m_Playing>>o.m_Master>>o.m_LoopPoint>>
404 	  o.m_Speed>>o.m_Volume>>o.m_Balance>>o.m_LeftVol>>o.m_RightVol>>o.m_Filter>>
405 	  o.m_EffectsOn>>o.m_Delay>>o.m_Reverb;
406 
407 	return s;
408 }
409 
410 ostream &operator<<(ostream &s, Loop &o)
411 {
412 	s<<o.m_Id<<" "<<o.m_Pos<<" "<<o.m_IntPos<<" "<<o.m_PlayBufPos<<" "<<o.m_Playing
413 	 <<" "<<o.m_Master<<" "<<o.m_LoopPoint<<" "<<o.m_Speed<<" "<<o.m_Volume<<" "
414 	 <<o.m_Balance<<" "<<o.m_LeftVol<<" "<<o.m_RightVol<<" "<<o.m_Filter<<" "
415 	 <<o.m_EffectsOn<<" "<<o.m_Delay<<" "<<o.m_Reverb<<" ";
416 
417 	return s;
418 }
419 
420