+++ /dev/null
-/* a little modified code from http://iki.fi/too/sw/xring/ */
-
-/* embedding modified midifile.h and midifile.c into this file */
-
-/***** midifile.h ******/
-
-struct MF {
-/* definitions for MIDI file parsing code */
- int (*Mf_getc)(struct MF *);
- void (*Mf_header)(struct MF *, int, int, int);
- void (*Mf_trackstart)(struct MF *);
- void (*Mf_trackend)(struct MF *);
- void (*Mf_noteon)(struct MF *, int, int, int);
- void (*Mf_noteoff)(struct MF *, int, int, int);
- void (*Mf_pressure)(struct MF *, int, int, int);
- void (*Mf_parameter)(struct MF *, int, int, int);
- void (*Mf_pitchbend)(struct MF *, int, int, int);
- void (*Mf_program)(struct MF *, int, int);
- void (*Mf_chanpressure)(struct MF *, int, int);
- void (*Mf_sysex)(struct MF *, int, char *);
- void (*Mf_metamisc)(struct MF *, int, int, char * );
- void (*Mf_seqspecific)(struct MF *, int, int, char *);
- void (*Mf_seqnum)(struct MF *, int);
- void (*Mf_text)(struct MF *, int, int, char *);
- void (*Mf_eot)(struct MF *);
- void (*Mf_timesig)(struct MF *, int, int, int, int);
- void (*Mf_smpte)(struct MF *, int, int, int, int, int);
- void (*Mf_tempo)(struct MF *, long);
- void (*Mf_keysig)(struct MF *, int, int);
- void (*Mf_arbitrary)(struct MF *, int, char *);
- void (*Mf_error)(struct MF *, char * );
-#if 0
-/* definitions for MIDI file writing code */
- void (*Mf_putc)(struct MF *);
- void (*Mf_writetrack)(struct MF *);
- void (*Mf_writetempotrack)(struct MF *);
-#endif
- /* variables */
- int Mf_nomerge; /* 1 => continue'ed system exclusives are */
- /* not collapsed. */
- long Mf_currtime; /* current time in delta-time units */
-
-/* private stuff */
- long Mf_toberead;
- long Mf_numbyteswritten;
-
- char *Msgbuff; /* message buffer */
- int Msgsize; /* Size of currently allocated Msg */
- int Msgindex; /* index of next available location in Msg */
-
-};
-
-float mf_ticks2sec(unsigned long ticks,int division,unsigned int tempo);
-unsigned long mf_sec2ticks(float secs,int division, unsigned int tempo);
-
-void mferror(struct MF * mf, char * s);
-
-/*void mfwrite(); */
-
-
-/* MIDI status commands most significant bit is 1 */
-#define note_off 0x80
-#define note_on 0x90
-#define poly_aftertouch 0xa0
-#define control_change 0xb0
-#define program_chng 0xc0
-#define channel_aftertouch 0xd0
-#define pitch_wheel 0xe0
-#define system_exclusive 0xf0
-#define delay_packet (1111)
-
-/* 7 bit controllers */
-#define damper_pedal 0x40
-#define portamento 0x41
-#define sostenuto 0x42
-#define soft_pedal 0x43
-#define general_4 0x44
-#define hold_2 0x45
-#define general_5 0x50
-#define general_6 0x51
-#define general_7 0x52
-#define general_8 0x53
-#define tremolo_depth 0x5c
-#define chorus_depth 0x5d
-#define detune 0x5e
-#define phaser_depth 0x5f
-
-/* parameter values */
-#define data_inc 0x60
-#define data_dec 0x61
-
-/* parameter selection */
-#define non_reg_lsb 0x62
-#define non_reg_msb 0x63
-#define reg_lsb 0x64
-#define reg_msb 0x65
-
-/* Standard MIDI Files meta event definitions */
-#define meta_event 0xFF
-#define sequence_number 0x00
-#define text_event 0x01
-#define copyright_notice 0x02
-#define sequence_name 0x03
-#define instrument_name 0x04
-#define lyric 0x05
-#define marker 0x06
-#define cue_point 0x07
-#define channel_prefix 0x20
-#define end_of_track 0x2f
-#define set_tempo 0x51
-#define smpte_offset 0x54
-#define time_signature 0x58
-#define key_signature 0x59
-#define sequencer_specific 0x74
-
-/* Manufacturer's ID number */
-#define Seq_Circuits (0x01) /* Sequential Circuits Inc. */
-#define Big_Briar (0x02) /* Big Briar Inc. */
-#define Octave (0x03) /* Octave/Plateau */
-#define Moog (0x04) /* Moog Music */
-#define Passport (0x05) /* Passport Designs */
-#define Lexicon (0x06) /* Lexicon */
-#define Tempi (0x20) /* Bon Tempi */
-#define Siel (0x21) /* S.I.E.L. */
-#define Kawai (0x41)
-#define Roland (0x42)
-#define Korg (0x42)
-#define Yamaha (0x43)
-
-/* miscellaneous definitions */
-#define MThd 0x4d546864
-#define MTrk 0x4d54726b
-#define lowerbyte(x) ((unsigned char)(x & 0xff))
-#define upperbyte(x) ((unsigned char)((x & 0xff00)>>8))
-
-/* the midifile interface */
-void midifile(struct MF * mf);
-
-/***** midifile.c ******/
-
-/*
- * midifile 1.11
- *
- * Read and write a MIDI file. Externally-assigned function pointers are
- * called upon recognizing things in the file.
- *
- * Original release ?
- * June 1989 - Added writing capability, M. Czeiszperger.
- *
- * The file format implemented here is called
- * Standard MIDI Files, and is part of the Musical
- * instrument Digital Interface specification.
- * The spec is avaiable from:
- *
- * International MIDI Association
- * 5316 West 57th Street
- * Los Angeles, CA 90056
- *
- * An in-depth description of the spec can also be found
- * in the article "Introducing Standard MIDI Files", published
- * in Electronic Musician magazine, April, 1989.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-
-#ifdef WIN32\r
-\r
- #include <windows.h>\r
-\r
-#else\r
-\r
- #include <unistd.h>\r
-#endif\r
-
-#include "gsm-common.h"
-#include "gsm-ringtones.h"
-
-#define NULLFUNC NULL
-
-static void readheader(struct MF * mf);
-static int readtrack(struct MF * mf);
-static void chanmessage(struct MF * mf,int status,int c1,int c2);
-static void msginit(struct MF * mf);
-static void msgadd(struct MF * mf,int c);
-static void metaevent(struct MF * mf, int type);
-static void sysex(struct MF * mf);
-static int msgleng(struct MF * mf);
-static void badbyte(struct MF * mf,int c);
-static void biggermsg(struct MF * mf);
-
-
-static long readvarinum(struct MF * mf);
-static long read32bit(struct MF * mf);
-static long to32bit(int, int, int, int);
-static int read16bit(struct MF * mf);
-static int to16bit(int, int);
-static char * msg(struct MF * mf);
-
-/* The only non-static function in this file. */
-void mfread(struct MF * mf)
-{
- if ( mf->Mf_getc == NULLFUNC )
- mferror(mf, "mfread() called without setting Mf_getc");
-
- readheader(mf);
- while ( readtrack(mf) )
- ;
-}
-
-/* for backward compatibility with the original lib */
-void midifile(struct MF * mf)
-{
- mfread(mf);
-}
-
-/* read through the "MThd" or "MTrk" header string */
-static int readmt(struct MF * mf, char * s)
-{
- int n = 0;
- char *p = s;
- int c=0;
-
- while ( n++<4 && (c=mf->Mf_getc(mf)) != EOF ) {
- if ( c != *p++ ) {
- char buff[32];
- (void) strcpy(buff, "expecting ");
- (void) strcat(buff, s);
- mferror(mf, buff);
- }
- }
- return c;
-}
-
-/* read a single character and abort on EOF */
-static int egetc(struct MF * mf)
-{
- int c = mf->Mf_getc(mf);
-
- if ( c == EOF )
- mferror(mf, "premature EOF");
- mf->Mf_toberead--;
- return c;
-}
-
-/* read a header chunk */
-static void readheader(struct MF * mf)
-{
- int format, ntrks, division;
-
- if ( readmt(mf, "MThd") == EOF )
- return;
-
- mf->Mf_toberead = read32bit(mf);
- format = read16bit(mf);
- ntrks = read16bit(mf);
- division = read16bit(mf);
-
- if ( mf->Mf_header )
- (*mf->Mf_header)(mf, format,ntrks,division);
-
- /* flush any extra stuff, in case the length of header is not 6 */
- while ( mf->Mf_toberead > 0 )
- (void) egetc(mf);
-}
-
-static int readtrack(struct MF * mf) /* read a track chunk */
-{
- /* This array is indexed by the high half of a status byte. It's */
- /* value is either the number of bytes needed (1 or 2) for a channel */
- /* message, or 0 (meaning it's not a channel message). */
- static int chantype[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */
- 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */
- };
- long lookfor;
- int c, c1, type;
- int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */
- int running = 0; /* 1 when running status used */
- int status = 0; /* status value (e.g. 0x90==note-on) */
- int needed;
-
- if ( readmt(mf, "MTrk") == EOF )
- return(0);
-
- mf->Mf_toberead = read32bit(mf);
- mf->Mf_currtime = 0;
-
- if ( mf->Mf_trackstart )
- (*mf->Mf_trackstart)(mf);
-
- while ( mf->Mf_toberead > 0 ) {
-
- mf->Mf_currtime += readvarinum(mf); /* delta time */
-
- c = egetc(mf);
-
- if ( sysexcontinue && c != 0xf7 )
- mferror(mf, "didn't find expected continuation of a sysex");
-
- if ( (c & 0x80) == 0 ) { /* running status? */
- if ( status == 0 )
- mferror(mf, "unexpected running status");
- running = 1;
- }
- else {
- status = c;
- running = 0;
- }
-
- needed = chantype[ (status>>4) & 0xf ];
-
- if ( needed ) { /* ie. is it a channel message? */
-
- if ( running )
- c1 = c;
- else
- c1 = egetc(mf);
- chanmessage(mf, status, c1, (needed>1)? egetc(mf): 0);
- continue;;
- }
-
- switch ( c ) {
-
- case 0xff: /* meta event */
-
- type = egetc(mf);
- lookfor = mf->Mf_toberead - readvarinum(mf);
- msginit(mf);
-
- while ( mf->Mf_toberead > lookfor )
- msgadd(mf, egetc(mf));
-
- metaevent(mf, type);
- break;
-
- case 0xf0: /* start of system exclusive */
-
- lookfor = mf->Mf_toberead - readvarinum(mf);
- msginit(mf);
- msgadd(mf, 0xf0);
-
- while ( mf->Mf_toberead > lookfor )
- msgadd(mf, c=egetc(mf));
-
- if ( c==0xf7 || mf->Mf_nomerge==0 )
- sysex(mf);
- else
- sysexcontinue = 1; /* merge into next msg */
- break;
-
- case 0xf7: /* sysex continuation or arbitrary stuff */
-
- lookfor = mf->Mf_toberead - readvarinum(mf);
-
- if ( ! sysexcontinue )
- msginit(mf);
-
- while ( mf->Mf_toberead > lookfor )
- msgadd(mf, c=egetc(mf));
-
- if ( ! sysexcontinue ) {
- if ( mf->Mf_arbitrary )
- (*mf->Mf_arbitrary)(mf, msgleng(mf),msg(mf));
- }
- else if ( c == 0xf7 ) {
- sysex(mf);
- sysexcontinue = 0;
- }
- break;
- default:
- badbyte(mf, c);
- break;
- }
- }
- if ( mf->Mf_trackend )
- (*mf->Mf_trackend)(mf);
- return(1);
-}
-
-static void badbyte(struct MF * mf,int c)
-{
- char buff[32];
-
- (void) sprintf(buff,"unexpected byte: 0x%02x",c);
- mferror(mf, buff);
-}
-
-static void metaevent(struct MF * mf, int type)
-{
- int leng = msgleng(mf);
- char *m = msg(mf);
-
- switch ( type ) {
- case 0x00:
- if ( mf->Mf_seqnum )
- (*mf->Mf_seqnum)(mf, to16bit(m[0],m[1]));
- break;
- case 0x01: /* Text event */
- case 0x02: /* Copyright notice */
- case 0x03: /* Sequence/Track name */
- case 0x04: /* Instrument name */
- case 0x05: /* Lyric */
- case 0x06: /* Marker */
- case 0x07: /* Cue point */
- case 0x08:
- case 0x09:
- case 0x0a:
- case 0x0b:
- case 0x0c:
- case 0x0d:
- case 0x0e:
- case 0x0f:
- /* These are all text events */
- if ( mf->Mf_text )
- (*mf->Mf_text)(mf, type,leng,m);
- break;
- case 0x2f: /* End of Track */
- if ( mf->Mf_eot )
- (*mf->Mf_eot)(mf);
- break;
- case 0x51: /* Set tempo */
- if ( mf->Mf_tempo )
- (*mf->Mf_tempo)(mf, to32bit(0,m[0],m[1],m[2]));
- break;
- case 0x54:
- if ( mf->Mf_smpte )
- (*mf->Mf_smpte)(mf, m[0],m[1],m[2],m[3],m[4]);
- break;
- case 0x58:
- if ( mf->Mf_timesig )
- (*mf->Mf_timesig)(mf, m[0],m[1],m[2],m[3]);
- break;
- case 0x59:
- if ( mf->Mf_keysig )
- (*mf->Mf_keysig)(mf, m[0],m[1]);
- break;
- case 0x7f:
- if ( mf->Mf_seqspecific )
- (*mf->Mf_seqspecific)(mf, type, leng, m);
- break;
- default:
- if ( mf->Mf_metamisc )
- (*mf->Mf_metamisc)(mf, type,leng,m);
- }
-}
-
-static void sysex(struct MF * mf)
-{
- if ( mf->Mf_sysex )
- (*mf->Mf_sysex)(mf, msgleng(mf),msg(mf));
-}
-
-static void chanmessage(struct MF * mf,int status,int c1,int c2)
-{
- int chan = status & 0xf;
-
- switch ( status & 0xf0 ) {
- case 0x80:
- if ( mf->Mf_noteoff )
- (*mf->Mf_noteoff)(mf, chan,c1,c2);
- break;
- case 0x90:
- if ( mf->Mf_noteon )
- (*mf->Mf_noteon)(mf, chan,c1,c2);
- break;
- case 0xa0:
- if ( mf->Mf_pressure )
- (*mf->Mf_pressure)(mf, chan,c1,c2);
- break;
- case 0xb0:
- if ( mf->Mf_parameter )
- (*mf->Mf_parameter)(mf, chan,c1,c2);
- break;
- case 0xe0:
- if ( mf->Mf_pitchbend )
- (*mf->Mf_pitchbend)(mf, chan,c1,c2);
- break;
- case 0xc0:
- if ( mf->Mf_program )
- (*mf->Mf_program)(mf, chan,c1);
- break;
- case 0xd0:
- if ( mf->Mf_chanpressure )
- (*mf->Mf_chanpressure)(mf, chan,c1);
- break;
- }
-}
-
-/* readvarinum - read a varying-length number, and return the */
-/* number of characters it took. */
-
-static long readvarinum(struct MF * mf)
-{
- long value;
- int c;
-
- c = egetc(mf);
- value = c;
- if ( c & 0x80 ) {
- value &= 0x7f;
- do {
- c = egetc(mf);
- value = (value << 7) + (c & 0x7f);
- } while (c & 0x80);
- }
- return (value);
-}
-
-static long to32bit(int c1,int c2,int c3,int c4)
-{
- long value = 0L;
-
- value = (c1 & 0xff);
- value = (value<<8) + (c2 & 0xff);
- value = (value<<8) + (c3 & 0xff);
- value = (value<<8) + (c4 & 0xff);
- return (value);
-}
-
-static int to16bit(int c1,int c2)
-{
- return ((c1 & 0xff ) << 8) + (c2 & 0xff);
-}
-
-static long read32bit(struct MF * mf)
-{
- int c1, c2, c3, c4;
-
- c1 = egetc(mf);
- c2 = egetc(mf);
- c3 = egetc(mf);
- c4 = egetc(mf);
- return to32bit(c1,c2,c3,c4);
-}
-
-static int read16bit(struct MF * mf)
-{
- int c1, c2;
- c1 = egetc(mf);
- c2 = egetc(mf);
- return to16bit(c1,c2);
-}
-
-/* static */
-void mferror(struct MF * mf, char * s)
-{
- if ( mf->Mf_error )
- (*mf->Mf_error)(mf, s);
- exit(1);
-}
-
-/* The code below allows collection of a system exclusive message of */
-/* arbitrary length. The Msgbuff is expanded as necessary. The only */
-/* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */
-
-#define MSGINCREMENT 128
-
-static void msginit(struct MF * mf)
-{
- mf->Msgindex = 0;
-}
-
-static char * msg(struct MF * mf)
-{
- return(mf->Msgbuff);
-}
-
-static int msgleng(struct MF * mf)
-{
- return(mf->Msgindex);
-}
-
-static void msgadd(struct MF * mf,int c)
-{
- /* If necessary, allocate larger message buffer. */
- if ( mf->Msgindex >= mf->Msgsize )
- biggermsg(mf);
- mf->Msgbuff[mf->Msgindex++] = c;
-}
-
-static void biggermsg(struct MF * mf)
-{
- char *newmess;
- char *oldmess = mf->Msgbuff;
- int oldleng = mf->Msgsize;
-
- mf->Msgsize += MSGINCREMENT;
- newmess = (char *) malloc( (unsigned)(sizeof(char) * mf->Msgsize) );
-
- if(newmess == NULL)
- mferror(mf, "malloc error!");
-
- /* copy old message into larger new one */
- if ( oldmess != NULL ) {
- register char *p = newmess;
- register char *q = oldmess;
- register char *endq = &oldmess[oldleng];
-
- for ( ; q!=endq ; p++,q++ )
- *p = *q;
- free(oldmess);
- }
- mf->Msgbuff = newmess;
-}
-
-#if 0 /* saving time not converting write function at this time
- */
-/*
- * mfwrite() - The only fuction you'll need to call to write out
- * a midi file.
- *
- * format 0 - Single multi-channel track
- * 1 - Multiple simultaneous tracks
- * 2 - One or more sequentially independent
- * single track patterns
- * ntracks The number of tracks in the file.
- * division This is kind of tricky, it can represent two
- * things, depending on whether it is positive or negative
- * (bit 15 set or not). If bit 15 of division is zero,
- * bits 14 through 0 represent the number of delta-time
- * "ticks" which make up a quarter note. If bit 15 of
- * division is a one, delta-times in a file correspond to
- * subdivisions of a second similiar to SMPTE and MIDI
- * time code. In this format bits 14 through 8 contain
- * one of four values - 24, -25, -29, or -30,
- * corresponding to the four standard SMPTE and MIDI
- * time code frame per second formats, where -29
- * represents 30 drop frame. The second byte
- * consisting of bits 7 through 0 corresponds the the
- * resolution within a frame. Refer the Standard MIDI
- * Files 1.0 spec for more details.
- * fp This should be the open file pointer to the file you
- * want to write. It will have be a global in order
- * to work with Mf_putc.
- */
-void
-mfwrite(format,ntracks,division,fp)
-int format,ntracks,division;
-FILE *fp;
-{
- int i; void mf_write_track_chunk(), mf_write_header_chunk();
-
- if ( mf->Mf_putc == NULLFUNC )
- mferror(mf, "mfmf_write() called without setting Mf_putc");
-
- if ( mf->Mf_writetrack == NULLFUNC )
- mferror(mf, "mfmf_write() called without setting Mf_mf_writetrack");
-
- /* every MIDI file starts with a header */
- mf_write_header_chunk(format,ntracks,division);
-
- /* In format 1 files, the first track is a tempo map */
- if(format == 1 && ( mf->Mf_writetempotrack ))
- {
- (*mf->Mf_writetempotrack)();
- }
-
- /* The rest of the file is a series of tracks */
- for(i = 0; i < ntracks; i++)
- mf_write_track_chunk(i,fp);
-}
-
-void
-mf_write_track_chunk(which_track,fp)
-int which_track;
-FILE *fp;
-{
- unsigned long trkhdr,trklength;
- long offset, place_marker;
- void write16bit(),write32bit();
-
-
- trkhdr = MTrk;
- trklength = 0;
-
- /* Remember where the length was written, because we don't
- know how long it will be until we've finished writing */
- offset = ftell(fp);
-
-#ifdef DEBUG
- printf("offset = %d\n",(int) offset);
-#endif
-
- /* Write the track chunk header */
- write32bit(trkhdr);
- write32bit(trklength);
-
- mf->Mf_numbyteswritten = 0L; /* the header's length doesn't count */
-
- if( mf->Mf_writetrack )
- {
- (*mf->Mf_writetrack)(which_track);
- }
-
- /* mf_write End of track meta event */
- eputc(mf, 0);
- eputc(mf, meta_event);
- eputc(mf, end_of_track);
-
- eputc(mf, 0);
-
- /* It's impossible to know how long the track chunk will be beforehand,
- so the position of the track length data is kept so that it can
- be written after the chunk has been generated */
- place_marker = ftell(fp);
-
- /* This method turned out not to be portable because the
- parameter returned from ftell is not guaranteed to be
- in bytes on every machine */
- /* track.length = place_marker - offset - (long) sizeof(track); */
-
-#ifdef DEBUG
-printf("length = %d\n",(int) trklength);
-#endif
-
- if(fseek(fp,offset,0) < 0)
- mferror(mf, "error seeking during final stage of write");
-
- trklength = mf->Mf_numbyteswritten;
-
- /* Re-mf_write the track chunk header with right length */
- write32bit(trkhdr);
- write32bit(trklength);
-
- fseek(fp,place_marker,0);
-} /* End gen_track_chunk() */
-
-
-void
-mf_write_header_chunk(format,ntracks,division)
-int format,ntracks,division;
-{
- unsigned long ident,length;
- void write16bit(),write32bit();
-
- ident = MThd; /* Head chunk identifier */
- length = 6; /* Chunk length */
-
- /* individual bytes of the header must be written separately
- to preserve byte order across cpu types :-( */
- write32bit(ident);
- write32bit(length);
- write16bit(format);
- write16bit(ntracks);
- write16bit(division);
-} /* end gen_header_chunk() */
-
-
-#ifdef WHENISTHISNEEDED
-/*
- * mf_write_midi_event()
- *
- * Library routine to mf_write a single MIDI track event in the standard MIDI
- * file format. The format is:
- *
- * <delta-time><event>
- *
- * In this case, event can be any multi-byte midi message, such as
- * "note on", "note off", etc.
- *
- * delta_time - the time in ticks since the last event.
- * type - the type of meta event.
- * chan - The midi channel.
- * data - A pointer to a block of chars containing the META EVENT,
- * data.
- * size - The length of the meta-event data.
- */
-int
-mf_write_midi_event(delta_time, type, chan, data, size)
-unsigned long delta_time;
-unsigned int chan,type;
-unsigned long size;
-unsigned char *data;
-{
- int i;
- void WriteVarLen();
- unsigned char c;
-
- WriteVarLen(delta_time);
-
- /* all MIDI events start with the type in the first four bits,
- and the channel in the lower four bits */
- c = type | chan;
-
- if(chan > 15)
- perror("error: MIDI channel greater than 16\n");
-
- eputc(mf, c);
-
- /* write out the data bytes */
- for(i = 0; i < size; i++)
- eputc(mf, data[i]);
-
- return(size);
-} /* end mf_write MIDI event */
-
-/*
- * mf_write_meta_event()
- *
- * Library routine to mf_write a single meta event in the standard MIDI
- * file format. The format of a meta event is:
- *
- * <delta-time><FF><type><length><bytes>
- *
- * delta_time - the time in ticks since the last event.
- * type - the type of meta event.
- * data - A pointer to a block of chars containing the META EVENT,
- * data.
- * size - The length of the meta-event data.
- */
-int
-mf_write_meta_event(delta_time, type, data, size)
-unsigned long delta_time;
-unsigned char *data,type;
-unsigned long size;
-{
- int i;
-
- WriteVarLen(delta_time);
-
- /* This marks the fact we're writing a meta-event */
- eputc(mf, meta_event);
-
- /* The type of meta event */
- eputc(mf, type);
-
- /* The length of the data bytes to follow */
- WriteVarLen(size);
-
- for(i = 0; i < size; i++)
- {
- if(eputc(mf, data[i]) != data[i])
- return(-1);
- }
- return(size);
-} /* end mf_write_meta_event */
-
-void
-mf_write_tempo(tempo)
-unsigned long tempo;
-{
- /* Write tempo */
- /* all tempos are written as 120 beats/minute, */
- /* expressed in microseconds/quarter note */
- eputc(mf, 0);
- eputc(mf, meta_event);
- eputc(mf, set_tempo);
-
- eputc(mf, 3);
- eputc(mf, (unsigned)(0xff & (tempo >> 16)));
- eputc(mf, (unsigned)(0xff & (tempo >> 8)));
- eputc(mf, (unsigned)(0xff & tempo));
-}
-
-#endif
-/*
- * Write multi-length bytes to MIDI format files
- */
-void
-WriteVarLen(value)
-unsigned long value;
-{
- unsigned long buffer;
-
- buffer = value & 0x7f;
- while((value >>= 7) > 0)
- {
- buffer <<= 8;
- buffer |= 0x80;
- buffer += (value & 0x7f);
- }
- while(1){
- eputc(mf, (unsigned)(buffer & 0xff));
-
- if(buffer & 0x80)
- buffer >>= 8;
- else
- return;
- }
-}/* end of WriteVarLen */
-
-
-/*
- * write32bit()
- * write16bit()
- *
- * These routines are used to make sure that the byte order of
- * the various data types remains constant between machines. This
- * helps make sure that the code will be portable from one system
- * to the next. It is slightly dangerous that it assumes that longs
- * have at least 32 bits and ints have at least 16 bits, but this
- * has been true at least on PCs, UNIX machines, and Macintosh's.
- *
- */
-void
-write32bit(data)
-unsigned long data;
-{
- eputc(mf, x(unsigned)((data >> 24) & 0xff));
- eputc(mf, (unsigned)((data >> 16) & 0xff));
- eputc(mf, (unsigned)((data >> 8 ) & 0xff));
- eputc(mf, (unsigned)(data & 0xff));
-}
-
-void
-write16bit(data)
-int data;
-{
- eputc(mf, (unsigned)((data & 0xff00) >> 8));
- eputc(mf, (unsigned)(data & 0xff));
-}
-
-/* write a single character and abort on error */
-eputc(mf, c)
-unsigned char c;
-{
- int return_val;
-
- if((mf->Mf_putc) == NULLFUNC)
- {
- mferror(mf, "Mf_putc undefined");
- return(-1);
- }
-
- return_val = (mf->Mf_putc)(mf, c);
-
- if ( return_val == EOF )
- mferror(mf, "error writing");
-
- mf->Mf_numbyteswritten++;
- return(return_val);
-}
-
-#endif
-
-unsigned long mf_sec2ticks(float secs,int division, unsigned int tempo)
-{
- return (long)(((secs * 1000.0) / 4.0 * division) / tempo);
-}
-
-
-/*
- * This routine converts delta times in ticks into seconds. The
- * else statement is needed because the formula is different for tracks
- * based on notes and tracks based on SMPTE times.
- *
- */
-float mf_ticks2sec(unsigned long ticks,int division,unsigned int tempo)
-{
- float smpte_format, smpte_resolution;
-
- if(division > 0)
- return ((float) (((float)(ticks) * (float)(tempo)) / ((float)(division) * 1000000.0)));
- else
- {
- smpte_format = upperbyte(division);
- smpte_resolution = lowerbyte(division);
- return (float) ((float) ticks / (smpte_format * smpte_resolution * 1000000.0));
- }
-} /* end of ticks2sec() */
-
-/* code to utilize the interface */
-
-#define TRACE(x, y) do { if (x) printf y; } while (0)
-
-
-typedef unsigned long ulg;
-typedef unsigned char uch;
-typedef unsigned int ui;
-
-struct NoteInfo
-{
- int beats;
- int nrnotes;
- struct Notes {
- ui note : 4;
- ui scale : 4;
- ui length : 4;
- ui lextra : 4;
- } note[1];
-};
-
-#define IBUFSIZE 1024
-struct MFX
-{
- struct MF mfi;
- struct NoteInfo * ni;
- int allocated;
-
- int division;
- int trackstate;
-
- int prevnoteonpitch; /* -1, nothing, 0 pause, 1-x note. */
- ulg prevnoteontime;
-
- struct {
- int fd;
- uch buf[IBUFSIZE];
- int len;
- int p;
- } istrm;
-};
-
-enum { TRK_NONE, TRK_READING, TRK_FINISHED };
-
-#define ALLOCSIZE 256
-
-#define NIALLOC(size) (struct NoteInfo *)malloc(sizeof (struct NoteInfo) + ((size) - 1) * sizeof (struct Notes))
-
-#define NIREALLOC(ni, size) (struct NoteInfo *)realloc((ni), sizeof (struct NoteInfo) + ((size) - 1) * sizeof (struct Notes))
-
-
-static void lm_error(struct MF * mf, char * s);
-
-static int lm_getc(struct MF * mf);
-static void lm_header(struct MF * mf, int, int, int);
-static void lm_trackstart(struct MF * mf);
-static void lm_trackend(struct MF * mf);
-static void lm_tempo(struct MF *, long);
-static void lm_noteon(struct MF *, int, int, int);
-static void lm_noteoff(struct MF *, int, int, int);
-
-
-struct NoteInfo * readmidi(int fd)
-{
- struct MFX mfxi = { { 0 } };
- struct MF * mf = (struct MF *)&mfxi;
-
- mfxi.ni = NIALLOC(ALLOCSIZE);
- mfxi.allocated = ALLOCSIZE;
-
- /* set variables to their initial values */
- mfxi.division = 0;
- mfxi.trackstate = TRK_NONE;
- mfxi.prevnoteonpitch = -1;
- mfxi.ni->nrnotes = 0;
- mfxi.ni->beats = 120;
-
- mfxi.istrm.fd = fd;
- mfxi.istrm.p = mfxi.istrm.len = 0;
- mf->Mf_getc = lm_getc;
-
- mf->Mf_header = lm_header;
- mf->Mf_tempo = lm_tempo;
- mf->Mf_trackstart = lm_trackstart;
- mf->Mf_trackend = lm_trackend;
- mf->Mf_noteon = lm_noteon;
- mf->Mf_noteoff = lm_noteoff;
-
- mf->Mf_error = lm_error;
-
- midifile(mf);
-
- return mfxi.ni;
-}
-
-static void lm_error(struct MF * mf, char * s)
-{
- fprintf(stderr, "%s\n", s);
-}
-
-static int lm_getc(struct MF * mf)
-{
- struct MFX * mfx = (struct MFX *)mf;
-
- /* printf("p %d, len %d\n", mfx->istrm.p, mfx->istrm.len); */
- if (mfx->istrm.p == mfx->istrm.len)
- {
- mfx->istrm.len = read(mfx->istrm.fd, mfx->istrm.buf, IBUFSIZE);
- /* printf("readlen %d\n", mfx->istrm.len); */
- if (mfx->istrm.len <= 0)
- return -1;
-
- mfx->istrm.p = 1;
- return mfx->istrm.buf[0];
- }
- /* else */
- return mfx->istrm.buf[mfx->istrm.p++];
-}
-
-static void lm_header(struct MF * mf, int format, int ntrks, int division)
-{
- struct MFX * mfx = (struct MFX *)mf;
-
- TRACE(0, ("lm_header(%p, %d, %d, %d)\n", mf, format, ntrks, division));
-
- mfx->division = division;
-}
-
-/* this is just a quess */
-static void lm_tempo(struct MF * mf, long tempo)
-{
- struct MFX * mfx = (struct MFX *)mf;
-
- TRACE(0, ("lm_tempo(%p, %ld)\n", mf, tempo));
-
- if (mfx->trackstate != TRK_FINISHED)
- mfx->ni->beats = 60000000 / tempo;
-}
-
-
-static void addnote(struct MFX * mfx, int pitch, int duration, int special)
-{
- int nr, p, s;
- struct NoteInfo * ni;
-
- if (mfx->ni->nrnotes == mfx->allocated)
- {
- mfx->allocated += ALLOCSIZE;
- mfx->ni = NIREALLOC(mfx->ni, mfx->allocated);
- if (mfx->ni == NULL)
- exit(1);
- }
- ni = mfx->ni; /* mfx->ni pointer value may have changed above */
- nr = ni->nrnotes++;
-
-
- if (pitch == 0) { p = 0; s = 0; }
- else { pitch--; p = (pitch % 12) + 1; s = pitch / 12; }
-
- ni->note[nr].note = p;
- ni->note[nr].scale = s;
-
- ni->note[nr].length = duration;
- ni->note[nr].lextra = special;
-}
-
-/* currently supported */
-static /* N 32 32. 16 16. 8 8. 4 4. 2 2. 1 1. */
-int vals[] = { 15, 38, 54, 78, 109, 156, 218, 312, 437, 625, 875, 1250 };
-
-static void writenote(struct MFX * mfx, int delta)
-{
- ulg millinotetime = delta * 250 / mfx->division;
- int i;
- int duration;
- int special;
-
- for(i = 0; i < sizeof vals / sizeof vals[0]; i++)
- {
- if (millinotetime < vals[i])
- break;
- }
-
- if (i == 0)
- return;
-
- i--;
- duration = i / 2;
- special = i & 1;
-
- addnote(mfx, mfx->prevnoteonpitch, duration, special); /* XXX think this */
-}
-
-
-static void lm_trackstart(struct MF * mf)
-{
- struct MFX * mfx = (struct MFX *)mf;
-
- TRACE(0, ("lm_trackstart(%p)\n", mf));
-
- if (mfx->trackstate == TRK_NONE)
- mfx->trackstate = TRK_READING;
-
- mfx->prevnoteonpitch = -1;
-}
-
-static void lm_trackend(struct MF * mf)
-{
- struct MFX * mfx = (struct MFX *)mf;
- long time = mf->Mf_currtime;
-
- TRACE(0, ("lm_trackend(%p)\n", mf));
-
- if (mfx->trackstate == TRK_READING && mfx->ni->nrnotes > 0)
- mfx->trackstate = TRK_FINISHED;
-
- if (mfx->prevnoteonpitch >= 0)
- writenote(mfx, time - mfx->prevnoteontime);
-
- mfx->prevnoteonpitch = -1;
-}
-
-static void lm_noteon(struct MF * mf, int chan, int pitch, int vol)
-{
- struct MFX * mfx = (struct MFX *)mf;
- long time = mf->Mf_currtime;
-
- TRACE(0, ("lm_noteon(%p, %d, %d, %d)\n", mf, chan, pitch, vol));
-
- if (vol == 0) /* kludge? to handle some (format 1? midi files) */
- return;
-
- if (mfx->trackstate != TRK_READING)
- return;
-
- if (mfx->prevnoteonpitch >= 0)
- writenote(mfx, time - mfx->prevnoteontime);
-
- if (vol == 0)
- mfx->prevnoteonpitch = 0;
- else
- mfx->prevnoteonpitch = pitch + 1;
-
- mfx->prevnoteontime = time;
-}
-
-static void lm_noteoff(struct MF * mf, int chan, int pitch, int vol)
-{
- struct MFX * mfx = (struct MFX *)mf;
- long time = mf->Mf_currtime;
-
- TRACE(0, ("lm_noteoff(%p, %d, %d, %d)\n", mf, chan, pitch, vol));
-
- if (mfx->prevnoteonpitch >= 0)
- {
- writenote(mfx, time - mfx->prevnoteontime);
- mfx->prevnoteonpitch = -1;
- }
- mfx->prevnoteonpitch = 0;
- mfx->prevnoteontime = time;
-}
-
-//{ "p", "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "h" };
-char notes[] =
- { 255, 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 , 12 };
-
-u8 lengths[] = { 4, 8, 16, 32, 64, 128 };
-
-static void countdefaults(struct NoteInfo * ni, int * length_p, int * scale_p)
-{
- int lengths[15] = { 0 };
- int scales[15] = { 0 };
- int maxlenval = 0; /* (*) */
- int maxscaleval = 0;
- int i;
-
- for (i = 0; i < ni->nrnotes; i++)
- {
- struct Notes * note = &ni->note[i];
-
- lengths[note->length]++;
- scales[note->scale]++;
- }
-
- maxlenval = lengths[0]; /* (*) smart compiler eliminates dead code */
- *length_p = 0;
-
- for (i = 1; i < 15; i++) /* `p' incremented scales[0], therefore ignored */
- {
- TRACE(0, ("%d - len: %d, scale: %d\n", i, lengths[i], scales[i]));
-
- if (lengths[i] > maxlenval) {
- *length_p = i;
- maxlenval = lengths[i];
- }
- if (scales[i] > maxscaleval) {
- *scale_p = i;
- maxscaleval = scales[i];
- }
- }
-}
-
-GSM_Error loadmid(char *filename, GSM_Ringtone *ringtone)
-{
- int fd;
- struct NoteInfo * ni;
- int i;
- int deflen, defscale;
-
-#ifdef WIN32
- if ((fd = open(filename, O_RDONLY | O_BINARY)) < 0)
- {
- perror("open");
- return GE_CANTOPENFILE;
- }
-#else
- if ((fd = open(filename, O_RDONLY)) < 0)
- {
- perror("open");
- return GE_CANTOPENFILE;
- }
-#endif
-
- ni = readmidi(fd);
-
- if (ni == NULL)
- return 0;
-
- countdefaults(ni, &deflen, &defscale);
-
- strcpy(ringtone->name,"GNOKII");
-
- if (ni->nrnotes<MAX_RINGTONE_NOTES)
- ringtone->NrNotes=ni->nrnotes;
- else
- ringtone->NrNotes=MAX_RINGTONE_NOTES;
-
- for (i = 0; i < ringtone->NrNotes; i++)
- {
- struct Notes * note = &ni->note[i];
-
- ringtone->notes[i].note=notes[note->note];
- ringtone->notes[i].note=notes[note->note]+(note->scale%4)*14;
-
- ringtone->notes[i].duration=lengths[note->length];
- if (note->lextra)
- ringtone->notes[i].duration=ringtone->notes[i].duration*1.5;
-
- ringtone->notes[i].tempo=ni->beats;
-
- }
-
- ringtone->Loop=15;
-
- return 0;
-}