22#include <wx/wxcrtvararg.h>
28#include "../lib-src/header-substitutes/allegro.h"
32#define ROUND(x) ((int) ((x) + 0.5))
50#define SON_AutoSave 67
51#define SON_ModifyState 60
52#define SON_NoteBackground 72
53#define SON_NoteForeground 74
54#define SON_Measures 76
55#define SON_Serialize 77
56#define SON_Unserialize 79
61bool sonificationStarted =
false;
65 PmError err = Pm_OpenOutput(&sonMidiStream, Pm_GetDefaultOutputDeviceID(),
66 NULL, 0, NULL, NULL, 0);
67 if (err) sonMidiStream = NULL;
69 Pm_WriteShort(sonMidiStream, 0, Pm_Message(0xC0, SON_PROGRAM, 0));
70 sonificationStarted =
true;
76 if (sonMidiStream) Pm_Close(sonMidiStream);
77 sonificationStarted =
false;
83void SonifyNoteOnOff(
int p,
int v)
85 if (!sonificationStarted)
88 Pm_WriteShort(sonMidiStream, 0, Pm_Message(0x90, p, v));
92 void SonifyBegin ## name() { SonifyNoteOnOff(SON_ ## name, SON_VEL); } \
93 void SonifyEnd ## name() { SonifyNoteOnOff(SON_ ## name, 0); }
117 auto result = tracks.Add( std::make_shared<NoteTrack>());
118 result->AttachedTrackObjects::BuildAll();
142 mSeq = std::make_unique<Alg_seq>();
144 std::unique_ptr<Alg_track> alg_track
145 { Alg_seq::unserialize
147 wxASSERT(alg_track->get_type() ==
's');
148 mSeq.reset(
static_cast<Alg_seq*
>(alg_track.release()) );
162 auto duplicate = std::make_shared<NoteTrack>();
163 duplicate->Init(*
this);
172 mSeq->serialize(&buffer,
173 &duplicate->mSerializationLength);
174 duplicate->mSerializationBuffer.reset( (
char*)buffer );
181 duplicate->mSerializationBuffer.reset
183 memcpy( duplicate->mSerializationBuffer.get(),
184 this->mSerializationBuffer.get(), this->mSerializationLength );
194#ifdef EXPERIMENTAL_MIDI_OUT
195 duplicate->SetVelocity(GetVelocity());
222 seq.convert_to_seconds();
225 if (t1 > seq.get_dur()) {
227 if (t0 >= t1)
return;
229 Alg_iterator iter(
mSeq.get(),
false);
232 while (0 != (event = iter.next()) && event->time < t1) {
233 if (event->is_note() && event->time >= t0) {
234 event->set_pitch(event->get_pitch() + semitones);
239 seq.convert_to_beats();
240 Alg_time_map_ptr map = seq.get_time_map();
241 map->insert_beat(t0, map->time_to_beat(t0));
242 map->insert_beat(t1, map->time_to_beat(t1));
243 int i, len = map->length();
244 for (i = 0; i < len; i++) {
245 Alg_beat &beat = map->beats[i];
246 beat.time = warper.
Warp(beat.time + offset) - offset;
249 seq.convert_to_seconds();
255(
const NoteTrack *pTrack, wxDC & dc,
const wxRect &rect,
int highlightedChannel )
258 wxASSERT_MSG(rect.width % 4 == 0,
"Midi channel control rect width must be divisible by 4");
259 wxASSERT_MSG(rect.height % 4 == 0,
"Midi channel control rect height must be divisible by 4");
261 auto cellWidth = rect.width / 4;
262 auto cellHeight = rect.height / 4;
265 for (
int row = 0; row < 4; row++) {
266 for (
int col = 0; col < 4; col++) {
269 int chanName = row * 4 + col + 1;
271 box.x = rect.x + col * cellWidth;
272 box.y = rect.y + row * cellHeight;
273 box.width = cellWidth;
274 box.height = cellHeight;
276 bool visible = pTrack ? pTrack->
IsVisibleChan(chanName - 1) :
true;
279 if ( chanName == highlightedChannel + 1 )
283 dc.DrawRectangle(box);
287#define CHANNEL_ON_IS_DOWN 1
288#if CHANNEL_ON_IS_DOWN
293 AColor::Line(dc, box.x, box.y, box.x + box.width - 1, box.y);
294 AColor::Line(dc, box.x, box.y, box.x, box.y + box.height - 1);
296#if CHANNEL_ON_IS_DOWN
302 box.x + box.width - 1, box.y,
303 box.x + box.width - 1, box.y + box.height - 1);
305 box.x, box.y + box.height - 1,
306 box.x + box.width - 1, box.y + box.height - 1);
308 if ( chanName == highlightedChannel + 1 )
312 dc.DrawRectangle(box);
313#if CHANNEL_ON_IS_DOWN
318 AColor::Line(dc, box.x, box.y, box.x + box.width - 1, box.y);
319 AColor::Line(dc, box.x, box.y, box.x, box.y + box.height - 1);
321#if CHANNEL_ON_IS_DOWN
327 box.x + box.width - 1, box.y,
328 box.x + box.width - 1, box.y + box.height - 1);
330 box.x, box.y + box.height - 1,
331 box.x + box.width - 1, box.y + box.height - 1);
339 text.Printf(
wxT(
"%d"), chanName);
340 dc.GetTextExtent(text, &w, &h);
342 dc.DrawText(text, box.x + (box.width - w) / 2, box.y + (box.height - h) / 2);
351 wxASSERT_MSG(rect.width % 4 == 0,
"Midi channel control rect width must be divisible by 4");
352 wxASSERT_MSG(rect.height % 4 == 0,
"Midi channel control rect height must be divisible by 4");
354 auto cellWidth = rect.width / 4;
355 auto cellHeight = rect.height / 4;
357 int col = (mx - rect.x) / cellWidth;
358 int row = (my - rect.y) / cellHeight;
360 return row * 4 + col;
381 mSeq = std::move(seq);
388 debugOutput = fopen(
"debugOutput.txt",
"wt");
389 wxFprintf(debugOutput,
"Importing MIDI...\n");
396 while(i < mSeq->length()) {
397 wxFprintf(debugOutput,
"--\n");
398 wxFprintf(debugOutput,
"type: %c\n",
399 ((Alg_event_ptr)
mSeq->track_list.tracks[i])->get_type());
400 wxFprintf(debugOutput,
"time: %f\n",
401 ((Alg_event_ptr)
mSeq->track_list.tracks[i])->time);
402 wxFprintf(debugOutput,
"channel: %li\n",
403 ((Alg_event_ptr)
mSeq->track_list.tracks[i])->chan);
405 if(((Alg_event_ptr)
mSeq->track_list.tracks[i])->get_type() ==
wxT(
'n'))
407 wxFprintf(debugOutput,
"pitch: %f\n",
408 ((Alg_note_ptr)
mSeq->track_list.tracks[i])->pitch);
409 wxFprintf(debugOutput,
"duration: %f\n",
410 ((Alg_note_ptr)
mSeq->track_list.tracks[i])->dur);
411 wxFprintf(debugOutput,
"velocity: %f\n",
412 ((Alg_note_ptr)
mSeq->track_list.tracks[i])->loud);
414 else if(((Alg_event_ptr)
mSeq->track_list.tracks[i])->get_type() ==
wxT(
'n'))
416 wxFprintf(debugOutput,
"key: %li\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->get_identifier());
417 wxFprintf(debugOutput,
"attribute type: %c\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type());
418 wxFprintf(debugOutput,
"attribute: %s\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_name());
420 if(((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type() ==
wxT(
'r'))
422 wxFprintf(debugOutput,
"value: %f\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.r);
424 else if(((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type() ==
wxT(
'i')) {
425 wxFprintf(debugOutput,
"value: %li\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.i);
427 else if(((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type() ==
wxT(
's')) {
428 wxFprintf(debugOutput,
"value: %s\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.s);
437 wxFprintf(debugOutput,
"No sequence defined!\n");
453 auto newTrack = std::make_shared<NoteTrack>();
455 newTrack->Init(*
this);
458 seq.convert_to_seconds();
459 newTrack->mSeq.reset(seq.cut(t0 -
GetOffset(), len,
false));
460 newTrack->SetOffset(0);
480 auto newTrack = std::make_shared<NoteTrack>();
482 newTrack->Init(*
this);
485 seq.convert_to_seconds();
486 newTrack->mSeq.reset(seq.copy(t0 -
GetOffset(), len,
false));
487 newTrack->SetOffset(0);
505 seq.convert_to_seconds();
507 seq.clear(t1 -
GetOffset(), seq.get_dur() + 10000.0,
false);
530 auto start = t0 - offset;
535 seq.clear(0, len + start,
false);
545 seq.clear(start, len,
false);
576 auto offset = other->GetOffset();
578 seq.convert_to_seconds();
579 seq.insert_silence( t -
GetOffset(), offset );
591 seq.paste(t -
GetOffset(), &other->GetSeq());
611 seq.convert_to_seconds();
615 seq.silence(t0 -
GetOffset(), len,
false);
624 seq.convert_to_seconds();
625 seq.insert_silence(t -
GetOffset(), len);
631#ifdef EXPERIMENTAL_MIDI_OUT
632void NoteTrack::SetVelocity(
float velocity)
634 if (GetVelocity() != velocity) {
635 DoSetVelocity(velocity);
640void NoteTrack::DoSetVelocity(
float velocity)
642 mVelocity.store(velocity, std::memory_order_relaxed);
653 seq.convert_to_beats();
655 double tempo = seq.get_tempo(0.0);
656 double beats_per_measure = seq.get_bar_len(0.0);
657 int m =
ROUND(t * tempo / beats_per_measure);
661 tempo = beats_per_measure * m / t;
662 seq.insert_silence(0.0, beats_per_measure * m);
663 seq.set_tempo(tempo * 60.0 , 0.0, beats_per_measure * m);
664 seq.write(
"afterShift.gro");
667 seq.convert_to_seconds();
668 seq.clear(0, t,
true);
681 seq_time = seq.nearest_beat_time(seq_time, &beat);
689 {
"note",
"midi",
XO(
"Note Track") },
true,
706 auto pNewTrack = std::make_shared<NoteTrack>();
707 pNewTrack->Init(*
this);
708 pNewTrack->Paste(0.0,
this);
722 results.emplace_back( GetStartTime(), GetEndTime() );
731 seq.set_real_dur( seq.get_real_dur() + delta );
733 seq.convert_to_seconds();
734 seq.set_dur( seq.get_dur() + delta );
742 bool result = seq.stretch_region( t0.second, t1.second, newDur );
744 const auto oldDur = t1.first - t0.first;
752 void swap(std::unique_ptr<Alg_seq> &a, std::unique_ptr<Alg_seq> &b)
754 std::unique_ptr<Alg_seq> tmp = std::move(a);
767 double start = -offset;
768 if (start < 0) start = 0;
771 cleanup.reset(
GetSeq().copy(start,
GetSeq().get_dur() - start,
false) );
772 auto seq = cleanup.get();
777 auto cleanup2 =
finally( [&] {
swap( this->
mSeq, cleanup ); } );
784 double beats_per_measure = 4.0;
785 Alg_time_sig_ptr tsp = NULL;
786 if (seq->time_sig.length() > 0 && seq->time_sig[0].beat < ALG_EPS) {
788 tsp = &(seq->time_sig[0]);
789 beats_per_measure = (tsp->num * 4) / tsp->den;
792 double bps = ALG_DEFAULT_BPM / 60;
793 Alg_time_map_ptr map = seq->get_time_map();
794 Alg_beat_ptr bp = &(map->beats[0]);
795 if (bp->time < ALG_EPS) {
796 if (map->beats.len > 1) {
797 bps = (map->beats[1].beat - map->beats[0].beat) /
798 (map->beats[1].time - map->beats[0].time);
799 }
else if (seq->get_time_map()->last_tempo_flag) {
800 bps = seq->get_time_map()->last_tempo;
805 double measure_time = beats_per_measure / bps;
806 int n =
ROUND(offset / measure_time);
809 measure_time = offset / n;
810 bps = beats_per_measure / measure_time;
812 seq->convert_to_beats();
813 seq->insert_silence(0, beats_per_measure * n);
816 seq->set_time_sig(0, tsp->num, tsp->den);
819 seq->set_tempo(bps * 60.0, 0, beats_per_measure * n);
829 double beat = mySeq.get_time_map()->time_to_beat(start);
831 int i = mySeq.time_sig.find_beat(beat);
836 if (mySeq.time_sig.length() > 0 &&
837 within(beat, mySeq.time_sig[i].beat, ALG_EPS)) {
842 }
else if (i == 0 && (mySeq.time_sig.length() == 0 ||
843 mySeq.time_sig[i].beat > beat)) {
846 double measures = beat / 4.0;
847 double imeasures =
ROUND(measures);
848 if (!
within(measures, imeasures, ALG_EPS)) {
849 double bar_offset = ((int)(measures) + 1) * 4.0 - beat;
850 seq->set_time_sig(bar_offset, 4, 4);
860 Alg_time_sig_ptr tsp = &(mySeq.time_sig[i]);
861 double beats_per_measure = (tsp->num * 4) / tsp->den;
862 double measures = (beat - tsp->beat) / beats_per_measure;
863 int imeasures =
ROUND(measures);
864 if (!
within(measures, imeasures, ALG_EPS)) {
868 double bar = tsp->beat + beats_per_measure * ((int)(measures) + 1);
869 double bar_offset = bar - beat;
873 seq->set_time_sig(bar_offset, tsp->num, tsp->den);
885 std::unique_ptr<Alg_seq> cleanup;
887 bool rslt = seq->smf_write(f.mb_str());
897 seq.convert_to_seconds();
899 seq.convert_to_beats();
901 return seq.write(f.mb_str(), offset);
908 return (nValue >= 0 && nValue < (1 << 16));
914 if (tag ==
"notetrack") {
915 for (
auto pair : attrs)
917 auto attr = pair.first;
918 auto value = pair.second;
926 else if (attr ==
"offset" && value.TryGet(dblValue))
928 else if (attr ==
"visiblechannels") {
929 if (!value.TryGet(nValue) ||
934#ifdef EXPERIMENTAL_MIDI_OUT
935 else if (attr ==
"velocity" && value.TryGet(dblValue))
936 DoSetVelocity(
static_cast<float>(dblValue));
938 else if (attr ==
"bottomnote" && value.TryGet(nValue))
940 else if (attr ==
"topnote" && value.TryGet(nValue))
942 else if (attr ==
"data") {
943 std::string s(value.ToWString());
944 std::istringstream data(s);
945 mSeq = std::make_unique<Alg_seq>(data,
false);
961 std::ostringstream data;
968 saveme =
static_cast<NoteTrack*
>(holder.get());
970 saveme->
GetSeq().write(data,
true);
971 xmlFile.StartTag(
wxT(
"notetrack"));
972 saveme->Track::WriteCommonXMLAttributes( xmlFile );
975 xmlFile.WriteAttr(
wxT(
"visiblechannels"),
978#ifdef EXPERIMENTAL_MIDI_OUT
979 xmlFile.WriteAttr(
wxT(
"velocity"),
980 static_cast<double>(saveme->GetVelocity()));
983 xmlFile.WriteAttr(
wxT(
"topnote"), saveme->
mTopNote);
984 xmlFile.WriteAttr(
wxT(
"data"), wxString(data.str().c_str(), wxConvUTF8));
985 xmlFile.EndTag(
wxT(
"notetrack"));
1022 if (note2 < note1) {
auto tmp = note1; note1 = note2; note2 = tmp; }
1039void NoteTrack::StartVScroll()
1044void NoteTrack::VScroll(
int start,
int end)
1046 int ph = GetPitchHeight();
1047 int delta = ((
end - start) + ph / 2) / ph;
1057 int newExtent = (int) (extent / multiplier);
1066 int newBottomNote = clickedPitch - (newExtent * position);
1067 int newTopNote = clickedPitch + (newExtent * (1 - position));
1074 wxRect trackRect(0, rect.GetY(), 1, rect.GetHeight());
1078 if (pitch1 == pitch2) {
1080 Zoom(rect, start, 1,
true);
1089 Alg_iterator iterator( &
GetSeq(),
false );
1094 bool hasNotes =
false;
1098 while (NULL != (evt = iterator.next())) {
1099 if (evt->is_note()) {
1100 int pitch = (int) evt->get_pitch();
1102 if (pitch < minPitch)
1104 if (pitch > maxPitch)
1122 mMargin =
std::min((
int) (r.height / (
float)(span)) / 2, r.height / 4);
1125 int numC = 0, numF = 0;
1128 if (topOctave == botOctave)
1130 if (botNote == 0) numC = 1;
1131 if (topNote <= 5) numF = 1;
1135 numC = topOctave - botOctave;
1136 numF = topOctave - botOctave - 1;
1137 if (botNote == 0) numC++;
1138 if (botNote <= 5) numF++;
1139 if (topOctave <= 5) numF++;
1142 auto effectiveHeight = r.height - (2 * (
mMargin + 1)) - numC - numF;
1174#include <wx/sstream.h>
1175#include <wx/txtstrm.h>
1177#include "portmidi.h"
1182 wxStringOutputStream o;
1183 wxTextOutputStream s(o, wxEOL_UNIX);
1186 return XO(
"Stream is active ... unable to gather information.\n")
1192 int recDeviceNum = Pm_GetDefaultInputDeviceID();
1193 int playDeviceNum = Pm_GetDefaultOutputDeviceID();
1194 int cnt = Pm_CountDevices();
1197 wxLogDebug(
wxT(
"PortMidi reports %d MIDI devices"), cnt);
1199 s <<
wxT(
"==============================\n");
1200 s <<
XO(
"Default recording device number: %d\n").Format( recDeviceNum );
1201 s <<
XO(
"Default playback device number: %d\n").Format( playDeviceNum );
1208 s <<
XO(
"No devices found\n");
1209 return o.GetString();
1212 for (
int i = 0; i < cnt; i++) {
1213 s <<
wxT(
"==============================\n");
1215 const PmDeviceInfo* info = Pm_GetDeviceInfo(i);
1217 s <<
XO(
"Device info unavailable for: %d\n").Format( i );
1221 wxString
name = wxSafeConvertMB2WX(info->name);
1222 wxString hostName = wxSafeConvertMB2WX(info->interf);
1224 s <<
XO(
"Device ID: %d\n").Format( i );
1225 s <<
XO(
"Device name: %s\n").Format(
name );
1226 s <<
XO(
"Host name: %s\n").Format( hostName );
1228 s <<
XO(
"Supports output: %d\n").Format( info->output );
1230 s <<
XO(
"Supports input: %d\n").Format( info->input );
1231 s <<
XO(
"Opened: %d\n").Format( info->opened );
1233 if (
name == playDevice && info->output)
1236 if (
name == recDevice && info->input)
1241 if (recDeviceNum < 0 && info->input){
1244 if (playDeviceNum < 0 && info->output){
1249 bool haveRecDevice = (recDeviceNum >= 0);
1250 bool havePlayDevice = (playDeviceNum >= 0);
1252 s <<
wxT(
"==============================\n");
1254 s <<
XO(
"Selected MIDI recording device: %d - %s\n").Format( recDeviceNum, recDevice );
1256 s <<
XO(
"No MIDI recording device found for '%s'.\n").Format( recDevice );
1259 s <<
XO(
"Selected MIDI playback device: %d - %s\n").Format( playDeviceNum, playDevice );
1261 s <<
XO(
"No MIDI playback device found for '%s'.\n").Format( playDevice );
1267 s <<
wxT(
"==============================\n");
1268#ifdef EXPERIMENTAL_MIDI_OUT
1269 s <<
wxT(
"EXPERIMENTAL_MIDI_OUT is enabled\n");
1271 s <<
wxT(
"EXPERIMENTAL_MIDI_OUT is NOT enabled\n");
1273#ifdef EXPERIMENTAL_MIDI_IN
1274 s <<
wxT(
"EXPERIMENTAL_MIDI_IN is enabled\n");
1276 s <<
wxT(
"EXPERIMENTAL_MIDI_IN is NOT enabled\n");
1281 return o.GetString();
const TranslatableString name
MessageBoxException for violation of preconditions or assertions.
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
IntSetting MIDISynthLatency_ms
StringSetting MIDIRecordingDevice
static ProjectFileIORegistry::ObjectReaderEntry readerEntry
wxString GetMIDIDeviceInfo()
StringSetting MIDIPlaybackDevice
static const Track::TypeInfo & typeInfo()
#define SonifyEndSerialize()
#define SonifyBeginSerialize()
#define SonifyEndSonification()
#define SonifyBeginSonification()
std::pair< double, double > QuantizedTimeAndBeat
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
bool within(A a, B b, DIST d)
std::vector< Attribute > AttributesList
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
static void LightMIDIChannel(wxDC *dc, int channel)
static void MIDIChannel(wxDC *dc, int channel)
static void DarkMIDIChannel(wxDC *dc, int channel)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
static AudioIOBase * Get()
Track subclass holding data representing sound (as notes, or samples, or ...)
bool HandleXMLAttribute(const std::string_view &, const XMLAttributeValueView &)
void WriteXMLAttributes(XMLWriter &WXUNUSED(xmlFile)) const
static EnumSetting< bool > AllegroStyleSetting
Specialization of Setting for int.
Data used to display a note track.
int GetPitchHeight(int factor) const
int GetNotePos(int p) const
int GetOctaveHeight() const
NoteTrackDisplayData(const NoteTrack *track, const wxRect &r)
int GetNoteMargin() const
int YToIPitch(int y) const
int IPitchToY(int p) const
A Track that is used for Midi notes. (Somewhat old code).
void SetSequence(std::unique_ptr< Alg_seq > &&seq)
const TypeInfo & GetTypeInfo() const override
static const TypeInfo & ClassTypeInfo()
ConstIntervals GetIntervals() const override
Report times on the track where important intervals begin and end, for UI to snap to.
bool ExportAllegro(const wxString &f) const
Track::Holder Cut(double t0, double t1) override
void SetNoteRange(int note1, int note2)
Sets the top and bottom note (both pitches) automatically, swapping them if needed.
void AddToDuration(double delta)
std::unique_ptr< char[]> mSerializationBuffer
void Paste(double t, const Track *src) override
double GetOffset() const override
bool ExportMIDI(const wxString &f) const
bool IsVisibleChan(int c) const
void SetVisibleChannels(unsigned value)
void WriteXML(XMLWriter &xmlFile) const override
double GetEndTime() const override
int FindChannel(const wxRect &rect, int mx, int my)
static void DrawLabelControls(const NoteTrack *pTrack, wxDC &dc, const wxRect &rect, int highlightedChannel=-1)
void ShiftNoteRange(int offset)
Shifts all notes vertically by the given pitch.
std::unique_ptr< Alg_seq > mSeq
void InsertSilence(double t, double len) override
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
bool StretchRegion(QuantizedTimeAndBeat t0, QuantizedTimeAndBeat t1, double newDur)
Alg_seq * MakeExportableSeq(std::unique_ptr< Alg_seq > &cleanup) const
void ZoomAllNotes()
Zooms so that all notes are visible.
static NoteTrack * New(AudacityProject &project)
void SetTopNote(int note)
Sets the top note (a pitch), making sure that it is never less than the bottom note.
unsigned GetVisibleChannels() const
QuantizedTimeAndBeat NearestBeatTime(double time) const
void Zoom(const wxRect &rect, int y, float multiplier, bool center)
void WarpAndTransposeNotes(double t0, double t1, const TimeWarper &warper, double semitones)
void ZoomTo(const wxRect &rect, int start, int end)
void ToggleVisibleChan(int c)
bool Trim(double t0, double t1)
void SoloVisibleChan(int c)
Track::Holder Clone() const override
Track::Holder PasteInto(AudacityProject &) const override
Find or create the destination track for a paste, maybe in a different project.
double GetStartTime() const override
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
void SetBottomNote(int note)
Sets the bottom note (a pitch), making sure that it is never greater than the top note.
int GetBottomNote() const
Gets the current bottom note (a pitch)
static const float ZoomStep
int GetTopNote() const
Gets the current top note (a pitch)
void Clear(double t0, double t1) override
long mSerializationLength
bool LabelClick(const wxRect &rect, int x, int y, bool right)
void Silence(double t0, double t1) override
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
static const TypeInfo & ClassTypeInfo()
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Specialization of Setting for strings.
wxColour & Colour(int iIndex)
Transforms one point in time to another point. For example, a time stretching effect might use one to...
virtual double Warp(double originalTime) const =0
Abstract base class for an object holding data associated with points on a time axis.
virtual void SetOffset(double o)
R TypeSwitch(const Functions &...functions)
Use this function rather than testing track type explicitly and making down-casts.
std::shared_ptr< Track > Holder
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
std::vector< Interval > Intervals
std::vector< ConstInterval > ConstIntervals
void SetName(const wxString &n)
static TrackList & Get(AudacityProject &project)
This class is an interface which should be implemented by classes which wish to be able to load and s...
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
bool IsValidVisibleChannels(const int nValue)
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)