<s> from io import BytesIO <EOL> import six <EOL> from sebastian . core import OFFSET_64 , MIDI_PITCH , DURATION_64 <EOL> def write_chars ( out , chars ) : <EOL> out . write ( chars . encode ( '<STR_LIT:ascii>' ) ) <EOL> def write_byte ( out , b ) : <EOL> out . write ( six . int2byte ( b ) ) <EOL> def write_ushort ( out , s ) : <EOL> write_byte ( out , ( s >> <NUM_LIT:8> ) % <NUM_LIT> ) <EOL> write_byte ( out , ( s >> <NUM_LIT:0> ) % <NUM_LIT> ) <EOL> def write_ulong ( out , l ) : <EOL> write_byte ( out , ( l >> <NUM_LIT> ) % <NUM_LIT> ) <EOL> write_byte ( out , ( l >> <NUM_LIT:16> ) % <NUM_LIT> ) <EOL> write_byte ( out , ( l >> <NUM_LIT:8> ) % <NUM_LIT> ) <EOL> write_byte ( out , ( l >> <NUM_LIT:0> ) % <NUM_LIT> ) <EOL> def write_varlen ( out , n ) : <EOL> data = six . int2byte ( n & <NUM_LIT> ) <EOL> while True : <EOL> n = n >> <NUM_LIT:7> <EOL> if n : <EOL> data = six . int2byte ( ( n & <NUM_LIT> ) | <NUM_LIT> ) + data <EOL> else : <EOL> break <EOL> out . write ( data ) <EOL> class SMF ( object ) : <EOL> def __init__ ( self , tracks , instruments = None ) : <EOL> self . tracks = tracks <EOL> if instruments is None : <EOL> instruments = [ <NUM_LIT:0> ] * len ( tracks ) <EOL> assert len ( instruments ) == len ( tracks ) <EOL> self . instruments = instruments <EOL> def write ( <EOL> self , out , <EOL> title = "<STR_LIT>" , <EOL> time_signature = ( <NUM_LIT:4> , <NUM_LIT:2> , <NUM_LIT> , <NUM_LIT:8> ) , <EOL> key_signature = ( <NUM_LIT:0> , <NUM_LIT:0> ) , <EOL> tempo = <NUM_LIT> <EOL> ) : <EOL> num_tracks = <NUM_LIT:1> + len ( self . tracks ) <EOL> Thd ( format = <NUM_LIT:1> , num_tracks = num_tracks , division = <NUM_LIT:16> ) . write ( out ) <EOL> T = <NUM_LIT:1> <EOL> t = Trk ( ) <EOL> t0 , t1 , t2 , t3 = time_signature <EOL> t . time_signature ( t0 , t1 , t2 , t3 ) <EOL> k0 , k1 = key_signature <EOL> t . key_signature ( k0 , k1 ) <EOL> t . tempo ( tempo ) <EOL> t . sequence_track_name ( title ) <EOL> t . track_end ( ) <EOL> t . write ( out ) <EOL> for channel , track in enumerate ( self . tracks ) : <EOL> t = Trk ( ) <EOL> t . program_change ( channel , self . instruments [ channel ] ) <EOL> events_with_noteoff = [ ] <EOL> for point in track : <EOL> offset , note_value , duration = point . tuple ( OFFSET_64 , MIDI_PITCH , DURATION_64 ) <EOL> velocity = <NUM_LIT:64> if '<STR_LIT>' not in point else point [ '<STR_LIT>' ] <EOL> if note_value is not None : <EOL> events_with_noteoff . append ( ( True , offset , note_value , velocity ) ) <EOL> events_with_noteoff . append ( ( False , offset + duration , note_value , velocity ) ) <EOL> prev_offset = None <EOL> for on , offset , note_value , velocity in sorted ( events_with_noteoff , key = lambda x : x [ <NUM_LIT:1> ] ) : <EOL> if prev_offset is None : <EOL> time_delta = <NUM_LIT:0> <EOL> else : <EOL> time_delta = ( offset - prev_offset ) * T <EOL> if on : <EOL> t . start_note ( time_delta , channel , note_value , velocity ) <EOL> else : <EOL> t . end_note ( time_delta , channel , note_value ) <EOL> prev_offset = offset <EOL> t . track_end ( ) <EOL> t . write ( out ) <EOL> class Thd ( object ) : <EOL> def __init__ ( self , format , num_tracks , division ) : <EOL> self . format = format <EOL> self . num_tracks = num_tracks <EOL> self . division = division <EOL> def write ( self , out ) : <EOL> write_chars ( out , "<STR_LIT>" ) <EOL> write_ulong ( out , <NUM_LIT:6> ) <EOL> write_ushort ( out , self . format ) <EOL> write_ushort ( out , self . num_tracks ) <EOL> write_ushort ( out , self . division ) <EOL> class Trk ( object ) : <EOL> def __init__ ( self ) : <EOL> self . data = BytesIO ( ) <EOL> def write_meta_info ( self , byte1 , byte2 , data ) : <EOL> "<STR_LIT>" <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> write_byte ( self . data , byte1 ) <EOL> write_byte ( self . data , byte2 ) <EOL> write_varlen ( self . data , len ( data ) ) <EOL> write_chars ( self . data , data ) <EOL> def instrument ( self , inst ) : <EOL> "<STR_LIT>" <EOL> self . write_meta_info ( <NUM_LIT> , <NUM_LIT> , inst ) <EOL> def program_name ( self , name ) : <EOL> self . write_meta_info ( <NUM_LIT> , <NUM_LIT> , name ) <EOL> def sequence_track_name ( self , name ) : <EOL> self . write_meta_info ( <NUM_LIT> , <NUM_LIT> , name ) <EOL> def time_signature ( self , a , b , c , d ) : <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_varlen ( self . data , <NUM_LIT:4> ) <EOL> write_byte ( self . data , a ) <EOL> write_byte ( self . data , b ) <EOL> write_byte ( self . data , c ) <EOL> write_byte ( self . data , d ) <EOL> def key_signature ( self , a , b ) : <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_varlen ( self . data , <NUM_LIT:2> ) <EOL> write_byte ( self . data , a ) <EOL> write_byte ( self . data , b ) <EOL> def tempo ( self , t ) : <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_varlen ( self . data , <NUM_LIT:3> ) <EOL> write_byte ( self . data , ( t >> <NUM_LIT:16> ) % <NUM_LIT> ) <EOL> write_byte ( self . data , ( t >> <NUM_LIT:8> ) % <NUM_LIT> ) <EOL> write_byte ( self . data , ( t >> <NUM_LIT:0> ) % <NUM_LIT> ) <EOL> def program_change ( self , channel , program ) : <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> write_byte ( self . data , <NUM_LIT> + channel ) <EOL> write_byte ( self . data , program ) <EOL> def start_note ( self , time_delta , channel , note_number , velocity = <NUM_LIT:64> ) : <EOL> write_varlen ( self . data , time_delta ) <EOL> write_byte ( self . data , <NUM_LIT> + channel ) <EOL> write_byte ( self . data , note_number ) <EOL> write_byte ( self . data , max ( min ( velocity , <NUM_LIT:255> ) , <NUM_LIT:0> ) ) <EOL> def end_note ( self , time_delta , channel , note_number ) : <EOL> write_varlen ( self . data , time_delta ) <EOL> write_byte ( self . data , <NUM_LIT> + channel ) <EOL> write_byte ( self . data , note_number ) <EOL> write_byte ( self . data , <NUM_LIT:0> ) <EOL> def track_end ( self ) : <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_byte ( self . data , <NUM_LIT> ) <EOL> write_varlen ( self . data , <NUM_LIT:0> ) <EOL> def write ( self , out ) : <EOL> write_chars ( out , "<STR_LIT>" ) <EOL> d = self . data . getvalue ( ) <EOL> write_ulong ( out , len ( d ) ) <EOL> out . write ( d ) <EOL> def write ( filename , tracks , instruments = None , ** kws ) : <EOL> with open ( filename , "<STR_LIT:w>" ) as f : <EOL> s = SMF ( tracks , instruments = instruments ) <EOL> s . write ( f , ** kws ) </s>
