1 /* 2 * 0BSD 3 * 4 * BSD Zero Clause License 5 * 6 * Copyright (c) 2020 Hermann Meyer 7 * 8 * Permission to use, copy, modify, and/or distribute this software for any 9 * purpose with or without fee is hereby granted. 10 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 16 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 * 19 */ 20 21 22 // workaround for libsmf which include glib.h in a extern "C" block 23 // that lead to a error when build with c++17 24 25 extern "C++" { 26 #include <type_traits> 27 } 28 29 #include <smf.h> 30 31 #include <atomic> 32 #include <vector> 33 #include <algorithm> 34 #include <thread> 35 #include <mutex> 36 #include <condition_variable> 37 #include <cmath> 38 39 #pragma once 40 41 #ifndef MAMBA_H 42 #define MAMBA_H 43 44 namespace mamba { 45 46 47 /**************************************************************** 48 ** struct MidiEvent 49 ** 50 ** store midi events in a vector 51 ** 52 */ 53 54 typedef struct { 55 unsigned char buffer[3]; 56 int num; 57 double deltaTime; 58 double absoluteTime; 59 } MidiEvent; 60 61 62 /**************************************************************** 63 ** class MidiMessenger 64 ** 65 ** create, collect and send all midi events to jack_midi out buffer 66 */ 67 68 class MidiMessenger { 69 private: 70 static const int max_midi_cc_cnt = 25; 71 std::atomic<bool> send_cc[max_midi_cc_cnt]; 72 uint8_t cc_num[max_midi_cc_cnt]; 73 uint8_t pg_num[max_midi_cc_cnt]; 74 uint8_t bg_num[max_midi_cc_cnt]; 75 uint8_t me_num[max_midi_cc_cnt]; 76 public: 77 MidiMessenger(); 78 int channel; 79 bool send_midi_cc(uint8_t _cc, const uint8_t _pg, const uint8_t _bgn, 80 const uint8_t _num, const bool have_channel) noexcept; 81 int next(int i = -1) const noexcept; size(const int i)82 inline uint8_t size(const int i) const noexcept { return me_num[i]; } 83 void fill(unsigned char *midi_send, const int i) noexcept; 84 }; 85 86 87 /**************************************************************** 88 ** class MidiLoad 89 ** 90 ** load data from midi file 91 ** 92 */ 93 94 class MidiLoad { 95 private: 96 smf_t *smf; 97 smf_track_t *tracks; 98 smf_event_t *smf_event; 99 MidiEvent ev; 100 void reset_smf(); 101 double deltaTime; 102 double absoluteTime; 103 bool load_file(std::vector<MidiEvent> *play, int *song_bpm, const char* file_name); 104 105 public: 106 MidiLoad(); 107 ~MidiLoad(); 108 std::vector<int> positions; 109 bool load_from_file(std::vector<MidiEvent> *play, int *song_bpm, const char* file_name); 110 bool add_from_file(std::vector<MidiEvent> *play, int *song_bpm, const char* file_name); 111 void remove_file(std::vector<MidiEvent> *play, int f); 112 }; 113 114 115 /**************************************************************** 116 ** class MidiSave 117 ** 118 ** save data to midi file 119 ** 120 */ 121 122 class MidiSave { 123 private: 124 smf_t *smf; 125 std::vector<smf_track_t*> tracks; 126 smf_event_t *smf_event; 127 int channel; 128 void reset_smf(); 129 double get_max_time(std::vector<MidiEvent> *play) noexcept; 130 131 public: 132 MidiSave(); 133 ~MidiSave(); 134 int freewheel; 135 136 void save_to_file(std::vector<MidiEvent> *play, const char* file_name); 137 }; 138 139 140 /**************************************************************** 141 ** class MidiRecord 142 ** 143 ** record the keyboard input in a extra thread 144 ** 145 */ 146 147 class MidiRecord { 148 private: 149 std::atomic<bool> _execute; 150 std::thread _thd; 151 std::mutex m; 152 153 public: 154 MidiRecord(); 155 ~MidiRecord(); 156 int channel; 157 void stop(); 158 void start(); 159 std::atomic<bool> is_sorted; 160 bool is_running() const noexcept; 161 std::condition_variable cv; 162 MidiEvent ev; 163 std::vector<MidiEvent> *st; 164 std::vector<MidiEvent> play[16]; 165 }; 166 167 168 } // namespace mamba 169 170 #endif //MAMBA_H_ 171