2010-07-18 20:28:15 +00:00
/*
* This code handles HMP files . It can :
* - Open / read / close HMP files
* - Play HMP via Windows MIDI
* - Convert HMP to MIDI for further use
* Based on work of Arne de Bruijn and the JFFEE project
*/
# include <string.h>
2006-03-20 16:43:15 +00:00
# include <stdlib.h>
2010-07-18 20:28:15 +00:00
# include <stdio.h>
2010-09-17 10:44:21 +00:00
2010-07-18 20:28:15 +00:00
# include "hmp.h"
# include "u_mem.h"
2006-03-20 16:43:15 +00:00
# include "cfile.h"
2010-07-18 20:28:15 +00:00
# ifdef WORDS_BIGENDIAN
# define MIDIINT(x) (x)
# define MIDISHORT(x) (x)
# else
# define MIDIINT(x) SWAPINT(x)
# define MIDISHORT(x) SWAPSHORT(x)
2006-03-20 16:43:15 +00:00
# endif
2010-07-19 17:05:41 +00:00
# ifdef _WIN32
2010-11-28 15:49:32 +00:00
int midi_volume ;
int channel_volume [ 16 ] ;
2010-07-19 17:05:41 +00:00
void hmp_stop ( hmp_file * hmp ) ;
# endif
2010-07-18 20:28:15 +00:00
// READ/OPEN/CLOSE HMP
2010-07-19 17:05:41 +00:00
2010-07-18 20:28:15 +00:00
void hmp_close ( hmp_file * hmp )
{
int i ;
2006-03-20 16:43:15 +00:00
2010-07-18 20:28:15 +00:00
# ifdef _WIN32
hmp_stop ( hmp ) ;
# endif
for ( i = 0 ; i < hmp - > num_trks ; i + + )
if ( hmp - > trks [ i ] . data )
d_free ( hmp - > trks [ i ] . data ) ;
d_free ( hmp ) ;
}
2006-03-20 16:43:15 +00:00
hmp_file * hmp_open ( const char * filename ) {
int i ;
char buf [ 256 ] ;
long data ;
CFILE * fp ;
hmp_file * hmp ;
int num_tracks ;
unsigned char * p ;
if ( ! ( fp = cfopen ( ( char * ) filename , " rb " ) ) )
return NULL ;
2008-01-23 17:25:09 +00:00
hmp = d_malloc ( sizeof ( hmp_file ) ) ;
2006-03-20 16:43:15 +00:00
if ( ! hmp ) {
cfclose ( fp ) ;
return NULL ;
}
memset ( hmp , 0 , sizeof ( * hmp ) ) ;
if ( ( cfread ( buf , 1 , 8 , fp ) ! = 8 ) | | ( memcmp ( buf , " HMIMIDIP " , 8 ) ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2006-03-20 16:43:15 +00:00
if ( cfseek ( fp , 0x30 , SEEK_SET ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2006-03-20 16:43:15 +00:00
if ( cfread ( & num_tracks , 4 , 1 , fp ) ! = 1 )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2006-03-20 16:43:15 +00:00
if ( ( num_tracks < 1 ) | | ( num_tracks > HMP_TRACKS ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2006-03-20 16:43:15 +00:00
hmp - > num_trks = num_tracks ;
2010-07-18 20:28:15 +00:00
hmp - > tempo = 120 ;
2006-03-20 16:43:15 +00:00
if ( cfseek ( fp , 0x308 , SEEK_SET ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2006-03-20 16:43:15 +00:00
2010-07-18 20:28:15 +00:00
for ( i = 0 ; i < num_tracks ; i + + ) {
2006-03-20 16:43:15 +00:00
if ( ( cfseek ( fp , 4 , SEEK_CUR ) ) | | ( cfread ( & data , 4 , 1 , fp ) ! = 1 ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2006-03-20 16:43:15 +00:00
data - = 12 ;
hmp - > trks [ i ] . len = data ;
2008-01-23 17:25:09 +00:00
if ( ! ( p = hmp - > trks [ i ] . data = d_malloc ( data ) ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
2006-03-20 16:43:15 +00:00
}
2010-07-18 20:28:15 +00:00
/* finally, read track data */
2006-03-20 16:43:15 +00:00
if ( ( cfseek ( fp , 4 , SEEK_CUR ) ) | | ( cfread ( p , data , 1 , fp ) ! = 1 ) )
2010-07-18 20:28:15 +00:00
{
cfclose ( fp ) ;
hmp_close ( hmp ) ;
return NULL ;
}
2010-11-28 15:49:32 +00:00
hmp - > trks [ i ] . loop_set = 0 ;
2010-07-18 20:28:15 +00:00
}
2010-11-30 11:19:41 +00:00
hmp - > filesize = PHYSFS_fileLength ( fp ) ;
2010-07-18 20:28:15 +00:00
cfclose ( fp ) ;
return hmp ;
2006-03-20 16:43:15 +00:00
}
2010-11-28 15:49:32 +00:00
# ifdef _WIN32
2010-07-18 20:28:15 +00:00
// PLAY HMP AS MIDI
void hmp_stop ( hmp_file * hmp )
{
2006-03-20 16:43:15 +00:00
MIDIHDR * mhdr ;
if ( ! hmp - > stop ) {
hmp - > stop = 1 ;
//PumpMessages();
midiStreamStop ( hmp - > hmidi ) ;
2010-07-18 20:28:15 +00:00
while ( hmp - > bufs_in_mm )
2006-03-20 16:43:15 +00:00
Sleep ( 0 ) ;
}
while ( ( mhdr = hmp - > evbuf ) ) {
midiOutUnprepareHeader ( ( HMIDIOUT ) hmp - > hmidi , mhdr , sizeof ( MIDIHDR ) ) ;
hmp - > evbuf = mhdr - > lpNext ;
2008-01-23 17:25:09 +00:00
d_free ( mhdr ) ;
2006-03-20 16:43:15 +00:00
}
if ( hmp - > hmidi ) {
midiStreamClose ( hmp - > hmidi ) ;
hmp - > hmidi = NULL ;
}
}
/*
2010-11-28 15:49:32 +00:00
* read a HMI type variable length number
2006-03-20 16:43:15 +00:00
*/
static int get_var_num_hmi ( unsigned char * data , int datalen , unsigned long * value ) {
unsigned char * p ;
unsigned long v = 0 ;
int shift = 0 ;
p = data ;
while ( ( datalen > 0 ) & & ! ( * p & 0x80 ) ) {
v + = * ( p + + ) < < shift ;
shift + = 7 ;
datalen - - ;
2010-07-18 20:28:15 +00:00
}
2006-03-20 16:43:15 +00:00
if ( ! datalen )
return 0 ;
2010-07-18 20:28:15 +00:00
v + = ( * ( p + + ) & 0x7f ) < < shift ;
2006-03-20 16:43:15 +00:00
if ( value ) * value = v ;
2010-07-18 20:28:15 +00:00
return p - data ;
2006-03-20 16:43:15 +00:00
}
/*
2010-11-28 15:49:32 +00:00
* read a MIDI type variable length number
2006-03-20 16:43:15 +00:00
*/
static int get_var_num ( unsigned char * data , int datalen ,
2010-07-18 20:28:15 +00:00
unsigned long * value ) {
2006-03-20 16:43:15 +00:00
unsigned char * orgdata = data ;
unsigned long v = 0 ;
while ( ( datalen > 0 ) & & ( * data & 0x80 ) )
v = ( v < < 7 ) + ( * ( data + + ) & 0x7f ) ;
if ( ! datalen )
return 0 ;
2010-07-18 20:28:15 +00:00
v = ( v < < 7 ) + * ( data + + ) ;
if ( value ) * value = v ;
return data - orgdata ;
2006-03-20 16:43:15 +00:00
}
static int get_event ( hmp_file * hmp , event * ev ) {
2010-07-18 20:28:15 +00:00
static int cmdlen [ 7 ] = { 3 , 3 , 3 , 3 , 2 , 2 , 3 } ;
2006-03-20 16:43:15 +00:00
unsigned long got ;
unsigned long mindelta , delta ;
int i , ev_num ;
hmp_track * trk , * fndtrk ;
mindelta = INT_MAX ;
fndtrk = NULL ;
for ( trk = hmp - > trks , i = hmp - > num_trks ; ( i - - ) > 0 ; trk + + ) {
2010-11-28 15:49:32 +00:00
if ( ! trk - > left | | hmp - > loop_start & & hmp - > looping & & ! trk - > loop_set )
2006-03-20 16:43:15 +00:00
continue ;
if ( ! ( got = get_var_num_hmi ( trk - > cur , trk - > left , & delta ) ) )
return HMP_INVALID_FILE ;
if ( trk - > left > got + 2 & & * ( trk - > cur + got ) = = 0xff
& & * ( trk - > cur + got + 1 ) = = 0x2f ) { /* end of track */
trk - > left = 0 ;
continue ;
}
2010-11-28 15:49:32 +00:00
if ( hmp - > loop_start & & hmp - > looping )
if ( trk - > cur = = trk - > loop )
delta = 0 ;
2006-03-20 16:43:15 +00:00
delta + = trk - > cur_time - hmp - > cur_time ;
if ( delta < mindelta ) {
mindelta = delta ;
fndtrk = trk ;
}
}
if ( ! ( trk = fndtrk ) )
return HMP_EOF ;
got = get_var_num_hmi ( trk - > cur , trk - > left , & delta ) ;
2010-11-28 15:49:32 +00:00
if ( hmp - > loop_start & & hmp - > looping )
if ( trk - > cur = = trk - > loop )
delta = 0 ;
2006-03-20 16:43:15 +00:00
trk - > cur_time + = delta ;
2010-11-28 15:49:32 +00:00
if ( ! hmp - > loop_start & & * ( trk - > cur + got ) > > 4 = = MIDI_CONTROL_CHANGE & & * ( trk - > cur + got + 1 ) = = HMP_LOOP_START )
2010-11-30 11:19:41 +00:00
{
hmp - > loop_start = trk - > cur_time ;
if ( ( hmp - > filesize = = 86949 ) & & ( trk - > cur_time = = 29 ) ) // special ugly HACK HACK HACK for Descent2-version of descent.hmp where loop at this point causes instruments not being reset properly. No track supporting HMP loop I know of meets the requirements for the condition below and even if so - it only disabled the HMP loop feature.
{
hmp - > loop_start = 0 ;
}
}
2010-11-28 15:49:32 +00:00
if ( ! hmp - > loop_end & & * ( trk - > cur + got ) > > 4 = = MIDI_CONTROL_CHANGE & & * ( trk - > cur + got + 1 ) = = HMP_LOOP_END )
hmp - > loop_end = trk - > cur_time ;
if ( hmp - > loop_start & & ! trk - > loop_set & & trk - > cur_time = = hmp - > loop_start )
{
trk - > loop = trk - > cur ;
trk - > len = trk - > left ;
trk - > loop_set = 1 ;
}
if ( hmp - > loop_end & & trk - > cur_time > hmp - > loop_end )
return HMP_EOF ;
2006-03-20 16:43:15 +00:00
ev - > delta = trk - > cur_time - hmp - > cur_time ;
hmp - > cur_time = trk - > cur_time ;
if ( ( trk - > left - = got ) < 3 )
2010-07-18 20:28:15 +00:00
return HMP_INVALID_FILE ;
2006-03-20 16:43:15 +00:00
trk - > cur + = got ;
/*memset(ev, 0, sizeof(*ev));*/ ev - > datalen = 0 ;
ev - > msg [ 0 ] = ev_num = * ( trk - > cur + + ) ;
trk - > left - - ;
if ( ev_num < 0x80 )
2010-07-18 20:28:15 +00:00
return HMP_INVALID_FILE ; /* invalid command */
2006-03-20 16:43:15 +00:00
if ( ev_num < 0xf0 ) {
ev - > msg [ 1 ] = * ( trk - > cur + + ) ;
trk - > left - - ;
if ( cmdlen [ ( ( ev_num ) > > 4 ) - 8 ] = = 3 ) {
ev - > msg [ 2 ] = * ( trk - > cur + + ) ;
trk - > left - - ;
2010-11-28 15:49:32 +00:00
if ( ev - > msg [ 0 ] > > 4 = = MIDI_CONTROL_CHANGE & & ev - > msg [ 1 ] = = MIDI_VOLUME )
{
channel_volume [ ev - > msg [ 0 ] & 0xf ] = ev - > msg [ 2 ] ;
ev - > msg [ 2 ] = ev - > msg [ 2 ] * midi_volume / MIDI_VOLUME_SCALE ;
}
2006-03-20 16:43:15 +00:00
}
} else if ( ev_num = = 0xff ) {
ev - > msg [ 1 ] = * ( trk - > cur + + ) ;
trk - > left - - ;
if ( ! ( got = get_var_num ( ev - > data = trk - > cur ,
trk - > left , ( unsigned long * ) & ev - > datalen ) ) )
return HMP_INVALID_FILE ;
2010-07-18 20:28:15 +00:00
trk - > cur + = ev - > datalen ;
2006-03-20 16:43:15 +00:00
if ( trk - > left < = ev - > datalen )
return HMP_INVALID_FILE ;
trk - > left - = ev - > datalen ;
} else /* sysex -> error */
return HMP_INVALID_FILE ;
return 0 ;
}
static int fill_buffer ( hmp_file * hmp ) {
MIDIHDR * mhdr = hmp - > evbuf ;
unsigned int * p = ( unsigned int * ) ( mhdr - > lpData + mhdr - > dwBytesRecorded ) ;
unsigned int * pend = ( unsigned int * ) ( mhdr - > lpData + mhdr - > dwBufferLength ) ;
unsigned int i ;
event ev ;
while ( p + 4 < = pend ) {
if ( hmp - > pending_size ) {
i = ( p - pend ) * 4 ;
if ( i > hmp - > pending_size )
i = hmp - > pending_size ;
* ( p + + ) = hmp - > pending_event | i ;
* ( p + + ) = 0 ;
memcpy ( ( unsigned char * ) p , hmp - > pending , i ) ;
hmp - > pending_size - = i ;
p + = ( i + 3 ) / 4 ;
} else {
if ( ( i = get_event ( hmp , & ev ) ) ) {
mhdr - > dwBytesRecorded = ( ( unsigned char * ) p ) - ( ( unsigned char * ) mhdr - > lpData ) ;
return i ;
}
if ( ev . datalen ) {
hmp - > pending_size = ev . datalen ;
hmp - > pending = ev . data ;
hmp - > pending_event = ev . msg [ 0 ] < < 24 ;
} else {
* ( p + + ) = ev . delta ;
* ( p + + ) = 0 ;
* ( p + + ) = ( ( ( DWORD ) MEVT_SHORTMSG ) < < 24 ) |
( ( DWORD ) ev . msg [ 0 ] ) |
( ( ( DWORD ) ev . msg [ 1 ] ) < < 8 ) |
( ( ( DWORD ) ev . msg [ 2 ] ) < < 16 ) ;
}
}
}
mhdr - > dwBytesRecorded = ( ( unsigned char * ) p ) - ( ( unsigned char * ) mhdr - > lpData ) ;
return 0 ;
}
static int setup_buffers ( hmp_file * hmp ) {
int i ;
MIDIHDR * buf , * lastbuf ;
lastbuf = NULL ;
for ( i = 0 ; i < HMP_BUFFERS ; i + + ) {
2008-01-23 17:25:09 +00:00
if ( ! ( buf = d_malloc ( HMP_BUFSIZE + sizeof ( MIDIHDR ) ) ) )
2006-03-20 16:43:15 +00:00
return HMP_OUT_OF_MEM ;
memset ( buf , 0 , sizeof ( MIDIHDR ) ) ;
buf - > lpData = ( unsigned char * ) buf + sizeof ( MIDIHDR ) ;
buf - > dwBufferLength = HMP_BUFSIZE ;
buf - > dwUser = ( DWORD ) hmp ;
buf - > lpNext = lastbuf ;
lastbuf = buf ;
}
hmp - > evbuf = lastbuf ;
return 0 ;
}
static void reset_tracks ( struct hmp_file * hmp )
{
int i ;
for ( i = 0 ; i < hmp - > num_trks ; i + + ) {
2010-11-28 15:49:32 +00:00
if ( hmp - > trks [ i ] . loop_set )
hmp - > trks [ i ] . cur = hmp - > trks [ i ] . loop ;
else
hmp - > trks [ i ] . cur = hmp - > trks [ i ] . data ;
hmp - > trks [ i ] . left = hmp - > trks [ i ] . len ;
hmp - > trks [ i ] . cur_time = 0 ;
2006-03-20 16:43:15 +00:00
}
2010-11-28 15:49:32 +00:00
hmp - > cur_time = 0 ;
2006-03-20 16:43:15 +00:00
}
static void _stdcall midi_callback ( HMIDISTRM hms , UINT uMsg , DWORD dwUser , DWORD dw1 , DWORD dw2 ) {
MIDIHDR * mhdr ;
hmp_file * hmp ;
int rc ;
if ( uMsg ! = MOM_DONE )
return ;
mhdr = ( ( MIDIHDR * ) dw1 ) ;
mhdr - > dwBytesRecorded = 0 ;
hmp = ( hmp_file * ) ( mhdr - > dwUser ) ;
mhdr - > lpNext = hmp - > evbuf ;
hmp - > evbuf = mhdr ;
hmp - > bufs_in_mm - - ;
if ( ! hmp - > stop ) {
while ( fill_buffer ( hmp ) = = HMP_EOF ) {
2008-05-01 21:40:34 +00:00
if ( hmp - > bLoop )
2006-03-20 16:43:15 +00:00
hmp - > stop = 0 ;
2006-05-05 14:14:55 +00:00
else
hmp - > stop = 1 ;
2010-11-28 15:49:32 +00:00
hmp - > looping = 1 ;
2006-03-20 16:43:15 +00:00
reset_tracks ( hmp ) ;
}
if ( ( rc = midiStreamOut ( hmp - > hmidi , hmp - > evbuf ,
sizeof ( MIDIHDR ) ) ) ! = MMSYSERR_NOERROR ) {
/* ??? */
} else {
hmp - > evbuf = hmp - > evbuf - > lpNext ;
hmp - > bufs_in_mm + + ;
}
}
}
static void setup_tempo ( hmp_file * hmp , unsigned long tempo ) {
MIDIHDR * mhdr = hmp - > evbuf ;
unsigned int * p = ( unsigned int * ) ( mhdr - > lpData + mhdr - > dwBytesRecorded ) ;
* ( p + + ) = 0 ;
* ( p + + ) = 0 ;
* ( p + + ) = ( ( ( DWORD ) MEVT_TEMPO ) < < 24 ) | tempo ;
mhdr - > dwBytesRecorded + = 12 ;
}
2010-11-28 15:49:32 +00:00
void hmp_setvolume ( hmp_file * hmp , int volume )
{
int channel ;
if ( hmp )
for ( channel = 0 ; channel < 16 ; channel + + )
midiOutShortMsg ( ( HMIDIOUT ) hmp - > hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_VOLUME < < 8 | ( channel_volume [ channel ] * volume / MIDI_VOLUME_SCALE ) < < 16 ) ) ;
midi_volume = volume ;
}
2006-03-20 16:43:15 +00:00
int hmp_play ( hmp_file * hmp , int bLoop )
{
int rc ;
MIDIPROPTIMEDIV mptd ;
2010-07-18 20:28:15 +00:00
2010-11-28 15:49:32 +00:00
hmp - > bLoop = bLoop ;
hmp - > loop_start = 0 ;
hmp - > loop_end = 0 ;
hmp - > looping = 0 ;
2006-03-20 16:43:15 +00:00
hmp - > devid = MIDI_MAPPER ;
if ( ( rc = setup_buffers ( hmp ) ) )
return rc ;
2010-07-18 20:28:15 +00:00
if ( ( midiStreamOpen ( & hmp - > hmidi , & hmp - > devid , 1 , ( DWORD ) ( size_t ) midi_callback , 0 , CALLBACK_FUNCTION ) ) ! = MMSYSERR_NOERROR ) {
2006-03-20 16:43:15 +00:00
hmp - > hmidi = NULL ;
return HMP_MM_ERR ;
}
mptd . cbStruct = sizeof ( mptd ) ;
mptd . dwTimeDiv = hmp - > tempo ;
2010-07-18 20:28:15 +00:00
if ( ( midiStreamProperty ( hmp - > hmidi , ( LPBYTE ) & mptd , MIDIPROP_SET | MIDIPROP_TIMEDIV ) ) ! = MMSYSERR_NOERROR ) {
2006-03-20 16:43:15 +00:00
return HMP_MM_ERR ;
}
reset_tracks ( hmp ) ;
setup_tempo ( hmp , 0x0f4240 ) ;
hmp - > stop = 0 ;
while ( hmp - > evbuf ) {
if ( ( rc = fill_buffer ( hmp ) ) ) {
if ( rc = = HMP_EOF ) {
reset_tracks ( hmp ) ;
continue ;
} else
return rc ;
}
if ( ( rc = midiOutPrepareHeader ( ( HMIDIOUT ) hmp - > hmidi , hmp - > evbuf ,
sizeof ( MIDIHDR ) ) ) ! = MMSYSERR_NOERROR ) {
return HMP_MM_ERR ;
}
if ( ( rc = midiStreamOut ( hmp - > hmidi , hmp - > evbuf ,
sizeof ( MIDIHDR ) ) ) ! = MMSYSERR_NOERROR ) {
return HMP_MM_ERR ;
}
hmp - > evbuf = hmp - > evbuf - > lpNext ;
hmp - > bufs_in_mm + + ;
}
midiStreamRestart ( hmp - > hmidi ) ;
return 0 ;
}
2010-11-28 15:49:32 +00:00
void hmp_pause ( hmp_file * hmp )
{
midiStreamPause ( hmp - > hmidi ) ;
}
void hmp_resume ( hmp_file * hmp )
{
midiStreamRestart ( hmp - > hmidi ) ;
}
void hmp_reset ( )
{
HMIDIOUT hmidi ;
MIDIHDR mhdr ;
int channel ;
unsigned char GS_Reset [ ] = { 0xF0 , 0x41 , 0x10 , 0x42 , 0x12 , 0x40 , 0x00 , 0x7F , 0x00 , 0x41 , 0xF7 } ;
midiOutOpen ( & hmidi , MIDI_MAPPER , 0 , 0 , 0 ) ;
for ( channel = 0 ; channel < 16 ; channel + + )
{
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_ALL_SOUNDS_OFF < < 8 | 0 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_RESET_ALL_CONTROLLERS < < 8 | 0 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_ALL_NOTES_OFF < < 8 | 0 < < 16 ) ) ;
channel_volume [ channel ] = 100 ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_PANPOT < < 8 | 64 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_REVERB < < 8 | 40 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_CHORUS < < 8 | 0 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_BANK_SELECT_MSB < < 8 | 0 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_BANK_SELECT_LSB < < 8 | 0 < < 16 ) ) ;
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_PROGRAM_CHANGE < < 4 | 0 < < 8 ) ) ;
}
mhdr . lpData = GS_Reset ;
mhdr . dwBufferLength = sizeof ( GS_Reset ) ;
mhdr . dwFlags = 0 ;
midiOutPrepareHeader ( hmidi , & mhdr , sizeof ( MIDIHDR ) ) ;
midiOutLongMsg ( hmidi , & mhdr , sizeof ( MIDIHDR ) ) ;
while ( ! ( mhdr . dwFlags & MHDR_DONE ) ) ;
midiOutUnprepareHeader ( hmidi , & mhdr , sizeof ( MIDIHDR ) ) ;
Sleep ( 50 ) ;
for ( channel = 0 ; channel < 16 ; channel + + )
midiOutShortMsg ( hmidi , ( DWORD ) ( channel | MIDI_CONTROL_CHANGE < < 4 | MIDI_VOLUME < < 8 | ( 100 * midi_volume / MIDI_VOLUME_SCALE ) < < 16 ) ) ;
midiOutClose ( hmidi ) ;
}
2010-07-18 20:28:15 +00:00
# endif
// CONVERSION FROM HMP TO MIDI
2010-10-29 15:40:21 +00:00
static unsigned int hmptrk2mid ( ubyte * data , int size , unsigned char * * midbuf , unsigned int * midlen )
2010-07-18 20:28:15 +00:00
{
ubyte * dptr = data ;
ubyte lc1 = 0 , last_com = 0 ;
2010-10-29 15:40:21 +00:00
uint d ;
2010-07-18 20:28:15 +00:00
int n1 , n2 ;
2010-10-29 15:40:21 +00:00
unsigned int offset = * midlen ;
2010-07-18 20:28:15 +00:00
while ( data < dptr + size )
{
if ( data [ 0 ] & 0x80 ) {
ubyte b = ( data [ 0 ] & 0x7F ) ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + 1 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & b , 1 ) ;
* midlen + = 1 ;
2010-07-18 20:28:15 +00:00
}
else {
d = ( data [ 0 ] & 0x7F ) ;
n1 = 0 ;
while ( ( data [ n1 ] & 0x80 ) = = 0 ) {
n1 + + ;
d + = ( data [ n1 ] & 0x7F ) < < ( n1 * 7 ) ;
}
n1 = 1 ;
while ( ( data [ n1 ] & 0x80 ) = = 0 ) {
n1 + + ;
if ( n1 = = 4 )
return 0 ;
}
for ( n2 = 0 ; n2 < = n1 ; n2 + + ) {
ubyte b = ( data [ n1 - n2 ] & 0x7F ) ;
if ( n2 ! = n1 )
b | = 0x80 ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + 1 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & b , 1 ) ;
* midlen + = 1 ;
2010-07-18 20:28:15 +00:00
}
data + = n1 ;
}
data + + ;
if ( * data = = 0xFF ) { //meta?
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + 3 + data [ 2 ] ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , data , 3 + data [ 2 ] ) ;
* midlen + = 3 + data [ 2 ] ;
2010-07-18 20:28:15 +00:00
if ( data [ 1 ] = = 0x2F )
break ;
}
else {
lc1 = data [ 0 ] ;
if ( ( lc1 & 0x80 ) = = 0 )
return 0 ;
switch ( lc1 & 0xF0 ) {
case 0x80 :
case 0x90 :
case 0xA0 :
case 0xB0 :
case 0xE0 :
if ( lc1 ! = last_com )
2010-10-29 15:40:21 +00:00
{
* midbuf = d_realloc ( * midbuf , * midlen + 1 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & lc1 , 1 ) ;
* midlen + = 1 ;
}
* midbuf = d_realloc ( * midbuf , * midlen + 2 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , data + 1 , 2 ) ;
* midlen + = 2 ;
2010-07-18 20:28:15 +00:00
data + = 3 ;
break ;
case 0xC0 :
case 0xD0 :
if ( lc1 ! = last_com )
2010-10-29 15:40:21 +00:00
{
* midbuf = d_realloc ( * midbuf , * midlen + 1 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & lc1 , 1 ) ;
* midlen + = 1 ;
}
* midbuf = d_realloc ( * midbuf , * midlen + 1 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , data + 1 , 1 ) ;
* midlen + = 1 ;
2010-07-18 20:28:15 +00:00
data + = 2 ;
break ;
default :
return 0 ;
}
last_com = lc1 ;
}
}
2010-10-29 15:40:21 +00:00
return ( * midlen - offset ) ;
2010-07-18 20:28:15 +00:00
}
ubyte tempo [ 19 ] = { ' M ' , ' T ' , ' r ' , ' k ' , 0 , 0 , 0 , 11 , 0 , 0xFF , 0x51 , 0x03 , 0x18 , 0x80 , 0x00 , 0 , 0xFF , 0x2F , 0 } ;
2010-10-29 15:40:21 +00:00
void hmp2mid ( char * hmp_name , unsigned char * * midbuf , unsigned int * midlen )
2010-07-18 20:28:15 +00:00
{
2010-10-29 15:40:21 +00:00
int mi , i ;
2010-07-18 20:28:15 +00:00
short ms ;
hmp_file * hmp = NULL ;
hmp = hmp_open ( hmp_name ) ;
if ( hmp = = NULL )
return ;
2010-10-29 15:40:21 +00:00
* midlen = 0 ;
2010-07-18 20:28:15 +00:00
// write MIDI-header
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + 4 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , " MThd " , 4 ) ;
* midlen + = 4 ;
2010-07-18 20:28:15 +00:00
mi = MIDIINT ( 6 ) ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + sizeof ( mi ) ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & mi , sizeof ( mi ) ) ;
* midlen + = sizeof ( mi ) ;
2010-07-18 20:28:15 +00:00
ms = MIDISHORT ( 1 ) ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + sizeof ( ms ) ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & ms , sizeof ( ms ) ) ;
* midlen + = sizeof ( ms ) ;
2010-07-18 20:28:15 +00:00
ms = MIDISHORT ( hmp - > num_trks ) ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + sizeof ( ms ) ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & ms , sizeof ( ms ) ) ;
* midlen + = sizeof ( ms ) ;
2010-07-18 20:28:15 +00:00
ms = MIDISHORT ( ( short ) 0xC0 ) ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + sizeof ( ms ) ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & ms , sizeof ( ms ) ) ;
* midlen + = sizeof ( ms ) ;
* midbuf = d_realloc ( * midbuf , * midlen + sizeof ( tempo ) ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , & tempo , sizeof ( tempo ) ) ;
* midlen + = sizeof ( tempo ) ;
2010-07-18 20:28:15 +00:00
// tracks
for ( i = 1 ; i < hmp - > num_trks ; i + + )
{
2010-10-29 15:40:21 +00:00
int midtrklenpos = 0 ;
* midbuf = d_realloc ( * midbuf , * midlen + 4 ) ;
memcpy ( & ( * midbuf ) [ * midlen ] , " MTrk " , 4 ) ;
* midlen + = 4 ;
midtrklenpos = * midlen ;
2010-07-18 20:28:15 +00:00
mi = 0 ;
2010-10-29 15:40:21 +00:00
* midbuf = d_realloc ( * midbuf , * midlen + sizeof ( mi ) ) ;
* midlen + = sizeof ( mi ) ;
mi = hmptrk2mid ( hmp - > trks [ i ] . data , hmp - > trks [ i ] . len , midbuf , midlen ) ;
2010-07-18 20:28:15 +00:00
mi = MIDIINT ( mi ) ;
2010-10-29 15:40:21 +00:00
memcpy ( & ( * midbuf ) [ midtrklenpos ] , & mi , 4 ) ;
2010-07-18 20:28:15 +00:00
}
2010-07-19 17:05:41 +00:00
hmp_close ( hmp ) ;
}