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

Add Windows native MIDI support #3431

Merged
merged 9 commits into from
Dec 6, 2024
89 changes: 89 additions & 0 deletions src/sound/asio/sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,23 @@ CSound::CSound ( void ( *fpNewCallback ) ( CVector<int16_t>& psData, void* arg )
asioCallbacks.sampleRateDidChange = &sampleRateChanged;
asioCallbacks.asioMessage = &asioMessages;
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;

// Optional MIDI initialization --------------------------------------------
if ( iCtrlMIDIChannel != INVALID_MIDI_CH )
{
MidiStart();
}
}

CSound::~CSound()
{
// stop MIDI if running
if ( iCtrlMIDIChannel != INVALID_MIDI_CH )
{
MidiStop();
}

UnloadCurrentDriver();
}

void CSound::ResetChannelMapping()
Expand Down Expand Up @@ -1218,3 +1235,75 @@ int64_t CSound::Flip64Bits ( const int64_t iIn )

return iOut;
}

// Windows Native MIDI support
void CSound::MidiStart()
{
/* Get the number of MIDI In devices in this computer */
iMidiDevs = midiInGetNumDevs();
if ( iMidiDevs > MAX_MIDI_DEVS )
{
iMidiDevs = MAX_MIDI_DEVS;
}

// printf("Found %d MIDI device%s\n", iMidiDevs, iMidiDevs == 1 ? "" : "s");

// open all connected MIDI devices and set the callback function to handle incoming messages
softins marked this conversation as resolved.
Show resolved Hide resolved
for ( int i = 0; i < iMidiDevs; i++ )
{
MMRESULT result = midiInOpen ( &hMidiIn[i], i, (DWORD_PTR) MidiCallback, 0, CALLBACK_FUNCTION );

if ( result != MMSYSERR_NOERROR )
{
qWarning() << "! Failed to open MIDI input device. Error code: " << result;
hMidiIn[i] = 0;
return;
}

result = midiInStart ( hMidiIn[i] );

if ( result != MMSYSERR_NOERROR )
{
qWarning() << "! Failed to start MIDI input. Error code: " << result;
midiInClose ( hMidiIn[i] );
hMidiIn[i] = 0;
return;
}
}
}

void CSound::MidiStop()
{
// stop MIDI if running
for ( int i = 0; i < iMidiDevs; i++ )
{
if ( hMidiIn[i] != 0 )
{
midiInStop ( hMidiIn[i] );
midiInClose ( hMidiIn[i] );
}
}
}

void CALLBACK CSound::MidiCallback ( HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
{
Q_UNUSED ( hMidiIn );
Q_UNUSED ( dwInstance );
Q_UNUSED ( dwParam2 );

if ( wMsg == MIM_DATA )
{
BYTE status = dwParam1 & 0xFF;
ann0see marked this conversation as resolved.
Show resolved Hide resolved
BYTE data1 = ( dwParam1 >> 8 ) & 0xFF;
BYTE data2 = ( dwParam1 >> 16 ) & 0xFF;

// copy packet and send it to the MIDI parser
CVector<uint8_t> vMIDIPaketBytes ( 3 );

vMIDIPaketBytes[0] = static_cast<uint8_t> ( status );
vMIDIPaketBytes[1] = static_cast<uint8_t> ( data1 );
vMIDIPaketBytes[2] = static_cast<uint8_t> ( data2 );

pSound->ParseMIDIMessage ( vMIDIPaketBytes );
}
}
12 changes: 11 additions & 1 deletion src/sound/asio/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class CSound : public CSoundBase
public:
CSound ( void ( *fpNewCallback ) ( CVector<int16_t>& psData, void* arg ), void* arg, const QString& strMIDISetup, const bool, const QString& );

virtual ~CSound() { UnloadCurrentDriver(); }
virtual ~CSound();

virtual int Init ( const int iNewPrefMonoBufferSize );
virtual void Start();
Expand Down Expand Up @@ -134,4 +134,14 @@ class CSound : public CSoundBase
static long asioMessages ( long selector, long value, void* message, double* opt );

char* cDriverNames[MAX_NUMBER_SOUND_CARDS];

// Windows native MIDI
#define MAX_MIDI_DEVS 4
softins marked this conversation as resolved.
Show resolved Hide resolved

int iMidiDevs;
HMIDIIN hMidiIn[MAX_MIDI_DEVS]; // windows handles

void MidiStart();
void MidiStop();
static void CALLBACK MidiCallback ( HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 );
};
Loading