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