lmms
Cross-platform music production software
Loading...
Searching...
No Matches
MidiFile.h
Go to the documentation of this file.
1/*
2 * MidiFile.h - support for exporting MIDI files
3 *
4 * Copyright (c) 2009 Mark Conway Wirt <emergentmusics) at (gmail . com>
5 * Copyright (c) 2015 Mohamed Abdel Maksoud <mohamed at amaksoud.com>
6 * Copyright (c) 2020 EmoonX
7 * Copyright (c) 2026 Dalton Messmer <messmer.dalton/at/gmail.com>
8 *
9 * This file was originally based on the Python module MidiFile.py from MIDIUtil
10 * by Mark Conway Wirt, which was later rewritten in C++ by Mohamed Abdel Maksoud.
11 *
12 * --------------------------------------------------------------------------
13 * MIDUTIL, Copyright (c) 2009, Mark Conway Wirt
14 * <emergentmusics) at (gmail . com>
15 *
16 * This software is distributed under an Open Source license, the
17 * details of which follow.
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a
20 * copy of this software and associated documentation files (the "Software"),
21 * to deal in the Software without restriction, including without limitation
22 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23 * and/or sell copies of the Software, and to permit persons to whom the
24 * Software is furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included
27 * in all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
32 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35 * OTHER DEALINGS IN THE SOFTWARE.
36 * --------------------------------------------------------------------------
37 *
38 */
39
40#ifndef LMMS_MIDI_FILE_H
41#define LMMS_MIDI_FILE_H
42
43#include <cstddef>
44#include <filesystem>
45#include <fstream>
46#include <initializer_list>
47#include <span>
48#include <string>
49#include <vector>
50
51#include "LmmsTypes.h"
52#include "MidiPatch.h"
53
54namespace lmms
55{
56
59{
60public:
62 static constexpr tick_t TicksPerBeat = 128;
63
65 static constexpr std::size_t BufferSize = 50 * 1024;
66
67private:
69 class Section
70 {
71 public:
73 std::vector<std::uint8_t> m_buffer;
74
75 protected:
77 Section();
78
81 void writeBytes(std::span<const std::uint8_t> bytes);
82
86 void writeBytes(std::initializer_list<std::uint8_t> bytes);
87
95 void writeVarLength(std::uint32_t val);
96
98 void writeBigEndian4(std::uint32_t val);
99
101 void writeBigEndian2(std::uint16_t val);
102
104 virtual void writeToBuffer() {}
105 };
106
107public:
109 class Header : public Section
110 {
111 public:
113 explicit Header(std::size_t numTracks, tick_t ticksPerBeat = TicksPerBeat);
114
116 void writeToBuffer() override;
117
118 private:
120 const std::size_t m_numTracks;
121
124 };
125
126private:
128 struct Event
129 {
131 enum class Type
132 {
133 NoteOn, NoteOff, Tempo, BankSelectMSB, BankSelectLSB, ProgramChange, TrackName
134 };
135 using enum Type;
136
138
141
143 std::uint8_t channel = 0;
144
146 union
147 {
149 struct
150 {
152 std::uint8_t pitch;
153
155 std::uint8_t volume;
156 }
157 note;
158
160 std::uint32_t tempo = 0;
161
164 };
165
167 // (too much trouble putting it inside union...)
168 std::string trackName;
169
172 bool operator<(const Event& b) const noexcept
173 {
174 if (time < b.time) { return true; }
175 return (time == b.time && type > b.type);
176 }
177 };
178
179public:
181 class Track : public Section
182 {
183 public:
184 void setChannel(std::uint8_t channel) { m_channel = channel; }
185
191 void addNote(std::uint8_t pitch, std::uint8_t volume,
192 double realTime, double duration);
193
195 void addTempo(std::uint32_t tempo, tick_t time);
196
198 void addPatch(MidiPatch patch, tick_t time);
199
201 void addName(std::string name, tick_t time);
202
204 void writeToBuffer();
205
206 private:
208 void addEvent(Event&& event, tick_t time);
209
211 void writeMIDIToBuffer();
212
214 void writeEventsToBuffer();
215
217 void writeSingleEventToBuffer(Event& event);
218
220 std::vector<Event> m_events;
221
223 std::uint8_t m_channel = 0;
224 };
225
228
230 std::vector<Track> m_tracks;
231
235 MidiFile(const std::filesystem::path& file, std::size_t numTracks);
236
238 void writeAllToStream();
239
240private:
242 std::ofstream m_stream;
243};
244
245} // namespace lmms
246
247#endif // LMMS_MIDI_FILE_H
Represents MIDI header info.
Definition MidiFile.h:110
const tick_t m_ticksPerBeat
How many ticks each beat has.
Definition MidiFile.h:123
void writeToBuffer() override
Write header info to buffer.
Definition MidiFile.cpp:126
const std::size_t m_numTracks
Number of tracks in MIDI file.
Definition MidiFile.h:120
Header(std::size_t numTracks, tick_t ticksPerBeat=TicksPerBeat)
Constructor.
Definition MidiFile.cpp:121
void writeBytes(std::span< const std::uint8_t > bytes)
Write bytes to buffer.
Definition MidiFile.cpp:77
void writeBigEndian4(std::uint32_t val)
Buffer gets four 8-bit values from left to right.
Definition MidiFile.cpp:109
void writeVarLength(std::uint32_t val)
Write a MIDI-compatible variable length stream.
Definition MidiFile.cpp:88
void writeBigEndian2(std::uint16_t val)
Buffer gets two 8-bit values from left to right.
Definition MidiFile.cpp:115
Section()
Reserve constant space for BufferSize capacity vector.
Definition MidiFile.cpp:72
std::vector< std::uint8_t > m_buffer
Constant-capacity buffer vector to be written to stream.
Definition MidiFile.h:73
virtual void writeToBuffer()
Write section info to buffer.
Definition MidiFile.h:104
Represents a MIDI track.
Definition MidiFile.h:182
std::uint8_t m_channel
Track channel number.
Definition MidiFile.h:223
void writeSingleEventToBuffer(Event &event)
Write a single event to buffer.
Definition MidiFile.cpp:235
void writeToBuffer()
Write MIDI track to buffer.
Definition MidiFile.cpp:184
std::vector< Event > m_events
Variable-length vector of events.
Definition MidiFile.h:220
void addName(std::string name, tick_t time)
Add a track name event.
Definition MidiFile.cpp:179
void writeMIDIToBuffer()
Write the meta data and note data to buffer.
Definition MidiFile.cpp:205
void addPatch(MidiPatch patch, tick_t time)
Add bank select and program change events.
Definition MidiFile.cpp:172
void addNote(std::uint8_t pitch, std::uint8_t volume, double realTime, double duration)
Add both NOTE_ON and NOTE_OFF effects.
Definition MidiFile.cpp:149
void addTempo(std::uint32_t tempo, tick_t time)
Add a tempo mark.
Definition MidiFile.cpp:167
void writeEventsToBuffer()
Write the sorted events in m_events to buffer.
Definition MidiFile.cpp:214
void setChannel(std::uint8_t channel)
Definition MidiFile.h:184
void addEvent(Event &&event, tick_t time)
Append a single event to vector.
Definition MidiFile.cpp:142
static constexpr tick_t TicksPerBeat
Default number of ticks per single beat.
Definition MidiFile.h:62
std::ofstream m_stream
Write-only data stream.
Definition MidiFile.h:242
MidiFile(const std::filesystem::path &file, std::size_t numTracks)
Open data stream for writing to file and create list of tracks.
Definition MidiFile.cpp:52
void writeAllToStream()
Write all data (both header and tracks) to stream.
Definition MidiFile.cpp:62
std::vector< Track > m_tracks
List of tracks.
Definition MidiFile.h:230
Header m_header
The sole file header.
Definition MidiFile.h:227
static constexpr std::size_t BufferSize
Maximum size of buffers used for each section.
Definition MidiFile.h:65
Definition RemotePluginBase.cpp:34
std::int32_t tick_t
Definition LmmsTypes.h:35
Represents a track event. See Event::Type for more info.
Definition MidiFile.h:129
Type
Possible event types, ordered from most important to least important.
Definition MidiFile.h:132
@ NoteOn
Definition MidiFile.h:133
std::string trackName
Name of track where event is.
Definition MidiFile.h:168
std::uint8_t channel
Channel number where event is.
Definition MidiFile.h:143
bool operator<(const Event &b) const noexcept
Comparison operator Events are sorted by their time (or, in case of tie, type priority).
Definition MidiFile.h:172
tick_t time
Time count when event happens.
Definition MidiFile.h:140
Type type
Definition MidiFile.h:137
Definition MidiPatch.h:34
MidiPatch patch
Bank select and program change.
std::uint32_t tempo
Tempo of event (in BPM).
struct lmms::MidiFile::Event::@061167220312050045362273031331131346236111101304::@142265040301173163372022147112246242240044163111 note