bplay (0.991-10) bplay.c

Summary

 bplay.c |  241 ++++++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 166 insertions(+), 75 deletions(-)

    
download this patch

Patch contents

--- bplay-0.991.orig/bplay.c
+++ bplay-0.991/bplay.c
@@ -5,13 +5,16 @@
 **
 **
 */
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
 
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
-#include <limits.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -24,6 +27,30 @@
 
 #include <sys/soundcard.h>
 
+/* 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"
 
 /* Types and constants */
@@ -39,6 +66,7 @@
 pid_t pid;
 int recorder = 0;
 int debug = 0;
+int verbose = 1;
 
 /* Prototypes */
 
@@ -52,10 +80,14 @@
 void ErrDie(char *err);
 void Die(char *err);
 
-void getbcount(int speed, int bits, int stereo, int *bcount,
+void cleanup(int val, void *arg);
+
+void getbcount(int speed, int bits, int stereo, long long int *bcount,
 	int timelim, int samplim, int timejmp, int sampjmp, int *bjump);
-void playraw(int thefd, char hd_buf[20], int speed, int bits, int stereo);
-void playwav(int thefd, char hd_buf[20], int mods, int speed, int bits, int stereo);
+void playraw(int thefd, char hd_buf[20], int speed, int bits, int stereo,
+	int jump, int secs);
+void playwav(int thefd, char hd_buf[20], int mods, int speed, int bits,
+	int stereo, int jump, int secs);
 void playvoc(int thefd, char hd_buf[20]);
 
 /* extern globals */
@@ -67,9 +99,9 @@
 extern void init_sound(int recorder);
 extern void snd_parm(int speed, int bits, int stereo);
 extern void init_shm(void);
-extern void shmrec(int outfd, int bcount, int terminate);
-extern void diskread(int outfd, int bcount, char hd_buf[20], int terminate,
-    int speed, int bits, int stereo);
+extern void shmrec(int outfd, long long int bcount, int terminate);
+extern void diskread(int outfd, long long int bcount, char hd_buf[20], int terminate,
+    int speed, int bits, int stereo, int jump);
 extern volatile void audiowrite(void);
 extern void initsems(int disks, int snds);
 extern void cleanupsems(void);
@@ -77,14 +109,14 @@
 
 int main(int argc, char *argv[])
 {
-	
+
 	int thefd;			/* The file descriptor */
 	int speed, bits, stereo;	/* Audio parameters */
 	int timelim;			/* Recording time in secs */
 	int samplim;			/* Recording time in samples */
 	int timejmp;			/* Skip time in secs */
 	int sampjmp;			/* Skip time in samples */
-	int bcount;			/* Number of bytes to record */
+	long long int bcount;			/* Number of bytes to record */
 	int bjump;			/* Number of bytes to skip */
 	int themask;			/* Permission mask for file */
 	sndf_t filetype;		/* The file type */
@@ -110,7 +142,7 @@
 	filetype = F_UNKNOWN;
 	mods = 0;
 	/* Parse the options */
-	while ((optc = getopt(argc, argv, "Ss:b:t:T:j:J:rvwd:B:D:")) != -1)
+	while ((optc = getopt(argc, argv, "Ss:b:t:T:j:J:rvwd:B:D:q")) != -1)
 	{
 		switch(optc)
 		{
@@ -142,6 +174,9 @@
 		case 'J':
 			sampjmp = atoi(optarg);
 			break;
+		case 'q':
+		        verbose = 0;
+			break;
 		case 'r':
 			filetype = F_RAW;
 			break;
@@ -172,7 +207,7 @@
 		    "%s: setpriority: %s: continuing anyway\n",
 		    progname, strerror(errno));
 	}
-	
+
 #endif
 	/* Drop out of suid mode before we open any files */
 	if(setreuid(geteuid(), getuid()) == -1)
@@ -199,12 +234,12 @@
 		/* Ok, get the mask for the opening the file */
 		themask = umask(0);
 		umask(themask);
-		if ((thefd = open(argv[optind], O_CREAT | O_TRUNC | O_WRONLY,
+		if ((thefd = open(argv[optind], O_CREAT | O_TRUNC | O_WRONLY | O_LARGEFILE,
 		    (~themask) & 0666)) == -1)
 		    ErrDie(argv[optind]);
 	    }
 	    else
-		if ((thefd = open(argv[optind], O_RDONLY)) == -1)
+		if ((thefd = open(argv[optind], O_RDONLY | O_LARGEFILE)) == -1)
 		    ErrDie(argv[optind]);
 	}
 
@@ -223,20 +258,21 @@
 #endif
 
 	/* Set up the shared buffers and semaphore blocks */
+	on_exit(cleanup, 0);
 	init_shm(); /* MUST be called after init_sound() */
 
 	/* Call the appropriate routine */
 	if (recorder)
 	{
 		if ((timelim == 0)  && (samplim == 0)) {
-			bcount = INT_MAX;
+			bcount = INT64_MAX - 1;
 		} else {
 			getbcount(speed, bits, stereo, &bcount, timelim,
 					samplim, timejmp, sampjmp,
 					&bjump);
 		}
 		if (debug)
-		        fprintf(stderr, "bcount: %d\n", bcount);
+		        fprintf(stderr, "bcount: %lld\n", bcount);
 
 		if (filetype == F_UNKNOWN)
 			filetype = F_RAW;	/* Change to change default */
@@ -244,9 +280,11 @@
 		{
 		case F_WAV:
 			/* Spit out header here... */
-			fprintf(stderr, "Writing MS WAV sound file");
+		  if (verbose)
+		    fprintf(stdout, "Writing MS WAV sound file");
 			{
 				wavhead header;
+				unsigned long long int tmp;
 
 				char *riff = "RIFF";
 				char *wave = "WAVE";
@@ -254,34 +292,45 @@
 				char *data = "data";
 
 				memcpy(&(header.main_chunk), riff, 4);
-				header.length = sizeof(wavhead) - 8 + bcount;
+				if ( (tmp = sizeof(wavhead) - 8 + bcount) >> 32 ) {
+				   header.length =  0xFFFFFFFF; // do not overload the header
+				   fprintf(stderr, " (WARNING: Resulting file size is larger than 4GiB, violating the WAVE format specification!)");
+				}
+				else
+				   header.length = cpu_to_le32(tmp);
+
 				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.byte_p_spl = ((bits > 8)? 2:1)*(stereo+1);
-				header.bit_p_spl = bits;
+				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);
+				header.byte_p_spl = cpu_to_le16(((bits > 8)?
+							2:1)*(stereo+1));
+				header.bit_p_spl = cpu_to_le16(bits);
 
 				memcpy(&(header.data_chunk), data, 4);
-				header.data_length = bcount;
+				header.data_length = ( bcount >> 32 ) ? 0xFFFFFFFF : cpu_to_le32(bcount) ; //FIXME see above, make sure that it works cleanly
 				write(thefd, &header, sizeof(header));
 			}
 		case F_RAW:
 			if (filetype == F_RAW)
-				fprintf(stderr, "Writing raw sound file");
-			fprintf(stderr, ", %dHz, %dbit, %s\n", speed, bits, (stereo)? "stereo":"");
+			  if (verbose) {
+			    fprintf(stdout, "Writing raw sound file");
+			    fprintf(stdout, ", %dHz, %dbit, %s\n", speed, bits, (stereo)? "stereo":"");
+			  }
 			snd_parm(speed, bits, stereo);
 			initsems(0, 1);
 			shmrec(thefd, bcount, 1);
 			break;
 		case F_VOC:
 			/* Spit out header here... */
-			fprintf(stderr, "Writing CL VOC sound file");
-			fprintf(stderr, ", %dHz, %dbit, %s\n", speed, bits, (stereo)? "stereo":"");
+		  if (verbose) {
+		    fprintf(stdout, "Writing CL VOC sound file");
+		    fprintf(stdout, ", %dHz, %dbit, %s\n", speed, bits, (stereo)? "stereo":"");}
 			{
 				vochead header;
 				blockTC ablk;
@@ -291,23 +340,29 @@
 
 				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);
 				initsems(0, 1);
 
-				i = (bcount >= 0xFFFFF2)? 0xFFFFF2 + 12 : bcount;
+				i = bcount;
+				if (bcount >= 0xFFFFF2)
+				{
+				   i = 0xFFFFF2 + 12;
+				   fprintf(stderr, "Warning: length is out of allowed range, consider using another sound format!\n");
+				}
+
 				ablk.BlockID = 9;
 				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);
@@ -338,9 +393,18 @@
 		if(strstr(hd_buf, VOC_MAGIC) != NULL)
 			playvoc(thefd, hd_buf);
 		else if(strstr(hd_buf, "RIFF") != NULL)
-			playwav(thefd, hd_buf, mods, speed, bits, stereo);
+      {
+          if (sampjmp)
+              playwav(thefd, hd_buf, mods, speed, bits, stereo, sampjmp, 0);
+          else
+              playwav(thefd, hd_buf, mods, speed, bits, stereo, timejmp, 1);
+      }
 		else /* Assume raw data */
-			playraw(thefd, hd_buf, speed, bits, stereo);
+          if (sampjmp)
+              playraw(thefd, hd_buf, speed, bits, stereo, sampjmp, 0);
+          else
+              playraw(thefd, hd_buf, speed, bits, stereo, timejmp, 1);
+
 
 		wait(NULL);
 		cleanupsems();
@@ -352,7 +416,7 @@
 void Usage(void)
 {
 	fprintf(stderr,
-		"Usage: %s [-d device] [-B buffersize] [-S] [-s Hz] [-b 8|16] [-t secs] [-D level] [-r|-v|-w] [filename]\n",
+		"Usage: %s [-d device] [-B buffersize] [-S] [-s Hz] [-b 8|16] [-t secs] [-q] [-D level] [-r|-v|-w] [filename]\n",
 		progname);
 	exit(1);
 }
@@ -370,12 +434,17 @@
 	exit(-1);
 }
 
-void getbcount(int speed, int bits, int stereo, int *bcount,
+void cleanup(int val, void *arg)
+{
+	cleanupsems();
+}
+
+void getbcount(int speed, int bits, int stereo, long long int *bcount,
 	int timelim, int samplim, int timejmp, int sampjmp, int *bjump)
 {
 	if(timelim)
 	{
-		*bcount = speed*timelim*(bits/8);
+		*bcount = (long long) speed * (long long) timelim * (bits/8);
 		if (stereo) *bcount <<= 1;
 	}
 	if(samplim)
@@ -395,14 +464,20 @@
 	}
 }
 
-void playraw(int thefd, char hd_buf[20], int speed, int bits, int stereo)
+void playraw(int thefd, char hd_buf[20], int speed, int bits, int stereo, int jump, int secs)
 {
-    fprintf(stderr, "Playing raw data : %d bit, Speed %d %s ...\n",
-	bits, speed, (stereo)? "Stereo" : "Mono");
-    diskread(thefd, 0, hd_buf, 1, speed, bits, stereo);
+  if (verbose) {
+    fprintf(stdout, "Playing raw data : %d bit, Speed %d %s ...\n",
+	    bits, speed, (stereo)? "Stereo" : "Mono");
+  }
+
+    if (secs == 0)
+        jump = jump / speed;
+
+    diskread(thefd, 0, hd_buf, 1, speed, bits, stereo, jump);
 }
 
-void playwav(int thefd, char hd_buf[20], int mods, int speed, int bits, int stereo)
+void playwav(int thefd, char hd_buf[20], int mods, int speed, int bits, int stereo, int jump, int secs)
 {
     wavhead wavhd;
     int count;
@@ -410,24 +485,20 @@
     memcpy((void*)&wavhd, (void*)hd_buf, 20);
     count = read(thefd, ((char*)&wavhd)+20, sizeof(wavhd) - 20);
 
-#if  __BYTE_ORDER == __BIG_ENDIAN
-#include<byteswap.h>
-    /* let's do a bit of reordering */
-    wavhd.length =  bswap_32 (wavhd.length);
-    wavhd.sc_len =  bswap_32 (wavhd.sc_len);
-    wavhd.format =  bswap_16 (wavhd.format);
-    wavhd.modus  =  bswap_16 (wavhd.modus);
-    
-    wavhd.sample_fq  =  bswap_32 (wavhd.sample_fq);
-    wavhd.byte_p_sec =  bswap_32 (wavhd.byte_p_sec);
-    
-    wavhd.byte_p_spl =  bswap_16 (wavhd.byte_p_spl);
-    wavhd.bit_p_spl  =  bswap_16 (wavhd.bit_p_spl);
-    
-    wavhd.data_chunk =  bswap_32 (wavhd.data_chunk);
-    wavhd.data_length =  bswap_32 (wavhd.data_length);
-#endif
-   
+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_chunk =  le32_to_cpu (wavhd.data_chunk);
+wavhd.data_length =  le32_to_cpu (wavhd.data_length);
+
     if(wavhd.format != 1) Die("input is not a PCM WAV file");
     if (! (mods&MSPEED))
       speed = wavhd.sample_fq;
@@ -435,9 +506,15 @@
       bits = wavhd.bit_p_spl;
     if (! (mods&MSTEREO))
       stereo = wavhd.modus - 1;
-    fprintf(stderr, "Playing WAVE : %d bit, Speed %d %s ...\n", 
+    if (verbose) {
+      fprintf(stdout, "Playing WAVE : %d bit, Speed %d %s ...\n",
 	    bits, speed, (stereo)? "Stereo" : "Mono");
-    diskread(thefd, 0, NULL, 1, speed, bits, stereo);
+    }
+
+    if (secs == 0)
+        jump = jump / speed;
+
+    diskread(thefd, 0, NULL, 1, speed, bits, stereo, jump);
 }
 
 void playvoc(int thefd, char hd_buf[20])
@@ -445,17 +522,24 @@
     int count;
     int speed=0, bits=0, stereo=0;
     int inloop=0, loop_times;
-    long bytecount, loop_pos=0;
+    long long bytecount, loop_pos=0;
     vochead vochd;
     blockTC ccblock;
     int lastblocktype = -1;
     int quit = 0;
 
-    fprintf(stderr, "Playing Creative Labs Voice file ...\n");
+    if (verbose) fprintf(stdout, "Playing Creative Labs Voice file ...\n");
     memcpy((void*)&vochd, (void*)hd_buf, 20);
     count = read(thefd, ((char*)&vochd)+20, sizeof(vochd) - 20);
-    fprintf(stderr, "Format version %d.%d\n", vochd.Version>>8,
+
+    vochd.BlockOffset = le16_to_cpu(vochd.BlockOffset);
+    vochd.Version = le16_to_cpu(vochd.Version);
+    vochd.IDCode = le16_to_cpu(vochd.IDCode);
+
+    if (verbose) {
+      fprintf(stdout, "Format version %d.%d\n", vochd.Version>>8,
 	vochd.Version&0xFF);
+    }
     if (vochd.IDCode != (~vochd.Version+0x1234))
 	fprintf(stderr, "Odd - version mismatch - %d != %d\n",
 	    vochd.IDCode, ~vochd.Version+0x1234);
@@ -463,7 +547,7 @@
     {
 	int off = vochd.BlockOffset - sizeof(vochd);
 	char *junk;
-	junk = (char*) malloc(off);    
+	junk = (char*) malloc(off);
 	read(thefd, junk, off);
     }
     while(!quit)
@@ -473,7 +557,7 @@
         if (debug)
 	    fprintf(stderr, "Terminating\n");
 
-	diskread(thefd, -1, NULL, 1, speed, bits, stereo);
+	diskread(thefd, -1, NULL, 1, speed, bits, stereo, 0);
 	quit = 1;
 	continue;
     }
@@ -494,7 +578,7 @@
 	    stereo = 0;
 	}
 	bytecount = DATALEN(ccblock) -2;
-	diskread(thefd, bytecount, NULL, 0, speed, bits, stereo);
+	diskread(thefd, bytecount, NULL, 0, speed, bits, stereo, 0);
 	lastblocktype = 1;
 	}
 	break;
@@ -502,6 +586,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;
@@ -514,13 +601,17 @@
 	{
 	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;
 	bits = tblock.BitsPerSample;
 	stereo = tblock.Channels - 1;
 	bytecount = DATALEN(ccblock) - 12;
-	diskread(thefd, bytecount, NULL, 0, speed, bits, stereo);
+	diskread(thefd, bytecount, NULL, 0, speed, bits, stereo, 0);
 	lastblocktype = 9;
 	}
 	break;
@@ -528,7 +619,7 @@
         if (debug)
 	    fprintf(stderr, "Terminating\n");
 
-	diskread(thefd, -1, NULL, 1, speed, bits, stereo);
+	diskread(thefd, -1, NULL, 1, speed, bits, stereo, 0);
 	quit = 1;
 	break;
     case 6:
@@ -568,11 +659,11 @@
 	{
 	int rd = 0, trgt = BUFSIZ;
 	char junkbuf[BUFSIZ];
-    
+
 	fprintf(stderr, "Ignored\n");
 	bytecount = DATALEN(ccblock);
 	while(rd < bytecount)
-	{
+	{//FIXME rd, trgt, not sure what this has to do with bytecount
 	    if (rd + trgt > bytecount)
 		trgt = bytecount - rd;
 	    count = read(thefd, junkbuf, trgt);