mirror of
https://github.com/cookiengineer/audacity
synced 2025-12-04 07:40:12 +01:00
New project. New track. Generate sound -- do not cancel. Select all, generate sound again -- this time, do cancel the progress dialog. Undo, so you see one, empty track again. Save. Close. Reopen. The cause of these orphans is different from the first case. The previous commit is necessary but not sufficient to fix this.
470 lines
13 KiB
C++
470 lines
13 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
Track.h
|
|
|
|
Dominic Mazzoni
|
|
|
|
**********************************************************************/
|
|
|
|
#ifndef __AUDACITY_TRACK__
|
|
#define __AUDACITY_TRACK__
|
|
|
|
#include "Audacity.h"
|
|
|
|
#include <wx/dynarray.h>
|
|
#include <wx/event.h>
|
|
#include <wx/gdicmn.h>
|
|
#include <wx/longlong.h>
|
|
#include <wx/string.h>
|
|
|
|
#include "Experimental.h"
|
|
#include "SampleFormat.h"
|
|
#include "xml/XMLTagHandler.h"
|
|
|
|
#ifdef __WXMSW__
|
|
#pragma warning(disable:4284)
|
|
#endif
|
|
|
|
class wxTextFile;
|
|
class DirManager;
|
|
class UndoStack;
|
|
class LabelTrack;
|
|
class TimeTrack;
|
|
class WaveTrack;
|
|
class AudacityProject;
|
|
|
|
WX_DEFINE_USER_EXPORTED_ARRAY(WaveTrack*, WaveTrackArray, class AUDACITY_DLL_API);
|
|
|
|
#if defined(USE_MIDI)
|
|
class NoteTrack;
|
|
WX_DEFINE_USER_EXPORTED_ARRAY(NoteTrack*, NoteTrackArray, class AUDACITY_DLL_API);
|
|
#endif
|
|
|
|
class TrackList;
|
|
struct TrackListNode;
|
|
|
|
class AUDACITY_DLL_API Track: public XMLTagHandler
|
|
{
|
|
|
|
// To be TrackDisplay
|
|
protected:
|
|
TrackList *mList;
|
|
TrackListNode *mNode;
|
|
int mIndex;
|
|
int mY;
|
|
int mHeight;
|
|
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
|
int mYv; //For mono a virtual Y value is necessary.
|
|
int mHeightv; // For mono a virtual height value is necessary.
|
|
float mPerY; //mY as a percent of mYv + mY
|
|
bool mVirtualStereo;
|
|
#endif
|
|
wxString mName;
|
|
wxString mDefaultName;
|
|
|
|
bool mSelected;
|
|
|
|
bool mLinked;
|
|
bool mMinimized;
|
|
|
|
public:
|
|
wxSize vrulerSize;
|
|
|
|
// This just returns a constant and can be overriden by subclasses
|
|
// to specify a different height for the case that the track is minimized.
|
|
virtual int GetMinimizedHeight() const;
|
|
int GetActualHeight() { return mHeight; };
|
|
|
|
int GetIndex() const;
|
|
void SetIndex(int index);
|
|
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
|
int GetY(bool vStereo = false) const;
|
|
void SetY(int y, bool vStereo = false);
|
|
int GetHeight(bool vStereo = false) const;
|
|
void SetHeight(int h, bool vStereo = false);
|
|
#else
|
|
int GetY() const;
|
|
void SetY(int y);
|
|
int GetHeight() const;
|
|
void SetHeight(int h);
|
|
#endif
|
|
bool GetMinimized() const;
|
|
void SetMinimized(bool isMinimized);
|
|
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
|
float GetVirtualTrackPercentage() { return mPerY;}
|
|
void SetVirtualTrackPercentage(float val) { mPerY = val;}
|
|
bool GetVirtualStereo() { return mVirtualStereo;}
|
|
void SetVirtualStereo(bool vStereo) { mVirtualStereo = vStereo;}
|
|
#endif
|
|
Track *GetLink() const;
|
|
|
|
const TrackListNode *GetNode();
|
|
void SetOwner(TrackList *list, TrackListNode *node);
|
|
|
|
// Keep in Track
|
|
|
|
protected:
|
|
int mChannel;
|
|
double mOffset;
|
|
bool mMute;
|
|
bool mSolo;
|
|
|
|
mutable DirManager *mDirManager;
|
|
|
|
public:
|
|
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
|
void ReorderList(bool resize = true);
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
LeftChannel = 0,
|
|
RightChannel = 1,
|
|
MonoChannel = 2
|
|
};
|
|
|
|
enum TrackKindEnum
|
|
{
|
|
None,
|
|
Wave,
|
|
#if defined(USE_MIDI)
|
|
Note,
|
|
#endif
|
|
Label,
|
|
Time,
|
|
All
|
|
};
|
|
|
|
Track(DirManager * projDirManager);
|
|
Track(const Track &orig);
|
|
|
|
virtual ~ Track();
|
|
|
|
void Init(const Track &orig);
|
|
virtual Track *Duplicate() = 0;
|
|
|
|
// Called when this track is merged to stereo with another, and should
|
|
// take on some paramaters of its partner.
|
|
virtual void Merge(const Track &orig);
|
|
|
|
wxString GetName() const { return mName; }
|
|
void SetName( wxString n ) { mName = n; }
|
|
wxString GetDefaultName() const { return mDefaultName; }
|
|
void SetDefaultName( wxString n ) { mDefaultName = n; }
|
|
|
|
bool GetSelected() const { return mSelected; }
|
|
bool GetMute () const { return mMute; }
|
|
bool GetLinked () const { return mLinked; }
|
|
bool GetSolo () const { return mSolo; }
|
|
|
|
void SetSelected(bool s) { mSelected = s; }
|
|
void SetMute (bool m) { mMute = m; }
|
|
void SetLinked (bool l);
|
|
void SetSolo (bool s) { mSolo = s; }
|
|
|
|
int GetChannel() const { return mChannel; }
|
|
virtual double GetOffset () { return mOffset; }
|
|
|
|
void Offset(double t) { SetOffset(GetOffset() + t); }
|
|
virtual void SetOffset (double o) { mOffset = o; }
|
|
|
|
void SetChannel(int c) { mChannel = c; }
|
|
|
|
// AS: Note that the dirManager is mutable. This is
|
|
// mostly to support "Duplicate" of const objects,
|
|
// but in general, mucking with the dir manager is
|
|
// separate from the Track.
|
|
DirManager* GetDirManager() const { return mDirManager; }
|
|
|
|
virtual bool Cut (double WXUNUSED(t0), double WXUNUSED(t1), Track ** WXUNUSED(dest)) {return false;}
|
|
virtual bool Copy (double WXUNUSED(t0), double WXUNUSED(t1), Track ** WXUNUSED(dest)) {return false;}
|
|
virtual bool Clear(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;}
|
|
virtual bool Paste(double WXUNUSED(t), Track * WXUNUSED(src)) {return false;}
|
|
|
|
// This can be used to adjust a sync-lock selected track when the selection
|
|
// is replaced by one of a different length.
|
|
virtual bool SyncLockAdjust(double oldT1, double newT1);
|
|
|
|
virtual bool Silence(double WXUNUSED(t0), double WXUNUSED(t1)) {return false;}
|
|
virtual bool InsertSilence(double WXUNUSED(t), double WXUNUSED(len)) {return false;}
|
|
|
|
virtual int GetKind() const { return None; }
|
|
|
|
// XMLTagHandler callback methods
|
|
|
|
virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) = 0;
|
|
virtual XMLTagHandler *HandleXMLChild(const wxChar *tag) = 0;
|
|
virtual void WriteXML(XMLWriter &xmlFile) = 0;
|
|
|
|
// Returns true if an error was encountered while trying to
|
|
// open the track from XML
|
|
virtual bool GetErrorOpening() { return false; }
|
|
|
|
virtual double GetStartTime() { return 0.0; }
|
|
virtual double GetEndTime() { return 0.0; }
|
|
|
|
// Checks if sync-lock is on and any track in its sync-lock group is selected.
|
|
bool IsSyncLockSelected();
|
|
};
|
|
|
|
struct TrackListNode
|
|
{
|
|
Track *t;
|
|
TrackListNode *next;
|
|
TrackListNode *prev;
|
|
};
|
|
|
|
class AUDACITY_DLL_API TrackListIterator
|
|
{
|
|
public:
|
|
TrackListIterator(TrackList * val = NULL);
|
|
virtual ~TrackListIterator() {};
|
|
|
|
// Iterate functions
|
|
virtual Track *First(TrackList * val = NULL);
|
|
virtual Track *StartWith(Track * val);
|
|
virtual Track *Next(bool skiplinked = false);
|
|
virtual Track *Prev(bool skiplinked = false);
|
|
virtual Track *Last(bool skiplinked = false);
|
|
|
|
Track *ReplaceCurrent(Track *t); // returns original
|
|
Track *RemoveCurrent(bool deletetrack = false); // returns next
|
|
|
|
protected:
|
|
TrackList *l;
|
|
TrackListNode *cur;
|
|
};
|
|
|
|
// TrackListCondIterator (base class for iterators that iterate over all tracks)
|
|
// that meet a condition)
|
|
class AUDACITY_DLL_API TrackListCondIterator: public TrackListIterator
|
|
{
|
|
public:
|
|
TrackListCondIterator(TrackList *val = NULL)
|
|
: TrackListIterator(val) {};
|
|
virtual ~TrackListCondIterator() {};
|
|
|
|
// Iteration functions
|
|
Track *First(TrackList *val = NULL);
|
|
Track *StartWith(Track *val);
|
|
Track *Next(bool skiplinked = false);
|
|
Track *Prev(bool skiplinked = false);
|
|
Track *Last(bool skiplinked = false);
|
|
|
|
protected:
|
|
virtual bool Condition(Track *t) = 0;
|
|
};
|
|
|
|
//
|
|
// TrackListOfKindIterator
|
|
//
|
|
// Based on TrackListIterator and returns only tracks of the specified type.
|
|
//
|
|
class AUDACITY_DLL_API TrackListOfKindIterator: public TrackListCondIterator
|
|
{
|
|
public:
|
|
TrackListOfKindIterator(int kind, TrackList * val = NULL);
|
|
virtual ~TrackListOfKindIterator() {};
|
|
|
|
protected:
|
|
virtual bool Condition(Track *t);
|
|
|
|
private:
|
|
int kind;
|
|
};
|
|
|
|
//
|
|
// SelectedTrackListOfKindIterator
|
|
//
|
|
// Based on TrackListOfKindIterator and returns only tracks selected.
|
|
//
|
|
class AUDACITY_DLL_API SelectedTrackListOfKindIterator: public TrackListOfKindIterator
|
|
{
|
|
public:
|
|
SelectedTrackListOfKindIterator(int kind, TrackList * val = NULL) : TrackListOfKindIterator(kind, val) {};
|
|
virtual ~SelectedTrackListOfKindIterator() {};
|
|
|
|
protected:
|
|
bool Condition(Track *t);
|
|
};
|
|
|
|
//
|
|
// VisibleTrackIterator
|
|
//
|
|
// Based on TrackListIterator returns only the currently visible tracks.
|
|
//
|
|
class AUDACITY_DLL_API VisibleTrackIterator: public TrackListCondIterator
|
|
{
|
|
public:
|
|
VisibleTrackIterator(AudacityProject *project);
|
|
virtual ~VisibleTrackIterator() {};
|
|
|
|
protected:
|
|
bool Condition(Track *t);
|
|
|
|
private:
|
|
AudacityProject *mProject;
|
|
wxRect mPanelRect;
|
|
};
|
|
|
|
|
|
// SyncLockedTracksIterator returns only tracks belonging to the sync-locked tracks
|
|
// in which the starting track is a member.
|
|
class AUDACITY_DLL_API SyncLockedTracksIterator : public TrackListIterator
|
|
{
|
|
public:
|
|
SyncLockedTracksIterator(TrackList * val);
|
|
virtual ~SyncLockedTracksIterator() {};
|
|
|
|
// Iterate functions
|
|
Track *First(Track *member);
|
|
Track *Next(bool skiplinked = false);
|
|
Track *Prev(bool skiplinked = false);
|
|
Track *Last(bool skiplinked = false);
|
|
|
|
private:
|
|
bool mInLabelSection;
|
|
};
|
|
|
|
|
|
/** \brief TrackList is a flat linked list of tracks supporting Add, Remove,
|
|
* Clear, and Contains, plus serialization of the list of tracks.
|
|
*/
|
|
|
|
// Posted when the horizontal positions within tracks have beed updated. The
|
|
// wxCommandEvent::GetClientData() method can be used to retrieve the first
|
|
// track that was updated. All positions following that track will have been
|
|
// updated as well.
|
|
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TRACKLIST_RESIZED, -1);
|
|
|
|
// Posted when tracks have been added or deleted from a tracklist. The pointer
|
|
// wxCommandEvent::GetClientData() returns will be NULL for deletions or the
|
|
// track that was added.
|
|
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TRACKLIST_UPDATED, -1);
|
|
|
|
class AUDACITY_DLL_API TrackList:public wxEvtHandler
|
|
{
|
|
public:
|
|
// Create an empty TrackList
|
|
TrackList(bool destructorDeletesTracks = false);
|
|
|
|
// Destructor
|
|
virtual ~TrackList();
|
|
|
|
friend class Track;
|
|
friend class TrackListIterator;
|
|
|
|
/// Add this Track or all children of this TrackList.
|
|
void Add(Track * t);
|
|
void AddToHead(Track * t);
|
|
|
|
/// Replace first track with second track
|
|
void Replace(Track * t, Track * with, bool deletetrack = false);
|
|
|
|
/// Remove this Track or all children of this TrackList.
|
|
void Remove(Track * t, bool deletetrack = false);
|
|
|
|
/// Make the list empty
|
|
void Clear(bool deleteTracks = false);
|
|
|
|
/** Select a track, and if it is linked to another track, select it, too. */
|
|
void Select(Track * t, bool selected = true);
|
|
|
|
/** If this track is linked to another track (the track immediately before or
|
|
* after it), return its partner. Otherwise return null. */
|
|
Track *GetLink(Track * t) const;
|
|
|
|
Track *GetPrev(Track * t, bool linked = false) const;
|
|
|
|
/** Return a track in the list that comes after Track t
|
|
* @param t a track in the list
|
|
* @param linked if true, skips over linked tracks, if false returns the next track even if it is a linked track
|
|
**/
|
|
Track *GetNext(Track * t, bool linked = false) const;
|
|
int GetGroupHeight(Track * t) const;
|
|
|
|
bool CanMoveUp(Track * t) const;
|
|
bool CanMoveDown(Track * t) const;
|
|
|
|
bool MoveUp(Track * t);
|
|
bool MoveDown(Track * t);
|
|
bool Move(Track * t, bool up) { return up ? MoveUp(t) : MoveDown(t); }
|
|
|
|
TimeTrack *GetTimeTrack();
|
|
|
|
/** \brief Find out how many channels this track list mixes to
|
|
*
|
|
* This is used in exports of the tracks to work out whether to export in
|
|
* Mono, Stereo etc. @param selectionOnly Whether to consider the entire track
|
|
* list or only the selected members of it
|
|
*/
|
|
int GetNumExportChannels(bool selectionOnly);
|
|
|
|
WaveTrackArray GetWaveTrackArray(bool selectionOnly);
|
|
/** Consider this function depricated in favor of GetWaveTrackArray */
|
|
void GetWaveTracks(bool selectionOnly, int *num, WaveTrack ***tracks);
|
|
|
|
#if defined(USE_MIDI)
|
|
NoteTrackArray GetNoteTrackArray(bool selectionOnly);
|
|
#endif
|
|
|
|
/// Mainly a test function. Uses a linear search, so could be slow.
|
|
bool Contains(Track * t) const;
|
|
|
|
bool IsEmpty() const;
|
|
int GetCount() const;
|
|
|
|
double GetStartTime() const;
|
|
double GetEndTime() const;
|
|
|
|
double GetMinOffset() const;
|
|
int GetHeight() const;
|
|
|
|
#if LEGACY_PROJECT_FILE_SUPPORT
|
|
// File I/O
|
|
virtual bool Load(wxTextFile * in, DirManager * dirManager);
|
|
virtual bool Save(wxTextFile * out, bool overwrite);
|
|
#endif
|
|
|
|
private:
|
|
void RecalcPositions(const TrackListNode *node);
|
|
void UpdatedEvent(const TrackListNode *node);
|
|
void ResizedEvent(const TrackListNode *node);
|
|
|
|
void Swap(TrackListNode * s1, TrackListNode * s2);
|
|
|
|
TrackListNode *head;
|
|
TrackListNode *tail;
|
|
|
|
bool mDestructorDeletesTracks;
|
|
};
|
|
|
|
class AUDACITY_DLL_API TrackFactory
|
|
{
|
|
private:
|
|
TrackFactory(DirManager *dirManager):
|
|
mDirManager(dirManager)
|
|
{
|
|
}
|
|
|
|
DirManager *mDirManager;
|
|
friend class AudacityProject;
|
|
friend class BenchmarkDialog;
|
|
|
|
public:
|
|
// These methods are defined in WaveTrack.cpp, NoteTrack.cpp,
|
|
// LabelTrack.cpp, and TimeTrack.cpp respectively
|
|
WaveTrack* DuplicateWaveTrack(WaveTrack &orig);
|
|
WaveTrack *NewWaveTrack(sampleFormat format = (sampleFormat)0,
|
|
double rate = 0);
|
|
LabelTrack *NewLabelTrack();
|
|
TimeTrack *NewTimeTrack();
|
|
#if defined(USE_MIDI)
|
|
NoteTrack *NewNoteTrack();
|
|
#endif
|
|
};
|
|
|
|
#endif
|