2012/06/07

C言語 wavファイルのエンディアン変換 (union)

オーディオrawデータのリトルエンディアンとビッグエンディアンを相互に変換するプログラム。前回作ったプログラムはchar単位だったけど、unionの応用ということでfloat単位で処理してみた。データは32bit-float専用。

wavファイルエンディアン変換 (union)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
union byteorder{
    float bfloat;            /* 4byte */
    unsigned char bchar[4];  /* 1byte ×4 */
    };

int main (int argc, char *argv[]){ 
  union  byteorder border;
  FILE *fpr,*fpw;
  int i;
  unsigned char str1[256], *str2;

  for(i=0; i<argc; i++){
    printf("%d = %s\n", i, argv[i]);
  }
  fpr = fopen(argv[1], "rb");
  if (fpr == NULL){
     printf("error rb");
     getchar();
     exit(EXIT_FAILURE);
  }
  strcpy(str1,argv[1]);
  str2 = strtok(str1,".");
  strcat(str2,"_new.wav");
  fpw = fopen(str2, "wb");
  if (fpw == NULL){
     printf("error wb");
     getchar();
     exit(EXIT_FAILURE);
  }
  /* float単位で処理 */
  for(;!feof(fpr);){
    /* read float単位*/
    fread(&border.bfloat, sizeof(float), 1, fpr);
    if(ferror(fpr)){
      perror("read error");
      break;
    }
    /* 32bit float  little endian - big endian */
    /* write byte単位 */
    for(i=sizeof(border.bchar)-1; i>=0; i--){
        fwrite(&border.bchar[i], sizeof(char), 1, fpw); 
    }
    if(ferror(fpw)){
        perror("write error");
        break;
    }
  }
  fclose(fpr);
  fclose(fpw);
  printf("success");
  getchar();
  return 0;
}
上記をコンパイルして出来たexeファイルに、wavファイル(ヘッダのないRawデータ)をドラッグ&ドロップすると処理されて、新規でwavファイル(Raw)をオリジナルと同じディレクトリに出力する。

unionでfloatとcharを共有することで、float4バイト分で読み込んでchar1バイト分を使って逆順で書き込んでいる。unionは違った変数でも同じメモリ空間を使うので、共通データを別の型で簡単に呼び出すことができる。こういう使い方が正しいか疑問だが、思いついたので作ってみただけ。処理が煩雑にならずにすっきりしたプログラムになった。動作も問題ないようだ。

今回float単位で処理するので、char単位で処理するよりは高速になった。1.8倍ぐらいのスピード。本来スピードを優先するならメモリに可能な限りロードしてから処理すべきだろう。今回はunionの応用として試してみたかっただけ。

下が変換したオーディオファイルのバイナリー。2桁がバイトで00からFFが存在する。そのバイトデータ4つ分でひとつのfloatのデータを構成。例ではリトルエンディアンを変換してビックエンディアンにしている。

sample.wav
00 00 00 00 3D 4D 40 00 3D CC E0 00 3E 19 28 00
3E 4B 48 00 3E 7C 98 00 3E 96 74 00 3E AE 08 00 
3E C4 EC 00 3E DB 08 00 3E F0 48 00 3F 02 4C 00 
3F 0B F0 00 3F 15 08 00 3F 1D 8A 00 3F 25 6E 00
変換すると、4つ単位で並び方が逆になっているのが分かる。

sample_new.wav
00 00 00 00 00 40 4D 3D 00 E0 CC 3D 00 28 19 3E
00 48 4B 3E 00 98 7C 3E 00 74 96 3E 00 08 AE 3E
00 EC C4 3E 00 08 DB 3E 00 48 F0 3E 00 4C 02 3F 
00 F0 0B 3F 00 08 15 3F 00 8A 1D 3F 00 6E 25 3F


C言語 ANSI C89 Meadow & MinGW GCC 目次はこちら