mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 16:10:06 +02:00
Group arguments to StartStream, and a bit less of #ifdef for MIDI play...
... And pull choice of tracks and options out of DoRecord
This commit is contained in:
parent
0635f8802b
commit
35a97e09e7
@ -1861,11 +1861,7 @@ void AudioIO::StartMonitoring(double sampleRate)
|
||||
}
|
||||
}
|
||||
|
||||
int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
|
||||
const WaveTrackArray &captureTracks,
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
const NoteTrackArray &midiPlaybackTracks,
|
||||
#endif
|
||||
int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
double t0, double t1,
|
||||
const AudioIOStartStreamOptions &options)
|
||||
{
|
||||
@ -1921,7 +1917,7 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
|
||||
}
|
||||
mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange; // meter goes -dBRange dB -> 0dB
|
||||
|
||||
if ( !captureTracks.empty() ) {
|
||||
if ( !tracks.captureTracks.empty() ) {
|
||||
// It does not make sense to apply the time warp during overdub recording,
|
||||
// which defeats the purpose of making the recording synchronized with
|
||||
// the existing audio. (Unless we figured out the inverse warp of the
|
||||
@ -1941,7 +1937,7 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
|
||||
DEFAULT_LATENCY_CORRECTION))
|
||||
/ 1000.0;
|
||||
mRecordingSchedule.mDuration = mT1 - mT0;
|
||||
if (captureTracks.size() > 0)
|
||||
if (tracks.captureTracks.size() > 0)
|
||||
// adjust mT1 so that we don't give paComplete too soon to fill up the
|
||||
// desired length of recording
|
||||
mT1 -= mRecordingSchedule.mLatencyCorrection;
|
||||
@ -1951,10 +1947,10 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
|
||||
mTime = t0;
|
||||
mSeek = 0;
|
||||
mLastRecordingOffset = 0;
|
||||
mCaptureTracks = captureTracks;
|
||||
mPlaybackTracks = playbackTracks;
|
||||
mCaptureTracks = tracks.captureTracks;
|
||||
mPlaybackTracks = tracks.playbackTracks;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mMidiPlaybackTracks = midiPlaybackTracks;
|
||||
mMidiPlaybackTracks = tracks.midiTracks;
|
||||
#endif
|
||||
|
||||
bool commit = false;
|
||||
@ -2057,9 +2053,9 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
|
||||
unsigned int captureChannels = 0;
|
||||
sampleFormat captureFormat = floatSample;
|
||||
|
||||
if (playbackTracks.size() > 0
|
||||
if (tracks.playbackTracks.size() > 0
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
|| midiPlaybackTracks.size() > 0
|
||||
|| tracks.midiTracks.size() > 0
|
||||
#endif
|
||||
)
|
||||
playbackChannels = 2;
|
||||
@ -2067,7 +2063,7 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
|
||||
if (mSoftwarePlaythrough)
|
||||
playbackChannels = 2;
|
||||
|
||||
if( captureTracks.size() > 0 )
|
||||
if (tracks.captureTracks.size() > 0)
|
||||
{
|
||||
// For capture, every input channel gets its own track
|
||||
captureChannels = mCaptureTracks.size();
|
||||
@ -2424,13 +2420,15 @@ void AudioIO::PrepareMidiIterator(bool send, double offset)
|
||||
mIterator = std::make_unique<Alg_iterator>(nullptr, false);
|
||||
// Iterator not yet intialized, must add each track...
|
||||
for (i = 0; i < nTracks; i++) {
|
||||
NoteTrack *t = mMidiPlaybackTracks[i].get();
|
||||
const auto t = mMidiPlaybackTracks[i].get();
|
||||
Alg_seq_ptr seq = &t->GetSeq();
|
||||
// mark sequence tracks as "in use" since we're handing this
|
||||
// off to another thread and want to make sure nothing happens
|
||||
// to the data until playback finishes. This is just a sanity check.
|
||||
seq->set_in_use(true);
|
||||
mIterator->begin_seq(seq, t, t->GetOffset() + offset);
|
||||
mIterator->begin_seq(seq,
|
||||
// casting away const, but allegro just uses the pointer as an opaque "cookie"
|
||||
(void*)t, t->GetOffset() + offset);
|
||||
}
|
||||
GetNextEvent(); // prime the pump for FillMidiBuffers
|
||||
|
||||
@ -2686,7 +2684,7 @@ void AudioIO::StopStream()
|
||||
// set in_use flags to false
|
||||
int nTracks = mMidiPlaybackTracks.size();
|
||||
for (int i = 0; i < nTracks; i++) {
|
||||
NoteTrack *t = mMidiPlaybackTracks[i].get();
|
||||
const auto t = mMidiPlaybackTracks[i].get();
|
||||
Alg_seq_ptr seq = &t->GetSeq();
|
||||
seq->set_in_use(false);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
class NoteTrack;
|
||||
using NoteTrackArray = std::vector < std::shared_ptr< NoteTrack > >;
|
||||
using NoteTrackConstArray = std::vector < std::shared_ptr< const NoteTrack > >;
|
||||
|
||||
#endif // EXPERIMENTAL_MIDI_OUT
|
||||
|
||||
@ -140,6 +141,14 @@ struct AudioIOStartStreamOptions
|
||||
#endif
|
||||
};
|
||||
|
||||
struct TransportTracks {
|
||||
WaveTrackConstArray playbackTracks;
|
||||
WaveTrackArray captureTracks;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
NoteTrackConstArray midiTracks;
|
||||
#endif
|
||||
};
|
||||
|
||||
// This workaround makes pause and stop work when output is to GarageBand,
|
||||
// which seems not to implement the notes-off message correctly.
|
||||
#define AUDIO_IO_GB_MIDI_WORKAROUND
|
||||
@ -169,10 +178,7 @@ class AUDACITY_DLL_API AudioIO final {
|
||||
* If successful, returns a token identifying this particular stream
|
||||
* instance. For use with IsStreamActive() below */
|
||||
|
||||
int StartStream(const WaveTrackConstArray &playbackTracks, const WaveTrackArray &captureTracks,
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
const NoteTrackArray &midiTracks,
|
||||
#endif
|
||||
int StartStream(const TransportTracks &tracks,
|
||||
double t0, double t1,
|
||||
const AudioIOStartStreamOptions &options);
|
||||
|
||||
@ -611,7 +617,7 @@ private:
|
||||
/// when true, mSendMidiState means send only updates, not note-on's,
|
||||
/// used to send state changes that precede the selected notes
|
||||
bool mSendMidiState;
|
||||
NoteTrackArray mMidiPlaybackTracks;
|
||||
NoteTrackConstArray mMidiPlaybackTracks;
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
|
||||
|
@ -1354,14 +1354,14 @@ WaveTrackConstArray TrackList::GetWaveTrackConstArray(bool selectionOnly, bool i
|
||||
}
|
||||
|
||||
#if defined(USE_MIDI)
|
||||
NoteTrackArray TrackList::GetNoteTrackArray(bool selectionOnly)
|
||||
NoteTrackConstArray TrackList::GetNoteTrackConstArray(bool selectionOnly) const
|
||||
{
|
||||
NoteTrackArray noteTrackArray;
|
||||
NoteTrackConstArray noteTrackArray;
|
||||
|
||||
for(const auto &track : *this) {
|
||||
if (track->GetKind() == Track::Note &&
|
||||
(track->GetSelected() || !selectionOnly)) {
|
||||
noteTrackArray.push_back( Track::Pointer<NoteTrack>(track) );
|
||||
noteTrackArray.push_back( Track::Pointer<const NoteTrack>(track) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1573,3 +1573,17 @@ bool TrackList::HasPendingTracks() const
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "AudioIO.h"
|
||||
TransportTracks GetAllPlaybackTracks(const TrackList &trackList, bool selectedOnly, bool useMidi)
|
||||
{
|
||||
TransportTracks result;
|
||||
result.playbackTracks = trackList.GetWaveTrackConstArray(selectedOnly);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
if (useMidi)
|
||||
result.midiTracks = trackList.GetNoteTrackConstArray(selectedOnly);
|
||||
#else
|
||||
WXUNUSED(useMidi);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
@ -50,7 +50,8 @@ class TimeShiftHandle;
|
||||
WX_DEFINE_USER_EXPORTED_ARRAY(Track*, TrackArray, class AUDACITY_DLL_API);
|
||||
using WaveTrackArray = std::vector < std::shared_ptr< WaveTrack > > ;
|
||||
using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >;
|
||||
using NoteTrackArray = std::vector < std::shared_ptr < NoteTrack > >;
|
||||
|
||||
using NoteTrackConstArray = std::vector < std::shared_ptr< const NoteTrack > >;
|
||||
|
||||
#if defined(USE_MIDI)
|
||||
class NoteTrack;
|
||||
@ -721,7 +722,7 @@ class TrackList final : public wxEvtHandler, public ListOfTracks
|
||||
WaveTrackConstArray GetWaveTrackConstArray(bool selectionOnly, bool includeMuted = true) const;
|
||||
|
||||
#if defined(USE_MIDI)
|
||||
NoteTrackArray GetNoteTrackArray(bool selectionOnly);
|
||||
NoteTrackConstArray GetNoteTrackConstArray(bool selectionOnly) const;
|
||||
#endif
|
||||
|
||||
/// Mainly a test function. Uses a linear search, so could be slow.
|
||||
@ -886,4 +887,8 @@ class AUDACITY_DLL_API TrackFactory
|
||||
#endif
|
||||
};
|
||||
|
||||
// global functions
|
||||
struct TransportTracks;
|
||||
TransportTracks GetAllPlaybackTracks(const TrackList &trackList, bool selectedOnly, bool useMidi = false);
|
||||
|
||||
#endif
|
||||
|
@ -2602,30 +2602,16 @@ void Effect::Preview(bool dryOnly)
|
||||
|
||||
if (success)
|
||||
{
|
||||
WaveTrackConstArray playbackTracks;
|
||||
WaveTrackArray recordingTracks;
|
||||
auto tracks = GetAllPlaybackTracks(*mTracks, true);
|
||||
|
||||
SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
|
||||
WaveTrack *src = (WaveTrack *) iter.First();
|
||||
while (src) {
|
||||
playbackTracks.push_back(Track::Pointer<WaveTrack>(src));
|
||||
src = (WaveTrack *) iter.Next();
|
||||
}
|
||||
// Some effects (Paulstretch) may need to generate more
|
||||
// than previewLen, so take the min.
|
||||
t1 = std::min(mT0 + previewLen, mT1);
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
NoteTrackArray empty;
|
||||
#endif
|
||||
// Start audio playing
|
||||
AudioIOStartStreamOptions options { rate };
|
||||
int token =
|
||||
gAudioIO->StartStream(playbackTracks, recordingTracks,
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
empty,
|
||||
#endif
|
||||
mT0, t1, options);
|
||||
gAudioIO->StartStream(tracks, mT0, t1, options);
|
||||
|
||||
if (token) {
|
||||
auto previewing = ProgressResult::Success;
|
||||
|
@ -686,13 +686,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
|
||||
myOptions.cutPreviewGapStart = t0;
|
||||
myOptions.cutPreviewGapLen = t1 - t0;
|
||||
token = gAudioIO->StartStream(
|
||||
mCutPreviewTracks->GetWaveTrackConstArray(false),
|
||||
WaveTrackArray(),
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
useMidi
|
||||
? mCutPreviewTracks->GetNoteTrackArray(false)
|
||||
: NoteTrackArray(),
|
||||
#endif
|
||||
GetAllPlaybackTracks(*mCutPreviewTracks, false, useMidi),
|
||||
tcp0, tcp1, myOptions);
|
||||
}
|
||||
else
|
||||
@ -706,14 +700,9 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
|
||||
timetrack = t->GetTimeTrack();
|
||||
}
|
||||
*/
|
||||
token = gAudioIO->StartStream(t->GetWaveTrackConstArray(false),
|
||||
WaveTrackArray(),
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
useMidi
|
||||
? t->GetNoteTrackArray(false)
|
||||
: NoteTrackArray(),
|
||||
#endif
|
||||
t0, t1, options);
|
||||
token = gAudioIO->StartStream(
|
||||
GetAllPlaybackTracks(*t, false, useMidi),
|
||||
t0, t1, options);
|
||||
}
|
||||
if (token != 0) {
|
||||
success = true;
|
||||
@ -1079,22 +1068,29 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
|
||||
}
|
||||
}
|
||||
|
||||
success = DoRecord(*p, existingTracks, t0, t1);
|
||||
TransportTracks transportTracks;
|
||||
if (UseDuplex()) {
|
||||
// Remove recording tracks from the list of tracks for duplex ("overdub")
|
||||
// playback.
|
||||
/* TODO: set up stereo tracks if that is how the user has set up
|
||||
* their preferences, and choose sample format based on prefs */
|
||||
transportTracks = GetAllPlaybackTracks(*p->GetTracks(), false, true);
|
||||
for (const auto &wt : existingTracks) {
|
||||
auto end = transportTracks.playbackTracks.end();
|
||||
auto it = std::find(transportTracks.playbackTracks.begin(), end, wt);
|
||||
if (it != end)
|
||||
transportTracks.playbackTracks.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
transportTracks.captureTracks = existingTracks;
|
||||
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
|
||||
success = DoRecord(*p, transportTracks, t0, t1, options);
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlToolBar::DoRecord(AudacityProject &project, WaveTrackArray &existingTracks, double t0, double t1)
|
||||
bool ControlToolBar::UseDuplex()
|
||||
{
|
||||
const auto p = &project;
|
||||
bool success = false;
|
||||
|
||||
/* TODO: set up stereo tracks if that is how the user has set up
|
||||
* their preferences, and choose sample format based on prefs */
|
||||
WaveTrackConstArray playbackTracks;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
NoteTrackArray midiTracks;
|
||||
#endif
|
||||
|
||||
bool duplex;
|
||||
gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex,
|
||||
#ifdef EXPERIMENTAL_DA
|
||||
@ -1103,39 +1099,30 @@ bool ControlToolBar::DoRecord(AudacityProject &project, WaveTrackArray &existing
|
||||
true
|
||||
#endif
|
||||
);
|
||||
return duplex;
|
||||
}
|
||||
|
||||
if (duplex){
|
||||
TrackList *trackList = p->GetTracks();
|
||||
playbackTracks = trackList->GetWaveTrackConstArray(false);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
midiTracks = trackList->GetNoteTrackArray(false);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
playbackTracks = WaveTrackConstArray();
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
midiTracks = NoteTrackArray();
|
||||
#endif
|
||||
}
|
||||
bool ControlToolBar::DoRecord(AudacityProject &project,
|
||||
const TransportTracks &tracks,
|
||||
double t0, double t1,
|
||||
const AudioIOStartStreamOptions &options)
|
||||
{
|
||||
auto transportTracks = tracks;
|
||||
|
||||
bool appendRecord = !existingTracks.empty();
|
||||
// Will replace any given capture tracks with temporaries
|
||||
transportTracks.captureTracks.clear();
|
||||
|
||||
const auto p = &project;
|
||||
bool success = false;
|
||||
|
||||
bool appendRecord = !tracks.captureTracks.empty();
|
||||
|
||||
{
|
||||
WaveTrackArray recordingTracks;
|
||||
|
||||
if (appendRecord) {
|
||||
// Append recording:
|
||||
// Pad selected/all wave tracks to make them all the same length
|
||||
// Remove recording tracks from the list of tracks for duplex ("overdub")
|
||||
// playback.
|
||||
for (const auto &wt : existingTracks)
|
||||
for (const auto &wt : tracks.captureTracks)
|
||||
{
|
||||
if (duplex) {
|
||||
auto end = playbackTracks.end();
|
||||
auto it = std::find(playbackTracks.begin(), end, wt);
|
||||
if (it != end)
|
||||
playbackTracks.erase(it);
|
||||
}
|
||||
t1 = wt->GetEndTime();
|
||||
|
||||
// A function that copies all the non-sample data between
|
||||
@ -1167,7 +1154,7 @@ bool ControlToolBar::DoRecord(AudacityProject &project, WaveTrackArray &existing
|
||||
pending->Clear(t1, t0);
|
||||
pending->Paste(t1, newTrack.get());
|
||||
}
|
||||
recordingTracks.push_back(pending);
|
||||
transportTracks.captureTracks.push_back(pending);
|
||||
}
|
||||
|
||||
if (t1 <= p->GetSel0() && p->GetSel1() > p->GetSel0()) {
|
||||
@ -1177,7 +1164,7 @@ bool ControlToolBar::DoRecord(AudacityProject &project, WaveTrackArray &existing
|
||||
}
|
||||
}
|
||||
|
||||
if( recordingTracks.empty() )
|
||||
if( transportTracks.captureTracks.empty() )
|
||||
{ // recording to NEW track(s).
|
||||
bool recordingNameCustom, useTrackNumber, useDateStamp, useTimeStamp;
|
||||
wxString defaultTrackName, defaultRecordingTrackName;
|
||||
@ -1268,7 +1255,7 @@ bool ControlToolBar::DoRecord(AudacityProject &project, WaveTrackArray &existing
|
||||
}
|
||||
|
||||
p->GetTracks()->RegisterPendingNewTrack( newTrack );
|
||||
recordingTracks.push_back( newTrack );
|
||||
transportTracks.captureTracks.push_back(newTrack);
|
||||
// Bug 1548. New track needs the focus.
|
||||
p->GetTrackPanel()->SetFocusedTrack( newTrack.get() );
|
||||
}
|
||||
@ -1279,13 +1266,7 @@ bool ControlToolBar::DoRecord(AudacityProject &project, WaveTrackArray &existing
|
||||
gAudioIO->AILAInitialize();
|
||||
#endif
|
||||
|
||||
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
|
||||
int token = gAudioIO->StartStream(playbackTracks,
|
||||
recordingTracks,
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
midiTracks,
|
||||
#endif
|
||||
t0, t1, options);
|
||||
int token = gAudioIO->StartStream(transportTracks, t0, t1, options);
|
||||
|
||||
success = (token != 0);
|
||||
|
||||
|
@ -41,6 +41,8 @@ enum class PlayMode : int;
|
||||
class WaveTrack;
|
||||
using WaveTrackArray = std::vector < std::shared_ptr < WaveTrack > >;
|
||||
|
||||
struct TransportTracks;
|
||||
|
||||
// In the GUI, ControlToolBar appears as the "Transport Toolbar". "Control Toolbar" is historic.
|
||||
class ControlToolBar final : public ToolBar {
|
||||
|
||||
@ -55,7 +57,9 @@ class ControlToolBar final : public ToolBar {
|
||||
void OnKeyEvent(wxKeyEvent & event);
|
||||
|
||||
// Find suitable tracks to record into, or return an empty array.
|
||||
WaveTrackArray ChooseExistingRecordingTracks(AudacityProject &proj, bool selectedOnly);
|
||||
static WaveTrackArray ChooseExistingRecordingTracks(AudacityProject &proj, bool selectedOnly);
|
||||
|
||||
static bool UseDuplex();
|
||||
|
||||
// msmeyer: These are public, but it's far better to
|
||||
// call the "real" interface functions like PlayCurrentRegion() and
|
||||
@ -64,7 +68,10 @@ class ControlToolBar final : public ToolBar {
|
||||
void OnPlay(wxCommandEvent & evt);
|
||||
void OnStop(wxCommandEvent & evt);
|
||||
void OnRecord(wxCommandEvent & evt);
|
||||
bool DoRecord(AudacityProject &project, WaveTrackArray &existingTracks, double t0, double t1);
|
||||
bool DoRecord(AudacityProject &project,
|
||||
const TransportTracks &transportTracks, // If captureTracks is empty, then tracks are created
|
||||
double t0, double t1,
|
||||
const AudioIOStartStreamOptions &options);
|
||||
void OnFF(wxCommandEvent & evt);
|
||||
void OnPause(wxCommandEvent & evt);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user