1 /*!
2  * @file seqscreen.cpp
3  * @brief Implementation of the SeqScreen class
4  *
5  *
6  *      Copyright 2009 - 2017 <qmidiarp-devel@lists.sourceforge.net>
7  *
8  *      This program is free software; you can redistribute it and/or modify
9  *      it under the terms of the GNU General Public License as published by
10  *      the Free Software Foundation; either version 2 of the License, or
11  *      (at your option) any later version.
12  *
13  *      This program is distributed in the hope that it will be useful,
14  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *      GNU General Public License for more details.
17  *
18  *      You should have received a copy of the GNU General Public License
19  *      along with this program; if not, write to the Free Software
20  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  *      MA 02110-1301, USA.
22  *
23  */
24 
25 #include "seqscreen.h"
26 
SeqScreen()27 SeqScreen::SeqScreen()
28 {
29     setPalette(QPalette(QColor(0, 20, 100), QColor(0, 20, 100)));
30     baseOctave = 3;
31     nOctaves= 4;
32     currentRecStep = 0;
33     loopMarker = 0;
34     currentIndex = 0;
35 }
36 
37 // Paint event handler.
paintEvent(QPaintEvent *)38 void SeqScreen::paintEvent(QPaintEvent*)
39 {
40     if (p_data.isEmpty()) return;
41 
42     QPainter p(this);
43     QPen pen;
44     pen.setWidth(1);
45     p.setFont(QFont("Helvetica", 8));
46     p.setPen(pen);
47 
48     int beat = 4;
49     int tmpval = 0;
50     int ypos, xpos, xscale, yscale;
51     w = QWidget::width();
52     h = QWidget::height();
53     int ofs;
54     int x, x1;
55     int minOctave = baseOctave;
56     int maxOctave = nOctaves + minOctave;
57     int notestreak_thick = 16 / nOctaves;
58 
59     //Grid setup
60     double nsteps = p_data.at(p_data.count() - 1).tick / TPQN;
61     int beatRes = (p_data.count() - 1) / nsteps;
62     int beatDiv = (beatRes * nsteps > 64) ? 64 / nsteps : beatRes;
63     int npoints = beatRes * nsteps;
64     xscale = (w - 2 * SEQSCR_HMARG) / nsteps;
65     yscale = h - 2 * SEQSCR_VMARG;
66 
67     //Blue Filled Frame
68     if (isMuted)
69         p.fillRect(0, 0, w, h, QColor(70, 70, 70));
70     else
71         p.fillRect(0, 0, w, h, QColor(10, 10, 50));
72     p.setViewport(0, 0, w, h);
73     p.setWindow(0, 0, w, h);
74     p.setPen(QColor(20, 20, 160));
75 
76     //Draw current record step
77     if (recordMode)
78     p.fillRect(currentRecStep * xscale * nsteps / npoints + SEQSCR_HMARG
79                 , SEQSCR_VMARG
80                 , xscale * nsteps / npoints
81                 , h - 2*SEQSCR_VMARG, QColor(5, 40, 100));
82 
83     //Beat separators
84     for (int l1 = 0; l1 < nsteps + 1; l1++) {
85 
86         if (l1 < 10) {
87             ofs = w / nsteps * .5 - 4 + SEQSCR_HMARG;
88         } else {
89             ofs = w / nsteps * .5 - 6 + SEQSCR_HMARG;
90         }
91         if ((bool)(l1%beat)) {
92             p.setPen(QColor(60, 100, 180));
93         } else {
94             p.setPen(QColor(100, 100, 180));
95         }
96         x = l1 * xscale;
97         p.drawLine(SEQSCR_HMARG + x, SEQSCR_VMARG,
98                 SEQSCR_HMARG + x, h-SEQSCR_VMARG);
99 
100         if (l1 < nsteps) {
101             //Beat numbers
102             p.setPen(QColor(100, 150, 180));
103             p.drawText(ofs + x, SEQSCR_VMARG, QString::number(l1+1));
104 
105             // Beat divisor separators
106             p.setPen(QColor(20, 60, 120));
107             for (int l2 = 1; l2 < beatDiv; l2++) {
108                 x1 = x + l2 * xscale / beatDiv;
109                 if (x1 < xscale * nsteps)
110                     p.drawLine(SEQSCR_HMARG + x1,
111                             SEQSCR_VMARG, SEQSCR_HMARG + x1,
112                             h - SEQSCR_VMARG);
113             }
114         }
115     }
116 
117     //Horizontal separators and numbers
118     for (int l1 = 0; l1 <= nOctaves * 12; l1++) {
119         int l3 = l1%12;
120 
121         ypos = yscale * l1 / nOctaves / 12 + SEQSCR_VMARG;
122 
123         if (!l3) {
124             p.setPen(QColor(30, 60, 180));
125             p.drawText(w - SEQSCR_HMARG / 2 - 4,
126                     ypos + SEQSCR_VMARG - 5 - yscale / nOctaves / 2,
127                     QString::number(maxOctave - l1 / 12));
128         }
129         else
130             p.setPen(QColor(10, 20, 100));
131 
132         p.drawLine(0, ypos, w - SEQSCR_HMARG, ypos);
133         if ((l3 == 2) || (l3 == 4) || (l3 == 6) || (l3 == 9) || (l3 == 11)) {
134             pen.setColor(QColor(20, 60, 180));
135             pen.setWidth(notestreak_thick);
136             p.setPen(pen);
137             p.drawLine(0, ypos - notestreak_thick / 2, SEQSCR_HMARG / 2,
138             ypos- notestreak_thick / 2);
139             pen.setWidth(1);
140             p.setPen(pen);
141         }
142     }
143 
144     //Draw function
145 
146     pen.setWidth(notestreak_thick);
147     p.setPen(pen);
148     for (int l1 = 0; l1 < npoints; l1++) {
149         x = (l1 + .01 * (double)grooveTick * (l1 % 2)) * nsteps * xscale / npoints;
150         tmpval = p_data.at(l1).value;
151         if ((tmpval >= 12 * baseOctave) && (tmpval < 12 * maxOctave)) {
152             ypos = yscale - yscale
153                 * (p_data.at(l1).value - 12 * baseOctave) / nOctaves / 12
154                 + SEQSCR_VMARG - pen.width() / 2;
155             xpos = SEQSCR_HMARG + x + pen.width() / 2;
156             if (p_data.at(l1).muted) {
157                 pen.setColor(QColor(5, 40, 100));
158             }
159             else {
160                 pen.setColor(QColor(50, 130, 180));
161             }
162             p.setPen(pen);
163             p.drawLine(xpos, ypos,
164                             xpos + (xscale / beatRes) - pen.width(), ypos);
165         }
166     }
167 
168     // Helper tickline on keyboard
169     ypos = yscale - yscale * (int)((1. - ((double)mouseY - SEQSCR_VMARG)
170             / (h - 2 * SEQSCR_VMARG)) * nOctaves * 12) / nOctaves / 12
171             + SEQSCR_VMARG - 1 - pen.width() / 2;
172 
173     pen.setWidth(2);
174     pen.setColor(QColor(50, 160, 220));
175     p.setPen(pen);
176     p.drawLine(SEQSCR_HMARG / 2, ypos, SEQSCR_HMARG *2 / 3, ypos);
177 
178     // Loop Marker
179     if (loopMarker) {
180         QPolygon trg;
181         pen.setWidth(2);
182         pen.setColor(QColor(80, 250, 120));
183         p.setPen(pen);
184         x = abs(loopMarker) * xscale * nsteps / npoints;
185         xpos = SEQSCR_HMARG + x + pen.width() / 2;
186         ypos = h - SEQSCR_VMARG;
187         tmpval = SEQSCR_VMARG / 2;
188         trg << QPoint(xpos, ypos);
189         if (loopMarker > 0)
190             trg << QPoint(xpos - tmpval, ypos + tmpval);
191         else
192             trg << QPoint(xpos + tmpval, ypos + tmpval);
193         trg << QPoint(xpos, h);
194         p.drawPolygon(trg, Qt::WindingFill);
195     }
196 }
197 
emitMouseEvent(QMouseEvent * event,int pressed)198 void SeqScreen::emitMouseEvent(QMouseEvent *event, int pressed)
199 {
200     mouseX = event->x();
201     mouseY = event->y();
202 
203     emit mouseEvent(((double)mouseX - SEQSCR_HMARG) /
204                             (w - 2 * SEQSCR_HMARG),
205                 1. - ((double)mouseY - SEQSCR_VMARG) /
206                 (h - 2 * SEQSCR_VMARG), event->buttons(), pressed);
207 }
208 
updateData(const QVector<Sample> & data)209 void SeqScreen::updateData(const QVector<Sample>& data)
210 {
211     p_data = data;
212     needsRedraw = true;
213 }
214 
setCurrentRecStep(int recStep)215 void SeqScreen::setCurrentRecStep(int recStep)
216 {
217     currentRecStep = recStep;
218     needsRedraw = true;
219 }
220 
setLoopMarker(int pos)221 void SeqScreen::setLoopMarker(int pos)
222 {
223     loopMarker = pos;
224     needsRedraw = true;
225 }
226 
updateDispVert(int mode)227 void SeqScreen::updateDispVert(int mode)
228 {
229     switch (mode) {
230         case 0:
231             nOctaves = 4;
232             baseOctave = 3;
233         break;
234         case 1:
235             nOctaves = 2;
236             baseOctave = 5;
237         break;
238         case 2:
239             nOctaves = 2;
240             baseOctave = 4;
241         break;
242         case 3:
243             nOctaves = 2;
244             baseOctave = 3;
245         break;
246         default:
247             nOctaves = 4;
248             baseOctave = 3;
249     }
250     update();
251 }
252