From 6e66db5a7931beebab9c977c165b8f06c6e50966 Mon Sep 17 00:00:00 2001 From: ahlstrom Date: Fri, 6 Oct 2023 17:09:07 -0400 Subject: [PATCH] Fixed issue #119 and some minor issues. --- TODO | 36 ++++++++---- libseq66/include/midi/eventlist.hpp | 4 +- libseq66/include/play/sequence.hpp | 4 +- libseq66/src/midi/eventlist.cpp | 55 +++++++++++++++--- libseq66/src/play/performer.cpp | 10 ++-- libseq66/src/play/sequence.cpp | 50 ++++++++++++---- resources/pixmaps/hide.xpm | 8 +-- seq_qt5/forms/qseditoptions.ui | 90 ++++++++++++++++++++++++++++- seq_qt5/src/qloopbutton.cpp | 6 +- seq_qt5/src/qseqeditframe64.cpp | 27 ++++++--- seq_qt5/src/qsmainwnd.cpp | 28 ++++----- 11 files changed, 247 insertions(+), 71 deletions(-) diff --git a/TODO b/TODO index 492abb62..279a12a4 100644 --- a/TODO +++ b/TODO @@ -1,23 +1,18 @@ TO DO for Seq66 0.99.10 Chris Ahlstrom -2019-04-13 to 2023-10-05 +2019-04-13 to 2023-10-06 Misc: + - Issue #117 + - Issue #118 - Document and test mute groups. Issues: - To do: - - Disable auto-save of the mutes file at exit in this - case, unless the name provided is identical. - - If "To Mutes" is set, "To MIDI" is not, and a change is made, - there is no MIDI modified flag, but closing prompts to save. - We need to forward the boolean changes immediately, e.g. - to cb_per().mutes().group_save_to_midi(); perhaps add - a flag set to performer::set_mutes()??? - performer: cliear_mute_groups(), reset_mute_groups(), and mutegroup_reset() all basically do the same things, except - that clear_mutes() also notifies subscribers. Probably - can get rid of "Fill" and its pix and documentation. + that clear_mutes() also notifies subscribers. - For scrolling to notes, use average note instead of first note. + Also should add about half the height of the piano roll, otherwise + the middle (average) appears at the top. - There are issues with Song / Zoom / Follow progress with the ulra-zoom-in in force. Pattern editor works. - In the Kraftwerk song, the Chorus seems to have the wrong pitch, @@ -336,6 +331,25 @@ ISSUES: STATUS: Cannot duplicate. +#117 Option to close pattern windows with esc key? + + STATUS: Thinking... This can be done if (1) not playing; and + (2) not in Paint mode. + +#118 When enabling virtual ports, make those new ports enabled by default? + Currently one has to tick the box to enable and enter the number of output + and input ports, restart seq66, and then tick all the input port + checkboxes in the list then restart seq66 again. + + STATUS: At least make it an rc option. + +#119 Quantized Record Active does not work + Having this button active has no effect; tried changing snap size to + different settings... Post processing quantize works as expected (i,e, + Ctrl-A then q) + + STATUS: Fixed in the portfix branch. An embarrasing misstep! + To close as fixed (and remove from TODO): 24 Release notes in release tag message? diff --git a/libseq66/include/midi/eventlist.hpp b/libseq66/include/midi/eventlist.hpp index 539ea555..d7ff8ac4 100644 --- a/libseq66/include/midi/eventlist.hpp +++ b/libseq66/include/midi/eventlist.hpp @@ -28,7 +28,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2015-09-19 - * \updates 2023-09-27 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * This module extracts the event-list functionality from the sequencer @@ -376,7 +376,7 @@ class eventlist void link_new (bool wrap = false); void clear_links (); int note_count () const; - bool first_note (midipulse & ts, int & n) const; + bool first_notes (midipulse & ts, int & n, midipulse snap = 0) const; #if defined SEQ66_USE_FILL_TIME_SIG_AND_TEMPO void scan_meta_events (); #endif diff --git a/libseq66/include/play/sequence.hpp b/libseq66/include/play/sequence.hpp index 080f5ea4..5722dfb1 100644 --- a/libseq66/include/play/sequence.hpp +++ b/libseq66/include/play/sequence.hpp @@ -28,7 +28,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2015-07-30 - * \updates 2023-09-27 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * The functions add_list_var() and add_long_list() have been replaced by @@ -1122,7 +1122,7 @@ class sequence int event_count () const; int note_count () const; - bool first_note (midipulse & ts, int & n) const; + bool first_notes (midipulse & ts, int & n) const; int playable_count () const; bool is_playable () const; bool minmax_notes (int & lowest, int & highest); diff --git a/libseq66/src/midi/eventlist.cpp b/libseq66/src/midi/eventlist.cpp index 9ed3ecf9..5a5d23f5 100644 --- a/libseq66/src/midi/eventlist.cpp +++ b/libseq66/src/midi/eventlist.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2015-09-19 - * \updates 2023-09-27 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * This container now can indicate if certain Meta events (time-signaure or @@ -526,18 +526,57 @@ eventlist::note_count () const return result; } +/** + * Look at note events within the snap interval. Return the first time-stamp + * and the first (or average within the snap interval) note value. This + * function is used for centering the seqroll on visible notes. + */ + bool -eventlist::first_note (midipulse & ts, int & n) const +eventlist::first_notes (midipulse & ts, int & n, midipulse snap) const { bool result = false; - for (const auto & e : m_events) + bool doaverage = snap > 0; + if (doaverage) { - if (e.is_note_on()) + midipulse ts_first = (-1); + int note_avg = 0; + int note_count = 0; + for (const auto & e : m_events) { - ts = e.timestamp(); - n = int(e.get_note()); - result = true; - break; + if (e.is_note_on()) + { + result = true; + + midipulse ts_temp = e.timestamp(); + if (ts_first == (-1)) + ts_first = ts_temp; + + int note = int(e.get_note()); + ++note_count; + if (ts_temp < (ts_first + snap)) + note_avg += note; + else + break; + } + } + if (result) + { + ts = ts_first; + n = note_avg / note_count; + } + } + else + { + for (const auto & e : m_events) + { + if (e.is_note_on()) + { + ts = e.timestamp(); + n = int(e.get_note()); + result = true; + break; + } } } return result; diff --git a/libseq66/src/play/performer.cpp b/libseq66/src/play/performer.cpp index 4fdf6948..275a79f6 100644 --- a/libseq66/src/play/performer.cpp +++ b/libseq66/src/play/performer.cpp @@ -1368,9 +1368,9 @@ performer::true_output_bus (bussbyte nominalbuss) const msg += "\""; } msg += - ". Check assigned ports in the song, 'rc', 'ctrl' files, " - "and the MIDI and Metronome tabs. Also check the Session " - "tab's file-names." + ". Check assigned ports in files: song, rc, ctrl, " + "usr buss-override, MIDI & Metronome tabs, and " + "Session tab file-names." ; m_port_map_error = true; /* mutable boolean */ append_error_message(msg); @@ -5260,7 +5260,7 @@ performer::auto_play_start () bool performer::auto_play_stop (midipulse tick) { - bool result = m_max_extent > 0 && tick >= m_max_extent; + bool result = m_max_extent > 0 && tick >= m_max_extent && song_mode(); if (result) { if (playlist_active()) @@ -5302,7 +5302,6 @@ performer::play (midipulse tick) { if (tick != get_tick() || tick == 0) /* avoid replays */ { - bool songmode = song_mode(); if (auto_play_stop(tick)) { (void) open_next_song(); @@ -5310,6 +5309,7 @@ performer::play (midipulse tick) } else { + bool songmode = song_mode(); set_tick(tick); for (auto seqi : play_set().seq_container()) { diff --git a/libseq66/src/play/sequence.cpp b/libseq66/src/play/sequence.cpp index 4a19df4c..96847d91 100644 --- a/libseq66/src/play/sequence.cpp +++ b/libseq66/src/play/sequence.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2015-07-24 - * \updates 2023-09-27 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * The functionality of this class also includes handling some of the @@ -546,11 +546,15 @@ sequence::note_count () const return m_events.note_count(); } +/** + * Gets the average of the notes within a snap value of the first note. + */ + bool -sequence::first_note (midipulse & ts, int & n) const +sequence::first_notes (midipulse & ts, int & n) const { automutex locker(m_mutex); - return m_events.first_note(ts, n); + return m_events.first_notes(ts, n, m_snap_tick); } int @@ -4050,9 +4054,6 @@ bool sequence::stream_event (event & ev) { automutex locker(m_mutex); - -/// printf("tick %ld, channel %d\n", ev.timestamp(), ev.channel()); - bool result = channels_match(ev); /* set if channel matches */ if (result) { @@ -4093,6 +4094,31 @@ sequence::stream_event (event & ev) if (ev.is_note_on() && m_rec_vol > usr().preserve_velocity()) ev.note_velocity(m_rec_vol); /* modify incoming */ + /* + * See USE_OLD_CODE below. We need to do this here, not there. + */ + + if (alter_recording() && ev.is_note()) + { + /* + * We want to quantize or tighten note-related events that + * comes in, This could potentially alter the note length + * by a couple of snaps. So what? Play better! + */ + + if (quantizing()) + { + (void) ev.quantize(snap(), get_length()); + } + else if (tightening()) + { + (void) ev.tighten(snap(), get_length()); + } + else if (notemapping()) + { + perf()->repitch(ev); + } + } add_event(ev); /* locks and sorts */ } else @@ -4172,10 +4198,7 @@ sequence::stream_event (event & ev) if (ev.is_note_off()) link_new(); - /* - * if (quantizing_or_tightening() && perf()->is_pattern_playing()) - */ - +#if defined USE_OLD_CODE if (alter_recording()) { /* @@ -4185,12 +4208,19 @@ sequence::stream_event (event & ev) */ if (quantizing()) + { (void) ev.quantize(snap(), get_length()); + } else if (tightening()) + { (void) ev.tighten(snap(), get_length()); + } else if (notemapping()) + { perf()->repitch(ev); + } } +#endif } return result; } diff --git a/resources/pixmaps/hide.xpm b/resources/pixmaps/hide.xpm index de231e86..8140ddf0 100644 --- a/resources/pixmaps/hide.xpm +++ b/resources/pixmaps/hide.xpm @@ -9,13 +9,13 @@ static const char * hide_xpm[] = { " ", " ", " ", +" ............ ", +" . . ", +" . . ", +" ............ ", " ", " ", " ", " ", " ", -" ............ ", -" . . ", -" . . ", -" ............ ", " "}; diff --git a/seq_qt5/forms/qseditoptions.ui b/seq_qt5/forms/qseditoptions.ui index a8b9a79e..5152756b 100644 --- a/seq_qt5/forms/qseditoptions.ui +++ b/seq_qt5/forms/qseditoptions.ui @@ -37,6 +37,7 @@ + 50 false @@ -44,7 +45,7 @@ - 7 + 6 @@ -64,6 +65,7 @@ + 50 false @@ -87,6 +89,7 @@ + 75 true @@ -207,6 +210,7 @@ + 75 true @@ -257,6 +261,7 @@ DejaVu Sans + 75 true @@ -313,6 +318,7 @@ + 75 true @@ -331,6 +337,7 @@ + 75 true @@ -359,6 +366,7 @@ + 75 true @@ -388,6 +396,7 @@ + 75 true @@ -427,6 +436,7 @@ + 75 true @@ -442,6 +452,7 @@ + 75 true @@ -511,6 +522,7 @@ Each port number can be found by name-lookup. + 50 false @@ -634,6 +646,7 @@ slot by channel number (0 to 15). + 75 true @@ -654,6 +667,7 @@ slot by channel number (0 to 15). DejaVu Sans + 75 true @@ -720,6 +734,7 @@ slot by channel number (0 to 15). + 75 true @@ -755,6 +770,7 @@ slot by channel number (0 to 15). + 50 false @@ -1385,6 +1401,7 @@ Range: 0.5 to 3.0 + 50 true false @@ -1404,6 +1421,7 @@ Range: 0.5 to 3.0 + 75 true @@ -1422,6 +1440,7 @@ Range: 0.5 to 3.0 + 75 true @@ -1463,6 +1482,7 @@ Range: 0.5 to 3.0 + 75 true @@ -1481,6 +1501,7 @@ Range: 0.5 to 3.0 + 75 true @@ -1730,6 +1751,7 @@ connects to the MIDI I/O ports it finds. + 75 true @@ -1748,6 +1770,7 @@ connects to the MIDI I/O ports it finds. + 50 true false @@ -1816,6 +1839,7 @@ in the Song Editor. + 75 true @@ -1833,6 +1857,7 @@ in the Song Editor. + 50 false @@ -1855,6 +1880,7 @@ playback resumes. + 50 false @@ -1878,6 +1904,7 @@ the default PPQN. + 50 false @@ -1898,6 +1925,7 @@ the default PPQN. Sans + 75 true @@ -1969,6 +1997,7 @@ Seq66 exits. + 75 true @@ -1986,6 +2015,7 @@ Seq66 exits. + 50 false @@ -2004,6 +2034,7 @@ Seq66 exits. + 50 false @@ -2022,6 +2053,7 @@ Seq66 exits. + 50 false @@ -2040,6 +2072,7 @@ Seq66 exits. + 50 false @@ -2065,6 +2098,7 @@ Seq66 exits. + 75 true @@ -2082,6 +2116,7 @@ Seq66 exits. + 50 false @@ -2100,6 +2135,7 @@ Seq66 exits. + 50 false @@ -2118,6 +2154,7 @@ Seq66 exits. + 50 false @@ -2163,6 +2200,7 @@ Seq66 exits. + 75 true @@ -2177,6 +2215,7 @@ Seq66 exits. + 75 true @@ -2192,6 +2231,7 @@ Seq66 exits. + 75 true @@ -2214,6 +2254,7 @@ Seq66 exits. + 75 true @@ -2229,6 +2270,7 @@ Seq66 exits. + 75 true @@ -2287,6 +2329,7 @@ Seq66 exits. + 75 true @@ -2302,6 +2345,7 @@ Seq66 exits. + 75 true @@ -2314,6 +2358,7 @@ Seq66 exits. + 75 true @@ -2326,6 +2371,7 @@ Seq66 exits. + 75 true @@ -2347,6 +2393,7 @@ Seq66 exits. + 75 true @@ -2368,6 +2415,7 @@ Seq66 exits. + 75 true @@ -2389,6 +2437,7 @@ Seq66 exits. + 75 true @@ -2445,6 +2494,7 @@ Seq66 exits. + 75 true @@ -2473,6 +2523,7 @@ Seq66 exits. + 75 true @@ -2514,6 +2565,7 @@ Seq66 exits. + 75 true @@ -2565,6 +2617,7 @@ Seq66 exits. + 75 true @@ -2593,6 +2646,7 @@ Seq66 exits. + 75 true @@ -2645,11 +2699,17 @@ Seq66 exits. 36 - 250 + 240 161 - 24 + 28 + + + 0 + 28 + + @@ -2755,6 +2815,12 @@ Seq66 exits. + + + 0 + 28 + + 2 @@ -2785,6 +2851,12 @@ Seq66 exits. + + + 0 + 28 + + 1 @@ -2819,6 +2891,7 @@ Seq66 exits. + 50 false @@ -2875,6 +2948,7 @@ Seq66 exits. + 75 true @@ -2895,6 +2969,7 @@ Seq66 exits. 11 + 50 true false @@ -2922,6 +2997,7 @@ required. + 75 true @@ -3151,6 +3227,7 @@ required. + 50 true false @@ -3170,6 +3247,7 @@ required. + 50 true false @@ -3267,6 +3345,7 @@ required. + 50 true false @@ -3331,6 +3410,7 @@ path added to this name is stripped. + 50 true false @@ -3350,6 +3430,7 @@ path added to this name is stripped. + 50 true false @@ -3369,6 +3450,7 @@ path added to this name is stripped. + 50 true false @@ -3449,6 +3531,7 @@ path added to this name is stripped. + 75 true @@ -3494,6 +3577,7 @@ path added to this name is stripped. 11 + 50 true false diff --git a/seq_qt5/src/qloopbutton.cpp b/seq_qt5/src/qloopbutton.cpp index f54255e3..67a1969b 100644 --- a/seq_qt5/src/qloopbutton.cpp +++ b/seq_qt5/src/qloopbutton.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2019-06-28 - * \updates 2023-08-31 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * A paint event is a request to repaint all/part of a widget. It happens for @@ -582,8 +582,6 @@ qloopbutton::paintEvent (QPaintEvent * pev) int radius = usr().scale_size(s_radius_record) + 2; int clx = m_top_right.m_x + m_top_right.m_w - radius - 2; int cly = m_top_right.m_y + m_top_right.m_h; - int tlx = clx + usr().scale_size(2) + 1; - int tly = cly + radius - usr().scale_size(2); QPen pen2(drum_paint()); QBrush brush(drum_paint(), Qt::SolidPattern); painter.save(); @@ -592,6 +590,8 @@ qloopbutton::paintEvent (QPaintEvent * pev) painter.drawEllipse(clx, cly, radius, radius); if (loop()->alter_recording()) /* Q, Tighten, etc. */ { + int tlx = clx + usr().scale_size(2); + int tly = cly + radius - usr().scale_size(2); int fontsize = usr().scale_font_size(s_fontsize_record); QFont font; font.setPointSize(fontsize); diff --git a/seq_qt5/src/qseqeditframe64.cpp b/seq_qt5/src/qseqeditframe64.cpp index cfdf1633..edf548d9 100644 --- a/seq_qt5/src/qseqeditframe64.cpp +++ b/seq_qt5/src/qseqeditframe64.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2018-06-15 - * \updates 2023-09-29 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * The data pane is the drawing-area below the seqedit's event area, and @@ -1424,19 +1424,23 @@ qseqeditframe64::initialize_panels () ui->keysScrollArea->attach_master(ui->rollScrollArea); ui->timeScrollArea->attach_master(ui->rollScrollArea); - /* - * int minimum = ui->rollScrollArea->verticalScrollBar()->minimum(); - * int maximum = ui->rollScrollArea->verticalScrollBar()->maximum(); - * ui->rollScrollArea->verticalScrollBar()->setValue((minimum + maximum) / 2); - */ - midipulse ts; int n; - bool gotnote = track().first_note(ts, n); - if (gotnote) + bool gotnotes = track().first_notes(ts, n); /* get average note value */ + if (gotnotes) { scroll_to_tick(ts); scroll_to_note(n); +printf("Avg note = %d\n", n); + } + else + { + int minimum = ui->rollScrollArea->verticalScrollBar()->minimum(); + int maximum = ui->rollScrollArea->verticalScrollBar()->maximum(); + ui->rollScrollArea->verticalScrollBar()->setValue + ( + (minimum + maximum) / 2 + ); } } @@ -2916,6 +2920,11 @@ qseqeditframe64::scroll_to_tick (midipulse tick) } } +/** + * How can we add a little bit to move the note value more to the middle of + * the piano roll, rather than to the top? + */ + void qseqeditframe64::scroll_to_note (int note) { diff --git a/seq_qt5/src/qsmainwnd.cpp b/seq_qt5/src/qsmainwnd.cpp index 6b3274e7..22a12947 100644 --- a/seq_qt5/src/qsmainwnd.cpp +++ b/seq_qt5/src/qsmainwnd.cpp @@ -24,7 +24,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2018-01-01 - * \updates 2023-10-03 + * \updates 2023-10-06 * \license GNU GPLv2 or above * * The main window is known as the "Patterns window" or "Patterns panel". It @@ -908,7 +908,7 @@ qsmainwnd::qsmainwnd */ ui->btnShowHide->setCheckable(true); - ui->btnShowHide->setChecked(true); /* start w/showing */ + ui->btnShowHide->setChecked(false); /* start w/showing */ ui->btnShowHide->setEnabled(true); ui->btnShowHide->setToolTip("Show/hide many controls to save space"); qt_set_icon(hide_xpm, ui->btnShowHide); @@ -3966,18 +3966,8 @@ qsmainwnd::slot_test () void qsmainwnd::slot_show_hide () { - bool showthem = ui->btnShowHide->isChecked(); - if (showthem) - { - qt_set_icon(hide_xpm, ui->btnShowHide); - ui->menuBar->show(); - ui->cmb_global_bus->show(); - ui->cmb_beat_measure->show(); - ui->cmb_beat_length->show(); - qt_set_layout_visibility(ui->hLayoutBottom_1, true); - qt_set_layout_visibility(ui->hLayoutBottom_2, true); - } - else + bool hidethem = ui->btnShowHide->isChecked(); + if (hidethem) { qt_set_icon(show_xpm, ui->btnShowHide); ui->menuBar->hide(); @@ -3987,6 +3977,16 @@ qsmainwnd::slot_show_hide () qt_set_layout_visibility(ui->hLayoutBottom_1, false); qt_set_layout_visibility(ui->hLayoutBottom_2, false); } + else + { + qt_set_icon(hide_xpm, ui->btnShowHide); + ui->menuBar->show(); + ui->cmb_global_bus->show(); + ui->cmb_beat_measure->show(); + ui->cmb_beat_length->show(); + qt_set_layout_visibility(ui->hLayoutBottom_1, true); + qt_set_layout_visibility(ui->hLayoutBottom_2, true); + } } bool