tag 292137 + pending thanks On Tue, Feb 01, 2005 at 02:58:50PM +0000, Paul Brossier wrote: > i found the following patches in #60041 and #126257. with this, > recorded files can be played using bplay, but the file header is still > somehow badly crafted: > > $ play new.wav > playing new.wav > sox: Premature EOF on .wav input file
Thanks. I had already looked through the bplay BTS entries, found the patches there and decided to craft my own. It's ready but stupid me forgot to apply the current patches to gramofile first, so I'll have to go through another round and do some patch merging. I'll attach the original version against the pristine upstream source for reference. > i also noted a few other things that could be grabbed from current > bplay: > - handling of very long files (see last patch in #126257) > - updated Die function to make sure the forked process is killed. > > And at the end of the recording, when showing the 'Recording > information', brec_gramo eats all the cpu available until OK is pressed. WAV format as spec'ed is limited to a 2GB max. file size. Therefore, apart from the sanity checks I see little use in applying the LFS patches. Regards, Daniel.
# Fix endianness bugs in WAV and VOC headers on big-endian archs. # Use POSIX size types to avoid broken headers on 64bit archs. # Disable padding in structs that read/write raw on-disk data. # [dk] #PATCHOPTIONS: -p0 Index: bplaysrc/bplay.c =================================================================== RCS file: /home/kobras/cvsroot/debian/gramofile/bplaysrc/bplay.c,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 bplay.c --- bplaysrc/bplay.c 2001/05/05 14:07:15 1.1.1.2 +++ bplaysrc/bplay.c 2005/01/31 15:54:06 @@ -26,6 +26,30 @@ #include <machine/soundcard.h> #endif +/* Needed for BYTE_ORDER and BIG/LITTLE_ENDIAN macros. */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +# include <endian.h> +# undef _BSD_SOURCE +#else +# include <endian.h> +#endif + +#include <sys/types.h> +#include <byteswap.h> + +/* Adapted from the byteorder macros in the Linux kernel. */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) +#else +#define cpu_to_le32(x) bswap_32((x)) +#define cpu_to_le16(x) bswap_16((x)) +#endif + +#define le32_to_cpu(x) cpu_to_le32((x)) +#define le16_to_cpu(x) cpu_to_le16((x)) + #include "fmtheaders.h" #include "../yesnowindow.h" @@ -290,23 +314,26 @@ char *data = "data"; memcpy(&(header.main_chunk), riff, 4); - header.length = sizeof(wavhead) - 8 + bcount; + header.length = cpu_to_le32(sizeof(wavhead) + - 8 + bcount); memcpy(&(header.chunk_type), wave, 4); memcpy(&(header.sub_chunk), fmt, 4); - header.sc_len = 16; - header.format = 1; - header.modus = stereo + 1; - header.sample_fq = speed; - header.byte_p_sec = ((bits > 8)? 2:1)*(stereo+1)*speed; + header.sc_len = cpu_to_le32(16); + header.format = cpu_to_le16(1); + header.modus = cpu_to_le16(stereo + 1); + header.sample_fq = cpu_to_le32(speed); + header.byte_p_sec = cpu_to_le32(((bits > 8)? + 2:1)*(stereo+1)*speed); /* Correction by J.A. Bezemer: */ - header.byte_p_spl = ((bits > 8)? 2:1)*(stereo+1); + header.byte_p_spl = cpu_to_le16(((bits > 8)? + 2:1)*(stereo+1)); /* was: header.byte_p_spl = (bits > 8)? 2:1; */ - header.bit_p_spl = bits; + header.bit_p_spl = cpu_to_le16(bits); memcpy(&(header.data_chunk), data, 4); - header.data_length = bcount; + header.data_length = cpu_to_le32(bcount); write(thefd, &header, sizeof(header)); } case F_RAW: @@ -336,9 +363,9 @@ for (i=0;i<20;i++) header.Magic[i] = VOC_MAGIC[i]; - header.BlockOffset = 0x1a; - header.Version = 0x0114; - header.IDCode = 0x111F; + header.BlockOffset = cpu_to_le16(0x1a); + header.Version = cpu_to_le16(0x0114); + header.IDCode = cpu_to_le16(0x111F); write(thefd, &header, sizeof(vochead)); snd_parm(speed, bits, stereo); @@ -349,10 +376,10 @@ ablk.BlockLen[0] = (i + 12) & 0xFF; ablk.BlockLen[1] = ((i + 12) >> 8) & 0xFF; ablk.BlockLen[2] = ((i + 12) >> 16) & 0xFF; - bblk.SamplesPerSec = speed; + bblk.SamplesPerSec = cpu_to_le32(speed); bblk.BitsPerSample = bits; bblk.Channels = stereo + 1; - bblk.Format = (bits == 8)? 0 : 4; + bblk.Format = cpu_to_le16((bits == 8)? 0 : 4); write(thefd, &ablk, sizeof(ablk)); write(thefd, &bblk, sizeof(bblk)); shmrec(thefd, i, 1); @@ -476,6 +503,17 @@ memcpy((void*)&wavhd, (void*)hd_buf, 20); count = read(thefd, ((char*)&wavhd)+20, sizeof(wavhd) - 20); + + wavhd.length = le32_to_cpu(wavhd.length); + wavhd.sc_len = le32_to_cpu(wavhd.sc_len); + wavhd.format = le16_to_cpu(wavhd.format); + wavhd.modus = le16_to_cpu(wavhd.modus); + wavhd.sample_fq = le32_to_cpu(wavhd.sample_fq); + wavhd.byte_p_sec = le32_to_cpu(wavhd.byte_p_sec); + wavhd.byte_p_spl = le16_to_cpu(wavhd.byte_p_spl); + wavhd.bit_p_spl = le16_to_cpu(wavhd.bit_p_spl); + wavhd.data_length = le32_to_cpu(wavhd.data_length); + if(wavhd.format != 1) Die("Input is not a PCM WAV file"); #ifndef LP2CD if (! (mods&MSPEED)) @@ -518,6 +556,11 @@ fprintf(stderr, "Playing Creative Labs Voice file ...\n"); memcpy((void*)&vochd, (void*)hd_buf, 20); count = read(thefd, ((char*)&vochd)+20, sizeof(vochd) - 20); + + vochd.BlockOffset = le16_to_cpu(vochd.BlockOffset); + vochd.Version = le16_to_cpu(vochd.Version); + vochd.IDCode = le16_to_cpu(vochd.IDCode); + fprintf(stderr, "Format version %d.%d\n", vochd.Version>>8, vochd.Version&0xFF); if (vochd.IDCode != (~vochd.Version+0x1234)) @@ -566,6 +609,9 @@ { blockT8 tblock; read(thefd, (char*)&tblock, sizeof(tblock)); + + tblock.TimeConstant = le16_to_cpu(tblock.TimeConstant); + if(tblock.PackMethod != 0) Die("Non PCM VOC block"); speed = 256000000/(65536 - tblock.TimeConstant); bits = 8; @@ -578,6 +624,10 @@ { blockT9 tblock; read(thefd, (char*)&tblock, sizeof(tblock)); + + tblock.SamplesPerSec = le32_to_cpu(tblock.SamplesPerSec); + tblock.Format = le16_to_cpu(tblock.Format); + if(tblock.Format != 0 && tblock.Format != 4) Die("Non PCM VOC block"); speed = tblock.SamplesPerSec; Index: bplaysrc/fmtheaders.h =================================================================== RCS file: /home/kobras/cvsroot/debian/gramofile/bplaysrc/fmtheaders.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 fmtheaders.h --- bplaysrc/fmtheaders.h 2001/05/05 13:52:25 1.1.1.1 +++ bplaysrc/fmtheaders.h 2005/01/31 15:54:06 @@ -3,44 +3,50 @@ #include <sys/types.h> +#ifdef __GNUC__ +# define PACKED(x) __attribute__((packed)) x +#else +# define PACKED(x) x +#endif + /* Definitions for .VOC files */ #define VOC_MAGIC "Creative Voice File\032" -#define DATALEN(bp) ((u_long)(bp.BlockLen[0]) | \ - ((u_long)(bp.BlockLen[1]) << 8) | \ - ((u_long)(bp.BlockLen[2]) << 16) ) +#define DATALEN(bp) ((u_int32_t)(bp.BlockLen[0]) | \ + ((u_int32_t)(bp.BlockLen[1]) << 8) | \ + ((u_int32_t)(bp.BlockLen[2]) << 16) ) typedef struct vochead { - u_char Magic[20]; /* must be VOC_MAGIC */ - u_short BlockOffset; /* Offset to first block from top of file */ - u_short Version; /* VOC-file version */ - u_short IDCode; /* complement of version + 0x1234 */ -} vochead; + u_int8_t Magic[20]; /* must be VOC_MAGIC */ + u_int16_t BlockOffset; /* Offset to first block from top of file */ + u_int16_t Version; /* VOC-file version */ + u_int16_t IDCode; /* complement of version + 0x1234 */ +} PACKED(vochead); typedef struct blockTC { - u_char BlockID; - u_char BlockLen[3]; /* low, mid, high byte of length of rest of block */ -} blockTC; + u_int8_t BlockID; + u_int8_t BlockLen[3]; /* low, mid, high byte of length of rest of block */ +} PACKED(blockTC); typedef struct blockT1 { - u_char TimeConstant; - u_char PackMethod; -} blockT1; + u_int8_t TimeConstant; + u_int8_t PackMethod; +} PACKED(blockT1); typedef struct blockT8 { - u_short TimeConstant; - u_char PackMethod; - u_char VoiceMode; -} blockT8; + u_int16_t TimeConstant; + u_int8_t PackMethod; + u_int8_t VoiceMode; +} PACKED(blockT8); typedef struct blockT9 { - u_int SamplesPerSec; - u_char BitsPerSample; - u_char Channels; - u_short Format; - u_char reserved[4]; -} blockT9; + u_int32_t SamplesPerSec; + u_int8_t BitsPerSample; + u_int8_t Channels; + u_int16_t Format; + u_int8_t reserved[4]; +} PACKED(blockT9); @@ -51,21 +57,21 @@ it works on all WAVE-file I have */ typedef struct wavhead { - u_long main_chunk; /* 'RIFF' */ - u_long length; /* Length of rest of file */ - u_long chunk_type; /* 'WAVE' */ - - u_long sub_chunk; /* 'fmt ' */ - u_long sc_len; /* length of sub_chunk, =16 (rest of chunk) */ - u_short format; /* should be 1 for PCM-code */ - u_short modus; /* 1 Mono, 2 Stereo */ - u_long sample_fq; /* frequence of sample */ - u_long byte_p_sec; - u_short byte_p_spl; /* samplesize; 1 or 2 bytes */ - u_short bit_p_spl; /* 8, 12 or 16 bit */ - - u_long data_chunk; /* 'data' */ - u_long data_length; /* samplecount (lenth of rest of block?)*/ -} wavhead; + u_int32_t main_chunk; /* 'RIFF' */ + u_int32_t length; /* Length of rest of file */ + u_int32_t chunk_type; /* 'WAVE' */ + + u_int32_t sub_chunk; /* 'fmt ' */ + u_int32_t sc_len; /* length of sub_chunk, =16 (rest of chunk) */ + u_int16_t format; /* should be 1 for PCM-code */ + u_int16_t modus; /* 1 Mono, 2 Stereo */ + u_int32_t sample_fq; /* frequence of sample */ + u_int32_t byte_p_sec; + u_int16_t byte_p_spl; /* samplesize; 1 or 2 bytes */ + u_int16_t bit_p_spl; /* 8, 12 or 16 bit */ + + u_int32_t data_chunk; /* 'data' */ + u_int32_t data_length; /* samplecount (lenth of rest of block?)*/ +} PACKED(wavhead); #endif Index: bplaysrc/sndfunc.c =================================================================== RCS file: /home/kobras/cvsroot/debian/gramofile/bplaysrc/sndfunc.c,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 sndfunc.c --- bplaysrc/sndfunc.c 2001/05/05 14:07:15 1.1.1.2 +++ bplaysrc/sndfunc.c 2005/01/31 15:54:06 @@ -64,6 +64,9 @@ sync_audio(); /* Set the sample speed, size and stereoness */ + /* We only use values of 8 and 16 for bits. This implies + * unsigned data for 8 bits, and little-endian signed for 16 bits. + */ if (ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &bits) < 0) ErrDie(AUDIO); if (ioctl(audio, SNDCTL_DSP_STEREO, &stereo) < 0)