diff --git a/libseq66/include/midi/event.hpp b/libseq66/include/midi/event.hpp
index 033923b4..7867e132 100644
--- a/libseq66/include/midi/event.hpp
+++ b/libseq66/include/midi/event.hpp
@@ -437,8 +437,6 @@ class event
event & operator = (const event & rhs);
virtual ~event ();
- void prep_for_send (midipulse tick, const event & source);
-
/*
* Operator overload, the only one needed for sorting events in a list
* or a map.
@@ -446,6 +444,7 @@ class event
bool operator < (const event & rhsevent) const;
bool match (const event & target) const;
+ void prep_for_send (midipulse tick, const event & source);
void set_input_bus (bussbyte b)
{
diff --git a/libseq66/include/midi/eventlist.hpp b/libseq66/include/midi/eventlist.hpp
index f529b374..d5d05be6 100644
--- a/libseq66/include/midi/eventlist.hpp
+++ b/libseq66/include/midi/eventlist.hpp
@@ -189,6 +189,12 @@ class eventlist
bool m_has_time_signature;
+ /**
+ * Another flag.
+ */
+
+ bool m_has_key_signature;
+
/**
* Stores the setting of usr().new_pattern_wraparound(). It is used in
* the link_new() function.
@@ -385,11 +391,7 @@ class eventlist
bool randomize_selected (midibyte status, int plus_minus);
bool randomize_selected_notes (int jitter, int range);
bool jitter_notes (int jitter);
- bool link_notes
- (
- event::iterator eon,
- event::iterator eoff
- );
+ bool link_notes (event::iterator eon, event::iterator eoff);
void link_tempos ();
void clear_tempo_links ();
bool mark_selected ();
diff --git a/libseq66/include/util/strfunctions.hpp b/libseq66/include/util/strfunctions.hpp
index bd69f55e..e0f02737 100644
--- a/libseq66/include/util/strfunctions.hpp
+++ b/libseq66/include/util/strfunctions.hpp
@@ -27,7 +27,7 @@
*
* \author Chris Ahlstrom
* \date 2018-11-23
- * \updates 2023-04-27
+ * \updates 2023-04-29
* \version $Revision$
*
* Also see the strfunctions.cpp module.
@@ -85,15 +85,18 @@ extern bool strncompare
extern bool strcasecompare (const std::string & a, const std::string & b);
extern std::string & ltrim
(
- std::string & str, const std::string & chars = SEQ66_TRIM_CHARS
+ std::string & str,
+ const std::string & chars = SEQ66_TRIM_CHARS
);
extern std::string & rtrim
(
- std::string & str, const std::string & chars = SEQ66_TRIM_CHARS
+ std::string & str,
+ const std::string & chars = SEQ66_TRIM_CHARS
);
extern std::string trim
(
- const std::string & str, const std::string & chars = SEQ66_TRIM_CHARS
+ const std::string & str,
+ const std::string & chars = SEQ66_TRIM_CHARS
);
extern std::string string_replace
(
@@ -125,6 +128,7 @@ extern double string_to_double
);
extern std::string double_to_string(double value, int precision = 0);
extern long string_to_long (const std::string & s, long defalt = 0L);
+extern std::string long_to_string (long value);
extern unsigned long string_to_unsigned_long
(
const std::string & s, unsigned long defalt = 0UL
diff --git a/libseq66/src/midi/eventlist.cpp b/libseq66/src/midi/eventlist.cpp
index 3b3d546d..1f78d2a4 100644
--- a/libseq66/src/midi/eventlist.cpp
+++ b/libseq66/src/midi/eventlist.cpp
@@ -58,6 +58,7 @@ eventlist::eventlist () :
m_is_modified (false),
m_has_tempo (false),
m_has_time_signature (false),
+ m_has_key_signature (false),
m_link_wraparound (usr().new_pattern_wraparound())
{
// No code needed
@@ -79,6 +80,7 @@ eventlist::eventlist (const eventlist & rhs) :
m_is_modified (rhs.m_is_modified),
m_has_tempo (rhs.m_has_tempo),
m_has_time_signature (rhs.m_has_time_signature),
+ m_has_key_signature (false),
m_link_wraparound (rhs.m_link_wraparound)
{
// no code
@@ -98,6 +100,7 @@ eventlist::operator = (const eventlist & rhs)
m_is_modified = rhs.m_is_modified;
m_has_tempo = rhs.m_has_tempo;
m_has_time_signature = rhs.m_has_time_signature;
+ m_has_key_signature = rhs.m_has_key_signature;
m_link_wraparound = rhs.m_link_wraparound;
}
return *this;
@@ -182,6 +185,9 @@ eventlist::append (const event & e)
if (e.is_time_signature())
m_has_time_signature = true;
+ if (e.is_key_signature())
+ m_has_key_signature = true;
+
return true;
}
@@ -356,13 +362,11 @@ eventlist::link_new (bool wrap)
{
if (link_notes(on, off))
{
-// #if defined USE_NEW_CODE
if (! wrap_em)
{
if (off->timestamp() < on->timestamp())
off->set_timestamp(get_length() - 1);
}
-// #endif
break;
}
++off;
@@ -480,12 +484,7 @@ void
eventlist::clear_links ()
{
for (auto & e : m_events)
- {
-#if 0
- if (not_nullptr(&e)) /* ca 2023-04-24 */
-#endif
- e.clear_links(); /* does unmark() and unlink() */
- }
+ e.clear_links(); /* does unmark() and unlink() */
}
int
@@ -804,7 +803,7 @@ eventlist::adjust_timestamp (event & er, midipulse delta_tick)
result = note_off_margin();
}
}
- else /* if (wrap) */
+ else /* if (wrap) */
{
if (result == seqlength)
{
@@ -1786,8 +1785,6 @@ eventlist::select_events
{
if (event_in_range(er, status, tick_s, tick_f))
{
- // midibyte d0, d1;
- // er.get_data(d0, d1);
if (er.is_desired(status, cc))
{
if (action == select::selecting)
diff --git a/libseq66/src/util/strfunctions.cpp b/libseq66/src/util/strfunctions.cpp
index 04d8faa5..0da6be23 100644
--- a/libseq66/src/util/strfunctions.cpp
+++ b/libseq66/src/util/strfunctions.cpp
@@ -25,7 +25,7 @@
* \library seq66 application
* \author Chris Ahlstrom
* \date 2018-11-24
- * \updates 2023-04-27
+ * \updates 2023-04-29
* \version $Revision$
*
* We basically include only the functions we need for Seq66, not
@@ -842,6 +842,14 @@ string_to_long (const std::string & s, long defalt)
return result;
}
+std::string
+long_to_string (long value)
+{
+ char temp[32];
+ (void) snprintf(temp, sizeof temp, "%ld", value);
+ return std::string(temp);
+}
+
/**
* Converts a string to an unsigned long integer.
*/
@@ -1084,7 +1092,7 @@ tokenize_stanzas
BR = brackets[1];
CBR = brackets[1];
}
- tokens.clear(); /* set size = 0 */
+ tokens.clear();
bleft = source.find_first_of(BL, bleft);
if (bleft != std::string::npos)
{
diff --git a/seq_qt5/forms/qsessionframe.ui b/seq_qt5/forms/qsessionframe.ui
index 1c659429..9224981b 100644
--- a/seq_qt5/forms/qsessionframe.ui
+++ b/seq_qt5/forms/qsessionframe.ui
@@ -643,16 +643,22 @@ author and dates. The size limit is 1024 characters.
26
+
+ <html><head/><body><p>Changes the current track number, ranging</p><p>from 0 to the highest pattern. Then, if</p><p>any Meta Text is present in that pattern,</p><p>then the first one is shown.</p></body></html>
+
- 110
+ 120
380
- 61
+ 41
26
+
+ <html><head/><body><p>Moves forward (not yet backward) to the</p><p>next Meta Text event, if any.</p></body></html>
+
Qt::Horizontal
@@ -672,6 +678,9 @@ author and dates. The size limit is 1024 characters.
22
+
+ <html><head/><body><p>Displays the time stamp of the current</p><p>Meta Text event. Editable as well.</p></body></html>
+
diff --git a/seq_qt5/include/qsessionframe.hpp b/seq_qt5/include/qsessionframe.hpp
index cc9576de..8df293bc 100644
--- a/seq_qt5/include/qsessionframe.hpp
+++ b/seq_qt5/include/qsessionframe.hpp
@@ -27,7 +27,7 @@
* \library seq66 application
* \author Chris Ahlstrom
* \date 2020-08-24
- * \updates 2023-04-29
+ * \updates 2023-04-30
* \license GNU GPLv2 or above
*
* We want to be able to survey the existing mute-groups.
@@ -93,6 +93,9 @@ class qsessionframe : public QFrame
return m_performer;
}
+ void sync_track_label ();
+ void sync_track_high ();
+
protected: // overrides of event handlers
virtual void keyPressEvent (QKeyEvent *) override;
@@ -105,6 +108,8 @@ private slots:
void slot_flag_reload ();
void slot_songinfo_change ();
void slot_save_info ();
+ void slot_track_number (int trk);
+ void slot_text_number (int textnum);
void slot_macros_active ();
void slot_macro_pick (const QString &);
void slot_log_file ();
@@ -121,8 +126,32 @@ private slots:
qsmainwnd * m_main_window;
+ /**
+ * The main player :-).
+ */
+
performer & m_performer;
+ /**
+ * Holds the currently selected track, needed when the track selection
+ * changes in order to clear the "next match" flag.
+ */
+
+ int m_current_track;
+
+ /**
+ * A counter for Meta Text events when a track contains more than one.
+ */
+
+ int m_current_text_number;
+
+ /**
+ * The highest-numbered track, plus one, kept synchronized with
+ * performer::m_sequence_high.
+ */
+
+ int m_track_high;
+
};
} // namespace seq66
diff --git a/seq_qt5/src/qsessionframe.cpp b/seq_qt5/src/qsessionframe.cpp
index d95817c8..15c19640 100644
--- a/seq_qt5/src/qsessionframe.cpp
+++ b/seq_qt5/src/qsessionframe.cpp
@@ -24,7 +24,7 @@
* \library seq66 application
* \author Chris Ahlstrom
* \date 2020-08-24
- * \updates 2023-04-29
+ * \updates 2023-04-30
* \license GNU GPLv2 or above
*
*/
@@ -73,10 +73,13 @@ qsessionframe::qsessionframe
qsmainwnd * mainparent,
QWidget * parent
) :
- QFrame (parent),
- ui (new Ui::qsessionframe),
- m_main_window (mainparent),
- m_performer (p)
+ QFrame (parent),
+ ui (new Ui::qsessionframe),
+ m_main_window (mainparent),
+ m_performer (p),
+ m_current_track (0),
+ m_current_text_number (0),
+ m_track_high (p.sequence_high())
{
ui->setupUi(this);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -111,15 +114,52 @@ qsessionframe::qsessionframe
ui->pushButtonSaveInfo, SIGNAL(clicked(bool)),
this, SLOT(slot_save_info())
);
+
#if defined USE_EXPERIMENTAL_TRACK_INFO
- ui->labelTrackInfo->setText("Track Info");
+
+ sync_track_label();
+
+ /*
+ * Track (pattern) spin-box.
+ */
+
+ ui->spinBoxTrackNumber->setReadOnly(false);
+ ui->spinBoxTrackNumber->setRange(0, m_track_high - 1);
+ ui->spinBoxTrackNumber->setValue(0);
+ connect
+ (
+ ui->spinBoxTrackNumber, SIGNAL(valueChanged(int)),
+ this, SLOT(slot_track_number(int))
+ );
+
+#if defined ALLOW_TRACK_NUMBER_EDIT // maybe later
+
+ connect
+ (
+ ui->spinBoxTrackNumber, SIGNAL(textChanged(const QString &)),
+ this, SLOT(slot_edit_track_number())
+ );
+
+#endif
+
+ ui->scrollBarTextNumber->setRange(0, 99999); /* way over the top */
+ connect
+ (
+ ui->scrollBarTextNumber, SIGNAL(valueChanged(int)),
+ this, SLOT(slot_text_number(int))
+ );
+
+ ui->lineEditTimeStamp->setReadOnly(false); // later, connect()
+
#else
+
/* Duty no for the FUTURE */
ui->spinBoxTrackNumber->hide();
ui->scrollBarTextNumber->hide();
ui->lineEditTimeStamp->hide();
ui->labelTimeStamp->hide();
+
#endif
}
@@ -128,6 +168,32 @@ qsessionframe::~qsessionframe()
delete ui;
}
+void
+qsessionframe::sync_track_label ()
+{
+ std::string tlabel = "Track Info ";
+ tlabel += std::to_string(int(m_current_track));
+ ui->labelTrackInfo->setText(qt(tlabel));
+}
+
+void
+qsessionframe::sync_track_high ()
+{
+ int high = int(perf().sequence_high());
+ if (m_track_high != high)
+ {
+ bool reduced = m_track_high < high;
+ m_track_high = high;
+ if (reduced)
+ {
+ m_current_track = high - 1;
+ ui->spinBoxTrackNumber->setValue(high - 1);
+ sync_track_label();
+ }
+ ui->spinBoxTrackNumber->setMaximum(high - 1);
+ }
+}
+
void
qsessionframe::enable_reload_button (bool flag)
{
@@ -168,6 +234,71 @@ qsessionframe::slot_save_info ()
ui->pushButtonSaveInfo->setEnabled(false);
}
+void
+qsessionframe::slot_track_number (int trk)
+{
+ sync_track_high(); /* adjust the maximum value */
+
+ if (trk != m_current_track)
+ {
+ if (trk == 0)
+ {
+ reload_song_info(); /* track zero is treated specially */
+ }
+ else
+ {
+ bool nextmatch = false;
+ seq66::event e = perf().get_track_info(trk, nextmatch);
+ std::string trkinfo = e.get_text();
+ if (trkinfo.empty())
+ {
+ ui->plainTextSongInfo->document()->setPlainText("*No text*");
+ ui->lineEditTimeStamp->setText("N/A");
+ ui->pushButtonSaveInfo->setEnabled(false);
+ }
+ else
+ {
+ // CUT-AND-PASTE-CODE
+ size_t remainder = c_meta_text_limit - trkinfo.size();
+ std::string rem = int_to_string(int(remainder));
+ midipulse ts = e.timestamp();
+ std::string tstr = long_to_string(long(ts));
+ ui->plainTextSongInfo->document()->setPlainText(qt(trkinfo));
+ ui->labelCharactersRemaining->setText(qt(rem));
+ ui->lineEditTimeStamp->setText(qt(tstr));
+// if (nextmatch)
+ ui->pushButtonSaveInfo->setEnabled(false);
+ }
+ }
+ }
+ m_current_track = trk;
+}
+
+void
+qsessionframe::slot_text_number (int textnum)
+{
+ if (textnum > m_current_text_number) // will allow reversal later
+ {
+ bool nextmatch = true;
+ seq66::event e = perf().get_track_info(m_current_track, nextmatch);
+ if (e.get_status() != 0)
+ {
+ // CUT-AND-PASTE-CODE
+ std::string trkinfo = e.get_text();
+ size_t remainder = c_meta_text_limit - trkinfo.size();
+ std::string rem = int_to_string(int(remainder));
+ midipulse ts = e.timestamp();
+ std::string tstr = long_to_string(long(ts));
+ ui->plainTextSongInfo->document()->setPlainText(qt(trkinfo));
+ ui->labelCharactersRemaining->setText(qt(rem));
+ ui->lineEditTimeStamp->setText(qt(tstr));
+// if (nextmatch)
+ ui->pushButtonSaveInfo->setEnabled(false);
+ ++m_current_text_number;
+ }
+ }
+}
+
/*
* New song-info edit control and the characters-remaining label..
* Tricky, when getting the song info from the performer, it is already
@@ -184,6 +315,7 @@ qsessionframe::reload_song_info ()
std::string rem = int_to_string(int(remainder));
ui->plainTextSongInfo->document()->setPlainText(qt(songinfo));
ui->labelCharactersRemaining->setText(qt(rem));
+ ui->lineEditTimeStamp->setText("0");
ui->pushButtonSaveInfo->setEnabled(false);
}
diff --git a/seq_qt5/src/qsmainwnd.cpp b/seq_qt5/src/qsmainwnd.cpp
index b8c15326..15da8b44 100644
--- a/seq_qt5/src/qsmainwnd.cpp
+++ b/seq_qt5/src/qsmainwnd.cpp
@@ -1148,6 +1148,9 @@ qsmainwnd::set_ppqn_combo ()
/**
* This gets called when just typing numbers into the BPM field! It gets
* called before edit_bpm().
+ *
+ * This doesn't make send, isn't the BPM value definitely different???
+ * We should fix for 0.99.5.
*/
void