Exemplo n.º 1
0
Arquivo: w64.c Projeto: joshlong/libcd
static int
w64_read_header	(SF_PRIVATE *psf, int *blockalign, int *framesperblock)
{	WAV_FMT wav_fmt ;
	int		dword = 0, marker, format = 0 ;
	sf_count_t	chunk_size, bytesread = 0 ;
	int		parsestage = 0, error, done = 0 ;
	
	/* Set position to start of file to begin reading header. */
	psf_binheader_readf (psf, "p", 0) ;	
		
	while (! done)
	{	/* Read the 4 byte marker and jump 12 bytes. */
		bytesread += psf_binheader_readf (psf, "h", &marker) ;
		chunk_size = 0 ;
		
		switch (marker)
		{	case riff_HASH16 :
					if (parsestage)
						return SFE_W64_NO_RIFF ;

					bytesread += psf_binheader_readf (psf, "e8", &chunk_size) ;
					
					if (psf->filelength  < chunk_size)
						psf_log_printf (psf, "riff : %d (should be %d)\n", chunk_size, psf->filelength) ;
					else
						psf_log_printf (psf, "riff : %d\n", chunk_size) ;

					parsestage |= HAVE_riff ;
					break ;
					
			case ACID_HASH16:
					psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ;
					return SFE_UNIMPLEMENTED ;

			case wave_HASH16 :
					if ((parsestage & HAVE_riff) != HAVE_riff)
						return SFE_W64_NO_WAVE ;
					psf_log_printf (psf, "wave\n") ;
					parsestage |= HAVE_wave ;
					break ;

			case fmt_HASH16 :
					if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave))
						return SFE_W64_NO_FMT ;
						
					bytesread += psf_binheader_readf (psf, "e8", &chunk_size) ;
					psf_log_printf (psf, " fmt : %d (0x%X)\n", chunk_size, chunk_size) ;
						
					/* size of 16 byte marker and 8 byte chunk_size value. */
					chunk_size -= 24 ;

					if ((error = wav_w64_read_fmt_chunk (psf, &wav_fmt, (int) chunk_size)))
						return error ;
						
					if (chunk_size % 8)
						psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ;
						
					format     = wav_fmt.format ;
					parsestage |= HAVE_fmt ;
					break ;

			case fact_HASH16:
					{	sf_count_t frames ;
					
						psf_binheader_readf (psf, "e88", &chunk_size, &frames) ;
						psf_log_printf (psf, "   fact : 0x%X\n"
											 "     frames : %d\n", 
										chunk_size, frames) ;
						} ;
					break ;

					
			case data_HASH16 :
					if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt))
						return SFE_W64_NO_DATA ;
					
					psf_binheader_readf (psf, "e8", &chunk_size) ;

					psf->dataoffset = psf_ftell (psf->filedes) ;
					
					psf->datalength = chunk_size - 24 ;

					if (chunk_size % 8)
						chunk_size += 8 - (chunk_size % 8) ;

					psf_log_printf (psf, "data : %d (0x%X)\n", chunk_size, psf->datalength) ;

					parsestage |= HAVE_data ;

					if (! psf->sf.seekable)
						break ;
					
					/* Seek past data and continue reading header. */
					psf_fseek (psf->filedes, chunk_size, SEEK_CUR) ;
					break ;

			default : 
					if (psf_ftell (psf->filedes) & 0x0F)
					{	psf_log_printf (psf, "  Unknown chunk marker at position %d. Resynching.\n", dword - 4) ;
						psf_binheader_readf (psf, "j", -3) ;
						break ;
						} ;
					psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ;
					done = SF_TRUE ;
					break ;
			} ;	/* switch (dword) */

		if (! psf->sf.seekable && (parsestage & HAVE_data))
			break ;

		if (psf_ferror (psf->filedes))
		{	psf_log_printf (psf, "*** Error on file handle. ***\n", marker) ;
			psf_fclearerr (psf->filedes) ;
			break ;
			} ;

		if (psf_ftell (psf->filedes) >= (int) (psf->filelength - (2 * sizeof (dword))))
			break ;

		if (psf->logindex >= sizeof (psf->logbuffer) - 2)
			return SFE_LOG_OVERRUN ;
		} ; /* while (1) */
		
	if (! psf->dataoffset)
		return SFE_W64_NO_DATA ;

	psf->endian = SF_ENDIAN_LITTLE ;		/* All WAV files are little endian. */
	
	psf_fseek (psf->filedes, psf->dataoffset, SEEK_SET) ;
	
	psf->close = w64_close ;

	if (psf->blockwidth)
	{	if (psf->filelength - psf->dataoffset < psf->datalength)
			psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
		else
			psf->sf.frames = psf->datalength / psf->blockwidth ;
		} ;

	switch (format)
	{	case WAVE_FORMAT_PCM :
		case WAVE_FORMAT_EXTENSIBLE :
					psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
					break ;
					
		case WAVE_FORMAT_MULAW :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ;
					break ;
	
		case WAVE_FORMAT_ALAW :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ;
					break ;
		
		case WAVE_FORMAT_MS_ADPCM : 
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ;
					*blockalign = wav_fmt.msadpcm.blockalign ;
					*framesperblock = wav_fmt.msadpcm.samplesperblock ;
					break ;

		case WAVE_FORMAT_IMA_ADPCM :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ;
					*blockalign = wav_fmt.ima.blockalign ;
					*framesperblock = wav_fmt.ima.samplesperblock ;
					break ;
		
		case WAVE_FORMAT_GSM610 :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ;
					break ;
		
		case WAVE_FORMAT_IEEE_FLOAT :
					psf->sf.format  = SF_FORMAT_W64 ;
					psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ;
					break ;
		
		default : return SFE_UNIMPLEMENTED ;
		} ;

	return 0 ;
} /* w64_read_header */
Exemplo n.º 2
0
static int
w64_read_header	(SF_PRIVATE *psf, int *blockalign, int *framesperblock)
{	WAV_PRIVATE *wpriv ;
	WAV_FMT 	*wav_fmt ;
	int			dword = 0, marker, format = 0 ;
	sf_count_t	chunk_size, bytesread = 0 ;
	int			parsestage = 0, error, done = 0 ;

	if ((wpriv = psf->container_data) == NULL)
		return SFE_INTERNAL ;
	wav_fmt = &wpriv->wav_fmt ;

	/* Set position to start of file to begin reading header. */
	psf_binheader_readf (psf, "p", 0) ;

	while (! done)
	{	/* Each new chunk must start on an 8 byte boundary, so jump if needed. */
		if (psf->headindex & 0x7)
			psf_binheader_readf (psf, "j", 8 - (psf->headindex & 0x7)) ;

		/* Generate hash of 16 byte marker. */
		marker = chunk_size = 0 ;
		bytesread = psf_binheader_readf (psf, "eh8", &marker, &chunk_size) ;
		if (bytesread == 0)
			break ;
		switch (marker)
		{	case riff_HASH16 :
					if (parsestage)
						return SFE_W64_NO_RIFF ;

					if (psf->filelength != chunk_size)
						psf_log_printf (psf, "riff : %D (should be %D)\n", chunk_size, psf->filelength) ;
					else
						psf_log_printf (psf, "riff : %D\n", chunk_size) ;

					parsestage |= HAVE_riff ;

					bytesread += psf_binheader_readf (psf, "h", &marker) ;
					if (marker == wave_HASH16)
					{ 	if ((parsestage & HAVE_riff) != HAVE_riff)
							return SFE_W64_NO_WAVE ;
						psf_log_printf (psf, "wave\n") ;
						parsestage |= HAVE_wave ;
					} ;
					chunk_size = 0 ;
					break ;

			case ACID_HASH16:
					psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ;
					return SFE_UNIMPLEMENTED ;

			case fmt_HASH16 :
					if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave))
						return SFE_WAV_NO_FMT ;

					psf_log_printf (psf, " fmt : %D\n", chunk_size) ;

					/* size of 16 byte marker and 8 byte chunk_size value. */
					chunk_size -= 24 ;

					if ((error = wav_w64_read_fmt_chunk (psf, (int) chunk_size)))
						return error ;

					if (chunk_size % 8)
						psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ;

					format		= wav_fmt->format ;
					parsestage |= HAVE_fmt ;
					chunk_size = 0 ;
					break ;

			case fact_HASH16:
					{	sf_count_t frames ;

						psf_binheader_readf (psf, "e8", &frames) ;
						psf_log_printf (psf, "   fact : %D\n     frames : %D\n",
										chunk_size, frames) ;
						} ;
					chunk_size = 0 ;
					break ;


			case data_HASH16 :
					if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt))
						return SFE_W64_NO_DATA ;

					psf->dataoffset = psf_ftell (psf) ;
					psf->datalength = SF_MIN (chunk_size - 24, psf->filelength - psf->dataoffset) ;

					if (chunk_size % 8)
						chunk_size += 8 - (chunk_size % 8) ;

					psf_log_printf (psf, "data : %D\n", chunk_size) ;

					parsestage |= HAVE_data ;

					if (! psf->sf.seekable)
						break ;

					/* Seek past data and continue reading header. */
					psf_fseek (psf, chunk_size, SEEK_CUR) ;
					chunk_size = 0 ;
					break ;

			case levl_HASH16 :
					psf_log_printf (psf, "levl : %D\n", chunk_size) ;
					chunk_size -= 24 ;
					break ;

			case list_HASH16 :
					psf_log_printf (psf, "list : %D\n", chunk_size) ;
					chunk_size -= 24 ;
					break ;

			case junk_HASH16 :
					psf_log_printf (psf, "junk : %D\n", chunk_size) ;
					chunk_size -= 24 ;
					break ;

			case bext_MARKER :
					psf_log_printf (psf, "bext : %D\n", chunk_size) ;
					chunk_size -= 24 ;
					break ;

			case MARKER_HASH16 :
					psf_log_printf (psf, "marker : %D\n", chunk_size) ;
					chunk_size -= 24 ;
					break ;

			case SUMLIST_HASH16 :
					psf_log_printf (psf, "summary list : %D\n", chunk_size) ;
					chunk_size -= 24 ;
					break ;

			default :
					psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %D. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ;
					done = SF_TRUE ;
					break ;
			} ;	/* switch (dword) */

		if (chunk_size >= psf->filelength)
		{	psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ;
			break ;
			} ;

		if (psf->sf.seekable == 0 && (parsestage & HAVE_data))
			break ;

		if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword))))
			break ;

		if (chunk_size > 0 && chunk_size < 0xffff0000)
		{	dword = chunk_size ;
			psf_binheader_readf (psf, "j", dword - 24) ;
			} ;
		} ; /* while (1) */

	if (psf->dataoffset <= 0)
		return SFE_W64_NO_DATA ;

	if (psf->sf.channels < 1)
		return SFE_CHANNEL_COUNT_ZERO ;

	if (psf->sf.channels >= SF_MAX_CHANNELS)
		return SFE_CHANNEL_COUNT ;

	psf->endian = SF_ENDIAN_LITTLE ;		/* All W64 files are little endian. */

	if (psf_ftell (psf) != psf->dataoffset)
		psf_fseek (psf, psf->dataoffset, SEEK_SET) ;

	if (psf->blockwidth)
	{	if (psf->filelength - psf->dataoffset < psf->datalength)
			psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
		else
			psf->sf.frames = psf->datalength / psf->blockwidth ;
		} ;

	switch (format)
	{	case WAVE_FORMAT_PCM :
		case WAVE_FORMAT_EXTENSIBLE :
					/* extensible might be FLOAT, MULAW, etc as well! */
					psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
					break ;

		case WAVE_FORMAT_MULAW :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ;
					break ;

		case WAVE_FORMAT_ALAW :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ;
					break ;

		case WAVE_FORMAT_MS_ADPCM :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ;
					*blockalign = wav_fmt->msadpcm.blockalign ;
					*framesperblock = wav_fmt->msadpcm.samplesperblock ;
					break ;

		case WAVE_FORMAT_IMA_ADPCM :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ;
					*blockalign = wav_fmt->ima.blockalign ;
					*framesperblock = wav_fmt->ima.samplesperblock ;
					break ;

		case WAVE_FORMAT_GSM610 :
					psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ;
					break ;

		case WAVE_FORMAT_IEEE_FLOAT :
					psf->sf.format = SF_FORMAT_W64 ;
					psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ;
					break ;

		default : return SFE_UNIMPLEMENTED ;
		} ;

	return 0 ;
} /* w64_read_header */
Exemplo n.º 3
0
int
wav_w64_read_fmt_chunk (SF_PRIVATE *psf, int fmtsize)
{   WAV_PRIVATE * wpriv ;
    WAV_FMT *wav_fmt ;
    int	bytesread, k, bytespersec = 0 ;

    if ((wpriv = psf->container_data) == NULL)
        return SFE_INTERNAL ;
    wav_fmt = &wpriv->wav_fmt ;

    memset (wav_fmt, 0, sizeof (WAV_FMT)) ;

    if (fmtsize < 16)
        return SFE_WAV_FMT_SHORT ;

    /* assume psf->rwf_endian is already properly set */

    /* Read the minimal WAV file header here. */
    bytesread = psf_binheader_readf (psf, "224422",
                                     &(wav_fmt->format), &(wav_fmt->min.channels),
                                     &(wav_fmt->min.samplerate), &(wav_fmt->min.bytespersec),
                                     &(wav_fmt->min.blockalign), &(wav_fmt->min.bitwidth)) ;

    psf_log_printf (psf, "  Format        : 0x%X => %s\n", wav_fmt->format, wav_w64_format_str (wav_fmt->format)) ;
    psf_log_printf (psf, "  Channels      : %d\n", wav_fmt->min.channels) ;
    psf_log_printf (psf, "  Sample Rate   : %d\n", wav_fmt->min.samplerate) ;
    psf_log_printf (psf, "  Block Align   : %d\n", wav_fmt->min.blockalign) ;

    if (wav_fmt->min.blockalign == 0)
    {   psf_log_printf (psf, "*** Error : wav_fmt->min.blockalign should not be zero.\n") ;
        return SFE_INTERNAL ;
    } ;

    if (wav_fmt->format == WAVE_FORMAT_PCM && wav_fmt->min.bitwidth == 24 &&
            wav_fmt->min.blockalign == 4 * wav_fmt->min.channels)
    {   psf_log_printf (psf, "  Bit Width     : 24\n") ;

        psf_log_printf (psf, "\n"
                        "  Ambiguous information in 'fmt ' chunk. Possibile file types:\n"
                        "    0) Invalid IEEE float file generated by Syntrillium's Cooledit!\n"
                        "    1) File generated by ALSA's arecord containing 24 bit samples in 32 bit containers.\n"
                        "    2) 24 bit file with incorrect Block Align value.\n"
                        "\n") ;

        wpriv->fmt_is_broken = 1 ;
    }
    else if (wav_fmt->min.bitwidth == 0)
    {   switch (wav_fmt->format)
        {
        case WAVE_FORMAT_GSM610 :
        case WAVE_FORMAT_IPP_ITU_G_723_1 :
            psf_log_printf (psf, "  Bit Width     : %d\n", wav_fmt->min.bitwidth) ;
            break ;
        default :
            psf_log_printf (psf, "  Bit Width     : %d (should not be 0)\n", wav_fmt->min.bitwidth) ;
        }
    }
    else
    {   switch (wav_fmt->format)
        {
        case WAVE_FORMAT_GSM610 :
        case WAVE_FORMAT_IPP_ITU_G_723_1 :
            psf_log_printf (psf, "  Bit Width     : %d (should be 0)\n", wav_fmt->min.bitwidth) ;
            break ;
        default :
            psf_log_printf (psf, "  Bit Width     : %d\n", wav_fmt->min.bitwidth) ;
        }
    } ;

    psf->sf.samplerate	= wav_fmt->min.samplerate ;
    psf->sf.frames 		= 0 ;					/* Correct this when reading data chunk. */
    psf->sf.channels	= wav_fmt->min.channels ;

    switch (wav_fmt->format)
    {
    case WAVE_FORMAT_PCM :
    case WAVE_FORMAT_IEEE_FLOAT :
        bytespersec = wav_fmt->min.samplerate * wav_fmt->min.blockalign ;
        if (wav_fmt->min.bytespersec != (unsigned) bytespersec)
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ;
        else
            psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->min.bytespersec) ;

        psf->bytewidth = BITWIDTH2BYTES (wav_fmt->min.bitwidth) ;
        break ;

    case WAVE_FORMAT_ALAW :
    case WAVE_FORMAT_MULAW :
        if (wav_fmt->min.bytespersec / wav_fmt->min.blockalign != wav_fmt->min.samplerate)
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d)\n", wav_fmt->min.bytespersec, wav_fmt->min.samplerate * wav_fmt->min.blockalign) ;
        else
            psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->min.bytespersec) ;

        psf->bytewidth = 1 ;
        if (fmtsize >= 18)
        {   bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->size20.extrabytes)) ;
            psf_log_printf (psf, "  Extra Bytes   : %d\n", wav_fmt->size20.extrabytes) ;
        } ;
        break ;

    case WAVE_FORMAT_IMA_ADPCM :
        if (wav_fmt->min.bitwidth != 4)
            return SFE_WAV_ADPCM_NOT4BIT ;
        if (wav_fmt->min.channels < 1 || wav_fmt->min.channels > 2)
            return SFE_WAV_ADPCM_CHANNELS ;

        bytesread +=
            psf_binheader_readf (psf, "22", &(wav_fmt->ima.extrabytes), &(wav_fmt->ima.samplesperblock)) ;

        bytespersec = (wav_fmt->ima.samplerate * wav_fmt->ima.blockalign) / wav_fmt->ima.samplesperblock ;
        if (wav_fmt->ima.bytespersec != (unsigned) bytespersec)
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d)\n", wav_fmt->ima.bytespersec, bytespersec) ;
        else
            psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->ima.bytespersec) ;

        psf->bytewidth = 2 ;
        psf_log_printf (psf, "  Extra Bytes   : %d\n", wav_fmt->ima.extrabytes) ;
        psf_log_printf (psf, "  Samples/Block : %d\n", wav_fmt->ima.samplesperblock) ;
        break ;

    case WAVE_FORMAT_MS_ADPCM :
        if (wav_fmt->msadpcm.bitwidth != 4)
            return SFE_WAV_ADPCM_NOT4BIT ;
        if (wav_fmt->msadpcm.channels < 1 || wav_fmt->msadpcm.channels > 2)
            return SFE_WAV_ADPCM_CHANNELS ;

        bytesread +=
            psf_binheader_readf (psf, "222", &(wav_fmt->msadpcm.extrabytes),
                                 &(wav_fmt->msadpcm.samplesperblock), &(wav_fmt->msadpcm.numcoeffs)) ;

        bytespersec = (wav_fmt->min.samplerate * wav_fmt->min.blockalign) / wav_fmt->msadpcm.samplesperblock ;
        if (wav_fmt->min.bytespersec == (unsigned) bytespersec)
            psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->min.bytespersec) ;
        else if (wav_fmt->min.bytespersec == (wav_fmt->min.samplerate / wav_fmt->msadpcm.samplesperblock) * wav_fmt->min.blockalign)
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d (MS BUG!))\n", wav_fmt->min.bytespersec, bytespersec) ;
        else
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ;


        psf->bytewidth = 2 ;
        psf_log_printf (psf, "  Extra Bytes   : %d\n", wav_fmt->msadpcm.extrabytes) ;
        psf_log_printf (psf, "  Samples/Block : %d\n", wav_fmt->msadpcm.samplesperblock) ;
        if (wav_fmt->msadpcm.numcoeffs > ARRAY_LEN (wav_fmt->msadpcm.coeffs))
        {   psf_log_printf (psf, "  No. of Coeffs : %d (should be <= %d)\n", wav_fmt->msadpcm.numcoeffs, ARRAY_LEN (wav_fmt->msadpcm.coeffs)) ;
            wav_fmt->msadpcm.numcoeffs = ARRAY_LEN (wav_fmt->msadpcm.coeffs) ;
        }
        else
            psf_log_printf (psf, "  No. of Coeffs : %d\n", wav_fmt->msadpcm.numcoeffs) ;

        psf_log_printf (psf, "    Index   Coeffs1   Coeffs2\n") ;
        for (k = 0 ; k < wav_fmt->msadpcm.numcoeffs ; k++)
        {   bytesread +=
                psf_binheader_readf (psf, "22", &(wav_fmt->msadpcm.coeffs [k].coeff1), &(wav_fmt->msadpcm.coeffs [k].coeff2)) ;
            snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), "     %2d     %7d   %7d\n", k, wav_fmt->msadpcm.coeffs [k].coeff1, wav_fmt->msadpcm.coeffs [k].coeff2) ;
            psf_log_printf (psf, psf->u.cbuf) ;
        } ;
        break ;

    case WAVE_FORMAT_GSM610 :
        if (wav_fmt->gsm610.channels != 1 || wav_fmt->gsm610.blockalign != 65)
            return SFE_WAV_GSM610_FORMAT ;

        bytesread +=
            psf_binheader_readf (psf, "22", &(wav_fmt->gsm610.extrabytes), &(wav_fmt->gsm610.samplesperblock)) ;

        if (wav_fmt->gsm610.samplesperblock != 320)
            return SFE_WAV_GSM610_FORMAT ;

        bytespersec = (wav_fmt->gsm610.samplerate * wav_fmt->gsm610.blockalign) / wav_fmt->gsm610.samplesperblock ;
        if (wav_fmt->gsm610.bytespersec != (unsigned) bytespersec)
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d)\n", wav_fmt->gsm610.bytespersec, bytespersec) ;
        else
            psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->gsm610.bytespersec) ;

        psf->bytewidth = 2 ;
        psf_log_printf (psf, "  Extra Bytes   : %d\n", wav_fmt->gsm610.extrabytes) ;
        psf_log_printf (psf, "  Samples/Block : %d\n", wav_fmt->gsm610.samplesperblock) ;
        break ;

    case WAVE_FORMAT_EXTENSIBLE :
        if (wav_fmt->ext.bytespersec / wav_fmt->ext.blockalign != wav_fmt->ext.samplerate)
            psf_log_printf (psf, "  Bytes/sec     : %d (should be %d)\n", wav_fmt->ext.bytespersec, wav_fmt->ext.samplerate * wav_fmt->ext.blockalign) ;
        else
            psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->ext.bytespersec) ;

        bytesread +=
            psf_binheader_readf (psf, "224", &(wav_fmt->ext.extrabytes), &(wav_fmt->ext.validbits),
                                 &(wav_fmt->ext.channelmask)) ;

        psf_log_printf (psf, "  Valid Bits    : %d\n", wav_fmt->ext.validbits) ;
        psf_log_printf (psf, "  Channel Mask  : 0x%X\n", wav_fmt->ext.channelmask) ;

        bytesread +=
            psf_binheader_readf (psf, "422", &(wav_fmt->ext.esf.esf_field1), &(wav_fmt->ext.esf.esf_field2),
                                 &(wav_fmt->ext.esf.esf_field3)) ;

        /* compare the esf_fields with each known GUID? and print? */
        psf_log_printf (psf, "  Subformat\n") ;
        psf_log_printf (psf, "    esf_field1 : 0x%X\n", wav_fmt->ext.esf.esf_field1) ;
        psf_log_printf (psf, "    esf_field2 : 0x%X\n", wav_fmt->ext.esf.esf_field2) ;
        psf_log_printf (psf, "    esf_field3 : 0x%X\n", wav_fmt->ext.esf.esf_field3) ;
        psf_log_printf (psf, "    esf_field4 : ") ;
        for (k = 0 ; k < 8 ; k++)
        {   bytesread += psf_binheader_readf (psf, "1", &(wav_fmt->ext.esf.esf_field4 [k])) ;
            psf_log_printf (psf, "0x%X ", wav_fmt->ext.esf.esf_field4 [k] & 0xFF) ;
        } ;
        psf_log_printf (psf, "\n") ;
        psf->bytewidth = BITWIDTH2BYTES (wav_fmt->ext.bitwidth) ;

        /* Compare GUIDs for known ones. */
        if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_PCM))
        {   psf->sf.format = SF_FORMAT_WAVEX | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
            psf_log_printf (psf, "    format : pcm\n") ;
        }
        else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_MS_ADPCM))
        {   psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM) ;
            psf_log_printf (psf, "    format : ms adpcm\n") ;
        }
        else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_IEEE_FLOAT))
        {   psf->sf.format = SF_FORMAT_WAVEX | ((psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT) ;
            psf_log_printf (psf, "    format : IEEE float\n") ;
        }
        else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_ALAW))
        {   psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_ALAW) ;
            psf_log_printf (psf, "    format : A-law\n") ;
        }
        else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_MULAW))
        {   psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_ULAW) ;
            psf_log_printf (psf, "    format : u-law\n") ;
        }
        else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM))
        {   psf->sf.format = SF_FORMAT_WAVEX | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
            psf_log_printf (psf, "    format : pcm (Ambisonic B)\n") ;
            wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ;
        }
        else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT))
        {   psf->sf.format = SF_FORMAT_WAVEX | ((psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT) ;
            psf_log_printf (psf, "    format : IEEE float (Ambisonic B)\n") ;
            wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ;
        }
        else
            return SFE_UNIMPLEMENTED ;

        break ;

    case WAVE_FORMAT_G721_ADPCM :
        psf_log_printf (psf, "  Bytes/sec     : %d\n", wav_fmt->g72x.bytespersec) ;
        if (fmtsize >= 20)
        {   bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->g72x.extrabytes), &(wav_fmt->g72x.auxblocksize)) ;
            if (wav_fmt->g72x.extrabytes == 0)
                psf_log_printf (psf, "  Extra Bytes   : %d (should be 2)\n", wav_fmt->g72x.extrabytes) ;
            else
                psf_log_printf (psf, "  Extra Bytes   : %d\n", wav_fmt->g72x.extrabytes) ;
            psf_log_printf (psf, "  Aux Blk Size  : %d\n", wav_fmt->g72x.auxblocksize) ;
        }
        else if (fmtsize == 18)
        {   bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->g72x.extrabytes)) ;
            psf_log_printf (psf, "  Extra Bytes   : %d%s\n", wav_fmt->g72x.extrabytes, wav_fmt->g72x.extrabytes != 0 ? " (should be 0)" : "") ;
        }
        else
            psf_log_printf (psf, "*** 'fmt ' chunk should be bigger than this!\n") ;
        break ;

    default :
        psf_log_printf (psf, "*** No 'fmt ' chunk dumper for this format!\n") ;
        return SFE_WAV_BAD_FMT ;
    } ;

    if (bytesread > fmtsize)
    {   psf_log_printf (psf, "*** wav_w64_read_fmt_chunk (bytesread > fmtsize)\n") ;
        return SFE_WAV_BAD_FMT ;
    }
    else
        psf_binheader_readf (psf, "j", fmtsize - bytesread) ;

    psf->blockwidth = wav_fmt->min.channels * psf->bytewidth ;

    return 0 ;
} /* wav_w64_read_fmt_chunk */