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