int fork(){return 0;}//リンカエラー回避
void free_wrd(){};   //リンカエラー回避

#include "timidity.c"
//timidity.c で static なグローバル変数にアクセスする必要がある
//timidity.c を一切書き換えないようにするためには、こうするしかないと
//思われる

void kbtim_initialize(char *szCfgFile);
void kbtim_uninitialize(void);
void kbtim_play_midi_file(char *szFileName);

static void kbtim_start_initialize(void);//timidity_start_initialize 相当
static void kbtim_init_player(void);//timidity_init_player 相当

void free_freq_data_by_Kobarin(void);

void kbtim_start_initialize(void)//timidity_start_initialize 相当
{
    int i;
    static int drums[] = DEFAULT_DRUMCHANNELS;

    if(!output_text_code){
	    output_text_code = safe_strdup(OUTPUT_TEXT_CODE);
    }
    if(!opt_aq_max_buff){
	    opt_aq_max_buff = safe_strdup("5.0");
    }
    if(!opt_aq_fill_buff){
	    opt_aq_fill_buff = safe_strdup("100%");
    }
    for(i = 0; i < MAX_CHANNELS; i++){
	    memset(&(channel[i]), 0, sizeof(Channel));
    }

    CLEAR_CHANNELMASK(quietchannels);
    CLEAR_CHANNELMASK(default_drumchannels);

    for(i = 0; drums[i] > 0; i++){
	    SET_CHANNELMASK(default_drumchannels, drums[i] - 1);
    }
    for(i = 16; i < MAX_CHANNELS; i++){
        if(IS_SET_CHANNELMASK(default_drumchannels, i & 0xF)){
	        SET_CHANNELMASK(default_drumchannels, i);
        }
    }
    for(i = 0; i < MAX_CHANNELS; i++){
	    default_program[i] = DEFAULT_PROGRAM;
	    memset(channel[i].drums, 0, sizeof(channel[i].drums));
    }
    {
        for(i = 0; url_module_list[i]; i++){
	        url_add_module(url_module_list[i]);
        }
    	init_string_table(&opt_config_string);
	    init_freq_table();
	    init_freq_table_tuning();
    	init_freq_table_pytha();
	    init_freq_table_meantone();
	    init_freq_table_pureint();
	    init_freq_table_user();
	    init_bend_fine();
	    init_bend_coarse();
	    init_tables();
	    init_gm2_pan_table();
	    init_attack_vol_table();
	    init_sb_vol_table();
	    init_modenv_vol_table();
	    init_def_vol_table();
	    init_gs_vol_table();
	    init_perceived_vol_table();
	    init_gm2_vol_table();
        for(i = 0; i < NSPECIAL_PATCH; i++){
	        special_patch[i] = NULL;
        }
	    init_midi_trace();
	    int_rand(-1);	// initialize random seed
	    int_rand(42);	// the 1st number generated is not very random
    }
}

void kbtim_init_player(void)//timidity_init_player 相当
{
    // Allocate voice[] 
    voice = (Voice *) safe_realloc(voice, max_voices * sizeof(Voice));
	memset(voice, 0, max_voices * sizeof(Voice));
    // save defaults 
    COPY_CHANNELMASK(drumchannels, default_drumchannels);
    COPY_CHANNELMASK(drumchannel_mask, default_drumchannel_mask);
}
void free_voice_by_Kobarin(void)
{
    //init_player で確保したメモリの解放
    if(voice){
        int i;
        for(i = 0; i < max_voices; i++){
            if(voice[i].pan_delay_buf){
                free(voice[i].pan_delay_buf);
            }
        }
        free(voice);
        voice=NULL;
    }
}
void free_freq_data_by_Kobarin(void)
{//freq_initialize_fft_arrays で確保したメモリ(magdata等)の解放
 //終了時に呼び出さないとメモリリークする。
 //本家に解放用の関数が新設されれば不要となる
    extern float *floatdata, *magdata, *prunemagdata;
    extern int *ip;
    extern float *w;
    extern uint32 oldfftsize;
    extern int *fft1_bin_to_pitch;
    if(magdata){
        free(magdata);magdata = NULL;
        free(prunemagdata);prunemagdata = NULL;
        free(ip);ip = NULL;
        free(w);w = NULL;
        free(fft1_bin_to_pitch);fft1_bin_to_pitch = NULL;
        oldfftsize = 0;
    }
}
void kbtim_initialize(char *szCfgFile)
{
    char local[1024];
    if(!opt_control_ratio){//init_load_soundfont の呼び出し前に conrol_ratio != 0 になっていないといけない
	    control_ratio = play_mode->rate / CONTROLS_PER_SECOND;
        if(control_ratio < 1){
            control_ratio = 1;
        }
        else if(control_ratio > MAX_CONTROL_RATIO){
            control_ratio = MAX_CONTROL_RATIO;
        }
    }
    kbtim_start_initialize();
    initialize_resampler_coeffs();
    //timidity_pre_load_configuration 相当
    lstrcpyn(local, szCfgFile, sizeof(local));
  	read_config_file(local, 0, 0);
    //timidity_post_load_configuration 相当
    if(opt_config_string.nstring > 0){
	    char **config_string_list;
	    config_string_list = make_string_array(&opt_config_string);
	    if(config_string_list != NULL){
    	    int i;
    	    for(i = 0; config_string_list[i]; i++){
                read_config_file(config_string_list[i], 1, 0);
	        }
	        free(config_string_list[0]);
	        free(config_string_list);
	    }
    }
    kbtim_init_player();
	init_load_soundfont();
}

void kbtim_uninitialize(void)
{
    int i;
	
    free_soft_queue();
	free_instruments(0);
	free_soundfonts();
	free_cache_data();
	free_readmidi();
	tmdy_free_config();
	free_reverb_buffer();
	free_effect_buffers();
	//free(voice);//CVS081206から呼ばれるようになったがこれだけでは不十分
    free_voice_by_Kobarin();//free(voice) の代わり
	free_gauss_table();
    free_archive_files();
	for (i = 0; i < MAX_CHANNELS; i++)
		free_drum_effect(i);
    
    //start_initialize で確保したメモリの解放
    if(output_text_code){
        free(output_text_code);output_text_code = NULL;
    }
    if(opt_aq_max_buff){
        free(opt_aq_max_buff);opt_aq_max_buff = NULL;
    }
    if(opt_aq_fill_buff){
        free(opt_aq_fill_buff);opt_aq_fill_buff = NULL;
    }
    //freq.c::freq_initialize_fft_arrays で確保したメモリの解放
    free_freq_data_by_Kobarin();
    free_global_mblock();
}

void kbtim_play_midi_file(char *szFileName)
{
    aq_setup();
	timidity_init_aq_buff();

    if(allocate_cache_size > 0)
	   resamp_cache_reset();

	if (def_prog >= 0)
		set_default_program(def_prog);
	if (*def_instr_name)
		set_default_instrument(def_instr_name);

    play_mode->open_output();
    play_midi_file(szFileName);
    aq_flush(1);
	play_mode->close_output();
	ctl->close();
	wrdt->close();
    if(free_instruments_afterwards){
        free_instruments(0);
    }
    free_all_midi_file_info();//これがないと曲切り替え時の演奏がおかしくなる（？）
    free_userdrum();          //init_userdrum() で確保したメモリの解放
    free_archive_files();
}
