1 /*
2  * Copyright (C) 2020-2021 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of Zrythm
5  *
6  * Zrythm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Zrythm is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "audio/midi_file.h"
21 
22 #include <ext/midilib/src/midifile.h>
23 
24 #include <gtk/gtk.h>
25 
26 /**
27  * Returns whether the given track in the midi file
28  * has data.
29  */
30 bool
midi_file_track_has_data(const char * abs_path,int track_idx)31 midi_file_track_has_data (
32   const char * abs_path,
33   int          track_idx)
34 {
35   MIDI_FILE * mf = midiFileOpen (abs_path);
36   g_return_val_if_fail (mf, false);
37 
38   MIDI_MSG msg;
39   midiReadInitMessage (&msg);
40 
41   int ev;
42   g_debug ("reading MIDI Track %d", track_idx);
43   bool have_data = false;
44   while (midiReadGetNextMessage (
45            mf, track_idx, &msg))
46     {
47       if (msg.bImpliedMsg)
48         {
49           ev = msg.iImpliedMsg;
50         }
51       else
52         {
53           ev = msg.iType;
54         }
55 
56       switch(ev)
57         {
58         case msgNoteOff:
59         case msgMetaEvent:
60           break;
61         case msgNoteOn:
62         case msgNoteKeyPressure:
63         case msgSetParameter:
64         case msgSetProgram:
65         case msgChangePressure:
66         case msgSetPitchWheel:
67         case msgSysEx1:
68         case msgSysEx2:
69           have_data = true;
70           break;
71         }
72 
73       if (have_data)
74         {
75           break;
76         }
77     }
78 
79   midiReadFreeMessage (&msg);
80   midiFileClose (mf);
81 
82   return have_data;
83 }
84 
85 /**
86  * Returns the number of tracks in the MIDI file.
87  */
88 int
midi_file_get_num_tracks(const char * abs_path,bool non_empty_only)89 midi_file_get_num_tracks (
90   const char * abs_path,
91   bool         non_empty_only)
92 {
93   MIDI_FILE * mf =
94     midiFileOpen (abs_path);
95   g_return_val_if_fail (mf, -1);
96 
97   int actual_num = 0;
98 
99   int num = midiReadGetNumTracks (mf);
100   g_debug ("%s: num tracks = %d", abs_path, num);
101 
102   if (!non_empty_only)
103   {
104     midiFileClose (mf);
105     return num;
106   }
107 
108   for (int i = 0; i < num; i++)
109     {
110       if (midi_file_track_has_data (abs_path, i))
111         {
112           actual_num++;
113         }
114     }
115 
116   midiFileClose (mf);
117 
118   return actual_num;
119 }
120