1 /*
2 SMF GUI Player test using the MIDI Sequencer C++ library
3 Copyright (C) 2006-2021, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "player.h"
20 #include "song.h"
21 #include <cmath>
22 #include <drumstick/alsaclient.h>
23 #include <drumstick/alsaqueue.h>
24
25 using namespace drumstick::ALSA;
26
Player(MidiClient * seq,int portId)27 Player::Player(MidiClient *seq, int portId)
28 : SequencerOutputThread(seq, portId),
29 m_song(nullptr),
30 m_songIterator(nullptr),
31 m_lastEvent(nullptr),
32 m_songPosition(0),
33 m_echoResolution(0),
34 m_pitchShift(0),
35 m_volumeFactor(100)
36 {
37 for (int chan = 0; chan < MIDI_CHANNELS; ++chan)
38 m_volume[chan] = 100;
39 }
40
~Player()41 Player::~Player()
42 {
43 if (isRunning()) {
44 stop();
45 }
46 delete m_songIterator;
47 delete m_lastEvent;
48 }
49
setSong(Song * s)50 void Player::setSong(Song* s)
51 {
52 m_song = s;
53 if (m_song != nullptr) {
54 delete m_songIterator;
55 m_songIterator = new SongIterator(*m_song);
56 m_echoResolution = m_song->getDivision() / 12;
57 m_songPosition = 0;
58 }
59 }
60
resetPosition()61 void Player::resetPosition()
62 {
63 if ((m_song != nullptr) && (m_songIterator != nullptr)) {
64 m_songIterator->toFront();
65 m_songPosition = 0;
66 }
67 }
68
setPosition(unsigned int pos)69 void Player::setPosition(unsigned int pos)
70 {
71 m_songPosition = pos;
72 m_songIterator->toFront();
73 while (m_songIterator->hasNext() &&
74 (m_songIterator->next()->getTick() < pos)) { };
75 if (m_songIterator->hasPrevious())
76 m_songIterator->previous();
77 }
78
hasNext()79 bool Player::hasNext()
80 {
81 auto res = m_songIterator->hasNext();
82 return res;
83 }
84
nextEvent()85 SequencerEvent* Player::nextEvent()
86 {
87 delete m_lastEvent;
88 m_lastEvent = m_songIterator->next()->clone();
89 switch (m_lastEvent->getSequencerType()) {
90 case SND_SEQ_EVENT_NOTE:
91 case SND_SEQ_EVENT_NOTEON:
92 case SND_SEQ_EVENT_NOTEOFF:
93 case SND_SEQ_EVENT_KEYPRESS: {
94 KeyEvent* kev = static_cast<KeyEvent*>(m_lastEvent);
95 if (kev->getChannel() != MIDI_GM_DRUM_CHANNEL)
96 kev->setKey(kev->getKey() + m_pitchShift);
97 }
98 break;
99 case SND_SEQ_EVENT_CONTROLLER: {
100 ControllerEvent *cev = static_cast<ControllerEvent*>(m_lastEvent);
101 if (cev->getParam() == MIDI_CTL_MSB_MAIN_VOLUME) {
102 int chan = cev->getChannel();
103 int value = cev->getValue();
104 m_volume[chan] = value;
105 value = floor(value * m_volumeFactor / 100.0);
106 if (value < 0) value = 0;
107 if (value > 127) value = 127;
108 cev->setValue(value);
109 }
110 }
111 break;
112 }
113 return m_lastEvent;
114 }
115
getInitialPosition()116 unsigned int Player::getInitialPosition()
117 {
118 return m_songPosition;
119 }
120
getEchoResolution()121 unsigned int Player::getEchoResolution()
122 {
123 return m_echoResolution;
124 }
125
getPitchShift()126 unsigned int Player::getPitchShift()
127 {
128 return m_pitchShift;
129 }
130
getVolumeFactor()131 unsigned int Player::getVolumeFactor()
132 {
133 return m_volumeFactor;
134 }
135
setPitchShift(unsigned int pitch)136 void Player::setPitchShift(unsigned int pitch)
137 {
138 bool playing = isRunning();
139 if (playing) {
140 stop();
141 unsigned int pos = m_Queue->getStatus().getTickTime();
142 m_Queue->clear();
143 allNotesOff();
144 setPosition(pos);
145 }
146 m_pitchShift = pitch;
147 if (playing)
148 start();
149 }
150
setVolumeFactor(unsigned int vol)151 void Player::setVolumeFactor(unsigned int vol)
152 {
153 m_volumeFactor = vol;
154 for(int chan = 0; chan < MIDI_CHANNELS; ++chan) {
155 int value = m_volume[chan];
156 value = floor(value * m_volumeFactor / 100.0);
157 if (value < 0) value = 0;
158 if (value > 127) value = 127;
159 sendController(chan, MIDI_CTL_MSB_MAIN_VOLUME, value);
160 }
161 }
162
sendController(int chan,int control,int value)163 void Player::sendController(int chan, int control, int value)
164 {
165 ControllerEvent ev(chan, control, value);
166 ev.setSource(m_PortId);
167 ev.setSubscribers();
168 ev.setDirect();
169 sendSongEvent(&ev);
170 }
171
allNotesOff()172 void Player::allNotesOff()
173 {
174 for(int chan = 0; chan < MIDI_CHANNELS; ++chan) {
175 sendController(chan, MIDI_CTL_ALL_NOTES_OFF, 0);
176 sendController(chan, MIDI_CTL_ALL_SOUNDS_OFF, 0);
177 }
178 }
179
sendVolumeEvents()180 void Player::sendVolumeEvents()
181 {
182 for(int chan = 0; chan < MIDI_CHANNELS; ++chan) {
183 int value = m_volume[chan] = 100;
184 value = floor(value * m_volumeFactor / 100.0);
185 if (value < 0) value = 0;
186 if (value > 127) value = 127;
187 sendController(chan, MIDI_CTL_MSB_MAIN_VOLUME, value);
188 }
189 }
190