質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

1回答

2484閲覧

C言語でMIDI編集

craftbosscoffee

総合スコア10

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2018/09/13 02:51

前提・実現したいこと

C言語初心者です。このサイトにて初めて質問させていただきます。
C言語でMIDIファイルの中身の16進数の一部を削除する編集プログラムを作っています。
こちらのサイト(http://torasukenote.blog120.fc2.com/blog-entry-104.html)の
「4.トラックチャンクも読み込もう!」のプログラムに16進数の一部を削除するプログラムを追加したいのですが、上手くいかず困っています。

とりあえず16進数1つでもいいので削除ができればと思っております。
拙い文章ではありますが、ご回答お待ちしております。

該当のソースコード

ソースコード #include <stdio.h> #include <stdlib.h> typedef struct { // トラックチャンクのデータを格納する構造体 char type[4]; // チャンクタイプを示す文字列を格納。「MTrk」が入るはず。[4byte] int size; // トラックチャンクデータのサイズ [4byte] char *data; // トラックデータ(MIDIイベントの羅列)へのポインタ } TrackChunk; 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; // カウンタ FILE *fp; // ファイルポインタ生成 int endian; // エンディアン判定にいろいろ使用(0:BigEndian, 1:LittleEndian) // ヘッダチャンク情報 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; // トラックチャンク情報を格納する配列のためのポインタ // エンディアン判定 endian = 1; if(*(char *)&endian){ // リトルエンディアンなら... endian = 1; // Little Endian } else { // ビッグエンディアンなら... endian = 0; // Big Endian } // MIDIファイルを開く if((fp = fopen("./midi/theme01.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(&header_chunk_size, sizeof(header_chunk_size)); convertEndian(&smf_format, sizeof(smf_format)); convertEndian(&tracks, sizeof(tracks)); convertEndian(&division, sizeof(division)); } // 読み取ったヘッダチャンク情報を出力 printf("# Header ========================\n"); printf("header_chunk_type : %c%c%c%c\n", header_chunk_type[0], header_chunk_type[1], header_chunk_type[2], header_chunk_type[3]); printf("header_chunk_size : %d\n", header_chunk_size); printf("smf_format : %hd\n", smf_format); printf("tracks : %hd\n", tracks); printf("division : %hd\n", division); // トラックチャンク取得 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); // データ(MIDIイベントの羅列) //fread関数は第一引数には格納先のバッファ、第二引数は読み込むデータ1つのバイト数、 //第三引数は読み込むデータの個数、第四引数はファイルポインタを指定します。 } // 読み取ったトラックチャンク情報を出力, for(i=0; i<tracks; i++){ // トラック数だけ繰返し printf("# Track[%02d] =====================\n", i); printf("track_chunks[%d].type : %c%c%c%c\n", i, track_chunks[i].type[0], track_chunks[i].type[1], track_chunks[i].type[2], track_chunks[i].type[3]); printf("track_chunks[%d].size : %d\n", i, track_chunks[i].size); printf("track_chunks[%d].data: \n", i); for(j=0; j<track_chunks[i].size; j++){ printf("%02x ", (unsigned char)track_chunks[i].data[j]); // 16進表記で出力 02は上位で足りない桁を文字0で埋め、最小2桁で表示する xは整数を16進で出力する if(!((j+1)%40)) printf("\n"); // 40バイト出力するたびに改行 //else if(!((j+1)%10)) printf(": "); // 10バイト出力するたびに区切る } printf(" \n"); } return 1; }

試したこと

補足情報(FW/ツールのバージョンなど)

OS:Windows10 使用環境:Atom

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takabosoft

2018/09/13 07:01

何が上手く行っていないのか不明なのと、具体的に何の情報を削除しようとしているんでしょう?
craftbosscoffee

2018/09/17 07:38

返信が遅れてしまい申し訳ありません。トラックデータの16進数の音の情報(90 54 31 00 90 56 31 00という音の情報の90 56 31 00 の部分だけを)削除して、音の数を減らしたいと思っております。
guest

回答1

0

~~回答じゃないですが、まずいところを。
~~
~~> if((temp = (char *)calloc(s, sizeof(char))) == NULL){
~~
これでは、tempには1文字分しか領域は確保されません

callocではこれでいいんですね。失礼しました

#ってか、エンディアン変換だけならこんなことしなくても。


入れ替える、んじゃなくて、BigEndian対応の読み出しルーチンにすれば。

unsigned char* s = input;
return (unsigned int)s[0]<<24 | s[1]<<16 | s[2]<<8 | s[3];

これだけで済みますぜ

んでもひとつ、
データを削除する、んじゃなくて、もひとつバッファを用意しといて、該当データを抜いてコピーする、という考え方で行くほうがいいかと。

投稿2018/09/13 03:33

編集2018/09/13 04:00
y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

craftbosscoffee

2018/09/19 05:06

なるほど...。その考えは思いつきませんでした。 具体的にどういった方法で該当データを抜き出してコピーすることができますか?
y_waiwai

2018/09/19 05:16

元データのバッファと、書き込み用データのバッファを用意して(それぞれ1Mbyteとってもびくともしないでしょ)、一括してバッファに読み込み、そのデータを書き込みバッファにコピー&編集して、それが済んだら書き込みバッファの内容をファイルに書き出し。 とするほうがわかりやすいんでは
craftbosscoffee

2018/09/19 05:29

#include <stdio.h> #include <stdlib.h> typedef struct { // トラックチャンクのデータを格納する構造体 char type[4]; // チャンクタイプを示す文字列を格納。「MTrk」が入るはず。[4byte] int size; // トラックチャンクデータのサイズ [4byte] char *data; // トラックデータ(MIDIイベントの羅列)へのポインタ } TrackChunk; 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; // カウンタ FILE *fp; // ファイルポインタ生成 int endian; // エンディアン判定にいろいろ使用(0:BigEndian, 1:LittleEndian) // ヘッダチャンク情報 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; // トラックチャンク情報を格納する配列のためのポインタ //------------------------------------------------------------------------------------------------------ TrackChunk *track_chunks1; //コピー用の新配列 //------------------------------------------------------------------------------------------------------ // エンディアン判定 endian = 1; if(*(char *)&endian){ // リトルエンディアンなら... endian = 1; // Little Endian } else { // ビッグエンディアンなら... endian = 0; // Big Endian } // MIDIファイルを開く if((fp = fopen("./midi/theme01.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(&header_chunk_size, sizeof(header_chunk_size)); convertEndian(&smf_format, sizeof(smf_format)); convertEndian(&tracks, sizeof(tracks)); convertEndian(&division, sizeof(division)); } // 読み取ったヘッダチャンク情報を出力 printf("# Header ========================\n"); printf("header_chunk_type : %c%c%c%c\n", header_chunk_type[0], header_chunk_type[1], header_chunk_type[2], header_chunk_type[3]); printf("header_chunk_size : %d\n", header_chunk_size); printf("smf_format : %hd\n", smf_format); printf("tracks : %hd\n", tracks); printf("division : %hd\n", division); // トラックチャンク取得 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); // データ(MIDIイベントの羅列) //fread関数は第一引数には格納先のバッファ、第二引数は読み込むデータ1つのバイト数、 //第三引数は読み込むデータの個数、第四引数はファイルポインタを指定します。 } //*---------------------------------------------------------------------------------------------------- for(i=0;i<tracks;i++){ for(j=0;j<track_chunks[i].size;j++){ (unsigned char)track_chunks1[i].data[j]= (unsigned char)track_chunks[i].data[j];//新配列にコピーする } } //----------------------------*/ // 読み取ったトラックチャンク情報を出力, for(i=0; i<tracks; i++){ // トラック数だけ繰返し printf("# Track[%02d] =====================\n", i); printf("track_chunks[%d].type : %c%c%c%c\n", i, track_chunks[i].type[0], track_chunks[i].type[1], track_chunks[i].type[2], track_chunks[i].type[3]); printf("track_chunks[%d].size : %d\n", i, track_chunks[i].size); printf("track_chunks[%d].data: \n", i); for(j=0; j<track_chunks[i].size; j++){ printf("%02x ", (unsigned char)track_chunks[i].data[j]); // 16進表記で出力 02は上位で足りない桁を文字0で埋め、最小2桁で表示する xは整数を16進で出力する if(!((j+1)%40)) printf("\n"); // 40バイト出力するたびに改行 //else if(!((j+1)%10)) printf(": "); // 10バイト出力するたびに区切る } printf(" \n"); } for(j=0; j<track_chunks[i].size; j++){ printf("%02x ", (unsigned char)track_chunks1[i].data[j]); } return 1; } 頂いたコメントを考慮して、まずは新しい配列にfor文でコピーするプログラムを書いてみたのですが、(unsigned char)track_chunks1[i].data[j]= (unsigned char)track_chunks[i].data[j]; の文のところで lvalue required as left operand of assignment というエラーが出てしまいました。 どのように改善すればよろしいでしょうか
craftbosscoffee

2018/09/19 05:30

--------で区切ったところが自分で追加したプログラム部分です
Eki

2018/09/24 03:19

とりあえず目先のエラーに関しては左辺のキャストを消せば大丈夫だと思います。 (それでそのエラーは消えますが、その操作が意味的に正しいこと・バグや間違いがないかどうかは分かりません。)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問