• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?


  • Subject: Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?
  • From: Paul Scott <email@hidden>
  • Date: Wed, 18 Aug 2010 21:20:52 -0700

I forgot to include the function LocateHeader(), so here it is. If there are any other pieces missing, let me know.

Paul

//---------------------------------------------------------------------------
/*
-------------------------------------------------------------------------
LocateHeader()


   This is a support routine for CombineWaves() that finds the named header
   in the given file, leaving the seek pointer at the header length field.
   The method simply seeks to just past the RIFF header and then starts
   skipping blocks until the correct header is located.
*/
bool LocateHeader( FILE *fp, PWAVEDATA p, char *id ) {
   fseek( fp, sizeof( WAVERIFF ), SEEK_SET );
   while ( 1 ) {
      int n = fread( p->id, 1, sizeof( p->id ), fp );
      if ( n != sizeof( p->id ) ) return false;
      if ( strnicmp( p->id, id, sizeof( p->id ) ) ) {
         fread( &(p->length), 1, sizeof( p->length ), fp );
         fseek( fp, p->length, SEEK_CUR );
      }
      else return true;
   }
}

On 8/18/2010 9:13 PM, Paul Scott wrote:
Here's code I wrote years ago for a now defunct company. It takes a list of input filenames (.WAV files) and an output file name (.WAV file), and combines the input files into a single output file. It isn't iPhone, it isn't Objective C, it isn't CoreAudio. But it does combine .WAV files by re-wrapping them into a single file. It was written in Borland C++, but with a tiny bit of tweaking it can work with any C++ compiler. Maybe it will be of use to someone.

Paul

//---------------------------------------------------------------------------

#ifndef CombinerH
#define CombinerH
//---------------------------------------------------------------------------



#define WAVBSIZE 32760

void ProcessTrafficFiles( TList *, AnsiString *, AnsiString * );
void CombineWaves( TList *, AnsiString *, bool );

typedef struct _WAVERIFF * PWAVERIFF;
typedef struct _WAVERIFF {
   char  id[4];
   int   length;
   char   wave[4];
} WAVERIFF;

typedef struct _WAVEFMT * PWAVEFMT;
typedef struct _WAVEFMT {
   char  id[4];
   int   length;
   short fmt;
   short channels;
   int   samplesps;
   int   avgbytesps;
   short align;
   short bitsps;
} WAVEFMT;

typedef struct _WAVEDATA * PWAVEDATA;
typedef struct _WAVEDATA {
   char  id[4];
   int   length;
   char  data[];
} WAVEDATA;

//---------------------------------------------------------------------------

#endif

//---------------------------------------------------------------------------

/*
-------------------------------------------------------------------------
CombineWaves()


Accepts a TList of AnsiString full-path file names, an AnsiString output
full-path file name, and a MultiBlock flag.


   Processing is as follows:

Remove from the TList any file name without a .wav extension. If no files
remain, then quit.


For each input file, copy the wave data into the output file according to
the MulitBlock flag.


   If the MultiBlock flag is false, then all wave data is combined into a
   single data block in the output file. The first file in the TList sets
   the output format, and the remaining input files must have the same
   format. The format blocks are not checked for consistency.

If the MultiBlock flag is true, then the input files may have different
formats, such as sampling rate, stereo, etc. The format block from each
file is copied to the output file, so that the .wav player can change
formats on-the-fly. This is the more powerful option, but may not be
compatible with all .wav players. In fact, I'm not aware of any that
support this, but it's here nonetheless.


-------------------------------------------------------------------------
*/
void CombineWaves( TList *FileList, AnsiString *OutFile, bool MultiBlock ) {


   WAVERIFF riff;                      // Wave RIFF CHUNK Layout
   WAVEFMT  fmt;                       // Wave FMT CHUNK Layout
   WAVEDATA data;                      // Wave DATA CHUNK Layout

FILE *iWave, *oWave; // Input and Output Stream Pointers
char buffer[WAVBSIZE];
bool bFormatWritten = false;
bool bDataWritten = false;
int n, total = 0;



// Remove items from list without a .wav extension

for ( int i = 0; i < FileList->Count; i++ ) {
AnsiString s( *((AnsiString *)(FileList->Items[i])) );
if ( s.LowerCase().AnsiPos( AnsiString( ".wav" ) ) != s.Length() - 3 ) {
FileList->Delete( i-- );
continue;
}
}


   // Return if nothing to process

   if ( FileList->Count < 1 ) return;

   // Open the Ouput File

   AnsiString oPath = *OutFile;

   if ( ( oWave = fopen( oPath.c_str(), "w+b" ) ) == NULL ) {
      AnsiString s = "Error opening '"; s += oPath; s += "'";
      //Application->MessageBox( s.c_str(), "Error Message", IDOK );
   }
   else {
      setvbuf( oWave, NULL, _IOFBF, 32767 );

      // Write the RIFF Header

      strncpy( riff.id, "RIFF", 4 );
      strncpy( riff.wave, "WAVE", 4 );
      riff.length = 0;
      fwrite( &riff, sizeof( riff ), 1, oWave );

      // Copy wave data from each input file to output file

      for ( int i = 0; i < FileList->Count; i++ ) {

         AnsiString iPath = *((AnsiString*) FileList->Items[i]);
         if ( ( iWave = fopen( iPath.c_str(), "rb" ) ) == NULL ) {
#           if defined( WRITELOG )
               fprintf( log, "%s Can't open %s\n", CTS, iPath.c_str() );
               fflush( log );
#           endif
            continue;
         }
         setvbuf( iWave, NULL, _IOFBF, 32767 );

// Write the FMT header
// If MultiBlock, write the FMT header for each input wave file,
// otherwise, only write one FMT header from the first input file


if ( ( ! bFormatWritten ) | MultiBlock ) {
if ( !LocateHeader( iWave, (PWAVEDATA) &fmt, "fmt " ) ) continue;
bFormatWritten = true;
fread( &fmt.length, 1, sizeof( fmt.length ), iWave );
if ( ! ( fmt.length < WAVBSIZE ) ) continue;
fread( &buffer, 1, fmt.length, iWave );
fseek( oWave, 0L, SEEK_END );
fwrite( &fmt, 1, sizeof( fmt.id ) + sizeof( fmt.length ), oWave );
fwrite( buffer, 1, fmt.length, oWave );
if ( MultiBlock ) total += fmt.length;
}


         // Find the DATA block and add data length to total length
         // Skip past any blocks between the FMT and DATA block, or
         // break out if fread() returns less than we expect

if ( !LocateHeader( iWave, (PWAVEDATA) &data, "data" ) ) continue;
n = fread( &data.length, 1, sizeof( data.length ), iWave );
if ( n != sizeof( data.length ) ) continue;
total += data.length;


         // Write the DATA header only for the first input file
         // OR, for each input file when MultiBlock is specified

         if ( ( !bDataWritten ) | MultiBlock ) {
            bDataWritten = true;
            fwrite( &data, 1, sizeof( data ), oWave );
            if ( MultiBlock ) total += sizeof( data );
         }

// Now, copy the actual data from input to output
// There is simple support here for a corrupt input wave file with
// an excessive data length, so that we stop at end of file.


for ( n = 0; data.length > WAVBSIZE; data.length -= n ) {
if ( ( n = fread( buffer, 1, WAVBSIZE, iWave ) ) == WAVBSIZE ) {
fwrite( buffer, 1, n, oWave );
}
else {
if ( n ) fwrite( buffer, 1, n, oWave );
total -= ( WAVBSIZE - n );
data.length = 0;
break;
}
}
if ( data.length ) {
if ( ( n = fread( buffer, 1, data.length, iWave ) ) == data.length ) {
fwrite( buffer, 1, n, oWave );
data.length -= n;
}
else {
if ( n ) fwrite( buffer, 1, n, oWave );
total -= ( data.length - n );
data.length = 0;
}
}
fclose( iWave );
}


// If the total length is zero (which could happen on a read error or
// when all the .wav files were missing) add dummy FMT and DATA blocks


      if ( ! total ) {

         fseek( oWave, sizeof( riff ), SEEK_SET );
         strncpy( fmt.id, "fmt ", 4 );
         fmt.length = 16;
         fmt.fmt = 1;
         fmt.channels = 1;
         fmt.samplesps = 22050;
         fmt.avgbytesps = 44100;
         fmt.align = 2;
         fmt.bitsps = 16;
         if ( MultiBlock ) total += sizeof( fmt );
         fwrite( &fmt, 1, sizeof( fmt ), oWave );

         strncpy( data.id, "data", 4 );
         data.length = 2;
         buffer[0] = buffer[1] = 0;
         total += data.length;
         if ( MultiBlock ) total += sizeof( data );
         fwrite( &data, 1, sizeof( data ), oWave );
         fwrite( buffer, 1, 2, oWave );
      }

      // Now that the data copy is done we need to update the length in
      // the data header to reflect the total of all files copied
      // EXCEPT in MultiBlock mode, which has the correct length already
      // in the individual data blocks

      if ( !MultiBlock ) {
         LocateHeader( oWave, (PWAVEDATA) &fmt, "fmt " );
         fread( &fmt.length, 1, sizeof( fmt.length ), oWave );
         fseek( oWave, fmt.length, SEEK_CUR );
         fread( &data, 1, sizeof( data ), oWave );
         data.length = total;
         fseek( oWave, sizeof( data )*-1, SEEK_CUR );
         fwrite( &data, 1, sizeof( data ), oWave );
      }

      // And, finally, update the RIFF header to reflect the total
      // output data length, and close up shop

      fseek( oWave, 0L, SEEK_SET );
      fread( &riff, 1, sizeof( riff ), oWave );
      riff.length = total + ( MultiBlock ? 0 : 8 + sizeof( fmt ) + 4 );
      fseek( oWave, 0L, SEEK_SET );
      fwrite( &riff, 1, sizeof( data ), oWave );

      fclose( oWave );
   }
}

_______________________________________________ Do not post admin requests to the list. They will be ignored. Coreaudio-api mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
References: 
 >Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way? (From: Eric Chamberlain <email@hidden>)
 >Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way? (From: William Stewart <email@hidden>)
 >Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way? (From: Eric Chamberlain <email@hidden>)
 >Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way? (From: Paul Scott <email@hidden>)

  • Prev by Date: Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?
  • Next by Date: Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?
  • Previous by thread: Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?
  • Next by thread: Re: Trying to concatenate two wav files on an iPhone is ExtAudioFile the best way?
  • Index(es):
    • Date
    • Thread