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); }
109std::shared_ptr<ChannelInterval>
113 return std::make_shared<ChannelInterval>();
125 auto result =
tracks.Add( std::make_shared<NoteTrack>());
126 result->AttachedTrackObjects::BuildAll();
150 mSeq = std::make_unique<Alg_seq>();
152 std::unique_ptr<Alg_track> alg_track
153 { Alg_seq::unserialize
155 wxASSERT(alg_track->get_type() ==
's');
156 mSeq.reset(
static_cast<Alg_seq*
>(alg_track.release()) );
170 auto duplicate = std::make_shared<NoteTrack>();
171 duplicate->Init(*
this);
180 mSeq->serialize(&buffer,
181 &duplicate->mSerializationLength);
182 duplicate->mSerializationBuffer.reset( (
char*)buffer );
189 duplicate->mSerializationBuffer.reset
191 memcpy( duplicate->mSerializationBuffer.get(),
192 this->mSerializationBuffer.get(), this->mSerializationLength );
202#ifdef EXPERIMENTAL_MIDI_OUT
203 duplicate->SetVelocity(GetVelocity());
210 const std::optional<double>& oldTempo,
double newTempo)
213 if (!oldTempo.has_value())
215 const auto ratio = *oldTempo / newTempo;
217 seq.convert_to_beats();
218 const auto b1 = seq.get_dur();
219 seq.convert_to_seconds();
220 const auto newDuration = seq.get_dur() * ratio;
221 seq.stretch_region(0, b1, newDuration);
222 seq.set_real_dur(newDuration);
231 seq.convert_to_seconds();
234 if (t1 > seq.get_dur()) {
236 if (t0 >= t1)
return;
238 Alg_iterator iter(
mSeq.get(),
false);
241 while (0 != (event = iter.next()) && event->time < t1) {
242 if (event->is_note() && event->time >= t0) {
243 event->set_pitch(event->get_pitch() + semitones);
248 seq.convert_to_beats();
249 Alg_time_map_ptr map = seq.get_time_map();
250 map->insert_beat(t0, map->time_to_beat(t0));
251 map->insert_beat(t1, map->time_to_beat(t1));
252 int i, len = map->length();
253 for (i = 0; i < len; i++) {
254 Alg_beat &beat = map->beats[i];
255 beat.time = warper.
Warp(beat.time + offset) - offset;
258 seq.convert_to_seconds();
264(
const NoteTrack *pTrack, wxDC & dc,
const wxRect &rect,
int highlightedChannel )
267 wxASSERT_MSG(rect.width % 4 == 0,
"Midi channel control rect width must be divisible by 4");
268 wxASSERT_MSG(rect.height % 4 == 0,
"Midi channel control rect height must be divisible by 4");
270 auto cellWidth = rect.width / 4;
271 auto cellHeight = rect.height / 4;
274 for (
int row = 0; row < 4; row++) {
275 for (
int col = 0; col < 4; col++) {
278 int chanName = row * 4 + col + 1;
280 box.x = rect.x + col * cellWidth;
281 box.y = rect.y + row * cellHeight;
282 box.width = cellWidth;
283 box.height = cellHeight;
285 bool visible = pTrack ? pTrack->
IsVisibleChan(chanName - 1) :
true;
288 if ( chanName == highlightedChannel + 1 )
292 dc.DrawRectangle(box);
296#define CHANNEL_ON_IS_DOWN 1
297#if CHANNEL_ON_IS_DOWN
302 AColor::Line(dc, box.x, box.y, box.x + box.width - 1, box.y);
303 AColor::Line(dc, box.x, box.y, box.x, box.y + box.height - 1);
305#if CHANNEL_ON_IS_DOWN
311 box.x + box.width - 1, box.y,
312 box.x + box.width - 1, box.y + box.height - 1);
314 box.x, box.y + box.height - 1,
315 box.x + box.width - 1, box.y + box.height - 1);
317 if ( chanName == highlightedChannel + 1 )
321 dc.DrawRectangle(box);
322#if CHANNEL_ON_IS_DOWN
327 AColor::Line(dc, box.x, box.y, box.x + box.width - 1, box.y);
328 AColor::Line(dc, box.x, box.y, box.x, box.y + box.height - 1);
330#if CHANNEL_ON_IS_DOWN
336 box.x + box.width - 1, box.y,
337 box.x + box.width - 1, box.y + box.height - 1);
339 box.x, box.y + box.height - 1,
340 box.x + box.width - 1, box.y + box.height - 1);
348 text.Printf(
wxT(
"%d"), chanName);
349 dc.GetTextExtent(text, &w, &h);
351 dc.DrawText(text, box.x + (box.width - w) / 2, box.y + (box.height - h) / 2);
360 wxASSERT_MSG(rect.width % 4 == 0,
"Midi channel control rect width must be divisible by 4");
361 wxASSERT_MSG(rect.height % 4 == 0,
"Midi channel control rect height must be divisible by 4");
363 auto cellWidth = rect.width / 4;
364 auto cellHeight = rect.height / 4;
366 int col = (mx - rect.x) / cellWidth;
367 int row = (my - rect.y) / cellHeight;
369 return row * 4 + col;
390 mSeq = std::move(seq);
397 debugOutput = fopen(
"debugOutput.txt",
"wt");
398 wxFprintf(debugOutput,
"Importing MIDI...\n");
405 while(i < mSeq->length()) {
406 wxFprintf(debugOutput,
"--\n");
407 wxFprintf(debugOutput,
"type: %c\n",
408 ((Alg_event_ptr)
mSeq->track_list.tracks[i])->get_type());
409 wxFprintf(debugOutput,
"time: %f\n",
410 ((Alg_event_ptr)
mSeq->track_list.tracks[i])->time);
411 wxFprintf(debugOutput,
"channel: %li\n",
412 ((Alg_event_ptr)
mSeq->track_list.tracks[i])->chan);
414 if(((Alg_event_ptr)
mSeq->track_list.tracks[i])->get_type() ==
wxT(
'n'))
416 wxFprintf(debugOutput,
"pitch: %f\n",
417 ((Alg_note_ptr)
mSeq->track_list.tracks[i])->pitch);
418 wxFprintf(debugOutput,
"duration: %f\n",
419 ((Alg_note_ptr)
mSeq->track_list.tracks[i])->dur);
420 wxFprintf(debugOutput,
"velocity: %f\n",
421 ((Alg_note_ptr)
mSeq->track_list.tracks[i])->loud);
423 else if(((Alg_event_ptr)
mSeq->track_list.tracks[i])->get_type() ==
wxT(
'n'))
425 wxFprintf(debugOutput,
"key: %li\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->get_identifier());
426 wxFprintf(debugOutput,
"attribute type: %c\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type());
427 wxFprintf(debugOutput,
"attribute: %s\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_name());
429 if(((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type() ==
wxT(
'r'))
431 wxFprintf(debugOutput,
"value: %f\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.r);
433 else if(((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type() ==
wxT(
'i')) {
434 wxFprintf(debugOutput,
"value: %li\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.i);
436 else if(((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.attr_type() ==
wxT(
's')) {
437 wxFprintf(debugOutput,
"value: %s\n", ((Alg_update_ptr)
mSeq->track_list.tracks[i])->parameter.s);
446 wxFprintf(debugOutput,
"No sequence defined!\n");
463 auto newTrack = std::make_shared<NoteTrack>();
465 newTrack->Init(*
this);
468 seq.convert_to_seconds();
469 newTrack->mSeq.reset(seq.cut(t0 -
mOrigin, len,
false));
490 auto newTrack = std::make_shared<NoteTrack>();
492 newTrack->Init(*
this);
495 seq.convert_to_seconds();
496 newTrack->mSeq.reset(seq.copy(t0 -
mOrigin, len,
false));
515 seq.convert_to_seconds();
517 seq.clear(t1 -
mOrigin, seq.get_dur() + 10000.0,
false);
519 seq.clear(0.0, t0 -
mOrigin,
false);
541 auto start = t0 - offset;
546 seq.clear(0, len + start,
false);
556 seq.clear(start, len,
false);
587 auto offset = other.mOrigin;
589 seq.convert_to_seconds();
590 seq.insert_silence(t -
mOrigin, offset);
602 seq.paste(t -
mOrigin, &other.GetSeq());
623 seq.convert_to_seconds();
627 seq.silence(t0 -
mOrigin, len,
false);
637 seq.convert_to_seconds();
638 seq.insert_silence(t -
mOrigin, len);
644#ifdef EXPERIMENTAL_MIDI_OUT
645void NoteTrack::SetVelocity(
float velocity)
647 if (GetVelocity() != velocity) {
648 DoSetVelocity(velocity);
653void NoteTrack::DoSetVelocity(
float velocity)
655 mVelocity.store(velocity, std::memory_order_relaxed);
666 seq.convert_to_beats();
668 double tempo = seq.get_tempo(0.0);
669 double beats_per_measure = seq.get_bar_len(0.0);
670 int m =
ROUND(t * tempo / beats_per_measure);
674 tempo = beats_per_measure * m / t;
675 seq.insert_silence(0.0, beats_per_measure * m);
676 seq.set_tempo(tempo * 60.0 , 0.0, beats_per_measure * m);
677 seq.write(
"afterShift.gro");
680 seq.convert_to_seconds();
681 seq.clear(0, t,
true);
691 double seq_time = time -
mOrigin;
694 seq_time = seq.nearest_beat_time(seq_time, &beat);
696 return { seq_time +
mOrigin, beat };
702 {
"note",
"midi",
XO(
"Note Track") },
true,
720 auto pNewTrack = std::make_shared<NoteTrack>();
721 pNewTrack->Init(*
this);
722 pNewTrack->Paste(0.0, *
this);
732std::shared_ptr<WideChannelGroupInterval>
735 if (iInterval == 0) {
738 const auto end = start +
GetSeq().get_real_dur();
739 return std::make_shared<Interval>(*
this, start,
end);
749 seq.set_real_dur( seq.get_real_dur() + delta );
751 seq.convert_to_seconds();
752 seq.set_dur( seq.get_dur() + delta );
760 bool result = seq.stretch_region( t0.second, t1.second, newDur );
762 const auto oldDur = t1.first - t0.first;
770 void swap(std::unique_ptr<Alg_seq> &a, std::unique_ptr<Alg_seq> &b)
772 std::unique_ptr<Alg_seq> tmp = std::move(a);
785 double start = -offset;
786 if (start < 0) start = 0;
790 auto seq = cleanup.get();
795 auto cleanup2 =
finally( [&] {
swap( this->
mSeq, cleanup ); } );
802 double beats_per_measure = 4.0;
803 Alg_time_sig_ptr tsp = NULL;
804 if (seq->time_sig.length() > 0 && seq->time_sig[0].beat < ALG_EPS) {
806 tsp = &(seq->time_sig[0]);
807 beats_per_measure = (tsp->num * 4) / tsp->den;
810 double bps = ALG_DEFAULT_BPM / 60;
811 Alg_time_map_ptr map = seq->get_time_map();
812 Alg_beat_ptr bp = &(map->beats[0]);
813 if (bp->time < ALG_EPS) {
814 if (map->beats.len > 1) {
815 bps = (map->beats[1].beat - map->beats[0].beat) /
816 (map->beats[1].time - map->beats[0].time);
817 }
else if (seq->get_time_map()->last_tempo_flag) {
818 bps = seq->get_time_map()->last_tempo;
823 double measure_time = beats_per_measure / bps;
824 int n =
ROUND(offset / measure_time);
827 measure_time = offset / n;
828 bps = beats_per_measure / measure_time;
830 seq->convert_to_beats();
831 seq->insert_silence(0, beats_per_measure * n);
834 seq->set_time_sig(0, tsp->num, tsp->den);
837 seq->set_tempo(bps * 60.0, 0, beats_per_measure * n);
847 double beat = mySeq.get_time_map()->time_to_beat(start);
849 int i = mySeq.time_sig.find_beat(beat);
854 if (mySeq.time_sig.length() > 0 &&
855 within(beat, mySeq.time_sig[i].beat, ALG_EPS)) {
860 }
else if (i == 0 && (mySeq.time_sig.length() == 0 ||
861 mySeq.time_sig[i].beat > beat)) {
864 double measures = beat / 4.0;
865 double imeasures =
ROUND(measures);
866 if (!
within(measures, imeasures, ALG_EPS)) {
867 double bar_offset = ((int)(measures) + 1) * 4.0 - beat;
868 seq->set_time_sig(bar_offset, 4, 4);
878 Alg_time_sig_ptr tsp = &(mySeq.time_sig[i]);
879 double beats_per_measure = (tsp->num * 4) / tsp->den;
880 double measures = (beat - tsp->beat) / beats_per_measure;
881 int imeasures =
ROUND(measures);
882 if (!
within(measures, imeasures, ALG_EPS)) {
886 double bar = tsp->beat + beats_per_measure * ((int)(measures) + 1);
887 double bar_offset = bar - beat;
891 seq->set_time_sig(bar_offset, tsp->num, tsp->den);
903 std::unique_ptr<Alg_seq> cleanup;
905 bool rslt = seq->smf_write(f.mb_str());
915 seq.convert_to_seconds();
917 seq.convert_to_beats();
919 return seq.write(f.mb_str(), offset);
926 return (nValue >= 0 && nValue < (1 << 16));
932 if (tag ==
"notetrack") {
933 for (
auto pair : attrs)
935 auto attr = pair.first;
936 auto value = pair.second;
944 else if (attr ==
"offset" && value.TryGet(dblValue))
946 else if (attr ==
"visiblechannels") {
947 if (!value.TryGet(nValue) ||
952#ifdef EXPERIMENTAL_MIDI_OUT
953 else if (attr ==
"velocity" && value.TryGet(dblValue))
954 DoSetVelocity(
static_cast<float>(dblValue));
956 else if (attr ==
"bottomnote" && value.TryGet(nValue))
958 else if (attr ==
"topnote" && value.TryGet(nValue))
960 else if (attr ==
"data") {
961 std::string s(value.ToWString());
962 std::istringstream data(s);
963 mSeq = std::make_unique<Alg_seq>(data,
false);
980 std::ostringstream data;
986 holder = (*Clone()->begin())->SharedPointer();
987 saveme =
static_cast<NoteTrack*
>(holder.get());
989 saveme->
GetSeq().write(data,
true);
990 xmlFile.StartTag(
wxT(
"notetrack"));
991 saveme->Track::WriteCommonXMLAttributes( xmlFile );
993 xmlFile.WriteAttr(
wxT(
"offset"), saveme->
mOrigin);
994 xmlFile.WriteAttr(
wxT(
"visiblechannels"),
997#ifdef EXPERIMENTAL_MIDI_OUT
998 xmlFile.WriteAttr(
wxT(
"velocity"),
999 static_cast<double>(saveme->GetVelocity()));
1002 xmlFile.WriteAttr(
wxT(
"topnote"), saveme->
mTopNote);
1003 xmlFile.WriteAttr(
wxT(
"data"), wxString(data.str().c_str(), wxConvUTF8));
1004 xmlFile.EndTag(
wxT(
"notetrack"));
1041 if (note2 < note1) {
auto tmp = note1; note1 = note2; note2 = tmp; }
1058void NoteTrack::StartVScroll()
1063void NoteTrack::VScroll(
int start,
int end)
1065 int ph = GetPitchHeight();
1066 int delta = ((
end - start) + ph / 2) / ph;
1076 int newExtent = (int) (extent / multiplier);
1085 int newBottomNote = clickedPitch - (newExtent * position);
1086 int newTopNote = clickedPitch + (newExtent * (1 - position));
1093 wxRect trackRect(0, rect.GetY(), 1, rect.GetHeight());
1097 if (pitch1 == pitch2) {
1099 Zoom(rect, start, 1,
true);
1108 Alg_iterator iterator( &
GetSeq(),
false );
1113 bool hasNotes =
false;
1117 while (NULL != (evt = iterator.next())) {
1118 if (evt->is_note()) {
1119 int pitch = (int) evt->get_pitch();
1121 if (pitch < minPitch)
1123 if (pitch > maxPitch)
1141 mMargin =
std::min((
int) (r.height / (
float)(span)) / 2, r.height / 4);
1144 int numC = 0, numF = 0;
1147 if (topOctave == botOctave)
1149 if (botNote == 0) numC = 1;
1150 if (topNote <= 5) numF = 1;
1154 numC = topOctave - botOctave;
1155 numF = topOctave - botOctave - 1;
1156 if (botNote == 0) numC++;
1157 if (botNote <= 5) numF++;
1158 if (topOctave <= 5) numF++;
1161 auto effectiveHeight = r.height - (2 * (
mMargin + 1)) - numC - numF;
1193#include <wx/sstream.h>
1194#include <wx/txtstrm.h>
1196#include "portmidi.h"
1201 wxStringOutputStream o;
1202 wxTextOutputStream s(o, wxEOL_UNIX);
1205 return XO(
"Stream is active ... unable to gather information.\n")
1211 int recDeviceNum = Pm_GetDefaultInputDeviceID();
1212 int playDeviceNum = Pm_GetDefaultOutputDeviceID();
1213 int cnt = Pm_CountDevices();
1216 wxLogDebug(
wxT(
"PortMidi reports %d MIDI devices"), cnt);
1218 s <<
wxT(
"==============================\n");
1219 s <<
XO(
"Default recording device number: %d\n").Format( recDeviceNum );
1220 s <<
XO(
"Default playback device number: %d\n").Format( playDeviceNum );
1227 s <<
XO(
"No devices found\n");
1228 return o.GetString();
1231 for (
int i = 0; i < cnt; i++) {
1232 s <<
wxT(
"==============================\n");
1234 const PmDeviceInfo* info = Pm_GetDeviceInfo(i);
1236 s <<
XO(
"Device info unavailable for: %d\n").Format( i );
1240 wxString
name = wxSafeConvertMB2WX(info->name);
1241 wxString hostName = wxSafeConvertMB2WX(info->interf);
1243 s <<
XO(
"Device ID: %d\n").Format( i );
1244 s <<
XO(
"Device name: %s\n").Format(
name );
1245 s <<
XO(
"Host name: %s\n").Format( hostName );
1247 s <<
XO(
"Supports output: %d\n").Format( info->output );
1249 s <<
XO(
"Supports input: %d\n").Format( info->input );
1250 s <<
XO(
"Opened: %d\n").Format( info->opened );
1252 if (
name == playDevice && info->output)
1255 if (
name == recDevice && info->input)
1260 if (recDeviceNum < 0 && info->input){
1263 if (playDeviceNum < 0 && info->output){
1268 bool haveRecDevice = (recDeviceNum >= 0);
1269 bool havePlayDevice = (playDeviceNum >= 0);
1271 s <<
wxT(
"==============================\n");
1273 s <<
XO(
"Selected MIDI recording device: %d - %s\n").Format( recDeviceNum, recDevice );
1275 s <<
XO(
"No MIDI recording device found for '%s'.\n").Format( recDevice );
1278 s <<
XO(
"Selected MIDI playback device: %d - %s\n").Format( playDeviceNum, playDevice );
1280 s <<
XO(
"No MIDI playback device found for '%s'.\n").Format( playDevice );
1286 s <<
wxT(
"==============================\n");
1287#ifdef EXPERIMENTAL_MIDI_OUT
1288 s <<
wxT(
"EXPERIMENTAL_MIDI_OUT is enabled\n");
1290 s <<
wxT(
"EXPERIMENTAL_MIDI_OUT is NOT enabled\n");
1292#ifdef EXPERIMENTAL_MIDI_IN
1293 s <<
wxT(
"EXPERIMENTAL_MIDI_IN is enabled\n");
1295 s <<
wxT(
"EXPERIMENTAL_MIDI_IN is NOT enabled\n");
1300 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,...
std::function< void(double)> ProgressReporter
std::shared_ptr< TrackList > TrackListHolder
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()
bool HandleXMLAttribute(const std::string_view &, const XMLAttributeValueView &)
void WriteXMLAttributes(XMLWriter &WXUNUSED(xmlFile)) const
double GetEndTime() const
Get the maximum of End() values of intervals, or 0 when none.
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()
bool ExportAllegro(const wxString &f) const
void SetNoteRange(int note1, int note2)
Sets the top and bottom note (both pitches) automatically, swapping them if needed.
void AddToDuration(double delta)
TrackListHolder Cut(double t0, double t1) override
Create tracks and modify this track.
size_t NIntervals() const override
Report the number of intervals.
std::shared_ptr< WideChannelGroupInterval > DoGetInterval(size_t iInterval) override
Retrieve an interval.
std::unique_ptr< char[]> mSerializationBuffer
Track::Holder PasteInto(AudacityProject &project, TrackList &list) const override
bool ExportMIDI(const wxString &f) const
bool IsVisibleChan(int c) const
void MoveTo(double origin) override
Change start time to given time point.
void SetVisibleChannels(unsigned value)
void WriteXML(XMLWriter &xmlFile) const override
void Paste(double t, const Track &src) override
Weak precondition allows overrides to replicate one channel into many.
TrackListHolder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
void Silence(double t0, double t1, ProgressReporter reportProgress={}) 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 DoOnProjectTempoChange(const std::optional< double > &oldTempo, double newTempo) override
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)
TrackListHolder Clone() const override
void ToggleVisibleChan(int c)
bool Trim(double t0, double t1)
void SoloVisibleChan(int c)
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)
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.
void Notify(bool allChannels, int code=-1)
R TypeSwitch(const Functions &...functions)
bool IsLeader() const override
std::shared_ptr< Track > Holder
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
void SetName(const wxString &n)
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
static TrackList & Get(AudacityProject &project)
static TrackListHolder Temporary(AudacityProject *pProject, const Track::Holder &left={}, const Track::Holder &right={})
Generates overrides of channel-related functions.
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)
void copy(const T *src, T *dst, int32_t n)
std::shared_ptr< ChannelInterval > DoGetChannel(size_t iChannel) override
Retrieve a channel.