アプリ版:「スタンプのみでお礼する」機能のリリースについて

LinuxでC言語を使ってWAVファイルの再生・停止・一時停止をしようとしています。
再生・停止は行えるのですが、一時停止後、停止したところから再生がうまくいきません。
再生した秒数(ミリ秒まで)を測って、再生し終わった秒数からバイト数を求めて、その分を前詰めして再生させようとしています。
 WAVファイルヘッダー    再生済み    未再生
├──────────┼──────┼──────┤
           ↓一時停止後再生
 WAVファイルヘッダー    未再生
├──────────┼──────┤
再生済みバイト数の求め方は
バイト数=再生時間×8÷ビット数÷サンプリングレート÷チャンネル数
で求めています。
理論上この式であっていると思うのですが、ずれてしまいます。なぜか上記バイト数を÷2するとちょうど良いぐらいになります。

よろしくお願いします。

A 回答 (6件)

質問の中の式はおかしいですよね。

(サンプリングレートで割ると、サンプリングレートが高いほどバイト数が減ってしまいますよ。ビット数、チャンネル数についてもしかり。)

もう少し質問を整理してください。

この回答への補足

元々は
再生時間=8×データサイズ÷ビット数÷サンプリングレート÷チャンネル数
      =8×データサイズ÷(ビット数×サンプリングレート×チャンネル数)
の計算式からデータサイズを求める計算式をだしました。
これが間違っていますか?

補足日時:2005/08/31 13:43
    • good
    • 0

なんか式が違っているような。

。。

1回のサンプルで必要なバイト数
=(量子化ビット数÷8)×チャンネル数

1秒で必要なバイト数
=1回のサンプルで必要なバイト数 × サンプリング周波数
=(量子化ビット数÷8)×チャンネル数 × サンプリング周波数

n秒で必要なバイト数
=1秒で必要なバイト数 × n

nミリ秒で必要なバイト数
=n秒で必要なバイト数 ÷ 1,000


だと思います。

この回答への補足

教えて頂いた式を使ってやってみたのですが、
症状は変わりませんでした。
上記で求めた数値÷2をすればうまくいくのですが・・・
問題なのは「WAVを途中から再生させること」なのですが、
再生し終わったバイト数を求めてやることに問題があるのでしょうか?

補足日時:2005/08/31 13:52
    • good
    • 0

#2です。



計算式は、#2のもので間違いありません。

この式を使ってズレるのなら、原因は他にあると思います。

例えば、

・経過時間のカウントが間違えている。
・計算式中の変数を間違えている。
 (モノラルデータをステレオで計算している)
・サウンド再生用関数への引数の渡し方を間違えている。

などです。
(他にもあるかもしれません)


怪しいのは、2番目でしょうね。

変数の値はどこから持ってきましたか?

この回答への補足

>経過時間のカウントが間違えている。
経過時間を出力して確認しているので大丈夫だと思われます。

>計算式中の変数を間違えている。
WAVファイルのヘッダーから取ってきています。
ビット数:16ビット
サンプリングレート:220050
チャンネル数:2
のファイルでテストしています。
上記情報を取るためのロジックは以下のとおり。


typedef struct {
  FILE* fp;    /* ファイル構造体 */
  short is_pcm;  /* PCM フォーマットの場合は 1、それ以外は 0 */
  short channel;  /* モノラルの場合は 1、ステレオの場合は 2 */
  int  rate;   /* サンプリング周波数 */
  short bits;   /* 量子化ビット数 */
  long offset;  /* ファイル先頭から PCM データまでのオフセット */
  int  len;    /* PCM データ部の長さ */
}
WAVE;
wave_readFile( char* fname )
{
  char  buf[32];
  int  len;

  if ( ( wave.fp = fopen( fname, "r" ) ) == NULL ) {
    fprintf( stderr, "Failed to open %s\n", fname );
    return -1;
  }
  /* 先頭 4 バイトが "RIFF" であることを確認 ( 更に 4 バイトスキップしておく ) */
  fread( buf, 8, 1, wave.fp );

  if ( strncmp( buf, "RIFF", 4 ) != 0 ) {
    fprintf( stderr, "Specified file is not RIFF file.\n" );
    fclose( wave.fp );
    return -1;
  }
  /* 次の 4 バイトが "WAVE" であることを確認 */
  fread( buf, 4, 1, wave.fp );

  if ( strncmp( buf, "WAVE", 4 ) != 0 ) {
    fprintf( stderr, "Specified file is not WAVE file.\n" );
    fclose( wave.fp );
    return -1;
  }
  /* fmt チャンクを探す */
  while ( 1 ) {
    fread( buf, 8, 1, wave.fp );
    len = *( int* )( &buf[4] );

    if ( strncmp( buf, "fmt ", 4 ) != 0 ) {
      if ( fseek( wave.fp, len, SEEK_CUR ) == -1 ) {
        fprintf( stderr, "Failed to find fmt chunk.\n" );
        fclose( wave.fp );
        return -1;
      }
    }
    else
      break;
  }
  /* WAVE フォーマットを読み込む */
  fread( buf, len, 1, wave.fp );

  wave.is_pcm = *( ( short* )( &buf[0] ) );
  wave.channel = *( ( short* )( &buf[2] ) );
  wave.rate  = *( ( int*  )( &buf[4] ) );
  wave.bits  = *( ( short* )( &buf[14] ) );
  if ( wave.is_pcm != 1 )
    wave.is_pcm = 0;

  /* data チャンクを探す */
  while ( 1 ) {
    fread( buf, 8, 1, wave.fp );
    len = *( int* )( &buf[4] );

    if ( strncmp( buf, "data", 4 ) != 0 ) {
      if ( fseek( wave.fp, len, SEEK_CUR ) == -1 ) {
        fprintf( stderr, "Failed to find data chunk.\n" );
        fclose( wave.fp );
        return -1;
      }
    }
    else
      break;
  }
  wave.len = len;
  if ( ( wave.offset = ftell( wave.fp ) ) == -1 ) {
    fprintf( stderr, "Failed to find offset of PCM data.\n" );
    fclose( wave.fp );
    return -1;
  }
  return 0;
}

>サウンド再生用関数への引数の渡し方を間違えている。
write関数に渡しているWAVデータの作り方に間違いがあることは考えたのですが、恐らく大丈夫です。
/* 元データよりヘッダー部コピー */
memcpy(再生データ,元データ,44);
/* 音声部分コピー */
memcpy(&再生データ[44],&元データ[44+求めたサイズ],再生データサイズ);

補足日時:2005/08/31 16:47
    • good
    • 0

使用しているwavファイルのデータ自体がおかしいということはありませんか?



wavファイルの大きさ、諸元、実際に再生したときの再生時間(実測値)は矛盾なく一致していますか?

この回答への補足

WAVファイルのヘッダー情報がおかしいと再生ができません。
他のプレイヤーで問題なく再生できるのでファイル自体に問題はないと考えます。

補足日時:2005/08/31 17:35
    • good
    • 0

#3です。



>サンプリングレート:220050

間違ってません?
(一応確認)


#3のコードは問題ないように思えます。
とすると原因は他にありそうです。

どういうデバッグをしたのかわかりませんが、

・#2の計算式を実行するときの変数、戻り値を表示
 (実際に計算をしている箇所で表示する)
・サウンド再生用関数に渡す内容をファイルに出力し、
 プレーヤーで再生し、バイナリエディタで元のファイル と位置関係を比較する。

ということをやってみたらどうでしょうか。
(あまり大きなファイルでは使いにくいので、2~3秒のファイルを作るといいと思います)
    • good
    • 0

>memcpy(&再生データ[44],&元データ[44+求めたサイズ],再生データサイズ);



この44というのは波形データの先頭ですか?
せっかくチャンクを探すコードを書いているのだから、波形データの先頭が44バイト目であると固定してしまうのはおかしいです。
WAVファイルのフォーマットとしては、"fmt "チャンクと"data"チャンクの間に別のチャンクが入る事もありえます。

あとは、元データの配列がshortだったりすると解決なんですが。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!