Blitzmax MIDI IN

BlitzMax Forums/BlitzMax Programming/Blitzmax MIDI IN

JRBCM(Posted 2007) [#1]
Anyone know of a way of achieving MIDI IN in blitzmax? I've read the old postings which seem never to have got anywhere, and the FMOD stuff, but no MIDI IN. Anyone planning on doing MIDI stuff for Blitzmax???


Blueapples(Posted 2007) [#2]
This is an interesting idea actually. I am getting more into the MIDI controller scene... never even thought to really write anything for it. A ReWire header would be really cool too...


Nigel Brown(Posted 2007) [#3]
Use portmidi it works! I have a C wrapper for BlitzMax and If I am able to find some time I will post it.


LAB[au](Posted 2007) [#4]
There was an attempt by Nigel Brown with portMidi, not sure if he succeeded.

EDIT : well it seems so! Just a tad faster than me at posting.


Garfield(Posted 2007) [#5]
If I have more time I would like to help

I guess, a professionell way is to integrate the Max/MSP Language into BMAX
maybe its possible and then the whole world of MIDI AUDIO and Video is open for BMAX PRogrammers

http://www.cycling74.com/


LAB[au](Posted 2007) [#6]
max/msp isn't language. Second it's closed source, so no hope to "integrate" it. But you can have max/msp and a program compiled in blitzmax talking, through midi, tcp/ip or osc (this one you would have to code it from scratch).

If you are considering making an osc library for blitzmax, I am in.


Ziltch(Posted 2007) [#7]
What level of midi-in do you need?

I have a simple midi in/out mod working. I use it for controller reading/setting.
It does not do sysex dumps and other more tricky stuff.

I am busy at the moment , but if my arm is twisted I could write a demo and make the module public.


Nigel Brown(Posted 2007) [#8]
Ok a quick hack, hope this helps. Really needs someone to make this into a module Brucey?

Download portmidi28aug06 and place it inside your project.

main.bmx
Strict

Import "portmidi28aug06/porttime/*.h"
Import "portmidi28aug06/porttime/porttime.c"

Import "portmidi28aug06/pm_common/*.h"
Import "portmidi28aug06/pm_common/portmidi.c"


?Win32

	Import "portmidi28aug06/porttime/ptwinmm.c"

	Import "portmidi28aug06/pm_win/*.h"
	Import "portmidi28aug06/pm_win/pmwin.c"
	Import "portmidi28aug06/pm_win/pmdll.c"
	Import "portmidi28aug06/pm_win/pmwinmm.c"

	Import "sysex.cpp"

Framework		brl.d3d7max2d

?MacOS
?Linux
?

Extern "C"		' sysex.cpp

	Global	OutputDevice:Int
	Global	InputDevice:Int
	Global	LoopbackInputDevice:Int
	Global	LoopbackOutputDevice:Int

	Global	midi_message:Byte[]

	Function 	midi_open:Int()
	Function 	midi_close:Int()
	Function 	midi_test:Byte Ptr()

	Function 	loopback_open:Int()
	Function 	loopback_close:Int()
	Function 	loopback_test:Int()

	Function 	get_midi_in()
	Function 	get_midi_out()

	Function 	sysex_receive_open:Int()
	Function 	sysex_receive_get:Byte Ptr()
	Function 	sysex_receive_close:Int()

	Function 	sysex_send( message:Byte Ptr )
	Function 	sysex_send_receive:Byte Ptr( message:Byte Ptr )

	Function 	sysex_initalise()
	Function 	sysex_set_device:Int( device:Byte Ptr, dir:Int )
	Function 	sysex_get_next_device:String( nxt:Int, dir:Int )
	Function 	sysex_get_number_of_devices:Int()

	Function 	sysex_finalise()

End Extern

Global device_enquiry:Byte[]=[ Byte($F0),Byte($7E),Byte($00),Byte($06),Byte($01),Byte($F7) ]

	sysex_initalise()
	Delay(1000)

	' List input / output devices
	For Local i:Int=0 To sysex_get_number_of_devices()-1
	
		If sysex_get_next_device(i,True) = ""
		Else
			DebugLog "Output Device [" + i + "] = " + sysex_get_next_device(i,True)
		EndIf
	
		If sysex_get_next_device(i,False) = ""
		Else
			DebugLog "Input Device [" + i + "] = " + sysex_get_next_device(i,False)
		EndIf
		
	Next

	' Change these to correct values for your setup.
	InputDevice = 2
	OutputDevice = 5

    '
    If sysex_get_next_device( InputDevice , False ) = ""
        If Not Confirm( "No compatible MIDI input device selected, Continue?", True )
            Return False
        EndIf
    EndIf

    '
    If sysex_get_next_device( OutputDevice, True ) = ""
        If Not Confirm( "No compatible MIDI output device selected, Continue?", True )
            Return False
        EndIf
    EndIf


    Global bp:Byte Ptr

    bp = sysex_send_receive(device_enquiry)

	'
	For Local i:Int=0 To 4
		DebugLog "bp[i] = " + bp[i]
	Next
	'
    If bp[0]=$F0 And bp[1]=$7E And bp[2]=$00 And bp[3]=$06 And bp[4]=$02	' Valid responce to device enquiry?
		'
		Notify( "Correct responce from device enquiry" )

    Else
		'
        Notify( "Invalid response from DeviceEnquiry(), Retry?", False )
    EndIf


sysex_finalise()

End


sysex.cpp
#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "string.h"

#include "portmidi28aug06/pm_common/portmidi.h"
#include "portmidi28aug06/porttime/porttime.h"

extern "C" {

#define MIDI_SYSEX 0xf0
#define MIDI_EOX 0xf7

#define STRING_MAX 80
#define MIDI_MESSAGE_SIZE 1024

#define is_real_time_msg(msg) ((0xF0 & Pm_MessageStatus(msg)) == 0xF8)

int InputDevice;
int OutputDevice;

int	 LoopbackInputDevice;
int	 LoopbackOutputDevice;

unsigned char midi_message[MIDI_MESSAGE_SIZE];

#define INPUT_BUFFER_SIZE 100
#define OUTPUT_BUFFER_SIZE 0
#define DRIVER_INFO NULL
#define TIME_PROC ((long (*)(void *)) Pt_Time)
#define TIME_INFO NULL
#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */

PmStream *midiIn = NULL; 
PmStream *midiOut = NULL;


//char dummy[256];

PmStream *midi_in_stream;

// ----------------------------------------------------------
// Reset the message buffer
// ----------------------------------------------------------
void	reset_message( void )
// ----------------------------------------------------------
{
//return;

int		i;

	for ( i=0; i<MIDI_MESSAGE_SIZE; i++ ) {
		midi_message[i] = 0;
	}
}

// ----------------------------------------------------------
// Open the MIDI ports
// ----------------------------------------------------------
bool midi_open( void )
// ----------------------------------------------------------
{
//return true;

	//
	Pm_OpenInput( &midi_in_stream, InputDevice, DRIVER_INFO, INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO );

	//
	if ( midi_in_stream != NULL ) {
		return true;
	}

	return false;	
}


// ----------------------------------------------------------
// Close the MIDI ports
// ----------------------------------------------------------
bool midi_close( void )
// ----------------------------------------------------------
{
//return true;
		
	//
	if ( midi_in_stream != NULL) {
		Pm_Close(midi_in_stream);
		midi_in_stream = NULL;			
		return true;
	} else {
		return false;
	}
}


// ----------------------------------------------------------
// Read a short message
// ----------------------------------------------------------
signed char *midi_test( void )
// ----------------------------------------------------------
{
//return true;

	PmEvent buffer[1];
	PmError status, length;

	//
	status = Pm_Poll( midi_in_stream );
	if ( status == true ) {

		reset_message();

		length = Pm_Read( midi_in_stream, buffer, 1 );
		if ( length > 0 ) {

			midi_message[0] = Pm_MessageStatus( buffer[0].message );
			midi_message[1] = Pm_MessageData1( buffer[0].message );			
			midi_message[2] = Pm_MessageData2( buffer[0].message );
			
//			printf("Got message: time %ld, %2lx %2lx %2lx\n",
	//					buffer[0].timestamp,
		//				midi_message[0] = Pm_MessageStatus( buffer[0].message ),
			//			Pm_MessageData1( buffer[0].message ),
				//		Pm_MessageData2( buffer[0].message ));

//			if ( Pm_MessageData1( buffer[0].message ) == 31 && Pm_MessageData2(buffer[0].message ) == 64 ) return true;			

			return (signed char *)midi_message;
		}
	}

	return NULL;
}


// ----------------------------------------------------------
// Open the MIDI loopback ports
// ----------------------------------------------------------
bool loopback_open()
// ----------------------------------------------------------
{
//return true;

	//
	Pm_OpenOutput( &midiOut, LoopbackOutputDevice, DRIVER_INFO, OUTPUT_BUFFER_SIZE, NULL, NULL, 0 );

	//
	Pm_OpenInput( &midiIn, LoopbackInputDevice, DRIVER_INFO, INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO );

	//
	if ( ( midiOut != NULL ) && ( midiIn != NULL ) ) {

		//
//		Pm_SetFilter( midiIn, PM_FILT_ACTIVE | PM_FILT_CLOCK );

	   // empty the buffer after setting filter, just in case anything got through.
//	    while (Pm_Poll(midiIn)) {
//	        Pm_Read( midiIn, buffer, 1 );
//	    }

		return true;
	}

	return false;	
}


// ----------------------------------------------------------
// Close the MIDI loopback ports
// ----------------------------------------------------------
bool loopback_close()
// ----------------------------------------------------------
{
//return true;

	//	
	if ( midiOut != NULL ) {
		Pm_Close(midiOut);
		midiOut = NULL;
		
		if ( midiIn != NULL) {
			Pm_Close(midiIn);
			midiIn = NULL;
			
			return true;
		} else {
			return false;
		}
	} else {
		return false;
	}
}


// ----------------------------------------------------------
// Write a short message then poll for a returned message
// ----------------------------------------------------------
bool loopback_test()
// ----------------------------------------------------------
{
//return true;

	PmEvent buffer[1];
	PmError status, length;

	// Note on
	Pm_WriteShort( midiOut, TIME_PROC(TIME_INFO), Pm_Message(0x90, 31, 64) );

	// Note off
//	Pm_WriteShort( midiOut, TIME_PROC(TIME_INFO), Pm_Message(0x80, 31, 40) );

//	buffer[0].timestamp = TIME_PROC(TIME_INFO);
//	buffer[0].message = Pm_Message(0x90,31,64);
//	Pm_Write( midiOut, buffer, 1);

	//
	status = Pm_Poll( midiIn );
	if ( status == true ) {

		length = Pm_Read( midiIn, buffer, 1 );
		if (length > 0) {

//			printf("Got message: time %ld, %2lx %2lx %2lx\n",
//						buffer[0].timestamp,
//						Pm_MessageStatus( buffer[0].message ),
//						Pm_MessageData1( buffer[0].message ),
//						Pm_MessageData2( buffer[0].message ));

			if ( Pm_MessageData1( buffer[0].message ) == 31 && Pm_MessageData2(buffer[0].message ) == 64 ) return true;			
		}
	}

	return false;
}


// ----------------------------------------------------------
// ----------------------------------------------------------
int		get_midi_in( void )
// ----------------------------------------------------------
{
//return true;

return InputDevice;
}


// ----------------------------------------------------------
// ----------------------------------------------------------
int		get_midi_out( void )
// ----------------------------------------------------------
{
//return true;

return OutputDevice;
}


// ----------------------------------------------------------
// ----------------------------------------------------------
void send_sysex( unsigned char *sysex_data ) 
// ----------------------------------------------------------
{
//return;

	PmStream *midi_out;
	
	//
	Pm_OpenOutput( &midi_out, OutputDevice, DRIVER_INFO, OUTPUT_BUFFER_SIZE, NULL, NULL, 0 );

	if ( midi_out != NULL ) {

		Pm_WriteSysEx( midi_out, 0, sysex_data );
		Pm_Close( midi_out );
		midi_out = NULL;
	}
}


// ----------------------------------------------------------
void receive_sysex( PmStream *midi )
// ----------------------------------------------------------
{
//return;

	int shift = 0;
	unsigned char data = 0;
	int bytes_on_line = 0;
	PmEvent msg;
	PmError count;

	// read data and write to file
	while ( data != MIDI_EOX ) {
		
		count = Pm_Read(midi, &msg, 1);
			
		// CAUTION: this causes busy waiting. It would be better to 
		// be in a polling loop to avoid being compute bound. PortMidi
		// does not support a blocking read since this is so seldom useful.
		
		if (count == 0) continue;
		
		// ignore real-time messages
		if (is_real_time_msg(Pm_MessageStatus(msg.message))) continue;

		// write 4 bytes of data until you reach an eox
		bool done = 0;
		for ( shift = 0; (shift < 32) && !done /*(data != MIDI_EOX)*/; shift += 8) {
			data = (msg.message >> shift) & 0xFF;
			
			// if this is a status byte that's not MIDI_EOX, the sysex
			// message is incomplete and there is no more sysex data
			
			midi_message[ bytes_on_line ] = data;
			++bytes_on_line;
			
			done = ( data == MIDI_EOX );
		}
	}
}


// ----------------------------------------------------------
unsigned char *sysex_send_receive( unsigned char *sysex_data ) 
// ----------------------------------------------------------
{
//return;

	PmStream *midi_in;
	PmStream *midi_out;

	Pm_OpenInput( &midi_in, InputDevice, DRIVER_INFO, INPUT_BUFFER_SIZE, NULL, NULL);
	Pm_OpenOutput( &midi_out, OutputDevice, DRIVER_INFO, OUTPUT_BUFFER_SIZE, NULL, NULL, 0);

	if ( midi_out != NULL ) {

		Pm_WriteSysEx( midi_out, 0, sysex_data );

		if ( midi_in != NULL) {
			reset_message();
			receive_sysex( midi_in );
			Pm_Close(midi_in);
			midi_in = NULL;
		}

		Pm_Close(midi_out);
		midi_out = NULL;
	}
	
	return midi_message;
}


// ----------------------------------------------------------
void sysex_send( unsigned char *message )
// ----------------------------------------------------------
{
//return;
int i;

	PmStream *midi_in;
	PmStream *midi_out;

//	fprintf( stderr, "opening output\n" );

	Pm_OpenOutput( &midi_out, OutputDevice, DRIVER_INFO, OUTPUT_BUFFER_SIZE, NULL, NULL, 0 );

//	fprintf( stderr, "opened output\n" );


	if ( midi_out != NULL ) {
	
		//
		Pm_WriteSysEx( midi_out, 0, message );
		
//		for( i=0; ( message[i] != MIDI_EOX ); i++ ) {
//			fprintf( stderr, "message[%d] = %.2x\n", i, message[i] );
//		}


		Pm_Close(midi_out);
		midi_out = NULL;

//		fprintf( stderr, "closed output\n" );
	}
	else {
	
		fprintf( stderr, "midi_out == NULL\n" );
	}
}


PmStream *midi_in = NULL;

// ----------------------------------------------------------
bool sysex_receive_open( void ) 
// ----------------------------------------------------------
{
//return true;

	Pm_OpenInput( &midi_in, InputDevice, NULL, 512, NULL, NULL );

	if ( midi_in != NULL) {
		return true;
	}

	return false;	
}


// ----------------------------------------------------------
unsigned char *sysex_receive_get( void ) 
// ----------------------------------------------------------
{
//return dummy;

	if ( midi_in != NULL) {

		if ( Pm_Poll( midi_in ) > 0 ) {
			reset_message();
			receive_sysex( midi_in );
			return midi_message;
		} else {
			return NULL;
		}
	} else {
		return NULL;
	}
}


// ----------------------------------------------------------
bool sysex_receive_close( void ) 
// ----------------------------------------------------------
{
//return true;

	if ( midi_in != NULL) {
		Pm_Close(midi_in);
		midi_in = NULL;
		return true;
	}
	return false;
}


#if 0
// ----------------------------------------------------------
char *sysex_send_receive( unsigned char *message )
// ----------------------------------------------------------
{
//return dummy;

	reset_message();

	send_receive_sysex( message );

	return midi_message;
}
#endif


// ----------------------------------------------------------
void	sysex_initalise( void )
// ----------------------------------------------------------
{
//return;

	int i;

	//
	Pm_Initialize();
	
#if 0	

	// list device information
	for (i = 0; i < Pm_CountDevices(); i++) {

        const PmDeviceInfo *info = Pm_GetDeviceInfo(i);

        printf("%d: %s, %s", i, info->interf, info->name);
        if (info->input) printf(" (input)");
        if (info->output) printf(" (output)");
        printf("\n");

		if ( ( strcmp( info->name, "USB Audio Device" ) == 0 ) && info->output ) {
			printf( "found output device %d\n", i );
			OutputDevice = i;
		}

		if ( ( strcmp( info->name, "USB Audio Device" ) == 0 ) && info->input ) {
			printf( "found input device @ %d\n", i );
			InputDevice = i;
		}


		if ( ( strcmp( info->name, "USB Audio Device [3]" ) == 0 ) && info->input ) {
			printf( "found intput loopback device @ %d\n", i );
			LoopbackInputDevice = i;
		}
	
		if ( ( strcmp( info->name, "USB Audio Device [2]" ) == 0 ) && info->output ) {
			printf( "found output loopback device @ %d\n", i );
			LoopbackOutputDevice = i;
		}		
	}

#endif

	//
	reset_message();
}


// ----------------------------------------------------------
int		sysex_set_device( char *select, int dir )
// ----------------------------------------------------------
{
	int i;

	// list device information
	for (i = 0; i < Pm_CountDevices(); i++) {
	
		const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
		
//		printf("%d: %s, %s", i, info->interf, info->name);
//		if (info->input) printf(" (input)");
//		if (info->output) printf(" (output)");
//		printf("\n");

		if ( dir == true ) {
			if ( ( strcmp( info->name, select ) == 0 ) && info->output ) {
				return i;
			}
		} else {
			if ( ( strcmp( info->name, select ) == 0 ) && info->input ) {
				return i;
			}
		}
	}
	return -1;
}


#include <brl.mod/blitz.mod/blitz_string.h>

// ----------------------------------------------------------
BBString *sysex_get_next_device( int nxt, int dir )
// ----------------------------------------------------------
{	
	const PmDeviceInfo *info = Pm_GetDeviceInfo( nxt );
	
//	printf( "pointer = %p", info );		
//	printf("%d: %s, %s", nxt, info->interf, info->name);
//	if (info->input) printf(" (input)");
//	if (info->output) printf(" (output)");
//	printf("\n");

	if ( info != NULL ) {

		if ( (dir == true) && info->output ) {
			return bbStringFromCString(info->name);
		}
	
		if ( (dir == false) && info->input ) {
			return bbStringFromCString(info->name);
		}
	}

	return bbStringFromCString("");
}


// ----------------------------------------------------------
int sysex_get_device_dir( int nxt )
// ----------------------------------------------------------
{	
int dir = 0;

	const PmDeviceInfo *info = Pm_GetDeviceInfo( nxt );

	if ( info != NULL ) {

		if ( info->output ) dir |= 1;
		if ( info->input ) dir |= 2;
		return dir;
	}
}


// ----------------------------------------------------------
int sysex_get_number_of_devices( void ) {
// ----------------------------------------------------------
	return Pm_CountDevices();
}


// ----------------------------------------------------------
void	sysex_finalise( void )
// ----------------------------------------------------------
{
//return;

	Pm_Terminate();
}

} // extern "C" }




JRBCM(Posted 2007) [#9]
Wow - thanks so much for that Nigel- soon as I get a minute (ie. never!) I'm gonna get stuck right in to it. I'm a Blitzmax newbie but very familiar with MIDI, being a musician.

Answer to Zilch: I don't need sysex or MIDI controller stuff for my project, I just need simple note on/off, velocity and pedal data (I'm aiming for Mac and PC versions).


Ziltch(Posted 2007) [#10]
I would go with nigels method then. As my mod only handles windows.


LAB[au](Posted 2007) [#11]
Hello,

In sysex_initialise there is a typo (you'll have to choose in between "sysex_initialise" or "sysex_initalise" without "i".

After that, I have an error building main.bmx...

Building main
Compiling:porttime.c
Compiling:portmidi.c
Compiling:ptwinmm.c
Compiling:pmwin.c
Compiling:pmdll.c
Compiling:pmwinmm.c
Compiling:sysex.cpp
Compiling:main.bmx
flat assembler version 1.66
3 passes, 3348 bytes.
Linking:main.exe
C:/Documents and Settings/jerome/Desktop/portmidi28aug06/portmidi28aug06/pm_win/.bmx/pmdll.c.release.win32.x86.o(.text+0x24):pmdll.c: multiple definition of `DllMain@12'
C:/Program Files/BlitzMax/mod/brl.mod/appstub.mod/appstub.release.win32.x86.a(appstub.win32.c.release.win32.x86.o)(.text+0x172):appstub.win32.c: first defined here
Build Error: Failed to link C:/Documents and Settings/jerome/Desktop/portmidi28aug06/main.exe
Process complete


LAB[au](Posted 2007) [#12]
any body succeeded in compiling this under windows?


Nigel Brown(Posted 2007) [#13]
Try renaming the DllMain() in \portmidi28aug06\pm_win\pmdll.c to DllMain2()

And using the edited code main.bmx above. This now compiles on my dev system.


LAB[au](Posted 2007) [#14]
Thanks Nigel it compiles. However it fails capturing any Midi in messages and even worst it doesn't close *always* cleanly. I looked at portmidi readme and I tried the #define USE_DLL_FOR_CLEANUP as recommended for windows.

The above example "main.bmx" fails silently on sysex_send_receive. The device detection is working(and I edited input/output device numbers) but I can't get anything working further than that.

I will continue messing up with it...


LAB[au](Posted 2007) [#15]
Could you indicate me how to open a port, and print the incoming messages? I am a bit confused by the wrapped functions... From there I should be able to test it completely.

Thanks


Nigel Brown(Posted 2007) [#16]
I have uploaded the whole folder including the port MIDI I am using to:

http://www.nigelibrown.pwp.blueyonder.co.uk/blitz/userlibs/index.htm

If you just want to deal exclusivley with MIDI messages then try opening - reading and then closing with something like this:

Strict

Import "portmidi28aug06/porttime/*.h"
Import "portmidi28aug06/porttime/porttime.c"

Import "portmidi28aug06/pm_common/*.h"
Import "portmidi28aug06/pm_common/portmidi.c"


?Win32

	Import "portmidi28aug06/porttime/ptwinmm.c"

	Import "portmidi28aug06/pm_win/*.h"
	Import "portmidi28aug06/pm_win/pmwin.c"
	Import "portmidi28aug06/pm_win/pmdll.c"
	Import "portmidi28aug06/pm_win/pmwinmm.c"

	Import "sysex.cpp"

Framework		brl.d3d7max2d

?MacOS
?Linux
?

Extern "C"		' sysex.cpp

	Global	OutputDevice:Int
	Global	InputDevice:Int
	Global	LoopbackInputDevice:Int
	Global	LoopbackOutputDevice:Int

	Global	midi_message:Byte[]

	Function 	midi_open:Int()
	Function 	midi_close:Int()
	Function 	midi_test:Byte Ptr()

	Function 	loopback_open:Int()
	Function 	loopback_close:Int()
	Function 	loopback_test:Int()

	Function 	get_midi_in()
	Function 	get_midi_out()

	Function 	sysex_receive_open:Int()
	Function 	sysex_receive_get:Byte Ptr()
	Function 	sysex_receive_close:Int()

	Function 	sysex_send( message:Byte Ptr )
	Function 	sysex_send_receive:Byte Ptr( message:Byte Ptr )

	Function 	sysex_initalise()
	Function 	sysex_set_device:Int( device:Byte Ptr, dir:Int )
	Function 	sysex_get_next_device:String( nxt:Int, dir:Int )
	Function 	sysex_get_number_of_devices:Int()

	Function 	sysex_finalise()

End Extern

	sysex_initalise()
	Delay(5000)

	' List input / output devices
	For Local i:Int=0 To sysex_get_number_of_devices()-1
	
		If sysex_get_next_device(i,True) = ""
		Else
			DebugLog "Output Device [" + i + "] = " + sysex_get_next_device(i,True)
		EndIf
	
		If sysex_get_next_device(i,False) = ""
		Else
			DebugLog "Input Device [" + i + "] = " + sysex_get_next_device(i,False)
		EndIf
		
	Next

	' Change these to correct values for your setup.
	InputDevice = 2
	OutputDevice = 5

    '
    If sysex_get_next_device( InputDevice , False ) = ""
        If Not Confirm( "No compatible MIDI input device selected, Continue?", True )
            Return False
        EndIf
    EndIf

    '
    If sysex_get_next_device( OutputDevice, True ) = ""
        If Not Confirm( "No compatible MIDI output device selected, Continue?", True )
            Return False
        EndIf
    EndIf


	Global bp:Byte Ptr

	midi_open()

	Repeat
	
		bp = midi_test()

		If bp <> Null
			DebugLog "status = " + bp[0]
			DebugLog "data1 = " + bp[1]
			DebugLog "data2 = " + bp[2]
			DebugLog ""
		EndIf
	
	Until KeyDown(KEY_ESCAPE)
	
	midi_close()
	

sysex_finalise()

End





LAB[au](Posted 2007) [#17]
Thanks Nigel, with the wrapped version downloaded on your website it works. It still doesn't close correctly all the time, but this could be my setup.


Nigel Brown(Posted 2007) [#18]
If I ever get enough time I will wrap this as a BMax module. And do things a little more elegantly.

If you need it to do more please let me know, when you say "It still doesn't close correctly all the time" can you be a little more specific so I can try and emulate the same problem here?


LAB[au](Posted 2007) [#19]
Well the problem occurs, when compiling the MIDI.bmx example, closing it pressing escape key, then one minute or 2 latter, recompiling it, it reports than midi.exe or midi.debug.exe is currently in use (so not closed properly although the exe doesn't appear in task manager anymore). It does it but not *always*, I tried a delay before closing bmx program (similar to the one after sysex_initialize), but it still happens "randomly".

My test system is WinXP pro, with a MAudio midisport Uno USB (input 1, output 4 in my setup) and a doepfer pocketdial (I have a Kaoss pad II, and a pocketfader as well but not wired currently).

I want to support Midi controllers principally (on the 3 platforms, from there comes my interest for portmidi), but some of them require midi feedback/ouput (to update a display or a motorized fader for example).

With Blitz3d I did a midichannel based dll (not based on devices), reading/writing midi messages only (the 3 nibbles).


Brucey(Posted 2007) [#20]
If I ever get enough time I will wrap this as a BMax module.

If I had anything remotely Midi I could test this with, I would have been happy to help with that...


LAB[au](Posted 2007) [#21]
Well I did my Blitz3D dll without Midi Hardware, I was using this software midi controller : http://www.analogx.com/contents/download/audio/mousemod.htm and the virtual piano controller (on the same website) along with Midi-Ox and Midi-Yoke http://www.midiox.com/

I suppose similar soft-midi exist for Linux and MacOS.


Nigel Brown(Posted 2007) [#22]
LAB[au]

Take a look at BAH modules. Brucey now has a portmidi module available. I will answer any questions that I am able to.


LAB[au](Posted 2007) [#23]
Yeah! It works perfect (didn't tried sysex yet).


eindbaas(Posted 2007) [#24]
I'd like to use Brucey's portmidi package, and it seems to work (just started, but it did find all my midi-devices) but i think i'm having the same prob as Lab[au] described earlier.

Whenever i open a midi-device ( midi.openInput(devicenum) ) the program doesn't want to close anymore. The code after the openInput (which is opening a graphics window and do a while-wend loop on not pressing escape) does run (the window is opened), but pressing escape doesn't do anything. I see the process in my TaskManager, but i cant kill it (the prg-window disappears but the exe stays in the taskmanager->processes).

It does kill itself after about 5 minutes, but that's a long wait to be able to recompile my prg :(

Does anybody have some info or hints on this?


eindbaas(Posted 2007) [#25]
Found out that the running process will shut down only if i turn off my (external) midi-interface (or wait 5 minutes). Tried that with 2 different midi-interfaces, and the same thing happens.


Nigel Brown(Posted 2007) [#26]
Example code please, and I will have a look. Here are some ideas you should try.

in \portmidi28aug06\pm_win\pmwin.dll make sure that the line #define USE_DLL_FOR_CLEANUP is not commented out.

in your source include:
Import "portmidi28aug06/pm_win/pmdll.c"

and make sure you have the pmdll.dll inside your project folder.


rendomizer(Posted 2015) [#27]
Where can i found portmidi28aug06 ? need help


markcw(Posted 2015) [#28]
Brucey has a zip version here: http://brucey.net/programming/blitz/#bahportmidi
It seems he has no svn or git version though.

Edit: wx.mod has a portmidi wrapper here: https://github.com/maxmods/wx.mod/tree/master/wxmidi.mod


Brucey(Posted 2015) [#29]
I highly recommend rtMidi instead.

It is available here (rtmidi.mod) : https://github.com/maxmods/bah.mod


Hardcoal(Posted May) [#30]
This peace of Crap Github is not allowing you to download a sub directory..
instead it forces you to download the whole Bah.mod.
what the hell is wrong in this world?


Hardcoal(Posted May) [#31]
why do i get this Compile Error: Can't find interface for module 'bah.rtmidi'


I put the bah.mod on the blitzmax mod and than tried to update modules
but still i get this error

i installed that silly mingw.. i think i did everything but yet it aint working and i get Error

Compile Error: Can't find interface for module 'bah.rtmidi'
Build Error: failed to compile D:/Portable/BlitzMax/mod/bah.mod/rtmidi.mod/examples/midi_in.bmx


markcw(Posted May) [#32]
I can see you're not in the best of moods today Hardcoal. Never mind, it is possible to download a subdirectory from github but you have to use the command line and you need SVN installed. The trick is to replace "tree/master" with "trunk" like so:
svn checkout https://github.com/maxmods/bah.mod/trunk/rtmidi.mod C:/myfolder
...

"Can't find interface for module" means it probably hasn't been built.
You can try deleting the .bmx folder (to remove .i files) and then rebuild modules or like I prefer use the command line "bmk makemods -a bah.rtmidi".
If this doesn't work then your setup of MinGW may not be installed properly, so you could follow my guide HERE.


Hardcoal(Posted May) [#33]
You are so right mark.. I feel rather awful today.. (various reasons..)
I really value you sensitivity and noticing of my feelings..

I greet you advices and I will try them on.

Many thanks to you Mark and Also Rick Nasher for cheering me up.

Ill try it later.. Im too tired right now