""" SoundFont Reader by Yui Kinomoto @arlez80 """ """ SampleLink """ const sample_link_mono_sample = 1 const sample_link_right_sample = 2 const sample_link_left_sample = 4 const sample_link_linked_sample = 8 const sample_link_rom_mono_sample = 0x8001 const sample_link_rom_right_sample = 0x8002 const sample_link_rom_left_sample = 0x8004 const sample_link_rom_linked_sample = 0x8008 """ GenerateOperator """ const gen_oper_start_addrs_offset = 0 const gen_oper_end_addrs_offset = 1 const gen_oper_startloop_addrs_offset = 2 const gen_oper_endloop_addrs_offset = 3 const gen_oper_start_addrs_coarse_offset = 4 const gen_oper_mod_lfo_to_pitch = 5 const gen_oper_vib_lfo_to_pitch = 6 const gen_oper_mod_env_to_pitch = 7 const gen_oper_initial_filter_fc = 8 const gen_oper_initial_filter_q = 9 const gen_oper_mod_lfo_to_filter_fc = 10 const gen_oper_mod_env_to_filter_fc = 11 const gen_oper_end_addrs_coarse_offset = 12 const gen_oper_mod_lfo_to_volume = 13 const gen_oper_unused1 = 14 const gen_oper_chorus_effects_send = 15 const gen_oper_reverb_effects_send = 16 const gen_oper_pan = 17 const gen_oper_unused2 = 18 const gen_oper_unused3 = 19 const gen_oper_unused4 = 20 const gen_oper_delay_mod_lfo = 21 const gen_oper_freq_mod_lfo = 22 const gen_oper_delay_vib_lfo = 23 const gen_oper_freq_vib_lfo = 24 const gen_oper_delay_mod_env = 25 const gen_oper_attack_mod_env = 26 const gen_oper_hold_mod_env = 27 const gen_oper_decay_mod_env = 28 const gen_oper_sustain_mod_env = 29 const gen_oper_release_mod_env = 30 const gen_oper_keynum_to_mod_env_hold = 31 const gen_oper_keynum_to_mod_env_decay = 32 const gen_oper_delay_vol_env = 33 const gen_oper_attack_vol_env = 34 const gen_oper_hold_vol_env = 35 const gen_oper_decay_vol_env = 36 const gen_oper_sustain_vol_env = 37 const gen_oper_release_vol_env = 38 const gen_oper_keynum_to_vol_env_hold = 39 const gen_oper_keynum_to_vol_env_decay = 40 const gen_oper_instrument = 41 const gen_oper_reserved1 = 42 const gen_oper_key_range = 43 const gen_oper_vel_range = 44 const gen_oper_startloop_addrs_coarse_offset = 45 const gen_oper_keynum = 46 const gen_oper_velocity = 47 const gen_oper_initial_attenuation = 48 const gen_oper_reserved2 = 49 const gen_oper_endloop_addrs_coarse_offset = 50 const gen_oper_coarse_tune = 51 const gen_oper_fine_tune = 52 const gen_oper_sample_id = 53 const gen_oper_sample_modes = 54 const gen_oper_reserved3 = 55 const gen_oper_scale_tuning = 56 const gen_oper_exclusive_class = 57 const gen_oper_overriding_root_key = 58 const gen_oper_unused5 = 59 const gen_oper_end_oper = 60 """ SampleMode """ const sample_mode_no_loop = 0 const sample_mode_loop_continuously = 1 const sample_mode_unused_no_loop = 2 const sample_mode_loop_ends_by_key_depression = 3 """ ファイルから読み込み @param path File path @return smf """ func read_file( path ): var f = File.new( ) if not f.file_exists( path ): print( "file %s is not found" % path ) breakpoint f.open( path, f.READ ) var stream = StreamPeerBuffer.new( ) stream.set_data_array( f.get_buffer( f.get_len( ) ) ) stream.big_endian = false f.close( ) return self._read( stream ) """ 配列から読み込み @param data PoolByteArray @return smf """ func read_data( data ): var stream = StreamPeerBuffer.new( ) stream.set_data_array( data ) stream.big_endian = false return self._read( stream ) """ 読み込み @param input @return SoundFont """ func _read( input ): self._check_chunk( input, "RIFF" ) self._check_header( input, "sfbk" ) var info = self._read_info( input ) var sdta = self._read_sdta( input ) var pdta = self._read_pdta( input ) return { "info": info, "sdta": sdta, "pdta": pdta, } """ チャンクチェック @param input @param hdr """ func _check_chunk( input, hdr ): self._check_header( input, hdr ) input.get_32( ) """ ヘッダーチェック @param input @param hdr """ func _check_header( input, hdr ): var chk = input.get_string( 4 ) if hdr != chk: print( "Doesn't exist " + hdr + " header" ) breakpoint """ チャンク読み込み @param input @param needs_header @param chunk """ func _read_chunk( stream, needs_header = null ): var header = stream.get_string( 4 ) if needs_header != null: if needs_header != header: print( "Doesn't exist " + needs_header + " header" ) breakpoint var size = stream.get_u32( ) var new_stream = StreamPeerBuffer.new( ) new_stream.set_data_array( stream.get_partial_data( size )[1] ) new_stream.big_endian = false return { "header": header, "size": size, "stream": new_stream, } """ INFOチャンクを読み込む @param stream @param chunk """ func _read_info( stream ): var chunk = self._read_chunk( stream, "LIST" ) self._check_header( chunk.stream, "INFO" ) var info = { "ifil":null, "isng":null, "inam":null, "irom":null, "iver":null, "icrd":null, "ieng":null, "iprd":null, "icop":null, "icmt":null, "isft":null, } while 0 < chunk.stream.get_available_bytes( ): var sub_chunk = self._read_chunk( chunk.stream ) match sub_chunk.header.to_lower( ): "ifil": info.ifil = self._read_version_tag( sub_chunk.stream ) "isng": info.isng = sub_chunk.stream.get_string( sub_chunk.size ) "inam": info.inam = sub_chunk.stream.get_string( sub_chunk.size ) "irom": info.irom = sub_chunk.stream.get_string( sub_chunk.size ) "iver": info.iver = self._read_version_tag( sub_chunk.stream ) "icrd": info.icrd = sub_chunk.stream.get_string( sub_chunk.size ) "ieng": info.ieng = sub_chunk.stream.get_string( sub_chunk.size ) "iprd": info.iprd = sub_chunk.stream.get_string( sub_chunk.size ) "icop": info.icop = sub_chunk.stream.get_string( sub_chunk.size ) "icmt": info.icmt = sub_chunk.stream.get_string( sub_chunk.size ) "isft": info.isft = sub_chunk.stream.get_string( sub_chunk.size ) _: print( "unknown header" ) breakpoint return info """ バージョンタグを読み込む @param stream @param chunk """ func _read_version_tag( stream ): var major = stream.get_u16( ) var minor = stream.get_u16( ) return { "major": major, "minor": minor, } """ SDTAを読み込む @param stream @param chunk """ func _read_sdta( stream ): var chunk = self._read_chunk( stream, "LIST" ) self._check_header( chunk.stream, "sdta" ) var smpl = self._read_chunk( chunk.stream, "smpl" ) var smpl_bytes = smpl.stream.get_partial_data( smpl.size )[1] var sm24_bytes = null if 0 < chunk.stream.get_available_bytes( ): var sm24_chunk = self._read_chunk( chunk.stream, "sm24" ) sm24_bytes = sm24_chunk.stream.get_partial_data( sm24_chunk.size )[1] return { "smpl": smpl_bytes, "sm24": sm24_bytes, } """ PDTAを読み込む @param stream @param chunk """ func _read_pdta( stream ): var chunk = self._read_chunk( stream, "LIST" ) self._check_header( chunk.stream, "pdta" ) var phdr = self._read_pdta_phdr( chunk.stream ) var pbag = self._read_pdta_bag( chunk.stream ) var pmod = self._read_pdta_mod( chunk.stream ) var pgen = self._read_pdta_gen( chunk.stream ) var inst = self._read_pdta_inst( chunk.stream ) var ibag = self._read_pdta_bag( chunk.stream ) var imod = self._read_pdta_mod( chunk.stream ) var igen = self._read_pdta_gen( chunk.stream ) var shdr = self._read_pdta_shdr( chunk.stream ) return { "phdr": phdr, "pbag": pbag, "pmod": pmod, "pgen": pgen, "inst": inst, "ibag": ibag, "imod": imod, "igen": igen, "shdr": shdr, } """ phdr 読み込み @param stream @param chunk """ func _read_pdta_phdr( stream ): var chunk = self._read_chunk( stream, "phdr" ) var phdrs = [] while 0 < chunk.stream.get_available_bytes( ): var phdr = { "name": "", "preset": 0, "bank": 0, "preset_bag_index": 0, "library": 0, "genre": 0, "morphology": 0, } phdr.name = chunk.stream.get_string( 20 ) phdr.preset = chunk.stream.get_u16( ) phdr.bank = chunk.stream.get_u16( ) phdr.preset_bag_index = chunk.stream.get_u16( ) phdr.library = chunk.stream.get_32( ) phdr.genre = chunk.stream.get_32( ) phdr.morphology = chunk.stream.get_32( ) phdrs.append( phdr ) return phdrs """ *bag読み込み @param stream @param chunk """ func _read_pdta_bag( stream ): var chunk = self._read_chunk( stream ) var bags = [] if chunk.header.substr( 1, 3 ) != "bag": print( "Doesn't exist *bag header." ) breakpoint while 0 < chunk.stream.get_available_bytes( ): var bag = { "gen_ndx": 0, "mod_ndx": 0, } bag.gen_ndx = chunk.stream.get_u16( ) bag.mod_ndx = chunk.stream.get_u16( ) bags.append( bag ) return bags """ *mod読み込み @param stream @param chunk """ func _read_pdta_mod( stream ): var chunk = self._read_chunk( stream ) var mods = [] if chunk.header.substr( 1, 3 ) != "mod": print( "Doesn't exist *mod header." ) breakpoint while 0 < chunk.stream.get_available_bytes( ): var mod = { "src_oper": null, "dest_oper": 0, "amount": 0, "amt_src_oper": null, "trans_oper": 0, } mod.src_oper = self._read_pdta_modulator( chunk.stream.get_u16( ) ) mod.dest_oper = chunk.stream.get_u16( ) mod.amount = chunk.stream.get_u16( ) mod.amt_src_oper = self._read_pdta_modulator( chunk.stream.get_u16( ) ) mod.trans_oper = chunk.stream.get_u16( ) mods.append( mod ) return mods """ PDTA-Modulator 読み込み @param stream @param chunk """ func _read_pdta_modulator( u ): return { "type": ( u >> 10 ) & 0x3f, "direction": ( u >> 8 ) & 0x01, "polarity": ( u >> 9 ) & 0x01, "controller": u & 0x7f, "controllerPallete": ( u >> 7 ) & 0x01, } """ gen 読み込み @param stream @param chunk """ func _read_pdta_gen( stream ): var chunk = self._read_chunk( stream ) var gens = [] if chunk.header.substr( 1, 3 ) != "gen": print( "Doesn't exist *gen header." ) breakpoint while 0 < chunk.stream.get_available_bytes( ): var gen = { "gen_oper": 0, "amount": 0, "uamount": 0, } gen.gen_oper = chunk.stream.get_u16( ) var u = chunk.stream.get_u16( ) gen.uamount = u gen.amount = u if 32767 < u: gen.amount = - ( 65536 - u ) gens.append( gen ) return gens """ inst読み込み @param stream @param chunk """ func _read_pdta_inst( stream ): var chunk = self._read_chunk( stream, "inst" ) var insts = [] while 0 < chunk.stream.get_available_bytes( ): var inst = { "name": "", "inst_bag_ndx": 0, } inst.name = chunk.stream.get_string( 20 ) inst.inst_bag_ndx = chunk.stream.get_u16( ) insts.append( inst ) return insts """ shdr 読み込み @param stream @param chunk """ func _read_pdta_shdr( stream ): var chunk = self._read_chunk( stream, "shdr" ) var shdrs = [] while 0 < chunk.stream.get_available_bytes( ): var shdr = { "name": "", "start": 0, "end": 0, "start_loop": 0, "end_loop": 0, "sample_rate": 0, "original_key": 0, "pitch_correction": 0, "sample_link": 0, "sample_type": 0, } shdr.name = chunk.stream.get_string( 20 ) shdr.start = chunk.stream.get_u32( ) shdr.end = chunk.stream.get_u32( ) shdr.start_loop = chunk.stream.get_u32( ) shdr.end_loop = chunk.stream.get_u32( ) shdr.sample_rate = chunk.stream.get_u32( ) shdr.original_key = chunk.stream.get_u8( ) shdr.pitch_correction = chunk.stream.get_8( ) shdr.sample_link = chunk.stream.get_u16( ) shdr.sample_type = chunk.stream.get_u16( ) shdrs.append( shdr ) return shdrs