1 /*
2  * Copyright (C) 2002 - David W. Durham
3  *
4  * This file is part of ReZound, an audio editing application.
5  *
6  * ReZound is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * ReZound is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  */
20 
21 #include "CPasteEdit.h"
22 
23 #include <algorithm>
24 #include <utility>
25 
26 #include "../AActionDialog.h"
27 #include "../ASoundClipboard.h"
28 #include "../CActionParameters.h"
29 
30 
31 /*
32  * - pasteChannels is a NxN matrix of bools that says how the channels are pasted into the sound
33  *    for example  if pasteChannels[0][1]==true    then data from the left channel gets pasted into the right channel
34  *    for example  if pasteChannels[1][1]==true    then data from the right channel gets pasted into the right channel
35  *
36  * ??? this should now be fixed with the abstraction of ASoundClipboard
37  * - Although the data could represent it, I ignore if two channels from the source data is to be pasted into one channel;
38  *   I just use the first one I come to... The GUI interface should have radio buttons to disallow the user creating that
39  *   senario
40  */
41 
42 //                                                    const bool _pasteChannels[MAX_CHANNELS][MAX_CHANNELS]
CPasteEdit(const AActionFactory * factory,const CActionSound * actionSound,const vector<vector<bool>> & _pasteChannels,PasteTypes _pasteType,MixMethods _mixMethod,double _repeatCount)43 CPasteEdit::CPasteEdit(const AActionFactory *factory,const CActionSound *actionSound,const vector<vector<bool> > &_pasteChannels,PasteTypes _pasteType,MixMethods _mixMethod,double _repeatCount) :
44 	AAction(factory,actionSound),
45 
46 	pasteType(_pasteType),
47 	mixMethod(_mixMethod),
48 
49 	repeatCount(_repeatCount),
50 
51 	pasteChannels(_pasteChannels),
52 
53 	undoRemoveLength(0)
54 {
55 	// create whichChannels which is true for each channel that will have something going into it from the clipboard
56 	for(unsigned y=0;y<MAX_CHANNELS;y++)
57 	{
58 		whichChannels[y]=false;
59 		for(unsigned x=0;x<MAX_CHANNELS;x++)
60 			whichChannels[y]|=pasteChannels[y][x];
61 	}
62 }
63 
~CPasteEdit()64 CPasteEdit::~CPasteEdit()
65 {
66 }
67 
68 #include <stdio.h> // ??? just for the printf below
doActionSizeSafe(CActionSound * actionSound,bool prepareForUndo)69 bool CPasteEdit::doActionSizeSafe(CActionSound *actionSound,bool prepareForUndo)
70 {
71 	for(unsigned y=0;y<MAX_CHANNELS;y++)
72 	{
73 		for(unsigned x=0;x<MAX_CHANNELS;x++)
74 		{
75 			printf("%d ",(int)pasteChannels[y][x]);
76 		}
77 		printf("\n");
78 	}
79 
80 	ASoundClipboard *clipboard=clipboards[gWhichClipboard];
81 	const sample_pos_t clipboardLength=clipboard->getLength(actionSound->sound->getSampleRate());
82 
83 	// this is the length of the clipboard after we repeat it the number of times the user asked for
84 	const sample_pos_t repeatedClipboardLength=(sample_pos_t)sample_fpos_floor((sample_fpos_t)clipboardLength*repeatCount);
85 
86 	if(repeatCount<0.0 || repeatedClipboardLength<1)
87 		return false;
88 
89 	// save info for undo
90 	undoRemoveLength=repeatedClipboardLength;
91 	originalLength=actionSound->sound->getLength();
92 
93 	switch(pasteType)
94 	{
95 	case ptInsert:
96 		// insert the space into the channels we need to
97 		actionSound->sound->addSpace(whichChannels,actionSound->start,repeatedClipboardLength);
98 		pasteData(clipboard,pasteChannels,actionSound,clipboardLength,repeatCount,false,mmOverwrite,mixMethod,sftNone);
99 		break;
100 
101 	case ptReplace:
102 		if(prepareForUndo)
103 		{
104 			CActionSound _actionSound(*actionSound);
105 			for(unsigned t=0;t<MAX_CHANNELS;t++)
106 				_actionSound.doChannel[t]=whichChannels[t];
107 
108 			moveSelectionToTempPools(&_actionSound,mmSelection,undoRemoveLength);
109 		}
110 		else
111 		{
112 			actionSound->sound->removeSpace(whichChannels,actionSound->start,actionSound->selectionLength());
113 			actionSound->sound->addSpace(whichChannels,actionSound->start,repeatedClipboardLength);
114 		}
115 
116 		pasteData(clipboard,pasteChannels,actionSound,clipboardLength,repeatCount,false,mmOverwrite,mixMethod,sftNone);
117 		break;
118 
119 	case ptOverwrite:
120 	case ptMix:
121 	{
122 		/*                    v--- start selection position
123 		 * Either:
124 		 * 	Sound:     [--|-----]
125 		 * 	Clipboard:    |---|
126 		 *
127 		 * 	or
128 		 *
129 		 * 	Sound:     [--|-----]
130 		 * 	Clipboard:    |---------|
131 		 *
132 		 * 	                    |___|
133 		 * 	                      ^-- extraLength
134 		 */
135 
136 
137 		// it is the amount that the clipboard, if pasted starting at the start position, overhangs the end of the sound
138 		sample_pos_t extraLength=0;
139 		if((actionSound->start+repeatedClipboardLength)>actionSound->sound->getLength())
140 			extraLength=(actionSound->start+repeatedClipboardLength)-actionSound->sound->getLength();
141 
142 		if(prepareForUndo)
143 		{
144 			CActionSound _actionSound(*actionSound);
145 			for(unsigned t=0;t<MAX_CHANNELS;t++)
146 				_actionSound.doChannel[t]=whichChannels[t];
147 
148 			if(extraLength>0)
149 				_actionSound.stop=actionSound->sound->getLength()-1;
150 			else // doesn't overhang the end
151 				_actionSound.stop=_actionSound.start+repeatedClipboardLength-1;
152 
153 			// move the data that is going to be affected into a temp pool and replace the space
154 			moveSelectionToTempPools(&_actionSound,mmSelection,_actionSound.selectionLength());
155 
156 			if(pasteType!=ptOverwrite && mixMethod!=mmOverwrite)
157 			{
158 				// copy the data back after moving it to the temp pool to mix on top of
159 				for(unsigned i=0;i<actionSound->sound->getChannelCount();i++)
160 				{
161 					if(whichChannels[i])
162 						actionSound->sound->getAudio(i).copyData(actionSound->start,actionSound->sound->getTempAudio(tempAudioPoolKey,i),0,_actionSound.selectionLength());
163 				}
164 			}
165 		}
166 
167 		// add silence at the end if the clipboard's data overhangs the end of the sound
168 		if(extraLength>0)
169 			actionSound->sound->addSpace(whichChannels,actionSound->sound->getLength(),extraLength,true);
170 
171 		pasteData(clipboard,pasteChannels,actionSound,clipboardLength,repeatCount,!prepareForUndo,pasteType==ptOverwrite ? mmOverwrite : mixMethod,mixMethod,sftNone);
172 
173 	}
174 		break;
175 
176 	case ptLimitedOverwrite:
177 	case ptLimitedMix:
178 		if(prepareForUndo)
179 		{
180 			CActionSound _actionSound(*actionSound);
181 			for(unsigned t=0;t<MAX_CHANNELS;t++)
182 				_actionSound.doChannel[t]=whichChannels[t];
183 
184 			_actionSound.stop=min(_actionSound.start+repeatedClipboardLength-1,_actionSound.stop);
185 
186 			// reassign this value for undo
187 			undoRemoveLength=_actionSound.selectionLength();
188 
189 			// move the data that is going to be affected into a temp pool and replace the space
190 			moveSelectionToTempPools(&_actionSound,mmSelection,_actionSound.selectionLength());
191 
192 			if(pasteType!=ptLimitedOverwrite && mixMethod!=mmOverwrite)
193 			{
194 				// copy the data back after moving it to the temp pool to mix on top of
195 				for(unsigned i=0;i<actionSound->sound->getChannelCount();i++)
196 				{
197 					if(whichChannels[i])
198 						actionSound->sound->getAudio(i).copyData(actionSound->start,actionSound->sound->getTempAudio(tempAudioPoolKey,i),0,_actionSound.selectionLength());
199 				}
200 			}
201 		}
202 
203 		{
204 			// send pasteData an adjustedRepeatCount, if the limited length (undoRemoveLength) is less than what we would like to paste (repeatedClipboardLength), then calculate how many times we can actually repeat the clipboard (which could be <=1 or even >1)
205 			double adjustedRepeatCount;
206 			if(undoRemoveLength<repeatedClipboardLength)
207 				adjustedRepeatCount=(double)((sample_fpos_t)undoRemoveLength/(sample_fpos_t)clipboardLength);
208 			else
209 				adjustedRepeatCount=repeatCount;
210 
211 			pasteData(clipboard,pasteChannels,actionSound,clipboardLength,adjustedRepeatCount,!prepareForUndo,pasteType==ptLimitedOverwrite ? mmOverwrite : mixMethod,mixMethod,sftNone);
212 		}
213 		break;
214 
215 	case ptFitMix:
216 		if(prepareForUndo)
217 		{
218 			CActionSound _actionSound(*actionSound);
219 			for(unsigned t=0;t<MAX_CHANNELS;t++)
220 				_actionSound.doChannel[t]=whichChannels[t];
221 
222 			// reassign this value for undo
223 			undoRemoveLength=actionSound->selectionLength();
224 
225 			// move the data that is going to be affected into a temp pool and replace the space
226 			moveSelectionToTempPools(&_actionSound,mmSelection,actionSound->selectionLength());
227 
228 			// copy the data back after moving it to the temp pool to mix on top of
229 			if(mixMethod!=mmOverwrite)
230 			{
231 				for(unsigned i=0;i<actionSound->sound->getChannelCount();i++)
232 				{
233 					if(whichChannels[i])
234 						actionSound->sound->getAudio(i).copyData(actionSound->start,actionSound->sound->getTempAudio(tempAudioPoolKey,i),0,_actionSound.selectionLength());
235 				}
236 			}
237 		}
238 
239 		// instead of being able to simply pass repeatCount to pasteData, I have to break it into its multiple repeats here
240 		{
241 			CActionSound _actionSound(*actionSound);
242 			double iRepeatCount;
243 			const double fRepeatCount=modf(repeatCount,&iRepeatCount);
244 
245 			// do all the n iterations of repeatCount as n.xyz
246 			const sample_pos_t oneIterationLength=(sample_pos_t)sample_fpos_floor((sample_fpos_t)_actionSound.selectionLength()/(sample_fpos_t)repeatCount);
247 			for(unsigned k=0;k<(unsigned)iRepeatCount;k++)
248 			{
249 				pasteData(clipboard,pasteChannels,&_actionSound,oneIterationLength,1,!prepareForUndo,mixMethod,mixMethod,sftChangeRate);
250 				_actionSound.start+=oneIterationLength;
251 			}
252 
253 
254 			// this would be the way to do it, but ...
255 			//sample_pos_t lastIterationLength=(sample_pos_t)sample_fpos_floor(((sample_fpos_t)actionSound->selectionLength()*(sample_fpos_t)fRepeatCount)/(sample_fpos_t)repeatCount);
256 
257 			// ... this will be sure to cover the remainder left off from flooring errors in the n iterations above
258 				// perhaps there's a better way, maybe rounding instead of flooring when calculating oneIterationLength
259 			const sample_pos_t lastIterationLength=actionSound->selectionLength()-(oneIterationLength*(unsigned)iRepeatCount);
260 
261 			if(lastIterationLength>0 && clipboardLength>1/*has a little bug from flooring if this is true*/)
262 			{
263 				const sample_pos_t shortenedClipboardLength=(sample_pos_t)sample_fpos_floor((sample_fpos_t)clipboard->getLength(_actionSound.sound->getSampleRate())*fRepeatCount);
264 				clipboard->temporarilyShortenLength(_actionSound.sound->getSampleRate(),max(shortenedClipboardLength,(sample_pos_t)1));
265 				try
266 				{
267 					pasteData(clipboard,pasteChannels,&_actionSound,lastIterationLength,1,!prepareForUndo,mixMethod,mixMethod,sftChangeRate);
268 
269 					clipboard->undoTemporaryShortenLength();
270 				}
271 				catch(...)
272 				{
273 					clipboard->undoTemporaryShortenLength();
274 					throw;
275 				}
276 			}
277 		}
278 		break;
279 
280 	default:
281 		throw runtime_error(string(__func__)+_(" -- unhandled pasteType: ")+istring(pasteType));
282 	}
283 
284 	return true;
285 }
286 
287 /*
288  * writes the data from the clipboard onto the sound...
289  * this method assumes there is already room to write the data
290  * 	whichChannels is true for each which which is going to have data written to, calculated from pasteChannels
291  * 	pasteChannels came from the user
292  */
293 //                                                          const bool pasteChannels[MAX_CHANNELS][MAX_CHANNELS]
pasteData(const ASoundClipboard * clipboard,const vector<vector<bool>> & pasteChannels,const CActionSound * actionSound,const sample_pos_t srcToUse,const double repeatCount,bool invalidatePeakData,MixMethods initialMixMethod,MixMethods nonInitialMixMethod,SourceFitTypes fitSrc)294 void CPasteEdit::pasteData(const ASoundClipboard *clipboard,const vector<vector<bool> > &pasteChannels,const CActionSound *actionSound,const sample_pos_t srcToUse,const double repeatCount,bool invalidatePeakData,MixMethods initialMixMethod,MixMethods nonInitialMixMethod,SourceFitTypes fitSrc)
295 {
296 	for(unsigned y=0;y<actionSound->sound->getChannelCount();y++)
297 	{
298 		bool first=true;
299 		for(unsigned x=0;x<MAX_CHANNELS;x++)
300 		{
301 			if(pasteChannels[y][x])
302 			{
303 				sample_pos_t start=actionSound->start;
304 				double iRepeatCount;
305 				const double fRepeatCount=modf(repeatCount,&iRepeatCount);
306 
307 				// do all the n iterations of repeatCount as n.xyz
308 				for(unsigned k=0;k<(unsigned)iRepeatCount;k++)
309 				{
310 					clipboards[gWhichClipboard]->copyTo(actionSound->sound,y,x,start,srcToUse,first ? initialMixMethod : nonInitialMixMethod,fitSrc,first && invalidatePeakData);
311 					start+=srcToUse;
312 				}
313 
314 				// do the .xyz remaining part of the paste
315 				if(fRepeatCount>0.0 && (srcToUse*fRepeatCount)>=1.0)
316 					clipboards[gWhichClipboard]->copyTo(actionSound->sound,y,x,start,(sample_pos_t)((sample_fpos_t)srcToUse*fRepeatCount),first ? initialMixMethod : nonInitialMixMethod,fitSrc,first && invalidatePeakData);
317 
318 				first=false;
319 			}
320 		}
321 	}
322 
323 	const sample_pos_t repeatedSrcToUse=(sample_pos_t)sample_fpos_floor((sample_fpos_t)srcToUse*repeatCount);
324 	actionSound->stop=actionSound->start+repeatedSrcToUse-1;
325 }
326 
canUndo(const CActionSound * actionSound) const327 AAction::CanUndoResults CPasteEdit::canUndo(const CActionSound *actionSound) const
328 {
329 	// should check some size constraint
330 	return curYes;
331 }
332 
undoActionSizeSafe(const CActionSound * actionSound)333 void CPasteEdit::undoActionSizeSafe(const CActionSound *actionSound)
334 {
335 	switch(pasteType)
336 	{
337 	case ptInsert:
338 		actionSound->sound->removeSpace(whichChannels,actionSound->start,undoRemoveLength,originalLength);
339 		break;
340 
341 	case ptReplace:
342 	case ptOverwrite:
343 	case ptLimitedOverwrite:
344 	case ptMix:
345 	case ptLimitedMix:
346 	case ptFitMix:
347 		{
348 		// I have to create undoActionSound (a copy of actionSound) and change its doChannel according
349 		// to pasteChannels (actually from whichChannels which came originally from pasteChannels)
350 		CActionSound undoActionSound(*actionSound);
351 		for(unsigned t=0;t<MAX_CHANNELS;t++)
352 			undoActionSound.doChannel[t]=whichChannels[t];
353 
354 		restoreSelectionFromTempPools(&undoActionSound,undoActionSound.start,undoRemoveLength);
355 		}
356 		break;
357 
358 	default:
359 		throw runtime_error(string(__func__)+_(" -- unhandled pasteType: ")+istring(pasteType));
360 	}
361 }
362 
getResultingCrossfadePoints(const CActionSound * actionSound,sample_pos_t & start,sample_pos_t & stop)363 bool CPasteEdit::getResultingCrossfadePoints(const CActionSound *actionSound,sample_pos_t &start,sample_pos_t &stop)
364 {
365 	const ASoundClipboard *clipboard=clipboards[gWhichClipboard];
366 	const sample_pos_t clipboardLength=clipboard->getLength(actionSound->sound->getSampleRate());
367 
368 	start=actionSound->start;
369 
370 	switch(pasteType)
371 	{
372 	case ptInsert:
373 		stop=start;
374 		break;
375 
376 	case ptReplace:
377 	case ptFitMix:
378 		stop=min(actionSound->stop+1,actionSound->sound->getLength()-1);
379 		break;
380 
381 	case ptOverwrite:
382 	case ptMix:
383 		stop=min(start+clipboardLength,actionSound->sound->getLength()-1);
384 		break;
385 
386 	case ptLimitedOverwrite:
387 	case ptLimitedMix:
388 		stop=min(start+clipboardLength,start+actionSound->selectionLength());
389 		break;
390 
391 	default:
392 		throw runtime_error(string(__func__)+_(" -- unhandled pasteType: ")+istring(pasteType));
393 	}
394 	return true;
395 }
396 
397 
398 
399 // ------------------------------
400 
401 
402 #define CHECK_FOR_DATA(ClassName) 						\
403 	bool ClassName::doPreActionSetup(CLoadedSound *loadedSound)		\
404 	{ 									\
405 		if(!AAction::clipboards[gWhichClipboard]->prepareForCopyTo())	\
406 			return false;						\
407 										\
408 		if(AAction::clipboards[gWhichClipboard]->isEmpty())		\
409 		{ 								\
410 			Message(_("No data has been cut or copied to the selected clipboard yet.")); \
411 			return false; 						\
412 		} 								\
413 		return true; 							\
414 	}
415 
getPasteChannels(AActionDialog * pasteChannelsDialog)416 static const vector<vector<bool> > getPasteChannels(AActionDialog *pasteChannelsDialog)
417 {
418 	static vector<vector<bool> > pasteChannels;
419 	pasteChannels.clear();
420 
421 	if(pasteChannelsDialog->wasShown)
422 	{
423 		const vector<vector<bool> > &m= *reinterpret_cast<const vector<vector<bool> > *>(pasteChannelsDialog->getUserData());
424 		for(unsigned y=0;y<MAX_CHANNELS;y++)
425 		{
426 			pasteChannels.push_back(vector<bool>() );
427 			for(unsigned x=0;x<MAX_CHANNELS;x++)
428 				pasteChannels[y].push_back(m[y][x]);
429 		}
430 	}
431 	else
432 	{ // if the dialog was not shown for this action, then make channel1 -> channel1, channel2 -> channel2, ...
433 		const ASoundClipboard *clipboard=AAction::clipboards[gWhichClipboard];
434 
435 		for(unsigned y=0;y<MAX_CHANNELS;y++)
436 		{
437 			pasteChannels.push_back(vector<bool>() );
438 			for(unsigned x=0;x<MAX_CHANNELS;x++)
439 			{
440 				if(y==x && clipboard->getWhichChannels()[y])
441 					pasteChannels[y].push_back(true);
442 				else
443 					pasteChannels[y].push_back(false);
444 			}
445 		}
446 	}
447 
448 	return pasteChannels;
449 }
450 
getMixMethod(const CActionParameters * actionParameters)451 static const MixMethods getMixMethod(const CActionParameters *actionParameters)
452 {
453 	return actionParameters->keyExists("MixMethod") ? (MixMethods)actionParameters->getValue<unsigned>("MixMethod") : mmAdd;
454 }
455 
getRepeatCount(const CActionParameters * actionParameters)456 static const double getRepeatCount(const CActionParameters *actionParameters)
457 {
458 	return actionParameters->keyExists("Repeat Count") ? actionParameters->getValue<double>("Repeat Count") : 1.0;
459 }
460 
461 
462 // ------------------------------
463 
CInsertPasteEditFactory(AActionDialog * channelSelectDialog)464 CInsertPasteEditFactory::CInsertPasteEditFactory(AActionDialog *channelSelectDialog) :
465 	AActionFactory(N_("Insert Paste"),_("Insert at the Start Position"),channelSelectDialog,NULL)
466 {
467 }
468 
~CInsertPasteEditFactory()469 CInsertPasteEditFactory::~CInsertPasteEditFactory()
470 {
471 }
472 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const473 CPasteEdit *CInsertPasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
474 {
475 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptInsert,getMixMethod(actionParameters),getRepeatCount(actionParameters));
476 }
477 
CHECK_FOR_DATA(CInsertPasteEditFactory)478 CHECK_FOR_DATA(CInsertPasteEditFactory)
479 
480 
481 // -----------------------------------
482 
483 
484 CReplacePasteEditFactory::CReplacePasteEditFactory(AActionDialog *channelSelectDialog) :
485 	AActionFactory(N_("Replace Paste"),_("Replace the Selection"),channelSelectDialog,NULL)
486 {
487 }
488 
~CReplacePasteEditFactory()489 CReplacePasteEditFactory::~CReplacePasteEditFactory()
490 {
491 }
492 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const493 CPasteEdit *CReplacePasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
494 {
495 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptReplace,getMixMethod(actionParameters),getRepeatCount(actionParameters));
496 }
497 
CHECK_FOR_DATA(CReplacePasteEditFactory)498 CHECK_FOR_DATA(CReplacePasteEditFactory)
499 
500 // -----------------------------------
501 
502 
503 COverwritePasteEditFactory::COverwritePasteEditFactory(AActionDialog *channelSelectDialog) :
504 	AActionFactory(N_("Overwrite Paste"),_("Overwrite Starting at the Start Position"),channelSelectDialog,NULL)
505 {
506 }
507 
~COverwritePasteEditFactory()508 COverwritePasteEditFactory::~COverwritePasteEditFactory()
509 {
510 }
511 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const512 CPasteEdit *COverwritePasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
513 {
514 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptOverwrite,getMixMethod(actionParameters),getRepeatCount(actionParameters));
515 }
516 
CHECK_FOR_DATA(COverwritePasteEditFactory)517 CHECK_FOR_DATA(COverwritePasteEditFactory)
518 
519 
520 // -----------------------------------
521 
522 
523 CLimitedOverwritePasteEditFactory::CLimitedOverwritePasteEditFactory(AActionDialog *channelSelectDialog) :
524 	AActionFactory(N_("Limited Overwrite Paste"),_("Overwrite Starting at the Start Position But Not Beyond the Stop Position"),channelSelectDialog,NULL)
525 {
526 }
527 
~CLimitedOverwritePasteEditFactory()528 CLimitedOverwritePasteEditFactory::~CLimitedOverwritePasteEditFactory()
529 {
530 }
531 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const532 CPasteEdit *CLimitedOverwritePasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
533 {
534 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptLimitedOverwrite,getMixMethod(actionParameters),getRepeatCount(actionParameters));
535 }
536 
CHECK_FOR_DATA(CLimitedOverwritePasteEditFactory)537 CHECK_FOR_DATA(CLimitedOverwritePasteEditFactory)
538 
539 
540 // -----------------------------------
541 
542 
543 CMixPasteEditFactory::CMixPasteEditFactory(AActionDialog *channelSelectDialog) :
544 	AActionFactory(N_("Mix Paste"),_("Mix Starting at the Start Position"),channelSelectDialog,NULL)
545 {
546 }
547 
~CMixPasteEditFactory()548 CMixPasteEditFactory::~CMixPasteEditFactory()
549 {
550 }
551 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const552 CPasteEdit *CMixPasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
553 {
554 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptMix,getMixMethod(actionParameters),getRepeatCount(actionParameters));
555 }
556 
CHECK_FOR_DATA(CMixPasteEditFactory)557 CHECK_FOR_DATA(CMixPasteEditFactory)
558 
559 // -----------------------------------
560 
561 
562 CLimitedMixPasteEditFactory::CLimitedMixPasteEditFactory(AActionDialog *channelSelectDialog) :
563 	AActionFactory(N_("Limited Mix Paste"),_("Mix Starting at the Start Position But Not Beyond the Stop Position"),channelSelectDialog,NULL)
564 {
565 }
566 
~CLimitedMixPasteEditFactory()567 CLimitedMixPasteEditFactory::~CLimitedMixPasteEditFactory()
568 {
569 }
570 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const571 CPasteEdit *CLimitedMixPasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
572 {
573 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptLimitedMix,getMixMethod(actionParameters),getRepeatCount(actionParameters));
574 }
575 
CHECK_FOR_DATA(CLimitedMixPasteEditFactory)576 CHECK_FOR_DATA(CLimitedMixPasteEditFactory)
577 
578 // -----------------------------------
579 
580 
581 CFitMixPasteEditFactory::CFitMixPasteEditFactory(AActionDialog *channelSelectDialog) :
582 	AActionFactory(N_("Fit Mix Paste"),_("Mix Starting at the Start Position But Change the Rate of the Clipboard to Fit Within the Selection"),channelSelectDialog,NULL)
583 {
584 }
585 
~CFitMixPasteEditFactory()586 CFitMixPasteEditFactory::~CFitMixPasteEditFactory()
587 {
588 }
589 
manufactureAction(const CActionSound * actionSound,const CActionParameters * actionParameters) const590 CPasteEdit *CFitMixPasteEditFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
591 {
592 	return new CPasteEdit(this,actionSound,getPasteChannels(channelSelectDialog),CPasteEdit::ptFitMix,getMixMethod(actionParameters),getRepeatCount(actionParameters));
593 }
594 
595 CHECK_FOR_DATA(CFitMixPasteEditFactory)
596 
597