Files
lmms/plugins/MidiExport/MidiFile.hpp
saker b2f2fc4ad1 Revisit the initialization for local variables (#7143)
* clang-tidy: Apply cppcoreguidelines-init-variables everywhere (treating NaNs as zeros)

* Initialize msec and tick outside switch

* Update plugins/Vestige/Vestige.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/Vestige/Vestige.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/Vestige/Vestige.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/VstEffect/VstEffectControls.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/VstEffect/VstEffectControls.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/VstEffect/VstEffectControls.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Use initialization with =

* Use tabs

* Use static_cast

* Update DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Do not use tabs for alignment in src/core/DrumSynth.cpp

Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>

* Move x variable inside loop

* Use ternary operator for b variable

* Revert "Use tabs"

This reverts commit 07afd8a83f58b539c3673310b2aad4b63c9198a0.

* Remove unnecessary variables in XpressiveView

* Simplify initialization in Plugin

* Combine declaration and initialization in EqCurve

* Combine declaration and initialization in Song

* Combine declaration and initialization in AudioAlsa

* Combine declaration and initialization in EqCurve (again)

* Missed some

* Undo changes made to non-LMMS files

* Undo indentation changes in SidInstrument.cpp

* Combine declaration with assignment in IoHelper

* Combine declaration with assignment using auto in Carla

* Combine declaration with assignment

* Combine declaration with assignment in BasicFilters

* Simplify assignments in AudioFileProcessorWaveView::zoom

* Simplify out sample variable in BitInvader

* Remove sampleLength variable in DelayEffect

* Move gain variable in DynamicsProcessor

* Combine peak variable declaration with assignment in EqSpectrumView

* Move left/right lfo variables in for loop in FlangerEffect

* Use ternary operator for group variable in LadspaControlDialog

* Combine declaration with assignment in Lb302

* Combine declaration with assignment in MidiExport

* Combine declaration with assignment in MidiFile

* Combine declaration with assignment in MidiImport

* Use ternary operator for vel_adjusted variable in OpulenZ

* Move tmpL and dcblkL variables in for loop in ReverbSC

* Combine declaration with initialization in SlicerT

* Combine declaration with assignment in SaSpectrumView

* Combine declaration with assignment in SaWaterfallView

* Combine declaration with assignment in StereoEnhancerEffect

* Combine declaration with assignment in VibratingString

* Combine declaration with assignment in VstEffectControls

* Combine declaration with assignment in Xpressive

* Combine declaration with assignment in AutomatableModel

* Combine declaration with assignment in AutomationClip

* Move sample variable in for loop in BandLimitedWave

* Combine declaration with assignment in DataFile

* Combine declaration with assignment in DrumSynth

* Combine declaration with assignment in Effect

* Remove redundant assignment to nphsLeft in InstrumentPlayHandle

* Combine declaration with assignment in LadspaManager

* Combine declaration with assignment in LinkedModelGroups

* Combine declaration with assignment in MemoryHelper

* Combine declaration with assignment in AudioAlsa

* Combine declaration with assignment in AudioFileOgg

* Combine declaration with assignment in AudioPortAudio

* Combine declaration with assignment in AudioSoundIo

* Combine declaration with assignment in Lv2Evbuf

* Combine declaration with assignment in Lv2Proc

* Combine declaration with assignment in main

* Combine declaration with assignment in MidiAlsaRaw

* Combine declaration with assignment in MidiAlsaSeq

* Combine declaration with assignment in MidiController

* Combine declaration with assignment in MidiJack

* Combine declaration with assignment in MidiSndio

* Combine declaration with assignment in ControlLayout

* Combine declaration with assignment in MainWindow

* Combine declaration with assignment in ProjectNotes

* Use ternary operator for nextValue variable in AutomationClipView

* Combine declaration with assignment in AutomationEditor

* Move length variable in for-loop in PianoRoll

* Combine declaration with assignment in ControllerConnectionDialog

* Combine declaration with assignment in Graph

* Combine declaration with assignment in LcdFloatSpinBox

* Combine declaration with assignment in TimeDisplayWidget

* Remove currentNote variable in InstrumentTrack

* Combine declaration with assignment in DrumSynth (again)

* Use ternary operator for factor variable in BitInvader

* Use ternary operator for highestBandwich variable in EqCurve

Bandwich?

* Move sum variable into for loop in Graph

* Fix format in MidiSndio

* Fixup a few more

* Cleanup error variables

* Use ternary operators and combine declaration with initialization

* Combine declaration with initialization

* Update plugins/LadspaEffect/LadspaControlDialog.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/OpulenZ/OpulenZ.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update plugins/SpectrumAnalyzer/SaProcessor.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/midi/MidiAlsaRaw.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/gui/MainWindow.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/gui/clips/AutomationClipView.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/gui/editors/AutomationEditor.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/gui/widgets/Fader.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Move static_cast conversion into separate variable

* Use real index when interpolating

* Remove empty line

* Make helpBtn a private member

* Move controller type into separate variable

* Fix format of DrumSynth::waveform function

* Use tabs and static_cast

* Remove redundant if branch

* Refactor using static_cast/reinterpret_cast

* Add std namespace prefix

* Store repeated conditional into boolean variable

* Cast to int before assigning to m_currentLength

* Rename note_frames to noteFrames

* Update src/core/Controller.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/core/DrumSynth.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Update src/gui/widgets/Graph.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Revert changes that initialized variables redudantly

For situations where the initialization is
more complex or passed into a function
by a pointer, we dont need to do
initialization ourselves since it is
already done for us, just in a different way.

* Remove redundant err variable

* Remove explicit check of err variable

* Clean up changes and address review

* Do not initialize to 0/nullptr when not needed

* Wrap condition in parentheses for readability

---------

Co-authored-by: Kevin Zander <veratil@gmail.com>
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
2024-03-28 17:21:31 -04:00

328 lines
7.8 KiB
C++

#ifndef MIDIFILE_HPP
#define MIDIFILE_HPP
/**
* Name: MidiFile.hpp
* Purpose: C++ re-write of the python module MidiFile.py
* Author: Mohamed Abdel Maksoud <mohamed at amaksoud.com>
*-----------------------------------------------------------------------------
* Name: MidiFile.py
* Purpose: MIDI file manipulation utilities
*
* Author: Mark Conway Wirt <emergentmusics) at (gmail . com>
*
* Created: 2008/04/17
* Copyright: (c) 2009 Mark Conway Wirt
* License: Please see License.txt for the terms under which this
* software is distributed.
*-----------------------------------------------------------------------------
*/
#include <string.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <assert.h>
#include <array>
using std::string;
using std::vector;
using std::set;
namespace MidiFile
{
const int TICKSPERBEAT = 128;
int writeVarLength(uint32_t val, uint8_t *buffer)
{
/*
Accept an input, and write a MIDI-compatible variable length stream
The MIDI format is a little strange, and makes use of so-called variable
length quantities. These quantities are a stream of bytes. If the most
significant bit is 1, then more bytes follow. If it is zero, then the
byte in question is the last in the stream
*/
int size = 0;
uint8_t little_endian[4];
uint8_t result = val & 0x7F;
little_endian[size++] = result;
val = val >> 7;
while (val > 0)
{
result = val & 0x7F;
result = result | 0x80;
little_endian[size++] = result;
val = val >> 7;
}
for (int i=0; i<size; i++)
{
buffer[i] = little_endian[size-i-1];
}
return size;
}
int writeBigEndian4(uint32_t val, uint8_t *buf)
{
buf[0] = val >> 24;
buf[1] = val >> 16 & 0xff;
buf[2] = val >> 8 & 0xff;
buf[3] = val & 0xff;
return 4;
}
int writeBigEndian2(uint16_t val, uint8_t *buf)
{
buf[0] = val >> 8 & 0xff;
buf[1] = val & 0xff;
return 2;
}
class MIDIHeader
{
// Class to encapsulate the MIDI header structure.
uint16_t numTracks;
uint16_t ticksPerBeat;
public:
MIDIHeader(uint16_t nTracks, uint16_t ticksPB=TICKSPERBEAT): numTracks(nTracks), ticksPerBeat(ticksPB) {}
inline int writeToBuffer(uint8_t *buffer, int start=0) const
{
// chunk ID
buffer[start++] = 'M'; buffer[start++] = 'T'; buffer[start++] = 'h'; buffer[start++] = 'd';
// chunk size (6 bytes always)
buffer[start++] = 0; buffer[start++] = 0; buffer[start++] = 0; buffer[start++] = 0x06;
// format: 1 (multitrack)
buffer[start++] = 0; buffer[start++] = 0x01;
start += writeBigEndian2(numTracks, buffer+start);
start += writeBigEndian2(ticksPerBeat, buffer+start);
return start;
}
};
struct Event
{
uint32_t time;
uint32_t tempo;
string trackName;
enum {NOTE_ON, NOTE_OFF, TEMPO, PROG_CHANGE, TRACK_NAME} type;
// TODO make a union to save up space
uint8_t pitch;
uint8_t programNumber;
uint8_t duration;
uint8_t volume;
uint8_t channel;
Event() {time=tempo=pitch=programNumber=duration=volume=channel=0; trackName="";}
inline int writeToBuffer(uint8_t *buffer) const
{
int size = 0;
switch (type)
{
case NOTE_ON:
{
uint8_t code = 0x9 << 4 | channel;
size += writeVarLength(time, buffer+size);
buffer[size++] = code;
buffer[size++] = pitch;
buffer[size++] = volume;
break;
}
case NOTE_OFF:
{
uint8_t code = 0x8 << 4 | channel;
size += writeVarLength(time, buffer+size);
buffer[size++] = code;
buffer[size++] = pitch;
buffer[size++] = volume;
break;
}
case TEMPO:
{
uint8_t code = 0xFF;
size += writeVarLength(time, buffer+size);
buffer[size++] = code;
buffer[size++] = 0x51;
buffer[size++] = 0x03;
std::array<uint8_t, 4> fourbytes;
writeBigEndian4(int(60000000.0 / tempo), fourbytes.data());
//printf("tempo of %x translates to ", tempo);
/*
for (int i=0; i<3; i++) printf("%02x ", fourbytes[i+1]);
printf("\n");
*/
buffer[size++] = fourbytes[1];
buffer[size++] = fourbytes[2];
buffer[size++] = fourbytes[3];
break;
}
case PROG_CHANGE:
{
uint8_t code = 0xC << 4 | channel;
size += writeVarLength(time, buffer+size);
buffer[size++] = code;
buffer[size++] = programNumber;
break;
}
case TRACK_NAME:
{
size += writeVarLength(time, buffer+size);
buffer[size++] = 0xFF;
buffer[size++] = 0x03;
size += writeVarLength(trackName.size(), buffer+size);
trackName.copy((char *)(&buffer[size]), trackName.size());
size += trackName.size();
break;
// buffer[size++] = '\0';
// buffer[size++] = '\0';
}
}
return size;
} // writeEventsToBuffer
// events are sorted by their time
inline bool operator < (const Event& b) const {
return this->time < b.time ||
(this->time == b.time && this->type > b.type);
}
};
template<const int MAX_TRACK_SIZE>
class MIDITrack
{
// A class that encapsulates a MIDI track
// Nested class definitions.
vector<Event> events;
public:
uint8_t channel;
MIDITrack(): channel(0) {}
inline void addEvent(const Event &e)
{
Event E = e;
events.push_back(E);
}
inline void addNote(uint8_t pitch, uint8_t volume, double time, double duration)
{
Event event; event.channel = channel;
event.volume = volume;
event.type = Event::NOTE_ON; event.pitch = pitch; event.time= (uint32_t) (time * TICKSPERBEAT);
addEvent(event);
event.type = Event::NOTE_OFF; event.pitch = pitch; event.time=(uint32_t) ((time+duration) * TICKSPERBEAT);
addEvent(event);
//printf("note: %d-%d\n", (uint32_t) time * TICKSPERBEAT, (uint32_t)((time+duration) * TICKSPERBEAT));
}
inline void addName(const string &name, uint32_t time)
{
Event event; event.channel = channel;
event.type = Event::TRACK_NAME; event.time=time; event.trackName = name;
addEvent(event);
}
inline void addProgramChange(uint8_t prog, uint32_t time)
{
Event event; event.channel = channel;
event.type = Event::PROG_CHANGE; event.time=time; event.programNumber = prog;
addEvent(event);
}
inline void addTempo(uint32_t tempo, uint32_t time)
{
Event event;
event.channel = channel;
event.type = Event::TEMPO;
event.time = time;
event.tempo = tempo;
addEvent(event);
}
inline int writeMIDIToBuffer(uint8_t *buffer, int start=0) const
{
// Write the meta data and note data to the packed MIDI stream.
// Process the events in the eventList
start += writeEventsToBuffer(buffer, start);
// Write MIDI close event.
buffer[start++] = 0x00;
buffer[start++] = 0xFF;
buffer[start++] = 0x2F;
buffer[start++] = 0x00;
// return the entire length of the data and write to the header
return start;
}
inline int writeEventsToBuffer(uint8_t *buffer, int start=0) const
{
// Write the events in MIDIEvents to the MIDI stream.
vector<Event> _events = events;
std::sort(_events.begin(), _events.end());
vector<Event>::const_iterator it;
uint32_t time_last = 0;
for (it = _events.begin(); it!=_events.end(); ++it)
{
Event e = *it;
if (e.time < time_last){
printf("error: e.time=%d time_last=%d\n", e.time, time_last);
assert(false);
}
uint32_t tmp = e.time;
e.time -= time_last;
time_last = tmp;
start += e.writeToBuffer(buffer+start);
if (start >= MAX_TRACK_SIZE) {
break;
}
}
return start;
}
inline int writeToBuffer(uint8_t *buffer, int start=0) const
{
uint8_t eventsBuffer[MAX_TRACK_SIZE];
uint32_t events_size = writeMIDIToBuffer(eventsBuffer);
//printf(">> track %lu events took 0x%x bytes\n", events.size(), events_size);
// chunk ID
buffer[start++] = 'M'; buffer[start++] = 'T'; buffer[start++] = 'r'; buffer[start++] = 'k';
// chunk size
start += writeBigEndian4(events_size, buffer+start);
// copy events data
memmove(buffer+start, eventsBuffer, events_size);
start += events_size;
return start;
}
};
}; // namespace
#endif