Esempio n. 1
0
enum mad_flow output(void *data,
                     struct mad_header const *header,
                     struct mad_pcm *pcm)
{
    register int nsamples = pcm->length;
    mad_fixed_t const *left_ch = pcm->samples[0], *right_ch = pcm->samples[1];
    
    static unsigned char stream[1152*4]; /* 1152 because that's what mad has as a max; *4 because
                                    there are 4 distinct bytes per sample (in 2 channel case) */
    static unsigned int rate = 0;
    static int channels = 0;
    static struct audio_dither dither;

    register char * ptr = stream;
    register signed int sample;
    register mad_fixed_t tempsample;

    /* We need to know information about the file before we can open the playdevice
       in some cases. So, we do it here. */
    if (!playdevice)
    {
        channels = MAD_NCHANNELS(header);
        rate = header->samplerate;
        open_ao_playdevice(header);        
    }

    else if ((channels != MAD_NCHANNELS(header) || rate != header->samplerate) && playdevice_is_live())
    {
        ao_close(playdevice);
        channels = MAD_NCHANNELS(header);
        rate = header->samplerate;
        open_ao_playdevice(header);        
    }        

    if (pcm->channels == 2)
    {
        while (nsamples--)
        {
            tempsample = (mad_fixed_t)((*left_ch++ * (double)options.volume)/MAD_F_ONE);
            sample = (signed int) audio_linear_dither(16, tempsample, &dither);

#ifndef WORDS_BIGENDIAN
            *ptr++ = (unsigned char) (sample >> 0);
            *ptr++ = (unsigned char) (sample >> 8);
#else
            *ptr++ = (unsigned char) (sample >> 8);
            *ptr++ = (unsigned char) (sample >> 0);
#endif
            
            tempsample = (mad_fixed_t)((*right_ch++ * (double)options.volume)/MAD_F_ONE);
            sample = (signed int) audio_linear_dither(16, tempsample, &dither);
#ifndef WORDS_BIGENDIAN
            *ptr++ = (unsigned char) (sample >> 0);
            *ptr++ = (unsigned char) (sample >> 8);
#else
            *ptr++ = (unsigned char) (sample >> 8);
            *ptr++ = (unsigned char) (sample >> 0);
#endif
        }

        ao_play(playdevice, stream, pcm->length * 4);
    }
    
    else if (options.opt & MPG321_FORCE_STEREO)
Esempio n. 2
0
enum mad_flow output(void *data,
                     struct mad_header const *header,
                     struct mad_pcm *pcm)
{
    register int nsamples = pcm->length;
    mad_fixed_t const *left_ch = pcm->samples[0], *right_ch = pcm->samples[1];
    
    static unsigned char stream[1152*4]; /* 1152 because that's what mad has as a max; *4 because
                                    there are 4 distinct bytes per sample (in 2 channel case) */
    static unsigned int rate = 0;
    static int channels = 0;
    static struct audio_dither dither;

    register char * ptr = stream;
    register signed int sample;
    register mad_fixed_t tempsample;


    /* Semaphore operations */
    static struct sembuf read_sops = {0, -1, 0};
    static struct sembuf write_sops = {1, 1, 0};

    if(options.opt & MPG321_ENABLE_BUFFER)
    {
	    semop(semarray,&read_sops,1);
	    ptr = (Output_Queue+mad_decoder_position)->data;
	    memcpy(&((Output_Queue+mad_decoder_position)->header),header,sizeof(struct mad_header));
			 
    }else{
	    /* We need to know information about the file before we can open the playdevice
	       in some cases. So, we do it here. */
	    if (!playdevice)
	    {
	    	    channels = MAD_NCHANNELS(header);
	    	    rate = header->samplerate;
	    	    open_ao_playdevice(header);        
	    }
	    else if ((channels != MAD_NCHANNELS(header) || rate != header->samplerate) && playdevice_is_live())
	    {
	    	    ao_close(playdevice);
	    	    channels = MAD_NCHANNELS(header);
	    	    rate = header->samplerate;
	    	    open_ao_playdevice(header);        
	    }        
    }

    static int peak_rate = 0;
    static unsigned short int peak = 0;


    if (pcm->channels == 2)
    {
        while (nsamples--)
        {
            tempsample = mad_f_mul(*left_ch++, options.volume);
            sample = (signed int) audio_linear_dither(16, tempsample, &dither);

	    peak = abs(sample) > peak ? abs(sample) : peak;

#ifndef WORDS_BIGENDIAN
            *ptr++ = (unsigned char) (sample >> 0);
            *ptr++ = (unsigned char) (sample >> 8);
#else
            *ptr++ = (unsigned char) (sample >> 8);
            *ptr++ = (unsigned char) (sample >> 0);
#endif
            
            tempsample = mad_f_mul(*right_ch++, options.volume);
            sample = (signed int) audio_linear_dither(16, tempsample, &dither);

	    peak = abs(sample) > peak ? abs(sample) : peak;

#ifndef WORDS_BIGENDIAN
            *ptr++ = (unsigned char) (sample >> 0);
            *ptr++ = (unsigned char) (sample >> 8);
#else
            *ptr++ = (unsigned char) (sample >> 8);
            *ptr++ = (unsigned char) (sample >> 0);
#endif
        }
	
	process_fft(stream, pcm->length * 4);
	if(options.opt & MPG321_ENABLE_BUFFER)
	{
		(Output_Queue+mad_decoder_position)->length = pcm->length * 4;
	}else
	{
		ao_play(playdevice, stream, pcm->length * 4);
	}
    }
    
    else if (options.opt & MPG321_FORCE_STEREO)
Esempio n. 3
0
ao_device *open_ao_playdevice_buffer(struct mad_header const *header)
{
        ao_sample_format format;
	ao_device *pldev = NULL;

        /* Because these can sometimes block, we stop our custom signal handler,
           and restore it afterwards */
        signal(SIGINT, SIG_DFL);
        
        format.bits = 16;
        format.rate = header->samplerate;
        format.channels = (options.opt & MPG321_FORCE_STEREO) ? 2 : MAD_NCHANNELS(header);
	
	/* Add this element as an option to mpg321 */
	format.matrix = "L,R";

        /* mad gives us little-endian data; we swap it on big-endian targets, to
          big-endian format, because that's what most drivers expect. */
        format.byte_format = AO_FMT_NATIVE; 
        
        if(options.opt & MPG321_USE_AU)
        {
            int driver_id = ao_driver_id("au");
            ao_option *ao_options = NULL;

            /* Don't have to check options.device here: we only define
               MPG321_USE_AU when --au <aufile> is defined, and <aufile>
               is pointd to by options.device */
            if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/,
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao file output driver to write AU data.\n");
                return NULL;
            }
        }

        else if (options.opt & MPG321_USE_CDR)
        {
            ao_option * ao_options = NULL;
            int driver_id = ao_driver_id("raw");

            /* because CDR is a special format, i.e. headerless PCM, big endian,
               this is a special case. */
            ao_append_option(&ao_options, "byteorder", "big");
        
            if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/, 
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao file output driver to write CDR data.\n");
                return NULL;
            }
        }
        
        /* if the user specifies both au and wave, wav will be prefered, so testing
         * later */
        else if(options.opt & MPG321_USE_WAV)
        {
            int driver_id = ao_driver_id("wav");
            ao_option *ao_options = NULL;

            /* Don't have to check options.device here: we only define
               MPG321_USE_WAV when -w <wavfile> is defined, and <wavfile>
               is pointd to by options.device */
            if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/,
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao wav file driver. (Do you have write permissions?)\n");
                return NULL;
            }
        }

        else if(options.opt & MPG321_USE_NULL)
        {
            int driver_id = ao_driver_id("null"); 
            /* null is dirty, create a proper options struct later */

            if((pldev = ao_open_live(driver_id, &format, NULL)) == NULL)
            {
                fprintf(stderr, "Error opening libao null driver. (This shouldn't have happened.)\n");
                return NULL;
            }
        }
        
        else if (options.opt & MPG321_USE_STDOUT)
        {
            ao_option * ao_options = NULL;
            int driver_id = ao_driver_id("raw");

            /* stdout output is expected to be little-endian generally */
            ao_append_option(&ao_options, "byteorder", "little");
        
            if((pldev=ao_open_file(driver_id, "-", 1 /*overwrite*/, 
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao raw output driver.\n");
                return NULL;
            }
        }
        
        else if (options.opt & MPG321_USE_USERDEF)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id(options.devicetype);
            
	    if (driver_id < 0)
            {
                fprintf(stderr, "Can't open unknown ao driver %s\n", options.devicetype);
                exit(1);
            }

            if (playdevice_is_live())
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't set output device to %s for unknown ao plugin %s",
                            options.device, options.devicetype);
                }

                if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
                {
                    fprintf(stderr, "Error opening unknown libao %s driver. (Is device in use?)\n",
                        options.devicetype);
                    return NULL;
                }
            }

            else
            {
                if (options.device)
                {
                    /* Just assume that options.device is a filename. The user can shoot 
                       themselves in the foot all they like... */
                    if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/,
                            &format, ao_options))==NULL)
                    {
                        fprintf(stderr, "Error opening unknown libao %s file driver for file %s. (Do you have write permissions?)\n",
                                options.devicetype, options.device);
                        return NULL;
                    }
                }
                
                else
                {
                    fprintf(stderr, "Filename must be specified (with -a filename) for unknown ao driver %s\n",
                            options.devicetype);
                }
            }
        } else {
            /* Hack-tacular. This code tries to the device as specified; if it can't, it'll
               fall through to the other devices, trying each in turn. If the user specified
               a device to use, though, it won't fall through: principle of least surprise */
        int opened = 0;

        if(!opened && options.opt & MPG321_USE_ALSA)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("alsa");
            char *c;
            char *card=(char *)malloc((int)16);
            memset(card,0,16); 
	    strncat(card,"alsa:\0",6);
	    
	    if (options.device)
            {
	    	strcat(card,options.device);
                //if ((c = strchr(options.device, ':')) == NULL || strlen(c+1) < 1)
                if ((c = strchr(card, ':')) == NULL || strlen(c+1) < 1)
                {
                    fprintf(stderr, "Poorly formed ALSA card:device specification %s", options.device);
                    exit(1);
                }

                *(c++) = '\0'; /* change the : to a null to create two separate strings */
                //ao_append_option(&ao_options, "card", options.device);
                ao_append_option(&ao_options, "card", card);
                ao_append_option(&ao_options, "dev", c);
            }

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_ALSA09;
            } else opened++;
        }

        if(!opened && options.opt & MPG321_USE_ALSA09)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("alsa09");

            if(options.device)
                ao_append_option(&ao_options, "dev", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_OSS;
            } else opened++;
        }

        if(!opened &&  options.opt & MPG321_USE_OSS)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("oss");

            if(options.device)
                ao_append_option(&ao_options, "dsp", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_SUN;
            } else opened++;
        }

        if(!opened && options.opt & MPG321_USE_SUN)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("sun");

            if(options.device)
                ao_append_option(&ao_options, "dev", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_ESD;
            }
        }

        if(!opened && options.opt & MPG321_USE_ESD)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("esd");

            if(options.device)
                ao_append_option(&ao_options, "host", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_ARTS;
            } else opened++;
        }

        if(!opened && options.opt & MPG321_USE_ARTS)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("arts");
        
            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                fprintf(stderr, "Can't find a suitable libao driver. (Is device in use?)\n");
                return NULL;
            }
        }
        
    }

    /* Restore signal handler */
    signal(SIGINT, handle_signals);
    return pldev;
}