1 /* 2 AlsaEngine.h 3 4 Copyright 2009-2010, Alan Calvert 5 Copyright 2014-2019, Will Godfrey & others 6 7 This file is part of yoshimi, which is free software: you can 8 redistribute it and/or modify it under the terms of the GNU General 9 Public License as published by the Free Software Foundation, either 10 version 2 of the License, or (at your option) any later version. 11 12 yoshimi is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with yoshimi. If not, see <http://www.gnu.org/licenses/>. 19 20 Modified May 2019 21 */ 22 23 #if defined(HAVE_ALSA) 24 25 #ifndef ALSA_ENGINE_H 26 #define ALSA_ENGINE_H 27 28 #include <pthread.h> 29 #include <alsa/asoundlib.h> 30 #include <string> 31 32 #include "MusicIO/MusicIO.h" 33 34 #define MIDI_CLOCKS_PER_BEAT 24 35 #define MIDI_CLOCK_DIVISION 3 36 37 #define MIDI_SONGPOS_BEAT_DIVISION 4 38 39 #define ALSA_MIDI_BPM_MEDIAN_WINDOW 48 40 #define ALSA_MIDI_BPM_MEDIAN_AVERAGE_WINDOW 20 41 42 class SynthEngine; 43 44 class AlsaEngine : public MusicIO 45 { 46 public: 47 AlsaEngine(SynthEngine *_synth, BeatTracker *_beatTracker); ~AlsaEngine()48 ~AlsaEngine() { } 49 50 bool openAudio(void); 51 bool openMidi(void); 52 bool Start(void); 53 void Close(void); 54 getSamplerate(void)55 unsigned int getSamplerate(void) { return audio.samplerate; } getBuffersize(void)56 int getBuffersize(void) { return audio.period_size; } 57 58 std::string audioClientName(void); 59 std::string midiClientName(void); audioClientId(void)60 int audioClientId(void) { return audio.alsaId; } midiClientId(void)61 int midiClientId(void) { return midi.alsaId; } registerAudioPort(int)62 virtual void registerAudioPort(int ) {} 63 64 bool little_endian; 65 bool card_endian; 66 int card_bits; 67 bool card_signed; 68 unsigned int card_chans; 69 70 private: 71 bool prepHwparams(void); 72 bool prepSwparams(void); 73 void Interleave(int buffersize); 74 void Write(snd_pcm_uframes_t towrite); 75 bool Recover(int err); 76 bool xrunRecover(void); 77 bool alsaBad(int op_result, std::string err_msg); 78 void closeAudio(void); 79 void closeMidi(void); 80 81 std::string findMidiClients(snd_seq_t *seq); 82 83 void *AudioThread(void); 84 static void *_AudioThread(void *arg); 85 void *MidiThread(void); 86 static void *_MidiThread(void *arg); 87 88 snd_pcm_sframes_t (*pcmWrite)(snd_pcm_t *handle, const void *data, 89 snd_pcm_uframes_t nframes); 90 91 void handleSongPos(float beat); 92 void handleMidiClock(); 93 94 struct { 95 std::string device; 96 snd_pcm_t *handle; 97 unsigned int period_count; 98 unsigned int samplerate; 99 snd_pcm_uframes_t period_size; 100 snd_pcm_uframes_t buffer_size; 101 int alsaId; 102 snd_pcm_state_t pcm_state; 103 pthread_t pThread; 104 } audio; 105 106 struct { 107 std::string device; 108 snd_seq_t *handle; 109 snd_seq_addr_t addr; 110 int alsaId; 111 pthread_t pThread; 112 113 // When receiving MIDI clock messages, to avoid precision errors 114 // (MIDI_CLOCKS_PER_BEAT (24) does not cleanly divide 1), store 115 // every third (MIDI_CLOCK_DIVISION) beat here. This is reset only 116 // every third clock ticks or on song repositioning. Note that the 117 // value is not necessarily an exact multiple of 118 // 1/MIDI_CLOCK_DIVISION, but we only ever add 119 // (1/MIDI_CLOCK_DIVISION) beats to it. 120 float lastDivSongBeat; 121 float lastDivMonotonicBeat; 122 // Reset to zero every MIDI_CLOCK_DIVISION. This is actually an 123 // integer, but stored as float for calculation purposes. 124 float clockCount; 125 126 float prevBpms[ALSA_MIDI_BPM_MEDIAN_WINDOW]; 127 int prevBpmsPos; 128 int64_t prevClockUs; 129 } midi; 130 }; 131 132 #endif 133 134 #endif 135