I was surprised how difficult it is to get a linux system that plays sounds in 
<1MB of flash, so tonight I wrote a 'wavplay' applet.

Cons:
- Endian issues?
- Probably doesn't follow BB coding standards (I never checked)
- Only a single device supported (/dev/dsp)
- No mixer


Pros:
- Only about 500 bytes extra weight on BB to play wavs, (486 cross-compiler).


Unfortunately your humble developer has wasted too much time correcting patches 
for open-source projects only to have them dropped on the floor at the end of 
it.  I may produce a proper patch.  If enough people beg.  Seriously!  Anyhow, 
this stuff isn't rocket science so you can always do it yourself.

regards,
Biff.

PS: Thanks to the BB devs for a really neat system!
/*
 * wavplay Busybox applet.
 * Copyright (c) Bifferos ([email protected]).  GPL v2 License.
 * 
 */


#include <linux/soundcard.h>
#include "libbb.h"


//usage:#define wavplay_trivial_usage
//usage:       "WAVFILE"
//usage:#define wavplay_full_usage "\n\n"
//usage:       "Plays a .WAV file\n"


typedef struct wav_header
{
    char    id[4];          // should always contain "RIFF"
    int     totallength;    // total file length minus 8
    char    wavefmt[8];     //  "WAVEfmt "
    int     format;         // 16 for PCM
    short   pcm;            // 1 for PCM 
    short   channels;       // # channels
    int     frequency;      // frequency
    int     bytes_per_second;
    short   bytes_by_capture;
    short   bits_per_sample;
    char    data[4];        // "data"
    int     bytes_in_data;
} wav_header;


static void NotWAV(void)
{
  bb_error_msg_and_die("Not a recognised format\n");
}


static void ioctl_or_bomb(int fd, int req, int param, const char* msg)
{
  int arg = param;
  ioctl_or_perror_and_die(fd, req, &arg, msg);
}


static int read_hdr(int fd_wav, int fd_dsp)
{
    int count;
    wav_header h;
    
    count = read(fd_wav, &h, sizeof(h));
    if (count != sizeof(h)) NotWAV();
    if (strncmp(h.id, "RIFF", 4)) NotWAV();
    if (strncmp(h.wavefmt, "WAVEfmt ", 8)) NotWAV();
    if (h.pcm != 1) NotWAV();
    if (h.format != 16) NotWAV();
    if (strncmp(h.data, "data", 4)) NotWAV();
    printf("Channels: %d\n", h.channels);
    printf("Frequency: %d\n", h.frequency);
    printf("Bits: %d\n", h.bits_per_sample);
    
    ioctl_or_bomb(fd_dsp, SOUND_PCM_WRITE_BITS, h.bits_per_sample, "WRITE_BITS");
    ioctl_or_bomb(fd_dsp, SOUND_PCM_WRITE_CHANNELS, h.channels, "WRITE_CHANNELS");
    ioctl_or_bomb(fd_dsp, SOUND_PCM_WRITE_RATE, h.frequency, "WRITE_RATE");
        
    return h.bytes_in_data;
}


static void play(int fd_wav, int fd_dsp)
{
	void* buffer;
	size_t buffer_len = 0x10000;  // 64k buffer.
	size_t read_result = 1;
	size_t write_result;

	buffer = malloc(buffer_len);
	
	if (!buffer) bb_error_msg_and_die("malloc");
	
	while(read_result)
	{
	  read_result = read(fd_wav, buffer, buffer_len);
	  if (read_result == -1)
	  {
	    bb_perror_msg_and_die("Reading WAV");
	  }
	  write_result = write(fd_dsp, buffer, read_result);
	  if (write_result != read_result)
	  {
	    break;
	  }
	}
}


int wavplay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int wavplay_main(int argc, char **argv )
{
        int wav, dsp; /* wav file and sound device */
        unsigned opts;
  
        opt_complementary = "=1";  /* must have exactly 1 argument */
        opts = getopt32(argv, "");
	
	wav = xopen(argv[argc - 1], O_RDONLY);
	dsp = xopen("/dev/dsp", O_RDWR);
	
	read_hdr(wav, dsp);
	play(wav, dsp);

	return 0;
}
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to