در مطلب قبل (PHP: آموزش کار با فایل‌های صوتی؛ بخش دوم - خواندن اطلاعات فیلد‌ها) اطلاعات خام در مورد فایل wav را از فایل wav خواندیم.

در این مطلب سعی می‌کنیم با استفاده از این اطلاعات از قسمت data در subchunk2 که شامل داده‌های مربوط به سیگنال صدا است، نمونه برداری کنیم.

توجه کنید تعداد کانال (num_channels) و تعداد بیت در نمونه (bit_per_sample) دو عدد هگز little endian هستند. از طرفی Field size آنها 2 است، یعنی شامل 2 بایت داده هستند. برای مثال در فایل sample.wav مقدار فیلد تعداد کانال 0100 است. مقدار هگز big endian آن 0001 و تبدیل آن به عدد صحیح مقدار 1 را نتیجه می‌دهد. از آنجا که num_channels و bit_per_sample برای فایل wav اعدادی کمتر از 256 هستند لذا عدد hex سمت چپ در عدد little endian داده‌ی خوانده شده برای ادامه پردازش کافی است. برای بدست آورد این مقادیر کد زیر کافی است.

$channel = $info['fmt']['num_channels'] = hexdec(substr($heading['fmt']['num_channels'], 0, 2));
$peek = $info['fmt']['bit_per_sample'] = hexdec(substr($heading['fmt']['bit_per_sample'], 0, 2));

از فیلد bit_per_sample تعداد byte_per_sample را بدست می‌آوریم.

$byte = $info['fmt']['byte_per_sample'] = $info['fmt']['bit_per_sample'] / 8;

سپس data_size را با استفاده از فرمول زیر محاسبه می‌کنیم.

$ratio = $info['fmt']['ratio'] = ($info['fmt']['num_channels'] == 2 ? 40 : 80);
// $data_size = (size_of_file - header_bytes_read) / skipped_bytes + 1
$data_size = $info['fmt']['data_size'] = floor((filesize($filename) - 44) / ($info['fmt']['ratio'] + $info['fmt']['byte_per_sample']) + 1);

با استفاده از این اطلاعات آرایه نمونه برداری را به صورت زیر بدست می‌آوریم.

$data_point = 0;
$datas = array();
while (!feof($handle) && $data_point < $data_size) {
  if ($data_point++ % DETAIL == 0) {
    $bytes = array();

    // get number of bytes depending on bitrate
    for ($i = 0; $i < $byte; $i++)
      $bytes[$i] = fgetc($handle);

    switch ($byte) {
      // get value for 8-bit wav
      case 1:
        $data = findValues($bytes[0], $bytes[1]);
        break;
      // get value for 16-bit wav
      case 2:
        if (ord($bytes[1]) & 128)
          $temp = 0;
        else
          $temp = 128;
        $temp = chr((ord($bytes[1]) & 127) + $temp);
        $data = floor(findValues($bytes[0], $temp) / 256);
        break;
    }

    // skip bytes for memory optimization
    fseek($handle, $ratio, SEEK_CUR);
    $datas[] = $data;
  } else {
    // skip this one due to lack of detail
    fseek($handle, $ratio + $byte, SEEK_CUR);
  }
}

 

برچسب ها: 

افزودن نظر جدید