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 "CFlangeEffect.h"
22 
23 #include <memory>
24 
25 #include "../DSP/FlangeEffect.h"
26 #include "../unit_conv.h"
27 
28 #include "../CActionParameters.h"
29 #include "../CActionSound.h"
30 
31 // LFO Speed is in Hertz, LFO Depth is in ?,LFO Phase is in degrees, Delay is in milliseconds
32 CFlangeEffect::CFlangeEffect(const AActionFactory *factory,const CActionSound *actionSound,float _delayTime,float _wetGain,float _dryGain,const CLFODescription &_flangeLFO,float _feedback) :
33 	AAction(factory,actionSound),
34 
35 	// ??? perhaps I should do these conversions down in the code because I might someday be able to stream the action to disk for later use and the sampleRate would not necessarily be the same
36 
37 	delayTime(_delayTime),
38 
39 	wetGain(_wetGain),
40 	dryGain(_dryGain),
41 
42 	flangeLFO(_flangeLFO),
43 
44 	feedback(_feedback)
45 {
46 	if(_delayTime<0.0)
47 		throw(runtime_error(string(__func__)+_(" -- _delayTime is negative")));
48 	if(flangeLFO.amp<0.0)
49 		throw(runtime_error(string(__func__)+_(" -- flangeLFO.amp is negative")));
50 }
51 
52 CFlangeEffect::~CFlangeEffect()
53 {
54 }
55 
56 bool CFlangeEffect::doActionSizeSafe(CActionSound *actionSound,bool prepareForUndo)
57 {
58 	const sample_pos_t start=actionSound->start;
59 	const sample_pos_t stop=actionSound->stop;
60 
61 	if(prepareForUndo)
62 		moveSelectionToTempPools(actionSound,mmSelection,actionSound->selectionLength());
63 
64 	unsigned channelsDoneCount=0;
65 	for(unsigned i=0;i<actionSound->sound->getChannelCount();i++)
66 	{
67 		if(actionSound->doChannel[i])
68 		{
69 			CStatusBar statusBar(_("Flange -- Channel ")+istring(++channelsDoneCount)+"/"+istring(actionSound->countChannels()),start,stop,true);
70 
71 			CRezPoolAccesser dest=actionSound->sound->getAudio(i);
72 			const CRezPoolAccesser src=prepareForUndo ? actionSound->sound->getTempAudio(tempAudioPoolKey,i) : actionSound->sound->getAudio(i);
73 
74 			auto_ptr<ALFO> LFO(gLFORegistry.createLFO(flangeLFO,actionSound->sound->getSampleRate()));
75 
76 			CDSPFlangeEffect flangeEffect(
77 				ms_to_samples(delayTime,actionSound->sound->getSampleRate()),
78 				wetGain,
79 				dryGain,
80 				LFO.get(),
81 				ms_to_samples(flangeLFO.amp,actionSound->sound->getSampleRate()),
82 				feedback
83 				);
84 
85 			sample_pos_t srcP=prepareForUndo ? 0 : start;
86 			for(sample_pos_t t=start;t<=stop;t++)
87 			{
88 				dest[t]=ClipSample(flangeEffect.processSample(src[srcP++]));
89 
90 				if(statusBar.update(t))
91 				{ // cancelled
92 					if(prepareForUndo)
93 						undoActionSizeSafe(actionSound);
94 					else
95 						actionSound->sound->invalidatePeakData(i,actionSound->start,t);
96 					return false;
97 				}
98 			}
99 
100 /* This code can be used to test what the LFOs actually look like
101 			for(sample_pos_t t=start;t<=stop;t++)
102 			{
103 				dest[t]=ClipSample(LFO->nextValue()*10000);
104 				UPDATE_PROGRESS_BAR(t);
105 			}
106 */
107 			if(!prepareForUndo)
108 				actionSound->sound->invalidatePeakData(i,actionSound->start,actionSound->stop);
109 		}
110 	}
111 
112 	return(true);
113 }
114 
115 AAction::CanUndoResults CFlangeEffect::canUndo(const CActionSound *actionSound) const
116 {
117 	return(curYes);
118 }
119 
120 void CFlangeEffect::undoActionSizeSafe(const CActionSound *actionSound)
121 {
122 	restoreSelectionFromTempPools(actionSound,actionSound->start,actionSound->selectionLength());
123 }
124 
125 
126 // ---------------------------------------------
127 
128 CFlangeEffectFactory::CFlangeEffectFactory(AActionDialog *channelSelectDialog,AActionDialog *dialog) :
129 	AActionFactory(N_("Flange"),"",channelSelectDialog,dialog)
130 {
131 }
132 
133 CFlangeEffectFactory::~CFlangeEffectFactory()
134 {
135 }
136 
137 CFlangeEffect *CFlangeEffectFactory::manufactureAction(const CActionSound *actionSound,const CActionParameters *actionParameters) const
138 {
139 	return(new CFlangeEffect(this,actionSound,
140 		actionParameters->getValue<float>("Delay"),
141 		actionParameters->getValue<float>("Wet Gain"),
142 		actionParameters->getValue<float>("Dry Gain"),
143 		actionParameters->getValue<CLFODescription>("Flange LFO"),
144 		actionParameters->getValue<float>("Feedback")
145 	));
146 }
147 
148