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