]>
code.delx.au - virtualtones/blob - stringinstrument.cpp
1 // stringinstrument.cpp - A stringed instrument simulator
2 // Written by James Bunton <james@delx.net.au>
3 // Licensed under the GPL, see COPYING.txt for more details
6 #include "stringinstrument.h"
10 // Images from http://www.asinari.it/bassoeng.htm
12 ViolinInstrument::ViolinInstrument(QWidget
*parent
)
13 : StringInstrument(parent
)
17 background
.load("violin.png");
22 void ViolinInstrument::setNotes(int array
[4])
24 array
[0] = 28; // 'E' string
25 array
[1] = 21; // 'A' string
26 array
[2] = 14; // 'D' string
27 array
[3] = 7; // 'G' string
32 ViolaInstrument::ViolaInstrument(QWidget
*parent
)
33 : StringInstrument(parent
)
37 background
.load("viola.png");
42 void ViolaInstrument::setNotes(int array
[4])
44 array
[0] = 21; // 'A' string below middle c
45 array
[1] = 14; // 'D' string
46 array
[2] = 7; // 'G' string
47 array
[3] = 0; // 'C' string
52 CelloInstrument::CelloInstrument(QWidget
*parent
)
53 : StringInstrument(parent
)
57 background
.load("cello.png");
62 void CelloInstrument::setNotes(int array
[4])
64 array
[0] = 21; // 'A' string 2 below middle c
65 array
[1] = 14; // 'D' string
66 array
[2] = 7; // 'G' string
67 array
[3] = 0; // 'C' string
72 ContrabassInstrument::ContrabassInstrument(QWidget
*parent
)
73 : StringInstrument(parent
)
77 background
.load("contrabass.png");
82 void ContrabassInstrument::setNotes(int array
[4])
84 array
[0] = 19; // 'G' string 2 below middle c
85 array
[1] = 14; // 'D' string
86 array
[2] = 9; // 'A' string
87 array
[3] = 4; // 'E' string
92 /* StringInstrument */
94 /* For reference (Violin).. First line, note, second line key presses, third line, MIDI number
98 76 77 78 79 80 81 82 83
102 None TabQ Q W WE E ER R
103 69 70 71 72 73 74 75 76
107 None CapsA A S SD D DF F
108 62 63 64 65 66 67 68 69
112 None ShiftZ Z ZX X C CV V
113 55 56 57 58 59 60 61 62
117 StringInstrument::StringInstrument(QWidget
*parent
)
120 // Set all the keys to false
121 memset(down
, 0, sizeof(down
));
122 memset(downFudge
, 0, sizeof(downFudge
));
123 memset(bow
, 0, sizeof(bow
));
124 memset(oldVolume
, 0, sizeof(oldVolume
));
125 memset(oldNote
, 0, sizeof(oldNote
));
126 memset(note
, 0, sizeof(note
));
127 memset(volume
, 0, sizeof(volume
));
129 QTimer::singleShot(50, this, SLOT(emitSounds()));
132 StringInstrument::~StringInstrument()
136 QString
StringInstrument::generateHelp()
145 "<li>The row '1' '2' '3' '4' is the E string</li>"
146 "<li>The row 'q' 'w' 'e' 'r' is the A string</li>"
147 "<li>The row 'a' 's' 'd' 'f' is the D string</li>"
148 "<li>The row 'z' 'x' 'c' 'v' is the G string</li>"
149 "<li>The further to the right the key is, the higher the note</li>"
150 "<li>Try pressing multiple keys on the same string to get sharp notes. On the A,D,G strings try the Tab, Caps and Shift keys for sharp notes</li>"
155 "<li>Use the keys '7' '8' '9' '0' to bow the E string</li>"
156 "<li>Use the keys 'u' 'i' 'o' 'p' to bow the A string</li>"
157 "<li>Use the keys 'j' 'k' 'l' ';' to bow the D string</li>"
158 "<li>Use the keys 'm' ',' '.' '/' to bow the G string</li>"
159 "<li>The further right the key is, the quieter the note</li>"
167 void StringInstrument::paintEvent(QPaintEvent
*) {
168 QPainter
paint(this);
170 paint
.drawPixmap(0, 0, background
);
172 paint
.setPen(Qt::black
);
174 for(int i
= 0; i
< 4; i
++) {
176 text
+= "Playing note: ";
177 text
+= midi2string(noteStart
+ note
[i
]);
178 text
+= " - Volume: " + QString::number(volume
[i
] / 30);
179 paint
.drawText(45, (i
+1)*20, text
);
183 void StringInstrument::keyPressEvent(QKeyEvent
*e
)
185 if(e
->isAutoRepeat() == true) {
192 // case Key_Tilde: // This is never used
193 // downFudge[0] = true;
262 // Bowing on volume 3 (max)
276 // Bowing on volume 2
290 // Bowing on volume 1
304 // Bowing on volume 0 (min)
319 memset(down
, 0, sizeof(down
));
320 memset(bow
, 0, sizeof(bow
));
328 QTimer::singleShot(50, this, SLOT(emitSounds()));
331 void StringInstrument::keyReleaseEvent(QKeyEvent
*e
)
333 if(e
->isAutoRepeat() == true) {
340 // case Key_Tilde: // This is never used
341 // downFudge[0] = true;
345 downFudge
[1] = false;
348 downFudge
[2] = false;
351 downFudge
[3] = false;
410 // Bowing on volume 3 (max)
424 // Bowing on volume 2
438 // Bowing on volume 1
452 // Bowing on volume 0 (min)
467 memset(down
, 0, sizeof(down
));
468 memset(bow
, 0, sizeof(bow
));
476 QTimer::singleShot(50, this, SLOT(emitSounds()));
479 void StringInstrument::emitSounds()
481 memcpy(oldVolume
, volume
, sizeof(oldVolume
));
482 memcpy(oldNote
, note
, sizeof(oldNote
));
484 memset(volume
, 0, sizeof(volume
));
485 memcpy(note
, stringnote
, sizeof(note
)); // Fudge for setNotes(note);
487 // Need to find the differences in oldVolume, volume and oldNote, note
488 // Then stop changed notes, and start new ones
491 // Get the volumes, 'i' is the string, 'j' is the volume
493 for(i
= 0; i
< 4; i
++) {
494 for(int j
= 0; j
< 4; j
++) {
495 if(bow
[i
][j
] == true) {
496 volume
[i
] = (j
+ 1) * 30;
499 if(volume
[i
] != oldVolume
[i
]) { // The volume changed, stop that string
500 emit
stopNote(oldNote
[i
] + noteStart
);
501 oldNote
[i
] = -1; // Flag to restart, just in case the pitch didn't change
505 // Get the notes, 'i' is the string, 'j' is the volume
506 for(i
= 0; i
< 4; i
++) {
507 for(int j
= 0; j
< 4; j
++) {
508 if(down
[i
][j
] == false) {
511 note
[i
] = stringnote
[i
] + 2 * (j
+ 1);
512 for(int k
= stringnote
[i
]; k
<= note
[i
]; k
++) {
513 if(checkSharp(k
) == true) {
517 if(j
> 0 && down
[i
][j
] == true && down
[i
][j
-1] == true) {
520 else if(j
== 0 && downFudge
[i
] == true) {
524 if(note
[i
] != oldNote
[i
]) { // The pitch changed, restart the string
526 if(oldNote
[i
] != -1) {
527 emit
stopNote(oldNote
[i
] + noteStart
);
530 emit
playNote(note
[i
] + noteStart
, volume
[i
], 0);