Create an audio stitching tool in PHP

Started by Kalyan, Nov 27, 2008, 02:09 PM

Previous topic - Next topic

Kalyan

Create an audio stitching tool in PHP

Understanding Microsoft PCM WAV files

Microsoft PCM WAV files contain information such as the audio type, the audio format, and the audio data split into three "chunks." The first chunk contains ChunkID, ChunkSize, and Format. In a few bytes, this chunk informs any application reading the media file that it's a WAVE audio file.

The second chunk contains Subchunk1ID, Subchunk1Size, AudioFormat, NumChannels, SampleRate, ByteRate, BlockAlign, and BitsPerSample. Respectively, this is "fmt"; 16 (for PCM); 1 (no compression); 1 or 2 (Mono or Stereo); 8000, 44100, etc.; SampleRate * NumChannels * BitsPerSample/8; NumChannels * BitsPerSample/8; and 8, 16, etc.

The third chunk contains the Subchunk2ID, Subchunk2Size, and Data: "data", data size (NumSamples * NumChannels * BitsPerSample/8), and the audio data. To retrieve this information, you simply read and store the appropriate bytes in the form of an audio file. With PHP, you do this with the stream functions.

Using PHP's stream functions

By using a combination of fopen(), fread(), and fclose(), read these values in to local variables. A method that I'm particularly fond of is storing the file information in a structure for easy organisation. You can do this with a class in PHP:

class FILESTRUCT {
  var $ChunkID;
  var $ChunkSize;
  var $Format;
  var $Subchunk1ID;
  var $Subchunk1Size;
  var $AudioFormat;
  var $NumChannels;
  var $SampleRate;
  var $ByteRate;
  var $BlockAlign;
  var $BitsPerSample;
  var $Subchunk2ID;
  var $Subchunk2Size;
  var $Data;

  function FILESTRUCT() {
    $this->ChunkID = array(0x0, 0x0, 0x0, 0x0);
    $this->ChunkSize = array(0x0, 0x0, 0x0, 0x0);
    $this->Format = array(0x0, 0x0, 0x0, 0x0);
    $this->Subchunk1ID = array(0x0, 0x0, 0x0, 0x0);
    $this->Subchunk1Size = array(0x0, 0x0, 0x0, 0x0);
    $this->AudioFormat = array(0x0, 0x0);
    $this->NumChannels = array(0x0, 0x0);
    $this->SampleRate = array(0x0, 0x0, 0x0, 0x0);
    $this->ByteRate = array(0x0, 0x0, 0x0, 0x0);
    $this->BlockAlign = array(0x0, 0x0);
    $this->BitsPerSample = array(0x0, 0x0);
    $this->Subchunk2ID = array(0x0, 0x0, 0x0, 0x0);
    $this->Subchunk2Size = array(0x0, 0x0, 0x0, 0x0);
    $this->Data = array();
  }
}



This file structure class contains information about the size of each section of the file. For instance, the ChunkID property is a four element array for containing four bytes of information. When I read in the binary data from the file, I can use the count() function to grab the number of bytes that makes up that portion of the file data. Given the basic information to retrieve the file data, you can start to conceptualise the end solution.

Stitching WAV files together

When a user visits a particular page, you want to provide the user with an audio file stitched together from multiple audio files. In order for this to happen, one of the input parameters needs to be an array of file paths. You must loop through these files, load the file information into the FILESTRUCT structures, and create a new FILESTRUCT structure that contains the information on the concatenated files. Then, using that FILESTRUCT structure, set the MIME type on the response and pump out the binary data.

I'll create a class to handle the file stitching operations. This is mostly because I use a class module in my Visual Basic solution to provide this functionality. The class will only contain one public method: StitchFiles. This method will accept a FILESTRUCT reference and an array of files:

class CStitcher {

  function StitchFiles(&$fsFile, &$sFiles) {
    ...
  }
}

This method contains the guts of the stitching process. A future article will delve deeper into implementation. Also, I'll provide the code to deliver the file and some HTML code to play the audio.

source : builderau