1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-30 07:29:29 +02:00

Update to non-real-time preview.

Fixes and updates on top of some code clean-up from Leland.
This commit is contained in:
Steve Daulton 2015-05-28 17:31:07 +01:00
parent ebb6709966
commit 5378b0a951
6 changed files with 108 additions and 71 deletions

View File

@ -1,6 +1,8 @@
;nyquist plug-in
;version 3
;version 4
;type process
;preview linear
;preview selection
;categories "http://lv2plug.in/ns/lv2core#MixerPlugin"
;name "Adjustable Fade..."
;action "Applying Fade..."
@ -22,6 +24,19 @@
;control preset " Handy Presets\n(override controls)" choice "None Selected,Linear In,Linear Out,Exponential In,Exponential Out,Logarithmic In,Logarithmic Out,Rounded In,Rounded Out,Cosine In,Cosine Out,S-Curve In,S-Curve Out" 0
(defun get-input (sig)
"When previewing, we only need to process preview length."
(if (get '*track* 'view) ;NIL if preview
sig
(multichan-expand #'trim-input sig)))
(defun trim-input (sig)
"Trim input when previewing."
(let ((dur (min (get-duration 1)
(get '*project* 'preview-duration))))
(setf sig (extract-abs 0 dur *track*))))
(setq err "")
; bad things may happen outside of the slider range.
(setq curve (min 1 (max -1 (/ curve 100.0))))
@ -57,7 +72,7 @@
;;; select and apply fade
(defun fade (sig type curve g0 g1)
(mult sig
(mult (get-input sig)
(case preset
(0 (case type ; Custom fade
(0 (simple (min g0 g1) (max g0 g1) curve))
@ -180,5 +195,5 @@
(check-values gain0 gain1)
(setf err (format nil "~a" (invalid-string gain0 gain1))))
(if (= (length err) 0)
(fade s type curve gain0 gain1)
(fade *track* type curve gain0 gain1)
(format nil "Error.~%~a." err)))

View File

@ -1,7 +1,7 @@
;nyquist plug-in
;version 3
;version 4
;type process
;preview enabled
;preview linear
;categories "http://lv2plug.in/ns/lv2core#HighpassPlugin"
;name "High Pass Filter..."
;action "Performing High Pass Filter..."
@ -10,7 +10,7 @@
;; highpass.ny by Dominic Mazzoni
;; Modified by David R. Sky
;; Updated by Steve Daulton June 2012
;; Updated by Steve Daulton June 2012, 2015.
;; Released under terms of the GNU General Public License version 2:
;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html .
@ -20,6 +20,7 @@
;;control q "Filter quality (Q) for 12 dB rolloff" real "" 0.7071 .1 20
;control frequency "Cutoff frequency (Hz)" real "" 1000 1 20000
(cond
((> frequency (/ *sound-srate* 2))
(format nil
@ -35,4 +36,4 @@
(T
(funcall
(nth rolloff '(hp highpass2 highpass4 highpass6 highpass8))
s frequency)))
*track* frequency)))

View File

@ -1,7 +1,7 @@
;nyquist plug-in
;version 3
;version 4
;type process
;preview enabled
;preview linear
;categories "http://lv2plug.in/ns/lv2core#LowpassPlugin"
;name "Low Pass Filter..."
;action "Performing Low Pass Filter..."
@ -35,4 +35,4 @@
(T
(funcall
(nth rolloff '(lp lowpass2 lowpass4 lowpass6 lowpass8))
s frequency)))
*track* frequency)))

View File

@ -32,6 +32,7 @@ greater use in future.
#include <wx/tglbtn.h>
#include <wx/timer.h>
#include <wx/utils.h>
#include <wx/log.h>
#include "audacity/ConfigInterface.h"
@ -46,6 +47,7 @@ greater use in future.
#include "../widgets/ProgressDialog.h"
#include "../ondemand/ODManager.h"
#include "TimeWarper.h"
#include "nyquist/Nyquist.h"
#if defined(__WXMAC__)
#include <wx/mac/private.h>
@ -91,8 +93,10 @@ Effect::Effect()
mT0 = 0.0;
mT1 = 0.0;
mDuration = 0.0;
mIsPreview = false;
mIsLinearEffect = false;
mPreviewWithNotSelected = false;
mPreviewFullSelection = false;
mNumTracks = 0;
mNumGroups = 0;
mProgress = NULL;
@ -734,7 +738,6 @@ void Effect::SetDuration(double seconds)
mDuration = seconds;
mT1 = mT0 + mDuration;
mSetDuration = mDuration;
mIsSelection = false;
@ -1556,7 +1559,16 @@ bool Effect::ProcessTrack(int count,
bool isProcessor = GetType() == EffectTypeProcess;
if (isGenerator)
{
genLength = left->GetRate() * mDuration;
double genDur;
if (mIsPreview) {
gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &genDur, 6.0);
genDur = wxMin(mDuration, CalcPreviewInputLength(genDur));
}
else {
genDur = mDuration;
}
genLength = left->GetRate() * genDur;
delayRemaining = genLength;
cleared = true;
@ -1827,11 +1839,13 @@ bool Effect::ProcessTrack(int count,
if (isGenerator)
{
AudacityProject *p = GetActiveProject();
StepTimeWarper *warper = new StepTimeWarper(mT0 + genLength, genLength - (mT1 - mT0));
// Transfer the data from the temporary tracks to the actual ones
genLeft->Flush();
left->ClearAndPaste(mT0, mT1, genLeft, true, true, warper);
// mT1 gives us the new selection. We want to replace up to GetSel1().
left->ClearAndPaste(mT0, p->GetSel1(), genLeft, true, true, warper);
delete genLeft;
if (genRight)
@ -1952,6 +1966,12 @@ void Effect::SetLinearEffectFlag(bool linearEffectFlag)
mIsLinearEffect = linearEffectFlag;
}
void Effect::SetPreviewFullSelectionFlag(bool previewDurationFlag)
{
mPreviewFullSelection = previewDurationFlag;
}
void Effect::IncludeNotSelectedPreviewTracks(bool includeNotSelected)
{
mPreviewWithNotSelected = includeNotSelected;
@ -2383,75 +2403,77 @@ void Effect::Preview(bool dryOnly)
else
wxLogDebug(wxT("Non-linear Effect"));
if (mNumTracks==0) // nothing to preview
if (mNumTracks == 0) { // nothing to preview
return;
}
wxWindow* FocusDialog = wxWindow::FindFocus();
if (gAudioIO->IsBusy())
if (gAudioIO->IsBusy()) {
return;
}
wxWindow *FocusDialog = wxWindow::FindFocus();
double previewDuration;
bool isNyquist = (GetFamily().IsSameAs(NYQUISTEFFECTS_FAMILY))? true : false;
bool isGenerator = GetType() == EffectTypeGenerate;
// Mix a few seconds of audio from all of the tracks
double previewLen = 6.0;
gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen);
double previewLen;
gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen, 6.0);
double rate = mProjectRate;
double warpedPreviewLength = CalcPreviewInputLength(previewLen);
double t0 = mT0;
double t1 = t0 + warpedPreviewLength;
// Generators can run without a selection.
if (GetType() == EffectTypeGenerate) {
// If a generator varies over time, it must use the selected duration.
// otherwise set it as a linear effect and process no more than the preview length.
// TODO: When previewing non-linear generate effect, calculate only the first 'preview length'.
// For generate effects derived from the Nyquist Prompt, the duration is unknow, so
// ensure that we have at least preview length to copy.
double dur = (mIsLinearEffect)? wxMin(mSetDuration, warpedPreviewLength) :
wxMax(mSetDuration, warpedPreviewLength);
t1 = t0 + dur;
this->SetDuration(dur);
if (isNyquist && isGenerator) {
previewDuration = CalcPreviewInputLength(previewLen);
}
else if (t1 > mT1) {
else {
previewDuration = wxMin(mDuration, CalcPreviewInputLength(previewLen));
}
double t1 = mT0 + previewDuration;
if ((t1 > mT1) && !(isNyquist && isGenerator)) {
t1 = mT1;
}
if (t1 <= t0)
if (t1 <= mT0)
return;
bool success = true;
WaveTrack *mixLeft = NULL;
WaveTrack *mixRight = NULL;
double oldT0 = mT0;
double oldT1 = mT1;
// Most effects should stop at t1.
if (!mPreviewFullSelection)
mT1 = t1;
// Save the original track list
TrackList *saveTracks = mTracks;
// Linear Effect preview optimised by pre-mixing to one track.
// Generators need to generate per track.
if (mIsLinearEffect && !(GetType() == EffectTypeGenerate)) {
success = ::MixAndRender(mTracks, mFactory, rate, floatSample, t0, t1,
&mixLeft, &mixRight);
}
// Build new tracklist from rendering tracks
mTracks = new TrackList();
if (mIsLinearEffect && !(GetType() == EffectTypeGenerate)) {
// Linear Effect preview optimised by pre-mixing to one track.
// Generators need to generate per track.
if (mIsLinearEffect && !isGenerator) {
success = ::MixAndRender(saveTracks, mFactory, rate, floatSample, mT0, t1,
&mixLeft, &mixRight);
if (!success) {
delete mTracks;
mTracks = saveTracks;
return;
}
mixLeft->InsertSilence(0.0, mT0);
mixLeft->SetSelected(true);
mixLeft->SetDisplay(WaveTrack::NoDisplay);
mTracks->Add(mixLeft);
if (mixRight) {
mixRight->InsertSilence(0.0, mT0);
mixRight->SetSelected(true);
mTracks->Add(mixRight);
}
// Reset t0 / t1 is required when source tracks have different start times.
t0 = mixLeft->GetStartTime();
t1 = mixLeft->GetEndTime();
}
else {
TrackListOfKindIterator iter(Track::Wave, saveTracks);
@ -2460,7 +2482,8 @@ void Effect::Preview(bool dryOnly)
{
WaveTrack *dest;
if (src->GetSelected() || mPreviewWithNotSelected) {
src->Copy(t0, t1, (Track **) &dest);
src->Copy(mT0, t1, (Track **) &dest);
dest->InsertSilence(0.0, mT0);
dest->SetSelected(src->GetSelected());
dest->SetDisplay(WaveTrack::NoDisplay);
mTracks->Add(dest);
@ -2472,25 +2495,14 @@ void Effect::Preview(bool dryOnly)
// Update track/group counts
CountWaveTracks();
double t0save = mT0;
double t1save = mT1;
if (mIsLinearEffect) {
mT0 = t0;
mT1 = t1;
}
else {
mT0 = 0;
mT1 = t1 - t0;
}
// Apply effect
if (!dryOnly) {
mProgress = new ProgressDialog(GetName(),
_("Preparing preview"),
pdlgHideCancelButton); // Have only "Stop" button.
mIsPreview = true;
success = Process();
mIsPreview = false;
delete mProgress;
mProgress = NULL;
}
@ -2502,11 +2514,12 @@ void Effect::Preview(bool dryOnly)
SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
WaveTrack *src = (WaveTrack *) iter.First();
while (src)
{
while (src) {
playbackTracks.Add(src);
src = (WaveTrack *) iter.Next();
}
if (isNyquist && isGenerator)
t1 = mT1;
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrackArray empty;
@ -2517,11 +2530,11 @@ void Effect::Preview(bool dryOnly)
#ifdef EXPERIMENTAL_MIDI_OUT
empty,
#endif
rate, mT0, mT1);
rate, mT0, t1);
if (token) {
int previewing = eProgressSuccess;
wxLogDebug(wxT("mT0 %.3f t1 %.3f"),mT0,t1);
// The progress dialog must be deleted before stopping the stream
// to allow events to flow to the app during StopStream processing.
// The progress dialog blocks these events.
@ -2530,7 +2543,7 @@ void Effect::Preview(bool dryOnly)
while (gAudioIO->IsStreamActive(token) && previewing == eProgressSuccess) {
::wxMilliSleep(100);
previewing = progress->Update(gAudioIO->GetStreamTime() - mT0, mT1);
previewing = progress->Update(gAudioIO->GetStreamTime() - mT0, t1 - mT0);
}
delete progress;
@ -2547,10 +2560,6 @@ void Effect::Preview(bool dryOnly)
}
}
// Restore original selection
mT0 = t0save;
mT1 = t1save;
if (FocusDialog) {
FocusDialog->SetFocus();
}
@ -2562,6 +2571,9 @@ void Effect::Preview(bool dryOnly)
delete mTracks;
mTracks = saveTracks;
mT0 = oldT0;
mT1 = oldT1;
// Effect is already inited; we call Process, End, and then Init
// again, so the state is exactly the way it was before Preview
// was called.

View File

@ -321,6 +321,10 @@ protected:
// To allow pre-mixing before Preview, set linearEffectFlag to true.
void SetLinearEffectFlag(bool linearEffectFlag);
// Most effects only need to preview a short selection. However some
// (such as fade effects) need to know the full selection length.
void SetPreviewFullSelectionFlag(bool previewDurationFlag);
// Most effects only require selected tracks to be copied for Preview.
// If IncludeNotSelectedPreviewTracks(true), then non-linear effects have
// preview copies of all wave tracks.
@ -400,12 +404,13 @@ private:
bool mIsLinearEffect;
bool mPreviewWithNotSelected;
bool mPreviewFullSelection;
bool mIsSelection;
double mDuration;
wxString mDurationFormat;
// mSetDuration should ONLY be set when SetDuration() is called.
double mSetDuration;
bool mIsPreview;
bool mUIDebug;

View File

@ -1366,6 +1366,10 @@ void NyquistEffect::Parse(wxString line)
mEnablePreview = true;
SetLinearEffectFlag(true);
}
else if (tokens[1] == wxT("selection")) {
mEnablePreview = true;
SetPreviewFullSelectionFlag(true);
}
else if (tokens[1] == wxT("disabled") || tokens[1] == wxT("false")) {
mEnablePreview = false;
}