Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored GOMidiPlayer for playing midi events though GOMidi instead of GOMOrganController #2040

Merged
merged 1 commit into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/core/midi/GOMidiEvent.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright 2006 Milan Digital Audio LLC
* Copyright 2009-2023 GrandOrgue contributors (see AUTHORS)
* Copyright 2009-2024 GrandOrgue contributors (see AUTHORS)
* License GPL-2.0 or later
* (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
*/
Expand All @@ -20,7 +20,8 @@ GOMidiEvent::GOMidiEvent()
m_time(0),
m_string(),
m_data(),
m_IsToUseNoteOff(true) {}
m_IsToUseNoteOff(true),
m_IsAllowedToReload(true) {}

GOMidiEvent::GOMidiEvent(const GOMidiEvent &e)
: m_MidiType(e.m_MidiType),
Expand All @@ -31,7 +32,8 @@ GOMidiEvent::GOMidiEvent(const GOMidiEvent &e)
m_time(e.m_time),
m_string(e.m_string.Clone()),
m_data(e.m_data),
m_IsToUseNoteOff(e.m_IsToUseNoteOff) {}
m_IsToUseNoteOff(e.m_IsToUseNoteOff),
m_IsAllowedToReload(e.m_IsAllowedToReload) {}

void GOMidiEvent::SetString(const wxString &str, unsigned length) {
unsigned len = str.length();
Expand Down
10 changes: 9 additions & 1 deletion src/core/midi/GOMidiEvent.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright 2006 Milan Digital Audio LLC
* Copyright 2009-2023 GrandOrgue contributors (see AUTHORS)
* Copyright 2009-2024 GrandOrgue contributors (see AUTHORS)
* License GPL-2.0 or later
* (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
*/
Expand Down Expand Up @@ -56,6 +56,11 @@ class GOMidiEvent {
wxString m_string;
std::vector<uint8_t> m_data;
bool m_IsToUseNoteOff;
/**
* Is allowing to close the organ and to load another organ when playing this
* midi event
*/
bool m_IsAllowedToReload;

public:
GOMidiEvent();
Expand Down Expand Up @@ -95,6 +100,9 @@ class GOMidiEvent {

void SetUseNoteOff(bool useNoteOff) { m_IsToUseNoteOff = useNoteOff; }
bool IsUsingNoteOff() const { return m_IsToUseNoteOff; }

bool IsAllowedToReload() const { return m_IsAllowedToReload; }
void SetAllowedToReload(bool value) { m_IsAllowedToReload = value; }
};

#endif
3 changes: 2 additions & 1 deletion src/grandorgue/GOOrganController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ void GOOrganController::Abort() {

GOEventDistributor::AbortPlayback();

m_MidiPlayer->StopPlaying();
m_MidiPlayer->Cleanup();
m_MidiRecorder->StopRecording();
m_AudioRecorder->StopRecording();
m_AudioRecorder->SetAudioRecorder(NULL);
Expand Down Expand Up @@ -1064,6 +1064,7 @@ void GOOrganController::PreparePlayback(

GOEventDistributor::StartPlayback();
GOEventDistributor::PrepareRecording();
m_MidiPlayer->Setup(midi);

// Light the OnState button
if (p_OnStateButton) {
Expand Down
14 changes: 8 additions & 6 deletions src/grandorgue/gui/frames/GOFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1345,12 +1345,14 @@ void GOFrame::OnMidiEvent(const GOMidiEvent &event) {
_("MIDI event: ") + event.ToString(m_Sound.GetMidi().GetMidiMap()));
}

ptr_vector<GOOrgan> &organs = m_config.GetOrganList();
for (unsigned i = 0; i < organs.size(); i++)
if (organs[i]->Match(event) && organs[i]->IsUsable(m_config)) {
SendLoadOrgan(*organs[i]);
return;
}
if (event.IsAllowedToReload()) {
ptr_vector<GOOrgan> &organs = m_config.GetOrganList();
for (auto pOrgan : organs)
if (pOrgan->Match(event) && pOrgan->IsUsable(m_config)) {
SendLoadOrgan(*pOrgan);
break;
}
}
}

void GOFrame::OnSetTitle(wxCommandEvent &event) {
Expand Down
5 changes: 3 additions & 2 deletions src/grandorgue/midi/GOMidi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,14 @@ void GOMidi::Recv(const GOMidiEvent &e) {
AddPendingEvent(event);
}

void GOMidi::OnMidiEvent(wxMidiEvent &event) {
GOMidiEvent e = event.GetMidiEvent();
void GOMidi::PlayEvent(const GOMidiEvent &e) {
for (unsigned i = 0; i < m_Listeners.size(); i++)
if (m_Listeners[i])
m_Listeners[i]->Send(e);
}

void GOMidi::OnMidiEvent(wxMidiEvent &e) { PlayEvent(e.GetMidiEvent()); }

void GOMidi::Send(const GOMidiEvent &e) {
for (unsigned j = 0; j < m_midi_out_devices.size(); j++)
((GOMidiOutPort *)m_midi_out_devices[j])->Send(e);
Expand Down
5 changes: 3 additions & 2 deletions src/grandorgue/midi/GOMidi.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright 2006 Milan Digital Audio LLC
* Copyright 2009-2023 GrandOrgue contributors (see AUTHORS)
* Copyright 2009-2024 GrandOrgue contributors (see AUTHORS)
* License GPL-2.0 or later
* (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
*/
Expand Down Expand Up @@ -33,7 +33,6 @@ class GOMidi : public wxEvtHandler {
int m_transpose;
std::vector<GOMidiListener *> m_Listeners;
GOMidiPortFactory m_MidiFactory;
void OnMidiEvent(wxMidiEvent &event);

public:
GOMidi(GOConfig &settings);
Expand All @@ -43,6 +42,8 @@ class GOMidi : public wxEvtHandler {
void UpdateDevices(const GOPortsConfig &portsConfig);

void Recv(const GOMidiEvent &e);
void PlayEvent(const GOMidiEvent &e);
void OnMidiEvent(wxMidiEvent &e);
void Send(const GOMidiEvent &e);

const ptr_vector<GOMidiPort> &GetInDevices() const {
Expand Down
66 changes: 38 additions & 28 deletions src/grandorgue/midi/GOMidiPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "midi/GOMidiMap.h"

#include "GOEvent.h"
#include "GOMidi.h"
#include "GOOrganController.h"

enum {
Expand All @@ -38,24 +39,29 @@ const struct GOElementCreator::ButtonDefinitionEntry *GOMidiPlayer::
return m_element_types;
}

void GOMidiPlayer::ResetUI() {
m_buttons[ID_MIDI_PLAYER_PLAY]->Display(false);
m_buttons[ID_MIDI_PLAYER_PAUSE]->Display(false);
UpdateDisplay();
}

GOMidiPlayer::GOMidiPlayer(GOOrganController *organController)
: m_OrganController(organController),
: r_MidiMap(organController->GetSettings().GetMidiMap()),
r_timer(*organController->GetTimer()),
p_midi(nullptr),
m_content(),
m_PlayingTime(organController),
m_Start(0),
m_PlayingSeconds(0),
m_Speed(1),
m_IsPlaying(false),
m_Pause(false) {
CreateButtons(*m_OrganController);
Clear();
m_DeviceID
= m_OrganController->GetSettings().GetMidiMap().GetDeviceIdByLogicalName(
_("GrandOrgue MIDI Player"));
UpdateDisplay();
CreateButtons(*organController);
m_DeviceID = r_MidiMap.GetDeviceIdByLogicalName(_("GrandOrgue MIDI Player"));
ResetUI();
}

GOMidiPlayer::~GOMidiPlayer() { StopPlaying(); }
GOMidiPlayer::~GOMidiPlayer() { Cleanup(); }

void GOMidiPlayer::Load(GOConfigReader &cfg) {
m_buttons[ID_MIDI_PLAYER_PLAY]->Init(cfg, wxT("MidiPlayerPlay"), _("PLAY"));
Expand All @@ -81,15 +87,11 @@ void GOMidiPlayer::ButtonStateChanged(int id, bool newState) {
}
}

void GOMidiPlayer::Clear() {
StopPlaying();
m_content.Clear();
}

void GOMidiPlayer::LoadFile(
const wxString &filename, unsigned manuals, bool pedal) {
Clear();
GOMidiFileReader reader(m_OrganController->GetSettings().GetMidiMap());
StopPlaying();
m_content.Clear();
GOMidiFileReader reader(r_MidiMap);
if (!reader.Open(filename)) {
GOMessageBox(
wxString::Format(_("Failed to load %s"), filename.c_str()),
Expand All @@ -98,11 +100,7 @@ void GOMidiPlayer::LoadFile(
NULL);
return;
}
if (!m_content.Load(
reader,
m_OrganController->GetSettings().GetMidiMap(),
manuals,
pedal)) {
if (!m_content.Load(reader, r_MidiMap, manuals, pedal)) {
m_content.Clear();
GOMessageBox(
wxString::Format(_("Failed to load %s"), filename.c_str()),
Expand Down Expand Up @@ -150,10 +148,17 @@ void GOMidiPlayer::Pause() {
m_Pause = true;
m_buttons[ID_MIDI_PLAYER_PAUSE]->Display(m_Pause);
m_Start = wxGetLocalTimeMillis() - m_Start;
m_OrganController->GetTimer()->DeleteTimer(this);
r_timer.DeleteTimer(this);
}
}

void GOMidiPlayer::PlayMidiEvent(const GOMidiEvent &e) {
GOMidi *pMidi = p_midi;

if (pMidi)
pMidi->PlayEvent(e);
}

void GOMidiPlayer::StopPlaying() {
if (m_IsPlaying) {
for (unsigned i = 1; i < 16; i++) {
Expand All @@ -164,15 +169,14 @@ void GOMidiPlayer::StopPlaying() {
e.SetValue(0);
e.SetDevice(m_DeviceID);
e.SetTime(wxGetLocalTimeMillis());
m_OrganController->ProcessMidi(e);
e.SetAllowedToReload(false);
PlayMidiEvent(e);
}
}

m_IsPlaying = false;
m_buttons[ID_MIDI_PLAYER_PLAY]->Display(false);
m_buttons[ID_MIDI_PLAYER_PAUSE]->Display(false);
UpdateDisplay();
m_OrganController->GetTimer()->DeleteTimer(this);
ResetUI();
r_timer.DeleteTimer(this);
}

bool GOMidiPlayer::IsPlaying() { return m_IsPlaying; }
Expand Down Expand Up @@ -207,12 +211,13 @@ void GOMidiPlayer::HandleTimer() {
}
e.SetDevice(m_DeviceID);
e.SetTime(wxGetLocalTimeMillis());
m_OrganController->ProcessMidi(e);
e.SetAllowedToReload(false);
PlayMidiEvent(e);
} else {
GOTime next = e.GetTime() * m_Speed + m_Start;
if (next > m_Start + m_Speed * (m_PlayingSeconds + 1) * 1000)
next = m_Start + m_Speed * (m_PlayingSeconds + 1) * 1000;
m_OrganController->GetTimer()->SetTimer(next, this);
r_timer.SetTimer(next, this);
return;
}
} while (true);
Expand All @@ -231,3 +236,8 @@ GOLabelControl *GOMidiPlayer::GetLabelControl(
return &m_PlayingTime;
return NULL;
}

void GOMidiPlayer::Cleanup() {
StopPlaying();
p_midi = nullptr;
}
29 changes: 27 additions & 2 deletions src/grandorgue/midi/GOMidiPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@
#include "GOTime.h"
#include "GOTimerCallback.h"

class GOMidi;
class GOMidiMap;
class GOMidiEvent;
class GOMidiFileReader;
class GOOrganController;
class GOTimer;

class GOMidiPlayer : public GOElementCreator, private GOTimerCallback {
private:
GOOrganController *m_OrganController;
GOMidiMap &r_MidiMap;
GOTimer &r_timer;
GOMidi *p_midi;
GOMidiPlayerContent m_content;
GOLabelControl m_PlayingTime;
GOTime m_Start;
Expand All @@ -43,13 +48,28 @@ class GOMidiPlayer : public GOElementCreator, private GOTimerCallback {
void ButtonStateChanged(int id, bool newState) override;

void UpdateDisplay();

/**
* Set the buttons and the display to the initial state
*/
void ResetUI();
/**
* Send midi event to the organ
* @param event the event to process
*/
void PlayMidiEvent(const GOMidiEvent &e);
void HandleTimer() override;

public:
GOMidiPlayer(GOOrganController *organController);
~GOMidiPlayer();

void Clear();
/**
* Set up for playing any midi
* @param pMidi - a pointer to the midi engine
*/
void Setup(GOMidi *pMidi) { p_midi = pMidi; }

void LoadFile(const wxString &filename, unsigned manuals, bool pedal);
bool IsLoaded();

Expand All @@ -61,6 +81,11 @@ class GOMidiPlayer : public GOElementCreator, private GOTimerCallback {
void Load(GOConfigReader &cfg) override;
GOEnclosure *GetEnclosure(const wxString &name, bool is_panel) override;
GOLabelControl *GetLabelControl(const wxString &name, bool is_panel) override;

/**
* Clean up. Playing will be impossible until Setup is called
*/
void Cleanup();
};

#endif
Loading