jdkmidi class library documentation

Copyright © 2004 J.D. Koftinoff Software, Ltd.

Released under the GNU General Public License (GPL)




Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

src/jdkmidi_filewrite.cpp

Go to the documentation of this file.
00001 /*
00002  *  libjdkmidi-2004 C++ Class Library for MIDI
00003  *
00004  *  Copyright (C) 2004  J.D. Koftinoff Software, Ltd.
00005  *  www.jdkoftinoff.com
00006  *  jeffk@jdkoftinoff.com
00007  *
00008  *  *** RELEASED UNDER THE GNU GENERAL PUBLIC LICENSE (GPL) April 27, 2004 ***
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 */
00024 /*
00025 **  Copyright 1986 to 1998 By J.D. Koftinoff Software, Ltd.
00026 **
00027 **  All rights reserved.
00028 **
00029 **  No one may duplicate this source code in any form for any reason
00030 **  without the written permission given by J.D. Koftinoff Software, Ltd.
00031 **
00032 */
00033 
00034 
00035 #include "jdkmidi/world.h"
00036 
00037 #include "jdkmidi/filewrite.h"
00038 
00039 #ifndef DEBUG_MDFWR
00040 # define DEBUG_MDFWR  0
00041 #endif
00042 
00043 #if DEBUG_MDFWR
00044 # undef DBG
00045 # define DBG(a) a
00046 #endif
00047 
00048 namespace jdkmidi
00049 {
00050   
00051   
00052   MIDIFileWriteStream::MIDIFileWriteStream()
00053   {
00054   }
00055   
00056   MIDIFileWriteStream::~MIDIFileWriteStream()
00057   {
00058   }
00059   
00060   MIDIFileWriteStreamFile::MIDIFileWriteStreamFile( FILE *f_ )
00061     : f(f_)
00062   {
00063   }
00064   
00065   MIDIFileWriteStreamFile::~MIDIFileWriteStreamFile()
00066   {
00067   }
00068   
00069   long MIDIFileWriteStreamFile::Seek( long pos, int whence )
00070   {
00071     return fseek( f, pos, whence );
00072   }
00073   
00074   int MIDIFileWriteStreamFile::WriteChar( int c )
00075   {
00076     if( fputc( c, f )==EOF )
00077     {
00078       return -1;
00079     }
00080     else
00081     {
00082       return 0;
00083     }
00084   }
00085   
00086   
00087   MIDIFileWrite::MIDIFileWrite( MIDIFileWriteStream *out_stream_ )
00088     : out_stream( out_stream_ ) 
00089   {
00090     ENTER( "MIDIFileWrite::MIDIFileWrite()" );
00091     
00092     file_length=0;
00093     error=0;
00094     track_length=0;
00095     track_time=0;
00096     running_status=0;
00097     track_position=0;
00098   } 
00099   
00100   MIDIFileWrite::~MIDIFileWrite() 
00101   {
00102     ENTER( "MIDIFileWrite::~MIDIFileWrite()" );
00103     
00104   } 
00105   
00106   void  MIDIFileWrite::Error(char *s) 
00107   {
00108     ENTER( "void  MIDIFileWrite::Error()" );
00109     
00110     // NULL method; can override.
00111     
00112     error=true;
00113   } 
00114   
00115   void    MIDIFileWrite::WriteShort( unsigned short c ) 
00116   {
00117     ENTER( "void    MIDIFileWrite::WriteShort()" );
00118     
00119     WriteCharacter( (unsigned char)((c>>8)&0xff) );
00120     WriteCharacter( (unsigned char)((c&0xff)) );
00121   } 
00122   
00123   void  MIDIFileWrite::Write3Char( long c ) 
00124   {
00125     ENTER( "void  MIDIFileWrite::Write3Char()" );
00126     
00127     WriteCharacter( (unsigned char)((c>>16)&0xff) );
00128     WriteCharacter( (unsigned char)((c>>8)&0xff) );
00129     WriteCharacter( (unsigned char)((c&0xff)) );
00130   } 
00131   
00132   void  MIDIFileWrite::WriteLong( unsigned long c ) 
00133   {
00134     ENTER( "void  MIDIFileWrite::WriteLong()" );
00135     
00136     WriteCharacter( (unsigned char) ((c>>24)&0xff) );
00137     WriteCharacter( (unsigned char) ((c>>16)&0xff) );
00138     WriteCharacter( (unsigned char) ((c>>8)&0xff) );
00139     WriteCharacter( (unsigned char) ((c&0xff)) );
00140   } 
00141   
00142   void  MIDIFileWrite::WriteFileHeader(
00143     int format,
00144     int ntrks,
00145     int division
00146     ) 
00147   {
00148     ENTER( "void  MIDIFileWrite::WriteFileHeader()" );
00149     
00150     WriteCharacter( (unsigned char) 'M' );
00151     WriteCharacter( (unsigned char) 'T' );
00152     WriteCharacter( (unsigned char) 'h' );
00153     WriteCharacter( (unsigned char) 'd' );
00154     WriteLong( 6 );
00155     WriteShort( (short)format );
00156     WriteShort( (short)ntrks );
00157     WriteShort( (short)division );
00158     file_length=4+4+6;
00159   } 
00160   
00161   void  MIDIFileWrite::WriteTrackHeader( unsigned long length ) 
00162   {
00163     ENTER( "void  MIDIFileWrite::WriteTrackHeader()" );
00164     
00165     track_position=file_length;
00166     track_length=0;
00167     track_time=0;
00168     running_status=0;
00169     
00170     WriteCharacter( (unsigned char) 'M' );
00171     WriteCharacter( (unsigned char) 'T' );
00172     WriteCharacter( (unsigned char) 'r' );
00173     WriteCharacter( (unsigned char) 'k' );
00174     
00175     WriteLong( length );
00176     file_length+=8;
00177     within_track=true;
00178   } 
00179   
00180   int MIDIFileWrite::WriteVariableNum( unsigned long n )  
00181   {
00182     ENTER( "short MIDIFileWrite::WriteVariableNum()" );
00183     
00184     register unsigned long buffer;
00185     short cnt=0;
00186     
00187     buffer=n&0x7f;
00188     while( (n>>=7) > 0)
00189     {
00190       buffer <<=8;
00191       buffer|=0x80;
00192       buffer+=(n&0x7f);
00193     }
00194     
00195     while( true )
00196     {
00197       WriteCharacter( (unsigned char) (buffer&0xff) );
00198       cnt++;
00199       if( buffer&0x80 )
00200         buffer>>=8;
00201       else
00202         break;
00203     }
00204     return cnt;
00205   } 
00206   
00207   void  MIDIFileWrite::WriteDeltaTime( unsigned long abs_time ) 
00208   {
00209     ENTER( "void  MIDIFileWrite::WriteDeltaTime()" );
00210     
00211     long dtime=abs_time-track_time;
00212     if( dtime<0 )
00213     {
00214 //    Error( "Events out of order" );
00215       dtime=0;
00216     }
00217     
00218     IncrementCounters( WriteVariableNum( dtime ) );
00219     track_time=abs_time;
00220   } 
00221   
00222   void    MIDIFileWrite::WriteEvent( const MIDITimedMessage &m )  
00223   {
00224     ENTER( "void    MIDIFileWrite::WriteEvent()" );
00225     
00226     if( m.IsNoOp() )
00227     {
00228       return;
00229     }
00230     
00231     if( m.IsMetaEvent() )
00232     {
00233       // TO DO: add more meta events.
00234       
00235       
00236       if( m.IsTempo() )
00237       {
00238         unsigned long tempo = (60000000/m.GetTempo32())*32;
00239         WriteTempo( m.GetTime(), tempo );
00240         return;
00241       }
00242       if( m.IsDataEnd() )
00243       {
00244         WriteEndOfTrack( m.GetTime() );
00245         return;
00246       }
00247       if( m.IsKeySig() )
00248       {
00249         WriteKeySignature( m.GetTime(), m.GetKeySigSharpFlats(), m.GetKeySigMajorMinor() );
00250         return;
00251       }
00252       return; // all other marks are ignored.
00253     }
00254     else
00255     {
00256       short len=m.GetLength();
00257       
00258       WriteDeltaTime( m.GetTime() );
00259       if( m.GetStatus()!=running_status )
00260       {
00261         running_status=m.GetStatus();
00262         WriteCharacter( (unsigned char) running_status );
00263         IncrementCounters(1);
00264       }
00265       if( len>1 )
00266       {
00267         WriteCharacter( (unsigned char) m.GetByte1() );
00268         IncrementCounters(1);
00269       }
00270       if( len>2 )
00271       {
00272         WriteCharacter( (unsigned char) m.GetByte2() );
00273         IncrementCounters(1);
00274       }
00275     }
00276     
00277   } 
00278   
00279   void  MIDIFileWrite::WriteEvent( const MIDITimedBigMessage &m )
00280   {
00281     if( m.IsNoOp() )
00282     {
00283       return;
00284     }
00285     
00286     if( m.IsMetaEvent() )
00287     {
00288       // if this meta-event has a sysex buffer attached, this
00289       // buffer contains the raw midi file meta data
00290       
00291       if( m.GetSysEx() )
00292       {
00293         WriteMetaEvent(
00294           m.GetTime(),
00295           m.GetMetaType(),
00296           m.GetSysEx()->GetBuf(),
00297           m.GetSysEx()->GetLength()
00298           );
00299       }
00300       else
00301       {
00302         // otherwise, it is a type of sysex that doesnt have
00303         // data...
00304         if( m.IsTempo() )
00305         {
00306           unsigned long tempo = (60000000/m.GetTempo32())*32;
00307           WriteTempo( m.GetTime(), tempo );
00308         }
00309         else if( m.IsDataEnd() )
00310         {
00311           WriteEndOfTrack( m.GetTime() );
00312         }
00313         else if( m.IsKeySig() )
00314         {
00315           WriteKeySignature( m.GetTime(), m.GetKeySigSharpFlats(), m.GetKeySigMajorMinor() );
00316         }
00317         
00318       }
00319       
00320     }
00321     else
00322     {
00323       short len=m.GetLength();
00324       
00325       if( m.IsSysEx() && m.GetSysEx() )
00326       {
00327         WriteEvent( m.GetTime(), m.GetSysEx() );
00328       }
00329       else if( len>0 )
00330       {
00331         WriteDeltaTime( m.GetTime() );
00332         if( m.GetStatus()!=running_status )
00333         {
00334           running_status=m.GetStatus();
00335           WriteCharacter( (unsigned char) running_status );
00336           IncrementCounters(1);
00337         }
00338         if( len>1 )
00339         {
00340           WriteCharacter( (unsigned char) m.GetByte1() );
00341           IncrementCounters(1);
00342         }
00343         if( len>2 )
00344         {
00345           WriteCharacter( (unsigned char) m.GetByte2() );
00346           IncrementCounters(1);
00347         }
00348       }
00349     }
00350     
00351   }
00352   
00353   void  MIDIFileWrite::WriteEvent(
00354     unsigned long time,
00355     const MIDISystemExclusive *e
00356     ) 
00357   {
00358     ENTER( "void  MIDIFileWrite::WriteEvent()" );
00359     
00360     int len=e->GetLength();
00361     
00362     WriteDeltaTime( time );
00363     
00364     WriteCharacter( (unsigned char)SYSEX_START );
00365     IncrementCounters( WriteVariableNum( len-1 ) );
00366     
00367     for( int i=1; i<len; i++ )  // skip the initial 0xF0
00368     {
00369       WriteCharacter( (unsigned char)(e->GetData(i)) );
00370     }
00371     IncrementCounters( len );
00372     running_status=0;
00373   } 
00374   
00375   void  MIDIFileWrite::WriteEvent( unsigned long time, unsigned short text_type, const char *text ) 
00376   {
00377     ENTER( "void  MIDIFileWrite::WriteEvent()" );
00378     
00379     WriteDeltaTime( time );
00380     
00381     WriteCharacter( (unsigned char) 0xff );   // META-Event
00382     WriteCharacter( (unsigned char) text_type );  // Text event type
00383     
00384     IncrementCounters(2);
00385     
00386     long len=strlen(text);
00387     
00388     IncrementCounters( WriteVariableNum( len ) );
00389     
00390     while( *text )
00391     {
00392       WriteCharacter( (unsigned char) *text++ );
00393     }
00394     IncrementCounters( len );
00395     running_status=0;
00396   } 
00397   
00398   void  MIDIFileWrite::WriteMetaEvent( unsigned long time, unsigned char type, const unsigned char *data, long length ) 
00399   {
00400     ENTER( "void  MIDIFileWrite::WriteMetaEvent()" );
00401     
00402     WriteDeltaTime( time );
00403     WriteCharacter( (unsigned char) 0xff ); // META-Event
00404     WriteCharacter( (unsigned char) type ); // Meta-event type
00405     
00406     IncrementCounters(2);
00407     
00408     IncrementCounters( WriteVariableNum( length ) );
00409     
00410     for( int i=0; i<length; i++ )
00411     {
00412       WriteCharacter( (unsigned char) data[i] );
00413     }
00414     IncrementCounters( length );
00415     running_status=0;
00416   } 
00417   
00418   void  MIDIFileWrite::WriteTempo( unsigned long time, long tempo ) 
00419   {
00420     ENTER( "void  MIDIFileWrite::WriteTempo()" );
00421     
00422     WriteDeltaTime( time );
00423     WriteCharacter( (unsigned char) 0xff ); // Meta-Event
00424     WriteCharacter( (unsigned char) 0x51 ); // Tempo event
00425     WriteCharacter( (unsigned char) 0x03 ); // length of event
00426     
00427     Write3Char( tempo );
00428     IncrementCounters(6);
00429     running_status=0;
00430   } 
00431   
00432   void  MIDIFileWrite::WriteKeySignature( unsigned long time, char sharp_flat, char minor ) 
00433   {
00434     ENTER( "void  MIDIFileWrite::WriteKeySignature()" );
00435     
00436     WriteDeltaTime( time );
00437     WriteCharacter( (unsigned char) 0xff );   // Meta-Event
00438     WriteCharacter( (unsigned char) 0x59 );   // Key Sig
00439     WriteCharacter( (unsigned char) 0x02 );   // length of event
00440     WriteCharacter( (unsigned char) sharp_flat ); // - for flats, + for sharps
00441     WriteCharacter( (unsigned char) minor );  // 1 if minor key
00442     IncrementCounters(5);
00443     running_status=0;
00444   } 
00445   
00446   void  MIDIFileWrite::WriteTimeSignature(
00447     unsigned long time,
00448     char numerator,
00449     char denominator_power,
00450     char midi_clocks_per_metronome,
00451     char num_32nd_per_midi_quarter_note)  
00452   {
00453     ENTER( "void  MIDIFileWrite::WriteTimeSignature()" );
00454     
00455     WriteDeltaTime( time );
00456     WriteCharacter( (unsigned char) 0xff );   // Meta-Event
00457     WriteCharacter( (unsigned char) 0x58 );   // time signature
00458     WriteCharacter( (unsigned char) 0x04 );   // length of event
00459     WriteCharacter( (unsigned char) numerator );
00460     WriteCharacter( (unsigned char) denominator_power );
00461     WriteCharacter( (unsigned char) midi_clocks_per_metronome );
00462     WriteCharacter( (unsigned char) num_32nd_per_midi_quarter_note );
00463     IncrementCounters(7);
00464     running_status=0;
00465   } 
00466   
00467   void  MIDIFileWrite::WriteEndOfTrack( unsigned long time )  
00468   {
00469     ENTER( "void  MIDIFileWrite::WriteEndOfTrack()" );
00470     
00471     if( within_track==true )
00472     {
00473       if( time==0 )
00474         time=track_time;
00475       WriteDeltaTime( time );
00476       WriteCharacter( (unsigned char) 0xff );   // Meta-Event
00477       WriteCharacter( (unsigned char) 0x2f );   // End of track
00478       WriteCharacter( (unsigned char) 0x00 );   // length of event
00479       IncrementCounters( 3 );
00480       within_track=false;
00481       running_status=0;
00482     }
00483   } 
00484   
00485   void  MIDIFileWrite::RewriteTrackLength() 
00486   {
00487     ENTER( "void  MIDIFileWrite::RewriteTrackLength()" );
00488     
00489     // go back and patch in the tracks length into the track chunk
00490     // header, now that we know the proper value.
00491     // then make sure we go back to the end of the file
00492     
00493     Seek( track_position+4 );
00494     WriteLong( track_length );
00495     Seek( track_position+8+track_length );
00496   } 
00497   
00498 }