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