スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
以後の更新内容の改善のために、是非ともご評価のほどよろしくお願いします!→

【C言語】MIDI(SMF)のノートの音程・ベロシティーに関する統計処理(平均値・分散値・標準偏差値の算出)

前回の"NoteOn-NoteOffの時間差に関する統計処理"に加え、
今度は、MIDI(SMF)のノートの音程・ベロシティーについて統計処理をしてみました!
(これも同様に、平均値・分散値・標準偏差値を算出するものです。)

(これもまた同様に...) この記事に掲載するプログラムは次の記事を継承したものですので、必要であれば合わせて御覧ください。
・「C言語でMIDI(SMF)データを読んでみる!
・「C言語でMIDI(SMF)データのNoteOn/NoteOffだけ表示する!
・「【C言語】MIDI(SMF)のNoteOn-NoteOffの時間差に関する統計処理(平均値・分散値・標準偏差値の算出)

なお、このプログラムに対するテストは明らかに不十分ですので、参考になさる場合は十分にご注意ください。


//
//  Reading MIDI(SMF) Data
//                2010.08.07 - 2010.08.16
//        NoteOn/Off Version : 2010.12.09
//            平均値・分散値 : 2011.01.02
//  平均値・分散値【修正版】 : 2011.01.03

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

//====== 設定項目 ======
#define DISP_TRACK   0   // トラック番号を表示するか否か(0:非表示、1:表示)
#define DISP_NOTEON  0   //  NoteOnを表示するか否か(0:非表示、1:表示)
#define DISP_NOTEOFF 0   // NoteOffを表示するか否か(0:非表示、1:表示)

#define CHECK_VELO_ZERO 1   // NoteOnのベロシティーが0の時に、それを計算に含めるかどうか
                            // (0:含めない、1:含める)

//====== 以降はプログラム ======
#define  ON 1   // NoteOn状態
#define OFF 0   // NoteOff状態

typedef struct st_noteonlist {
    // ノートオン情報のリスト
    int note;   // ノート番号
    int velo;   // ベロシティー
    struct st_noteonlist *next;   // 次のリストを指す
} NoteOnList;

typedef struct st_notelist {
    // ノート情報のリスト
    int tick;       // 発音の長さ
    struct st_notelist *next; // 次のリストを指す
} NoteList;

typedef struct {
    // ノートの状態を格納する構造体
    int state;   // 状態(ON/OFF)
    int time;   // NoteOnになったときの累計デルタタイム
} NoteInfo;

typedef struct {
    // トラックチャンクのデータを格納する構造体
    char type[4]; // チャンクタイプを示す文字列を格納。「MTrk」が入るはず。[4byte]
    int size;     // トラックチャンクデータのサイズ [4byte]
    char *data;   // トラックデータ(イベントの羅列)へのポインタ
} TrackChunk;

short mergeChar7bit(char x, char y){
    // charの下7bitずつを結合してshort型で出力
    // 【引数】:結合対象となる2つのchar型変数x, y
    short s;
    s = (unsigned char)x; // 上位バイトを先に入れておく
    s <<= 7;              // 7bit左シフト
    s = (s | (unsigned char)(y & 0x7f));   // 下位バイトの下7bitを合成。。。
    return s;
}

int convertEndian(void *input, size_t s){
    // エンディアン変換をおこなう関数
    // stdlib.hをインクルードしてください。
    // 【引数】: void *input...エンディアン変換対象へのポインタ
    // 【引数】: size_t    s...変換対象のバイト数

    int i;   // カウンタ
    char *temp;   // 変換時に用いる一時的配列

    if((temp = (char *)calloc(s, sizeof(char))) == NULL){
        perror("Error: Cannot get memory for temp.");
        return 0;   // 領域確保できず(失敗)
    }

    for(i=0; i<s; i++){   // inputデータをtempに一時保管
        temp[i] = ((char *)input)[i];
    }

    for(i=1; i<=s; i++){   // tempデータを逆方向にしてinputへ代入
        ((char *)input)[i-1] = temp[s-i];
    }

    free(temp);   // 確保した領域を解放

    return 1;   // 正常終了
}

int main(){
    int i, j, k, cnt;   // カウンタ
    FILE *fp;         // ファイルポインタ生成
    int endian; //   エンディアン判定にいろいろ使用(0:BigEndian, 1:LittleEndian)

    // 音階・ベロシティーに関する平均値・分散値を求めるための変数
    double sum_on_note = 0.0;   // NoteOnのノート番号の総和
    double sum_on_velo = 0.0;   // NoteOnの累計ベロシティー
    unsigned int cnt_on = 0;    // ノートオンの回数
    NoteOnList *on_list_top = NULL; // 先頭のリストを指すポインタ
    NoteOnList *on_list_pt;     // リスト作成などに使う一時的な変数
    NoteOnList *on_list_temp;   // リスト操作に使う一時的な変数
    double note_average  = 0;   // 音階の平均値
    double note_variance = 0;   // 音階の分散値
    double velo_average  = 0;   // ベロシティーの平均値
    double velo_variance = 0;   // ベロシティーの分散値

    // NoteOn-NoteOff間の時間差に関する平均値・分散値を求めるための変数
    unsigned int note_num = 0;   // 処理中のノート番号
    unsigned int velo_num = 0;   // 処理中のノートのベロシティー
    NoteInfo note[128];          // ノート状態(On/Off)を格納する配列
    unsigned int sum_length = 0; // ノートオンの累計時間(累計発音時間)
                                 //    (分散値算出にもこの変数を利用)
    unsigned int cnt_length = 0; // ノートオン(発音)の回数カウンタ
    NoteList *list_top = NULL;   // 先頭のリストを指すポインタ
    NoteList *list_pt;           // リスト作成などに使う一時的な変数
    double average;              // 平均値
    double variance;             // 分散値

    // ヘッダチャンク情報
    char  header_chunk_type[4]; // チャンクタイプを示す文字列を格納。「MThd」が入るはず。[4byte]
    int   header_chunk_size;    // ヘッダチャンクデータのサイズ [4byte]
    short smf_format;     // SMFのフォーマットタイプ(0か1か2) [2byte]
    short tracks;         // トラックチャンク総数 [2byte]
    short division;       // 四分音符あたりの分解能(ここではデルタタイム) [2byte]

    // トラックチャンク情報
    TrackChunk *track_chunks;   // トラックチャンク情報を格納する配列のためのポインタ
    unsigned char c;   // イベント解析の際に使用する一時保存用変数
    unsigned char status;   // ステータスバイト用の一時変数
    unsigned int delta;   // デルタタイム
    unsigned int sum_delta;   // 累計時間

    // 配列初期化
    for(i=0; i<128; i++){
        note[i].state = OFF;   // 最初は全てノートオフ状態
    }

    // エンディアン判定
    endian = 1;
    if(*(char *)&endian){   // リトルエンディアンなら...
        endian = 1;   // Little Endian
    } else {   // ビッグエンディアンなら...
        endian = 0;   // Big Endian
    }

    // MIDIファイルを開く
    if((fp = fopen("./sample.mid", "rb")) == NULL){   // バイナリ読み取りモードでファイルを開く
        perror("Error: Cannot open the file.
");   // 失敗したらエラーを吐く
        return 0;
    }

    // ヘッダチャンク取得
    fread(header_chunk_type, 1, 4, fp);   // チャンクタイプ
    fread(&header_chunk_size, 4, 1, fp);  // チャンクデータサイズ
    fread(&smf_format, 2, 1, fp);   // SMFフォーマットタイプ
    fread(&tracks, 2, 1, fp);       // トラックチャンク総数
    fread(&division, 2, 1, fp);     // 分解能(デルタタイム)

    if(endian){   // リトルエンディアンならビッグエンディアンに変換
        convertEndian(&tracks, sizeof(tracks));
    }

    // トラックチャンク取得
    if((track_chunks = (TrackChunk *)calloc(tracks, sizeof(TrackChunk))) == NULL){   // トラック数に応じて領域確保
        perror("Error: Cannot get memory for track_chunks.");
        return 0;   // 領域確保できず(失敗)
    }
    for(i=0; i<tracks; i++){   // トラック数だけ繰返し
        fread(track_chunks[i].type, 1, 4, fp);   // チャンクタイプ
        fread(&track_chunks[i].size, 4, 1, fp);   // チャンクデータサイズ
        if(endian){   // リトルエンディアンなら要変換
            convertEndian(&track_chunks[i].size, sizeof(track_chunks[i].size));
        }
        if((track_chunks[i].data = (char *)calloc(track_chunks[i].size, sizeof(char))) == NULL){   // データサイズに応じて領域確保
            perror("Error: Cannot get memory for track_chunks[i].data .");
            return 0;   // 領域確保できず(失敗)
        }
        fread(track_chunks[i].data, track_chunks[i].size, sizeof(char), fp);   // データ(イベントの羅列)
    }

    // 読み取ったトラックチャンク情報を出力
    for(i=0; i<tracks; i++){   // トラック数だけ繰返し
        sum_delta = 0;   // トラックごとに累計時間を算出
        if(DISP_TRACK) printf("# Track[%02d] =====================
", i+1);
        for(j=0; j<track_chunks[i].size; j++){   // データ分だけ繰返し

            delta = 0;   // 初期化
            while((c = (unsigned char)track_chunks[i].data[j++]) & 0x80){
                delta = delta | (c & 0x7F);   // 合成
                delta <<= 7;   // 7bit左シフト
            }
            delta = delta | c;    // 合成
            sum_delta += delta;   // 累計時間に加算

            // ランニングステータスルールに対する処理
            if((track_chunks[i].data[j] & 0x80) == 0x80){
                // ランニングステータスルールが適用されない場合は、ステータスバイト用変数を更新。
                status = (unsigned char)track_chunks[i].data[j];   // ステータスバイトを保持しておく
            } else {
                //printf("@");   // ランニングステータスルール適用のしるし...は出さない
                j--;   // データバイトの直前のバイト(デルタタイムかな?)を指すようにしておく。
                       // 次の処理でj++するはずなので、そうすればデータバイトにアクセスできる。
            }

            // データ判別
            if((status & 0xf0) == 0x80){
                // ノート・オフ【ボイスメッセージ】
                j++;
                note_num = (unsigned char)track_chunks[i].data[j++];  // ノート番号取得
                velo_num = (unsigned char)track_chunks[i].data[j];    // ベロシティー取得
                if(DISP_NOTEOFF){
                    printf("%7d [+%4d]:: ", sum_delta, delta);   // デルタタイム出力
                    printf("Note Off [%02dch] : ", (status & 0x0f));
                    printf("Note%d", note_num);
                    printf("[0x%02x] ", note_num);
                    printf("Velocity=%d
", velo_num);
                }
                if(note[note_num].state == ON){   // 状態がONなら処理する
                    list_pt = (NoteList *)calloc(1, sizeof(NoteList)); // リスト要素の領域確保
                    list_pt->next = list_top;                       // 直前まで"先頭要素"だったものを"次の要素"にする
                    list_top = list_pt;                             // 今作った要素を先頭要素とする
                    list_pt->tick = sum_delta - note[note_num].time;   // 発音時間を計算
                    sum_length += list_pt->tick;   // 累計発音時間を更新
                    cnt_length++;
                }
                note[note_num].state = OFF;   // ノートの状態をOFFに更新
            } else if((status & 0xf0) == 0x90){
                // ノート・オン【ボイスメッセージ】
                j++;
                note_num = (unsigned char)track_chunks[i].data[j++];  // ノート番号取得
                velo_num = (unsigned char)track_chunks[i].data[j];    // ベロシティー取得
                if(DISP_NOTEON){
                    printf("%7d [+%4d]:: ", sum_delta, delta);   // デルタタイム出力
                    printf("Note On  [%02dch] : ", (status & 0x0f));
                    printf("Note%d", note_num);
                    printf("[0x%02x] ", note_num);
                    printf("Velocity=%d
", velo_num);
                }
                if(velo_num == 0){   // ベロシティーが0ならノートオフ扱い
                    if(note[note_num].state == ON){   // 状態がONなら処理する
                        list_pt = (NoteList *)calloc(1, sizeof(NoteList)); // リスト要素の領域確保
                        list_pt->next = list_top;                       // 直前まで"先頭要素"だったものを"次の要素"にする
                        list_top = list_pt;                             // 今作った要素を先頭要素とする
                        list_pt->tick = sum_delta - note[note_num].time;   // 発音時間を計算
                        sum_length += list_pt->tick;   // 累計発音時間を更新
                        cnt_length++;
                    }
                    note[note_num].state = OFF;  // ノートの状態をOFFに更新
                } else {
                    note[note_num].state = ON;   // ノートの状態をONに更新
                    note[note_num].time  = sum_delta;   // ONになった時点での累積デルタタイム保管
                }
                if(velo_num!=0 || CHECK_VELO_ZERO){   // ベロシティーが0の時は、事前指定(CHECK_VELO_ZERO)によって処理したりしなかったり
                    on_list_pt = (NoteOnList *)calloc(1, sizeof(NoteOnList));   // リスト要素の領域確保
                    on_list_pt->next = on_list_top;
                    on_list_top = on_list_pt;
                    on_list_pt->note = note_num;   // ノート番号を記録
                    on_list_pt->velo = velo_num;   // ベロシティーを記録
                    sum_on_note += note_num;   // ノート番号の総和を更新
                    sum_on_velo += velo_num;   // 累計ベロシティーを更新
                    cnt_on++;   // NoteOnの回数をカウント
                }
            } else if((status & 0xf0) == 0xa0){   // ポリフォニック・キー・プレッシャー【ボイスメッセージ】
                j += 2;
            } else if((status & 0xf0) == 0xb0){   // コントロールチェンジ【ボイスメッセージ】、【モードメッセージ】
                j += 2;
            } else if((status & 0xf0) == 0xc0){   // プログラム・チェンジ【ボイスメッセージ】
                j += 1;
            } else if((status & 0xf0) == 0xd0){   // チャンネル・プレッシャー【ボイスメッセージ】
                j += 1;
            } else if((status & 0xf0) == 0xe0){   // ピッチ・ベンド・チェンジ【ボイスメッセージ】
                j += 2;
            } else if((status & 0xf0) == 0xf0){
                // 【システム・メッセージ】
                switch(status & 0x0f){
                    case 0x00:   // エクスクルーシブ・メッセージ
                        j++;
                        // SysExのデータ長を取得
                        cnt = 0;   // 初期化
                        while((c = (unsigned char)track_chunks[i].data[j++]) & 0x80){   // フラグビットが1の間はループ
                            cnt = cnt | c;   // 合成
                            cnt <<= 7;   // 7bit左シフト
                        }
                        cnt = cnt | c;   // 合成
                        for(k=1; k<=cnt; k++){   // 長さの分だけデータ取得
                            j++;
                        }
                        j--;   // 行き過ぎた分をデクリメント
                        break;
                    case 0x01:   // MIDIタイムコード
                        j += 1;
                        break;
                    case 0x02:   // ソング・ポジション・ポインタ
                        j += 2;
                        break;
                    case 0x03:   // ソング・セレクト
                        j += 1;
                        break;
                    case 0x06:   // チューン・リクエスト
                        break;
                    case 0x07:   // エクスクルーシブ・メッセージ(?)
                        j++;
                        // SysExのデータ長を取得
                        cnt = 0;   // 初期化
                        while((c = (unsigned char)track_chunks[i].data[j++]) & 0x80){   // フラグビットが1の間はループ
                            cnt = cnt | c;   // 合成
                            cnt <<= 7;   // 7bit左シフト
                        }
                        cnt = cnt | c;   // 合成
                        for(k=1; k<=cnt; k++){   // 長さの分だけデータ取得
                            j++;
                        }
                        j--;   // 行き過ぎた分をデクリメント
                        break;
                    case 0x08:   // タイミング・クロック
                    case 0x0A:   // スタート
                    case 0x0B:   // コンティニュー
                    case 0x0C:   // ストップ
                    case 0x0E:   // アクティブ・センシング
                        break;
                    //case 0x0F:   // システムリセット(何か間違っている気がする。。。)
                    //    printf("System Reset");
                    case 0x0F:   // メタイベント
                        j++;
                        switch((unsigned char)track_chunks[i].data[j]){
                            case 0x00:   // シーケンス番号
                                j += 3;  // データ長の分を通り越す
                                break;
                            case 0x01:   // テキスト[可変長]
                            case 0x02:   // 著作権表示[可変長]
                            case 0x03:   // シーケンス名(曲タイトル)・トラック名[可変長]
                            case 0x04:   // 楽器名[可変長]
                            case 0x05:   // 歌詞[可変長]
                            case 0x06:   // マーカー[可変長]
                            case 0x07:   // キューポイント[可変長]
                            case 0x08:   // プログラム名(音色名)[可変長]
                            case 0x09:   // デバイス名(音源名)[可変長]
                                j += 1;
                                cnt = 0;
                                while((c = (unsigned char)track_chunks[i].data[j++]) & 0x80){
                                    cnt = cnt | (c & 0x7F);   // 合成
                                    cnt <<= 7;   // 7bit左シフト
                                }
                                cnt = cnt | (c & 0x7F);   // 合成
                                for(k=1; k<=cnt; k++){
                                    j++;
                                }
                                j--;   // 行き過ぎた分をデクリメント
                                break;
                            case 0x20:   // MIDIチャンネルプリフィックス[1byte]
                            case 0x21:   // ポート指定[1byte]
                                j += 2;  // データ長の分を通り越す
                                break;
                            case 0x2F:   // トラック終端[0byte]
                                j += 1;  // データ長の分を通り越す
                                break;
                            case 0x51:   // テンポ設定[3byte]
                                j += 4;  // データ長の分を通り越す
                                break;
                            case 0x54:   // SMPTEオフセット[5byte]
                                j += 6;  // データ長の分を通り越す
                                break;
                            case 0x58:   // 拍子設定[4byte]
                                j += 5;  // データ長の分を通り越す
                                break;
                            case 0x59:   // 調設定[2byte]
                                j += 3;  // データ長の分を通り越す
                                break;
                            case 0x7F:   // シーケンサ特定メタイベント
                                j += 1;
                                cnt = 0;
                                while((c = (unsigned char)track_chunks[i].data[j++]) & 0x80){
                                    cnt = cnt | (c & 0x7F);   // 合成
                                    cnt <<= 7;   // 7bit左シフト
                                }
                                cnt = cnt | (c & 0x7F);   // 合成
                                for(k=1; k<=cnt; k++){
                                    j++;
                                }
                                j--;   // 行き過ぎた分をデクリメント
                                break;
                            default :
                                ;
                        }
                        break;
                    default:
                        ;   // 見知らぬステータスなら(知らぬフリ...)
                }
            } else {
                ;   // 見知らぬステータスなら(知らぬフリ...)
            }
        }
    }

    printf("## 統計結果 =====================
");
    
    printf("[音階]
");
    if(cnt_on){   // 1つでもNoteOnがあれば
        // まずは音階の平均値算出
        note_average = sum_on_note / (double)cnt_on;   // 平均値の計算
        printf(" @平均値  : %f
", note_average);   // 平均値を出力
        // 次に、音階の分散値算出
        sum_on_note = 0;
        on_list_temp = on_list_top;   // 一時的な変数に先頭要素アドレスをコピー
        while(on_list_pt = on_list_temp){   // NULL(末端)になるまでリスト要素にアクセス
            sum_on_note += (on_list_pt->note - note_average) * (on_list_pt->note - note_average);
            on_list_temp = on_list_pt->next;
        }
        note_variance = sum_on_note / (double)cnt_on;   // 分散値の計算
        printf(" @分散値  : %f
", note_variance);   // 分散値を出力
        printf(" @標準偏差 : %f
", sqrt(note_variance));   // 標準偏差を出力
    } else {   // NoteOnが1つもなかったら
        printf(" @NoteOnが存在しませんでした。");
    }

    printf("[ベロシティー]
");
    if(cnt_on){   // 1つでもNoteOnがあれば
        // まずはベロシティーの平均値算出
        velo_average = sum_on_velo / (double)cnt_on;   // 平均値の計算
        printf(" @平均値  : %f
", velo_average);   // 平均値を出力
        // 次に、ベロシティーの分散値算出
        sum_on_velo = 0;
        on_list_temp = on_list_top;   // 一時的な変数に先頭要素アドレスをコピー
        while(on_list_pt = on_list_temp){   // NULL(末端)になるまでリスト要素にアクセス
            sum_on_velo += (on_list_pt->velo - velo_average) * (on_list_pt->velo - velo_average);
            on_list_temp = on_list_pt->next;
        }
        velo_variance = sum_on_velo / (double)cnt_on;   // 分散値の計算
        printf(" @分散値  : %f
", velo_variance);   // 分散値を出力
        printf(" @標準偏差 : %f
", sqrt(velo_variance));   // 標準偏差を出力
    } else {   // NoteOnが1つもなかったら
        printf(" @NoteOnが存在しませんでした。");
    }

    while(on_list_pt = on_list_top){   // 確保していた領域を解放
        on_list_top = on_list_pt->next;
        free(on_list_pt);   // 確保いていた領域を解放
    }

    printf("[NoteOn-NoteOff間の時間差]
");
    if(cnt_length){   // 1つでもNoteOffがあれば
        // NoteOn-NoteOff間の時間差の平均値算出
        average = sum_length / (double)cnt_length;   // 平均値の計算
        printf(" @平均値  : %f
", average);   // 平均値を出力
        // 次に、その分散値を算出
        sum_length = 0;
        while(list_pt = list_top){   // NULL(末端)になるまでリスト要素にアクセス
            sum_length += (list_pt->tick - average) * (list_pt->tick - average);
            //printf("list_pt->tick : %d, average : %d, sum_length : %d
", list_pt->tick, (int)average, sum_length);
            list_top = list_pt->next;
            free(list_pt);   // 確保していた領域を解放
        }
        variance = sum_length / (double)cnt_length;   // 分散値の計算
        printf(" @分散値  : %f
", variance);   // 分散値を出力
        printf(" @標準偏差 : %f
", sqrt(variance));   // 標準偏差を出力
    } else {   // NoteOffが1つもなかったら
        printf(" @NoteOffが存在しませんでした。");
    }

    // track_chunks,track_chunks[i].dataはcalloc()で領域確保しているので解放し忘れないように!

    return 1;
}


以下に実行結果を示します。(以下、sample.midの解析結果)

$ gcc -o program ./program.c 
$ ./program 
## 統計結果 =====================
[音階]
 @平均値  : 65.153846
 @分散値  : 13.822485
 @標準偏差 : 3.717860
[ベロシティー]
 @平均値  : 100.000000
 @分散値  : 0.000000
 @標準偏差 : 0.000000
[NoteOn-NoteOff間の時間差]
 @平均値  : 480.000000
 @分散値  : 0.000000
 @標準偏差 : 0.000000

全トラックまとめて平均値・分散値・標準偏差値を求めます。
しかしこのテストでは、長さが480の音しかないので、分散値と標準偏差値は0になります。
それではテストになっていないので、もう一つMIDIファイルを作ってテストしてみます。
(以下、sample2.midの解析結果)

$ gcc -o program ./program.c 
$ ./program 
## 統計結果 =====================
[音階]
 @平均値  : 64.062500
 @分散値  : 14.308594
 @標準偏差 : 3.782670
[ベロシティー]
 @平均値  : 100.000000
 @分散値  : 0.000000
 @標準偏差 : 0.000000
[NoteOn-NoteOff間の時間差]
 @平均値  : 630.000000
 @分散値  : 164700.000000
 @標準偏差 : 405.832478

しまった...ベロシティーの値を変えてなかった...orz

他のMIDIファイルでも解析してみましたが、値はどれも正常なようです。
下に紹介するサイトで検算してみました。
JavaScriptによる統計計算など:http://aoki2.si.gunma-u.ac.jp/JavaScript/

(紹介したサイトでは分散ではなく不偏分散を求めています。「wikipedia:分散」における、標本分散の式と不偏分散の式を見比べてください。除数が「n」なのか「n-1」なのかの違いです。そこで今回のプログラムの除数を1小さくしてから計算させてみました。つまり不偏分散を求めるようにしたのです。すると、先程のJavaScriptによる計算結果と一致しました。なのできっと標本分散の値もあっているはず...ということです。テストになっていない気もしますが...^^;)


例によってテストに使用したMIDIファイルを置いておきます。
sample.mid【普通のMIDIファイル】
run_sample.mid【sample.midにランニングステータスルールを適用したMIDIファイル】
sample2.mid【異なる長さの音が含まれるMIDIファイル】


プログラムの冒頭部分には#defineによる設定項目を付けたので、必要な変更を適宜加えてください。
バグがあったらスミマセン...m(__;)m
以後の更新内容の改善のために、是非ともご評価のほどよろしくお願いします!→

テーマ : サウンド・プログラミング /  ジャンル : コンピュータ

コメントの投稿

非公開コメント

No title

前のブログで依頼したものです。本当にありがとうございます!
自分は簡単なのは組めるのですが、今回のはマニアックすぎてどうしようもなかったので、本当に助かりました。ありがとうございます
明日、試しにこちらの方でコンパイルしてみます。
同じファイルフォルダにmidiを入れてコマンドプロンクトでコンパイルすればいいんですよね?

Re: No title

とらすけです。こちらこそ、ご要望ありがとうございました!
確かに、MIDIの統計処理とはかなり特殊ですよね(笑)

MIDIファイルですが、上のプログラムをそのままコンパイルする場合は、同じフォルダ内にsample.midという名前で置いておけば解析できます。
あるいは、プログラム中の関数fopen()で指定しているファイル名を絶対パスor相対パスで改めて指定すると、他の場所にあるファイルでも解析可能です。

RE: RE: notitle

返信遅れてすいません。こちらでコンパイルしたところうまくいきました
ありがとうございます!!
また注文みたいな形ですいませんが、最後にテンポを出すようにしなかればならなりましたので、こっちは統計しなくていいので、曲のテンポの数値を出してくれればありがたいです。
あと、こちらは無茶かもしれませんが、フォルダにあるmidiファイルなら名前関係なしに解析するってのはできませんでしょうか。
なんか無茶な事でしたらすいません。できたらお願いします・・・

No title

すいません、ファイルどうのこうのはなかったことにしてください
流石に図々しかったです。
できたらテンポ表示ができれば、それだけでお願いします……

Re: No title

とらすけです。
とんでもないです。こちらこそ非常に良い経験になりました!!^^
新しく記事を掲載しましたので御覧ください!
[ http://torasukenote.blog120.fc2.com/blog-entry-117.html ]
カテゴリー
ようこそ!
Author: Torasuke
Profile: 地元大学の情報系学部に息をひそめる二回生。
   SA SW


ブログ内検索
最近のコメント
オススメ
京都の大学生のラボブログ
Python,Java,Objective-C,GAE,Macなど
Python独習中の大学生のブログ


ltzz.info
ここの管理者さんには謁見済み!(えっ

 Use OpenOffice.org
無補償でも良いなら、MSOfficeよりOpenOfficeで十分です。

Mozilla Firefox ブラウザ無料ダウンロード
当サイトは、Firefoxというブラウザで動作確認しています。私は以前、IE派でしたが、一度乗り換えて慣れてしまうと、Firefoxのほうが便利だということを実感しました。

是非よろしくお願いします。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。