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