Implement midi player using Windows API
This commit is contained in:
85
src/midiPlayer.cpp
Normal file
85
src/midiPlayer.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "midiPlayer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Default constructor */
|
||||
MidiPlayer::MidiPlayer()
|
||||
{
|
||||
init();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
MidiPlayer::MidiPlayer(const std::span<const pitches::Note> notes)
|
||||
{
|
||||
init();
|
||||
playBuffer(notes);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Set MIDI instrument */
|
||||
void MidiPlayer::setInstrument(uint8_t instrument) const
|
||||
{
|
||||
if (instrument > 127)
|
||||
instrument = 0; // Default to Acoustic Grand Piano if out of range
|
||||
|
||||
const DWORD message = 0xC0 | (instrument << 8); // Program Change
|
||||
midiOutShortMsg(m_midiOut, message);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
MidiPlayer::~MidiPlayer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Play a MIDI buffer */
|
||||
void MidiPlayer::playBuffer(const std::span<const pitches::Note> notes) const
|
||||
{
|
||||
for (const auto note : notes)
|
||||
{
|
||||
const auto noteNumber = frequencyToMidiNote(note.frequency);
|
||||
|
||||
// Send Note On message (0x90) with the note number and velocity
|
||||
DWORD message = 0x90 | (noteNumber << 8) | (m_velocity << 16); // Note On
|
||||
midiOutShortMsg(m_midiOut, message);
|
||||
|
||||
// Wait for the duration of the note
|
||||
std::this_thread::sleep_for(note.duration);
|
||||
|
||||
// Send Note Off message (0x80) with the note number
|
||||
message = 0x80 | (noteNumber << 8); // Note Off
|
||||
midiOutShortMsg(m_midiOut, message);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Initialize MIDI output */
|
||||
void MidiPlayer::init()
|
||||
{
|
||||
midiOutOpen(&m_midiOut, // phmo
|
||||
0, // uDeviceID
|
||||
0, // dwCallback
|
||||
0, // dwInstance
|
||||
CALLBACK_NULL); // fdwOpen
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Release MIDI output */
|
||||
void MidiPlayer::release()
|
||||
{
|
||||
midiOutClose(m_midiOut);
|
||||
m_midiOut = nullptr;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Convert frequency to MIDI note number */
|
||||
int MidiPlayer::frequencyToMidiNote(const uint16_t frequency) const
|
||||
{
|
||||
constexpr double A4_FREQUENCY = 440.0;
|
||||
constexpr double A4_MIDI_NOTE = 69.0;
|
||||
constexpr double SEMITONES_PER_OCTAVE = 12.0;
|
||||
|
||||
if (frequency == 0)
|
||||
return 0; // Silent
|
||||
|
||||
return static_cast<int>(std::round(A4_MIDI_NOTE + SEMITONES_PER_OCTAVE * log2(static_cast<double>(frequency) / A4_FREQUENCY)));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
38
src/midiPlayer.h
Normal file
38
src/midiPlayer.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "pitches/pitches.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
#include <windows.h>
|
||||
|
||||
// Include the Windows Multimedia API header for MIDI functions
|
||||
#include <mmsystem.h>
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class MidiPlayer
|
||||
{
|
||||
public:
|
||||
MidiPlayer(); // Default constructor
|
||||
virtual ~MidiPlayer(); // Default destructor
|
||||
MidiPlayer(const MidiPlayer &obj) = delete; // Copy constructor
|
||||
MidiPlayer(MidiPlayer &&obj) noexcept = delete; // Move constructor
|
||||
MidiPlayer &operator=(const MidiPlayer &obj) = delete; // Copy assignment operator
|
||||
MidiPlayer &operator=(MidiPlayer &&obj) noexcept = delete; // Move assignment operator
|
||||
|
||||
explicit MidiPlayer(std::span<const pitches::Note> notes); // Constructor
|
||||
|
||||
void setInstrument(uint8_t instrument) const; // Set MIDI instrument
|
||||
void playBuffer(std::span<const pitches::Note> notes) const; // Play a MIDI buffer
|
||||
|
||||
protected:
|
||||
HMIDIOUT m_midiOut = nullptr;
|
||||
uint16_t m_velocity = 127; // MIDI velocity (0-127)
|
||||
|
||||
private:
|
||||
void init(); // Initialize MIDI output
|
||||
void release(); // Release MIDI output
|
||||
|
||||
[[nodiscard]] int frequencyToMidiNote(uint16_t frequency) const; // Convert frequency to MIDI note number
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
Reference in New Issue
Block a user