Пример #1
0
internal
void hhxcb_init_alsa(hhxcb_context *context, hhxcb_sound_output *sound_output)
{
    // NOTE: "hw:0,0" doesn't seem to work with alsa running on top of pulseaudio
    char *device = (char *)"default";
    // char *device = (char *)"hw:0,0";

    int err;
    snd_pcm_sframes_t frames;
    err = snd_output_stdio_attach(&context->alsa_log, stderr, 0);

    if ((err = snd_pcm_open(&context->handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
    {
            printf("Playback open error: %s\n", snd_strerror(err));
            exit(EXIT_FAILURE);
    }

    snd_pcm_hw_params_t *hwparams;
    snd_pcm_hw_params_alloca(&hwparams);

    snd_pcm_hw_params_any(context->handle, hwparams);
    snd_pcm_hw_params_set_rate_resample(context->handle, hwparams, 0);
    snd_pcm_hw_params_set_access(context->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(context->handle, hwparams, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(context->handle, hwparams, 2);
    snd_pcm_hw_params_set_rate(context->handle, hwparams, sound_output->samples_per_second, 0);
    snd_pcm_hw_params_set_period_size(context->handle, hwparams, sound_output->samples_per_second / 60, 0);
    // NOTE: restricting this buffer size too much seems to crash the game
    sound_output->secondary_buffer_size = 48000 / 2;
    snd_pcm_hw_params_set_buffer_size(context->handle, hwparams, sound_output->secondary_buffer_size);
    snd_pcm_hw_params(context->handle, hwparams);
    snd_pcm_dump(context->handle, context->alsa_log);
}
Пример #2
0
    result alsa_init(Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer, unsigned int aChannels)
    {
        ALSAData *data = new ALSAData;
        memset(data, 0, sizeof(ALSAData));
        aSoloud->mBackendData = data;
        aSoloud->mBackendCleanupFunc = alsaCleanup;
        data->samples = aBuffer;
        data->channels = 2;
        data->soloud = aSoloud;

        int rc;
        snd_pcm_t *handle;
        rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
        if (rc < 0)
        {
            return UNKNOWN_ERROR;
        }
        
        data->alsaDeviceHandle = handle;
        
        snd_pcm_hw_params_t *params;
        snd_pcm_hw_params_alloca(&params);
        snd_pcm_hw_params_any(handle, params);

        snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
        snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
        snd_pcm_hw_params_set_channels(handle, params, 2);
        snd_pcm_hw_params_set_buffer_size(handle, params, aBuffer);
        
        unsigned int val = aSamplerate;
        int dir = 0;
        rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
        if (rc < 0)
        {
            return UNKNOWN_ERROR;
        }

        rc = snd_pcm_hw_params(handle, params);
        if (rc < 0) 
        {
            return UNKNOWN_ERROR;
        }

        snd_pcm_hw_params_get_rate(params, &val, &dir);
        aSamplerate = val;
        snd_pcm_hw_params_get_channels(params, &val);
        data->channels = val;

        data->buffer = new float[data->samples*data->channels];
        data->sampleBuffer = new short[data->samples*data->channels];
        aSoloud->postinit(aSamplerate, data->samples * data->channels, aFlags, 2);
        data->threadHandle = Thread::createThread(alsaThread, data);
        if (0 == data->threadHandle)
        {
            return UNKNOWN_ERROR;
        }
        aSoloud->mBackendString = "ALSA";
        return 0;
    }
Пример #3
0
static Int32 InitAudioCaptureDevice (Int32 channels, UInt32 sample_rate, Int32 driver_buf_size)
{
    snd_pcm_hw_params_t *hw_params;
    Int32 err;

    if ((err = snd_pcm_open (&capture_handle, ALSA_CAPTURE_DEVICE, SND_PCM_STREAM_CAPTURE, 0)) < 0)
    {
        fprintf (stderr, "AUDIO >>  cannot open audio device plughw:1,0 (%s)\n", snd_strerror (err));
        return  -1;
    }
//  printf ("AUDIO >>  opened %s device\n", ALSA_CAPTURE_DEVICE);
    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot allocate hardware parameter structure (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot initialize hardware parameter structure (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot set access type (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot set sample format (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &sample_rate, 0)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot set sample rate (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, channels)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot set channel count (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params_set_buffer_size (capture_handle, hw_params, driver_buf_size)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot set buffer size (%s)\n", err, capture_handle);
    }

    if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot set parameters (%s)\n", err, capture_handle);
    }

    snd_pcm_hw_params_free (hw_params);

    if ((err = snd_pcm_prepare (capture_handle)) < 0)
    {
        AUD_DEVICE_PRINT_ERROR_AND_RETURN("cannot prepare audio interface for use (%s)\n", err, capture_handle);
    }
    return 0;
}
Пример #4
0
void mixer_open()
{
	memset(&channels, 0, sizeof(channels));
	int err = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
	if (err < 0)
	{
		printf("Failed to open pcm device: %s\n", snd_strerror(err));
		exit(1);
	}
	
	unsigned int rate = 44100;
	snd_pcm_hw_params_t *hw_params = 0;
	snd_pcm_hw_params_alloca(&hw_params);
	snd_pcm_hw_params_any(pcm, hw_params);
	snd_pcm_hw_params_set_rate_resample(pcm, hw_params, 0);
	snd_pcm_hw_params_set_access(pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(pcm, hw_params, SND_PCM_FORMAT_S16_LE);
	snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, 0);
	snd_pcm_hw_params_set_channels(pcm, hw_params, 2);
	snd_pcm_hw_params_set_period_size(pcm, hw_params, BUFFER_SIZE, 0);
	snd_pcm_hw_params_set_buffer_size(pcm, hw_params, BUFFER_SIZE * 4);
	
	err = snd_pcm_hw_params(pcm, hw_params);
	if (err < 0)
	{
		printf("Failed to apply pcm hardware settings: %s\n", snd_strerror(err));
		exit(1);
	}
	
	snd_pcm_sw_params_t *sw_params = 0;
	snd_pcm_sw_params_alloca(&sw_params);
	snd_pcm_sw_params_current(pcm, sw_params);
	snd_pcm_sw_params_set_avail_min(pcm, sw_params, BUFFER_SIZE * 4);
	err = snd_pcm_sw_params(pcm, sw_params);
	if (err < 0)
	{
		printf("Failed to apply pcm software settings: %s\n", snd_strerror(err));
		exit(1);
	}
	
	err = snd_pcm_prepare(pcm);
	if (err < 0)
	{
		printf("Failed to prepare pcm interface: %s\n", snd_strerror(err));
		exit(1);
	}
	
	memset(delay_left, 0, sizeof(delay_left));
	memset(delay_right, 0, sizeof(delay_right));
}
Пример #5
0
static int setup_params(void)
{
	snd_pcm_hw_params_t *hw;

	/* FIXME: more finer error checks */
	snd_pcm_hw_params_alloca(&hw);
	snd_pcm_hw_params_any(pcm, hw);
	snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(pcm, hw, format);
	snd_pcm_hw_params_set_channels(pcm, hw, channels);
	snd_pcm_hw_params_set_rate(pcm, hw, rate, 0);
	snd_pcm_hw_params_set_period_size(pcm, hw, periodsize, 0);
	snd_pcm_hw_params_set_buffer_size(pcm, hw, bufsize);
	if (snd_pcm_hw_params(pcm, hw) < 0) {
		fprintf(stderr, "snd_pcm_hw_params error\n");
		return 1;
	}
	return 0;
}
Пример #6
0
/**
 * This method prepares ALSA system for 22050hz signed 16bits Little Endian
 * playback.
 */
void SoundThread::initAlsa()
{
	int err;
	ostringstream oss;

	/* Get a handle on the PCM device. */

	if ((err = snd_pcm_open (&playback_handle, deviceName, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
	{
		oss << "cannot open audio device : " << deviceName << snd_strerror(err) << endl;
		throw oss.str();
	}

	/* Allocate snd_pcm_hw_params_t structure. */
	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
	{
		oss << "cannot allocate hardware parameter structure : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Retrieve current parameters. */
	if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0)
	{
		oss << "cannot initialize hardware parameter structure : " << snd_strerror (err) << endl;
		throw oss.str();
	}


	/* Set Sample are NON Interleaved (mono !) */
	if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0)
	{
		oss << "cannot set access type : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Set Sample format: Signed 16bit little endian. */
	if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
	{
		oss << "cannot set sample format : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Set the Sample rate. */
	if ((err = snd_pcm_hw_params_set_rate (playback_handle, hw_params, 22050, 0)) < 0)
	{
		oss << "cannot set sample rate : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Set Channel number (MONO). */
	if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 1)) < 0)
	{
		oss << "cannot set channel count : " << snd_strerror (err) << endl;
		throw oss.str();
	}


	if ((err = snd_pcm_hw_params_set_buffer_size(playback_handle, hw_params, 2048)) < 0)
	{
		oss << "cannot set channel buffer size : " << snd_strerror (err) << endl;
		throw oss.str();
	}



	/* Apply these parameters. */
	if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0)
	{
		oss << "cannot apply parameters : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	snd_pcm_uframes_t bufferSize;
	snd_pcm_hw_params_get_buffer_size( hw_params, &bufferSize );
	//cout << "initAlsa: Buffer size = " << bufferSize << " frames." << endl;

	/* Free memoray allocated for snd_pcm_hw_params_t */
	snd_pcm_hw_params_free (hw_params);

	/* tell ALSA to wake us up whenever 4096 or more frames
	   of playback data can be delivered. Also, tell
	   ALSA that we'll start the device ourselves.
	*/

	/* Allocate snd_pcm_sw_params_t structure. */
	if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0)
	{
		oss << "cannot allocate software parameters structure : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Get the current software configuration*/
	if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0)
	{
		oss << "cannot initialize software parameters structure : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Set the wake up point to 2048 (92.9 ms). The minimum data available before asking*/
	/* for new ones. */
	if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 2048U)) < 0)
	{
		oss << "cannot set minimum available count : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Set when ALSA starts to play. */
	if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 1024U)) < 0)
	{
		oss << "cannot set start mode : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* Apply parameters. */
	if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0)
	{
		oss << "cannot apply software parameters : " << snd_strerror (err) << endl;
		throw oss.str();
	}

	/* the interface will interrupt the kernel every 4096 frames, and ALSA
	   will wake up this program very soon after that.
	*/

	if ((err = snd_pcm_prepare (playback_handle)) < 0)
	{
		oss << "cannot prepare audio interface for use : " << snd_strerror (err) << endl;
		throw oss.str();
	}
}
    /**
     * Create and initialize Alsa audio output device with given parameters.
     *
     * @param Parameters - optional parameters
     * @throws AudioOutputException  if output device cannot be opened
     */
    AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) {
        pcm_handle           = NULL;
        stream               = SND_PCM_STREAM_PLAYBACK;
        this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
        this->uiSamplerate   = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
        this->FragmentSize   = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt();
        uint Fragments       = ((DeviceCreationParameterInt*)Parameters["FRAGMENTS"])->ValueAsInt();
        String Card          = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString();

        dmsg(2,("Checking if hw parameters supported...\n"));
        if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) {
            pcm_name = "hw:" + Card;
        }
        else {
            fprintf(stderr, "Warning: your soundcard doesn't support chosen hardware parameters; ");
            fprintf(stderr, "trying to compensate support lack with plughw...");
            fflush(stdout);
            pcm_name = "plughw:" + Card;
        }
        dmsg(2,("HW check completed.\n"));

        int err;

        snd_pcm_hw_params_alloca(&hwparams);  // Allocate the snd_pcm_hw_params_t structure on the stack.

        /* Open PCM. The last parameter of this function is the mode. */
        /* If this is set to 0, the standard mode is used. Possible   */
        /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
        /* If SND_PCM_NONBLOCK is used, read / write access to the    */
        /* PCM device will return immediately. If SND_PCM_ASYNC is    */
        /* specified, SIGIO will be emitted whenever a period has     */
        /* been completely processed by the soundcard.                */
        if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
            throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
        }

        if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
            throw AudioOutputException(String("Error, cannot initialize hardware parameter structure: ") + snd_strerror(err));
        }

        /* Set access type. This can be either    */
        /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
        /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
        if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
            throw AudioOutputException(String("Error snd_pcm_hw_params_set_access: ") + snd_strerror(err));
        }

        /* Set sample format */
        #if WORDS_BIGENDIAN
        if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0)
        #else // little endian
        if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
        #endif
        {
            throw AudioOutputException(String("Error setting sample format: ") + snd_strerror(err));
        }

        int dir = 0;

        /* Set sample rate. If the exact rate is not supported */
        /* by the hardware, use nearest possible rate.         */
        #if ALSA_MAJOR > 0
        if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &uiSamplerate, &dir)) < 0)
        #else
        if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, uiSamplerate, &dir)) < 0)
        #endif
        {
            throw AudioOutputException(String("Error setting sample rate: ") + snd_strerror(err));
        }

        if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, uiAlsaChannels)) < 0) {
            throw AudioOutputException(String("Error setting number of channels: ") + snd_strerror(err));
        }

        /* Set number of periods. Periods used to be called fragments. */
        if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
            throw AudioOutputException(String("Error setting number of ") + ToString(Fragments) + " periods: " + snd_strerror(err));
        }

        /* Set buffer size (in frames). The resulting latency is given by */
        /* latency = periodsize * periods / (rate * bytes_per_frame)     */
        if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
            throw AudioOutputException(String("Error setting buffersize: ") + snd_strerror(err));
        }

        /* Apply HW parameter settings to */
        /* PCM device and prepare device  */
        if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
            throw AudioOutputException(String("Error setting HW params: ") + snd_strerror(err));
        }

        if (snd_pcm_sw_params_malloc(&swparams) != 0) {
            throw AudioOutputException(String("Error in snd_pcm_sw_params_malloc: ") + snd_strerror(err));
        }

        if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
            throw AudioOutputException(String("Error in snd_pcm_sw_params_current: ") + snd_strerror(err));
        }

        if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
            throw AudioOutputException(String("Error in snd_pcm_sw_params_set_stop_threshold: ") + snd_strerror(err));
        }

        if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
            throw AudioOutputException(String("Error in snd_pcm_sw_params: ") + snd_strerror(err));
        }

        if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
            throw AudioOutputException(String("Error snd_pcm_prepare: ") + snd_strerror(err));
        }

        // allocate Alsa output buffer
        pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize];

        // create audio channels for this audio device to which the sampler engines can write to
        for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));

	if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
		Play();
	}
    }
int 
set_hwparams(snd_pcm_t *handle, int sampleRate, int channels, int bufferSize)
{
    snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;

    int ret, dir;

    snd_pcm_hw_params_t *hwparams;

    snd_pcm_hw_params_alloca(&hwparams);

    /* choose all parameters */
    ret = snd_pcm_hw_params_any(handle, hwparams);
    if (ret < 0) {
        fprintf(stderr, "Broken configuration for playback: "
	    "no configurations available: %s\n", snd_strerror(ret));
        return ret;
    }
    /* set hardware resampling */
    ret = snd_pcm_hw_params_set_rate_resample(handle, hwparams, resample);
    if (ret < 0) {
	fprintf(stderr, "Resampling setup failed for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set the interleaved read/write format */
    ret = snd_pcm_hw_params_set_access(handle, hwparams, access);
    if (ret < 0) {
        fprintf(stderr, "Access type not available for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set the sample format */
    ret = snd_pcm_hw_params_set_format(handle, hwparams, format);
    if (ret < 0) {
        fprintf(stderr, "Sample format not available for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set the count of channels */
    ret = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
    if (ret < 0) {
        fprintf(stderr, 
	    "Channels count (%d) not available for playbacks: %s\n", 
	    channels, snd_strerror(ret));
        return ret;
    } 

    /* set the stream rate */
    int rate = sampleRate;

    ret = snd_pcm_hw_params_set_rate(handle, hwparams, rate, 0);
    if (ret < 0) {
        fprintf(stderr, "Rate %dHz not available for playback: %s\n", 
	    sampleRate, snd_strerror(ret));
        return ret;
    }

    if (rate != sampleRate) {
        fprintf(stderr, "Rate doesn't match (requested %dHz, get %dHz)\n", 
	    rate, ret);
        return -EINVAL;
    } 

    /* set the buffer frames */
    unsigned int buffer_frames = bufferSize / 2 / channels;  // bytes to frames

    ret = snd_pcm_hw_params_set_buffer_size(handle, hwparams, buffer_frames);
    if (ret < 0) {
        fprintf(stderr, "Unable to set buffer size %d for playback: %s\n", 
	    buffer_frames, snd_strerror(ret));
        return ret;
    }

    /* set the period time */
    dir = 0;
    ret = snd_pcm_hw_params_set_period_time_near(handle, hwparams, 
	&period_time, &dir);
    if (ret < 0) {
        fprintf(stderr, "Unable to set period time %d for playback: %s\n", 
	    period_time, snd_strerror(ret));
        return ret;
    }

    /* write the parameters to device */
    ret = snd_pcm_hw_params(handle, hwparams);
    if (ret < 0) {
        fprintf(stderr, "Unable to set hw params for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    dump_hwparams(handle);
}
Пример #9
0
static gboolean
alsa_open (void *dp)
{
    alsa_driver * const d = dp;
    gint mf, err, pers;

    if(pcm_open_and_load_hwparams(d) < 0)
	goto out;

    // ---
    // Set non-blocking mode.
    // ---

    d->outtime = 0;

    // --
    // Set channel parameters
    // --
    if((err = snd_pcm_hw_params_set_access(d->soundfd, d->hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
	alsa_error(N_("Unable to set access"), err);
	goto out;
    }

    if((err = snd_pcm_hw_params_set_format(d->soundfd, d->hwparams,
				    (d->bits - 8) ? d->signedness16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U16 :
						    d->signedness8 ? SND_PCM_FORMAT_S8 : SND_PCM_FORMAT_U8) < 0)) {
	alsa_error(N_("Unable to set audio format"), err);
	goto out;
    }
    /* Handle endianess aspects. TODO! */
    switch(d->bits) {
	case 16:
	    mf = d->signedness16 ? ST_MIXER_FORMAT_S16_LE : ST_MIXER_FORMAT_U16_LE;
	    break;
	case 8:
	default:
	    mf = d->signedness8 ? ST_MIXER_FORMAT_S8 : ST_MIXER_FORMAT_U8;
	    break;
    }

    if((err = snd_pcm_hw_params_set_channels(d->soundfd, d->hwparams, d->stereo + 1)) < 0) {
	alsa_error(N_("Unable to set channels number"), err);
	goto out;
    }
    if((d->stereo)) {
	mf |= ST_MIXER_FORMAT_STEREO;
    }
    d->mf = mf;

    d->p_mixfreq = d->playrate;
    if ((err = snd_pcm_hw_params_set_rate_near(d->soundfd, d->hwparams, &(d->p_mixfreq), NULL)) < 0) {
	alsa_error(N_("Unable to set sample rate"), err);
	goto out;
    }

    if(snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size) < 0) {
	/* Some soundcards report wrong maximal buffer size (maybe alsa bug). So we should try
	   to downscale its value before the reporting an error. The spinbutton still may display
	   the wrong number, but actually the correct value will be implemented.*/
	while((--d->buffer_size) >= 8)
	    if(!snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size))
		break;
	if(d->buffer_size < 8) {
	    error_error(N_("Unable to set appropriate buffer size"));
	    goto out;
	}
    }
    pers = 1 << d->num_periods;
    if ((err = snd_pcm_hw_params_set_periods_near(d->soundfd, d->hwparams, &pers, NULL)) < 0) {
	alsa_error(N_("Unable to set periods number"), err);
	goto out;
    }
    if ((err = snd_pcm_hw_params_get_period_size(d->hwparams, &(d->p_fragsize), NULL)) < 0) {
	alsa_error(N_("Unable to get period size"), err);
	goto out;
    }

    if((err = snd_pcm_hw_params(d->soundfd, d->hwparams))) {
	alsa_error(N_("Error setting hw parameters"), err);
	goto out;
    }

    /* The following piece of code is directly c_n_p'ed from the ALSA pcm example (whith a little adopting) */
    /* get the current swparams */
    err = snd_pcm_sw_params_current(d->soundfd, d->swparams);
    if (err < 0) {
            alsa_error(N_("Unable to determine current swparams for playback"), err);
	    goto out;
    }
    /* start the transfer when the buffer is full */
    err = snd_pcm_sw_params_set_start_threshold(d->soundfd, d->swparams, d->p_fragsize);
    if (err < 0) {
            alsa_error(N_("Unable to set start threshold mode for playback"), err);
	    goto out;
    }
    /* allow the transfer when at least period_size samples can be processed */
    err = snd_pcm_sw_params_set_avail_min(d->soundfd, d->swparams, d->p_fragsize);
    if (err < 0) {
            alsa_error(N_("Unable to set avail min for playback"), err);
	    goto out;
    }
    /* align all transfers to 1 sample */
    err = snd_pcm_sw_params_set_xfer_align(d->soundfd, d->swparams, 1);
    if (err < 0) {
            alsa_error(N_("Unable to set transfer align for playback"), err);
	    goto out;
    }
    /* write the parameters to the playback device */
    err = snd_pcm_sw_params(d->soundfd, d->swparams);
    if (err < 0) {
            alsa_error(N_("Unable to set sw params for playback"), err);
	    goto out;
    }

    err = snd_pcm_prepare(d->soundfd);
    if (err < 0) {
            alsa_error(N_("Unable to prepare playback"), err);
	    goto out;
    }
    // ---
    // Get buffering parameters
    // ---
   
    if(d->verbose)
        snd_pcm_dump(d->soundfd, d->output);
    d->sndbuf = calloc((d->stereo + 1) * (d->bits / 8), d->p_fragsize);

    d->pfd = malloc(sizeof(struct pollfd));
    if ((err = snd_pcm_poll_descriptors(d->soundfd, d->pfd, 1)) < 0) {
        alsa_error(N_("Unable to obtain poll descriptors for playback"), err);
        goto out;
    }

    d->polltag = audio_poll_add(d->pfd->fd, GDK_INPUT_WRITE, alsa_poll_ready_playing, d);

    d->playtime = 0;
    d->firstpoll = TRUE;

    return TRUE;

  out:
    alsa_release(dp);
    return FALSE;
}
Пример #10
0
static void* sound_thread(void* context)
{
    struct SPU* c = (struct SPU*)context;
    int div;
    snd_pcm_t* snd;
    snd_pcm_hw_params_t* hwp;
    int rate = c->sampling;
    int periods = 3;
    snd_pcm_hw_params_alloca(&hwp);
    if (snd_pcm_open(&snd, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
        return NULL;
    }
    if (snd_pcm_hw_params_any(snd, hwp) < 0) {
        return NULL;
    }
    div = c->bit / 8;
    switch (c->bit) {
        case 8:
            if (snd_pcm_hw_params_set_format(snd, hwp, SND_PCM_FORMAT_U8) < 0) {
                return NULL;
            }
            break;
        case 16:
            if (snd_pcm_hw_params_set_format(snd, hwp, SND_PCM_FORMAT_S16_LE) < 0) {
                return NULL;
            }
            break;
        case 24:
            if (snd_pcm_hw_params_set_format(snd, hwp, SND_PCM_FORMAT_S24_LE) < 0) {
                return NULL;
            }
            break;
        case 32:
            if (snd_pcm_hw_params_set_format(snd, hwp, SND_PCM_FORMAT_S32_LE) < 0) {
                return NULL;
            }
            break;
        default:
            return NULL;
    }
    if (snd_pcm_hw_params_set_rate_near(snd, hwp, &rate, 0) < 0) {
        return NULL;
    }
    if (rate != SAMPLE_RATE) {
        return NULL;
    }
    if (snd_pcm_hw_params_set_channels(snd, hwp, c->ch) < 0) {
        return NULL;
    }
    if (snd_pcm_hw_params_set_periods(snd, hwp, periods, 0) < 0) {
        return NULL;
    }
    if (snd_pcm_hw_params_set_buffer_size(snd, hwp, (periods * c->size) / 4) < 0) {
        return NULL;
    }
    if (snd_pcm_hw_params(snd, hwp) < 0) {
        return NULL;
    }
    while (c->alive) {
        c->callback(c->buffer, c->size);
        while (c->alive) {
            if (snd_pcm_writei(snd, c->buffer, c->size / div) < 0) {
                snd_pcm_prepare(snd);
            } else {
                break;
            }
        }
    }
    snd_pcm_drain(snd);
    snd_pcm_close(snd);
    return NULL;
}
Пример #11
0
void Float32ToNativeInt32( const float *src, int *dst, unsigned int numToConvert )
{
	const float *src0 = src;
	int *dst0 = dst;
	unsigned int count = numToConvert;
	
	if (count >= 4) {
		// vector -- requires 4+ samples
		ROUNDMODE_NEG_INF
		const __m128 vround = (const __m128) { 0.5f, 0.5f, 0.5f, 0.5f };
		const __m128 vmin = (const __m128) { -2147483648.0f, -2147483648.0f, -2147483648.0f, -2147483648.0f };
		const __m128 vmax = (const __m128) { kMaxFloat32, kMaxFloat32, kMaxFloat32, kMaxFloat32  };
		const __m128 vscale = (const __m128) { 2147483648.0f, 2147483648.0f, 2147483648.0f, 2147483648.0f  };
		__m128 vf0;
		__m128i vi0;
	
#define F32TOLE32(x) \
		vf##x = _mm_mul_ps(vf##x, vscale);			\
		vf##x = _mm_add_ps(vf##x, vround);			\
		vf##x = _mm_max_ps(vf##x, vmin);			\
		vf##x = _mm_min_ps(vf##x, vmax);			\
		vi##x = _mm_cvtps_epi32(vf##x);			\

		int falign = (uintptr_t)src & 0xF;
		int ialign = (uintptr_t)dst & 0xF;
	
		if (falign != 0 || ialign != 0) {
			// do one unaligned conversion
			vf0 = _mm_loadu_ps(src);
			F32TOLE32(0)
			_mm_storeu_si128((__m128i *)dst, vi0);
			
			// and advance such that the destination ints are aligned
			unsigned int n = (16 - ialign) / 4;
			src += n;
			dst += n;
			count -= n;

			falign = (uintptr_t)src & 0xF;
			if (falign != 0) {
				// unaligned loads, aligned stores
				while (count >= 4) {
					vf0 = _mm_loadu_ps(src);
					F32TOLE32(0)
					_mm_store_si128((__m128i *)dst, vi0);
					src += 4;
					dst += 4;
					count -= 4;
				}
				goto VectorCleanup;
			}
		}
	
		while (count >= 4) {
			vf0 = _mm_load_ps(src);
			F32TOLE32(0)
			_mm_store_si128((__m128i *)dst, vi0);
			
			src += 4;
			dst += 4;
			count -= 4;
		}
VectorCleanup:
		if (count > 0) {
			// unaligned cleanup -- just do one unaligned vector at the end
			src = src0 + numToConvert - 4;
			dst = dst0 + numToConvert - 4;
			vf0 = _mm_loadu_ps(src);
			F32TOLE32(0)
			_mm_storeu_si128((__m128i *)dst, vi0);
		}
		RESTORE_ROUNDMODE
		return;
	}
	
	// scalar for small numbers of samples
	if (count > 0) {
		double scale = 2147483648.0, round = 0.5, max32 = 2147483648.0 - 1.0 - 0.5, min32 = 0.;
		ROUNDMODE_NEG_INF
		
		while (count-- > 0) {
			double f0 = *src++;
			f0 = f0 * scale + round;
			int i0 = FloatToInt(f0, min32, max32);
			*dst++ = i0;
		}
		RESTORE_ROUNDMODE
	}
}


void NativeInt32ToFloat32( const int *src, float *dst, unsigned int numToConvert )
{
	const int *src0 = src;
	float *dst0 = dst;
	unsigned int count = numToConvert;

	if (count >= 4) {
		// vector -- requires 4+ samples
#define LEI32TOF32(x) \
	vf##x = _mm_cvtepi32_ps(vi##x); \
	vf##x = _mm_mul_ps(vf##x, vscale); \
		
		const __m128 vscale = (const __m128) { 1.0/2147483648.0f, 1.0/2147483648.0f, 1.0/2147483648.0f, 1.0/2147483648.0f  };
		__m128 vf0;
		__m128i vi0;

		int ialign = (uintptr_t)src & 0xF;
		int falign = (uintptr_t)dst & 0xF;
	
		if (falign != 0 || ialign != 0) {
			// do one unaligned conversion
			vi0 = _mm_loadu_si128((__m128i const *)src);
			LEI32TOF32(0)
			_mm_storeu_ps(dst, vf0);
			
			// and advance such that the destination floats are aligned
			unsigned int n = (16 - falign) / 4;
			src += n;
			dst += n;
			count -= n;

			ialign = (uintptr_t)src & 0xF;
			if (ialign != 0) {
				// unaligned loads, aligned stores
				while (count >= 4) {
					vi0 = _mm_loadu_si128((__m128i const *)src);
					LEI32TOF32(0)
					_mm_store_ps(dst, vf0);
					src += 4;
					dst += 4;
					count -= 4;
				}
				goto VectorCleanup;
			}
		}
	
		// aligned loads, aligned stores
		while (count >= 4) {
			vi0 = _mm_load_si128((__m128i const *)src);
			LEI32TOF32(0)
			_mm_store_ps(dst, vf0);
			src += 4;
			dst += 4;
			count -= 4;
		}
		
VectorCleanup:
		if (count > 0) {
			// unaligned cleanup -- just do one unaligned vector at the end
			src = src0 + numToConvert - 4;
			dst = dst0 + numToConvert - 4;
			vi0 = _mm_loadu_si128((__m128i const *)src);
			LEI32TOF32(0)
			_mm_storeu_ps(dst, vf0);
		}
		return;
	}
	// scalar for small numbers of samples
	if (count > 0) {
		double scale = 1./2147483648.0f;
		while (count-- > 0) {
			int i = *src++;
			double f = (double)i * scale;
			*dst++ = f;
		}
	}
}

int alsa_set_hwparams(alsa_dev_t *dev, snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access)
{
  unsigned int rrate;
  snd_pcm_uframes_t size;
  int err, dir;
  
  /* choose all parameters */
  err = snd_pcm_hw_params_any(handle, params);
  if (err < 0) {
    printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
    return err;
  }
  
  /* set the interleaved read/write format */
  err = snd_pcm_hw_params_set_access(handle, params, access);
  if (err < 0) {
    printf("Access type not available for playback: %s\n", snd_strerror(err));
    return err;
  }
  /* set the sample format */
  err = snd_pcm_hw_params_set_format(handle, params, dev->format);
  if (err < 0) {
    printf("Sample format not available for playback: %s\n", snd_strerror(err));
    return err;
  }
  /* set the count of channels */
  err = snd_pcm_hw_params_set_channels(handle, params, dev->channels);
  if (err < 0) {
    printf("Channels count (%d) not available for playbacks: %s\n", dev->channels, snd_strerror(err));
    return err;
  }
  /* set the stream rate */
  rrate = dev->rate;
  err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
  if (err < 0) {
    printf("Rate %d Hz not available for playback: %s\n", dev->rate, snd_strerror(err));
    return err;
  }
  if (rrate != dev->rate) {
    printf("Rate doesn't match (requested %dHz, get %dHz)\n", dev->rate, rrate);
    return -EINVAL;
  }
  
  /* set the period size */
  err = snd_pcm_hw_params_set_period_size(handle, params, dev->period_size, 0);
  if (err < 0) {
    printf("Unable to set period size %d for playback: %s\n", (int)dev->period_size, snd_strerror(err));
    return err;
  }
  
  err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
  if (err < 0) {
    printf("Unable to get period size for playback: %s\n", snd_strerror(err));
    return err;
  }
  
  if (dev->period_size != size) {
    printf("Period size doesn't match (requested %d, got %d)\n", (int)dev->period_size, (int)size);
    return -EINVAL;
  }
  
    /* set the buffer size */
  err = snd_pcm_hw_params_set_buffer_size(handle, params, dev->buffer_size);
  if (err < 0) {
    printf("Unable to set buffer size %d for playback: %s\n", (int)dev->buffer_size, snd_strerror(err));
    return err;
  }
  err = snd_pcm_hw_params_get_buffer_size(params, &size);
  if (err < 0) {
    printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
    return err;
  }
  
  if (size != (snd_pcm_uframes_t)dev->buffer_size) {
    printf("Buffer size doesn't match (requested %d, got %d)\n", (int)dev->buffer_size, (int)size);
    return -EINVAL;
  }

  /* write the parameters to device */
  err = snd_pcm_hw_params(handle, params);
  if (err < 0) {
    printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
    return err;
  }
  return 0;
}

int alsa_set_swparams(alsa_dev_t *dev, snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
{
  int err;
  
  /* get the current swparams */
  err = snd_pcm_sw_params_current(handle, swparams);
  if (err < 0) {
    printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
    return err;
  }
  /* allow the transfer when at least period_size samples can be processed */
  /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
  err = snd_pcm_sw_params_set_avail_min(handle, swparams, dev->period_size);
  if (err < 0) {
    printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
    return err;
  }
  /* enable period events */
  err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
  if (err < 0) {
    printf("Unable to set period event: %s\n", snd_strerror(err));
    return err;
  }

  /* write the parameters to the playback device */
  err = snd_pcm_sw_params(handle, swparams);
  if (err < 0) {
    printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
    return err;
  }
  return 0;
}
Пример #12
0
static void
check_period_sizes (alsa_driver *d)
{
    /* Almost everything (luckily except sampling frequency) can affect period size: buffer size,
       format, channel numbers... So we need to recheck it after at least one of the parameters is
       changed -- mutab0r */
    gint err;
    guint address = PARAMS_TO_ADDRESS(d);

    /* The procedure is time-consuming and may cause audio system lock. So be sure if we really
       need it before starting... -- mutab0r */
    if(d->bits == 0)
	return;
    if((address == d->address_old) && (d->buffer_size == d->bufsize_old))
	return;

    if(pcm_open_and_load_hwparams(d) < 0)
	return;

    if((err = snd_pcm_hw_params_set_format(d->soundfd, d->hwparams,
				    (d->bits - 8) ? d->signedness16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U16 :
						    d->signedness8 ? SND_PCM_FORMAT_S8 : SND_PCM_FORMAT_U8)) < 0) {
	alsa_error(N_("Unable to set audio format"), err);
	snd_pcm_close(d->soundfd);
	return;
    }
    if((err = snd_pcm_hw_params_set_channels(d->soundfd, d->hwparams, d->stereo + 1)) < 0) {
	alsa_error(N_("Unable to set channels number"), err);
	snd_pcm_close(d->soundfd);
	return;
    }
    if(snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size) < 0) {
	/* Some soundcards report wrong maximal buffer size (maybe alsa bug). So we should try
	   to downscale its value before the reporting an error. The spinbutton still may display
	   the wrong number, but actually the correct value will be implemented.*/
	while((--d->buffer_size) >= 8)
	    if(!snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size))
		break;
	if(d->buffer_size < 8) {
	    error_error(N_("Unable to set appropriate buffer size"));
	    snd_pcm_close(d->soundfd);
	    return;
	}
    }

    snd_pcm_close(d->soundfd);

    if ((err = snd_pcm_hw_params_get_period_size_min(d->hwparams, &(d->persizemin), 0)) < 0) {
	alsa_error(N_("Unable to get minimal period size"), err);
	return;
    }
    if ((err = snd_pcm_hw_params_get_period_size_max(d->hwparams, &(d->persizemax), 0)) < 0) {
	alsa_error(N_("Unable to get maximal period size"), err);
	return;
    }

    update_periods_range(d);
    update_estimate(d);

    d->address_old = address;
    d->bufsize_old = d->buffer_size;
}
Пример #13
0
int init_alsa()
{
	int dir = 0;
	unsigned int rate = PCM_RATE;

	/* Open PCM device for recording (capture). */
	if (snd_pcm_open(&handle, PCM_NAME, SND_PCM_STREAM_CAPTURE, 0) < 0) {
		//fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
		fprintf(stderr, "unable to open pcm device\n");
		return -1;
	}

	/* Allocate a hardware parameters object. */
	snd_pcm_hw_params_alloca(&params);

	/* Fill it in with default values. */
	snd_pcm_hw_params_any(handle, params);

	/* Set the desired hardware parameters. */
	/* Interleaved mode */
	if (snd_pcm_hw_params_set_access(handle, params, 
		SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
		fprintf(stderr, "Error setting access.\n");
		return -1;
	}

	/* Signed 16-bit little-endian format */
	if (snd_pcm_hw_params_set_format(handle, params, 
		SND_PCM_FORMAT_S16_LE) < 0) {
		fprintf(stderr, "Error setting format. \n");
		return -1;
	}

	/* Two channels (stereo) */
	if (snd_pcm_hw_params_set_channels(handle, params, PCM_CHANNELS) < 0) {
		fprintf(stderr, "Error setting channels \n");
		return -1;
	}

	/* sampling rate */
	dir = 0;
	if (snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir) < 0) {
		fprintf(stderr, "Error setting rate. \n");
		return -1;
	}
	if (rate != PCM_RATE) {
		fprintf(stderr, "The rate %d Hz is not supported by your hardware. \n"
		  "==> Using %d Hz instead. \n", PCM_RATE, rate);
		return -1;
	}

	/*Set number of periods. Periods used to be called fragments*/
	dir = 0;
	if (snd_pcm_hw_params_set_period_size_near(handle, params, 
		&period_frames, &dir) < 0) {
		fprintf(stderr, "Error setting periods. \n");
		return -1;
	}
	if (period_frames != PCM_PERIOD_FRAMES) {
		fprintf(stderr, "The periods %d is not supported by your hardware. \n"
		  "==> Using %d periods instead. \n", 
		  PCM_PERIOD_FRAMES, (int)period_frames);
		return -1;
	}

	/* Set buffer size (in frames). 
	buffersize = period_size * periods * framesize (bytes)
	The resulting latency is given by 
	latency = period_size * periods / (rate * bytes_per_frame)
	*/
	if (snd_pcm_hw_params_set_buffer_size(handle, params, buf_frames) < 0) {
		fprintf(stderr, "Error setting buffersize. \n");
		return -1;
	}

	/* Write the parameters to the driver */
	if (snd_pcm_hw_params(handle, params) < 0) {
		//fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
		fprintf(stderr, "unable to set hw parameters\n");
		return -1;
	}

	return 0;
}
Пример #14
0
/* Initialise audio devices. */
int digi_init()
{
 int err, tmp;
 char *device = "plughw:0,0";
 snd_pcm_hw_params_t *params;
 pthread_attr_t attr;
 pthread_mutexattr_t mutexattr;

 //added on 980905 by adb to init sound kill system
 memset(SampleHandles, 255, sizeof(SampleHandles));
 //end edit by adb

 /* Open the ALSA sound device */
 if ((err = snd_pcm_open(&snd_devhandle,device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {  
     con_printf(CON_CRITICAL, "open failed: %s\n", snd_strerror( err ));  
     return -1; 
 } 

 snd_pcm_hw_params_alloca(&params);
 err = snd_pcm_hw_params_any(snd_devhandle, params);
 if (err < 0) {
     con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err));
     return -1;
 }
 err = snd_pcm_hw_params_set_access(snd_devhandle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
 if (err < 0) {
     con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err));
     return -1;
 }
 err = snd_pcm_hw_params_set_format(snd_devhandle, params, SND_PCM_FORMAT_U8);
 if (err < 0) {
     con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err));
     return -1;
 }
 err = snd_pcm_hw_params_set_channels(snd_devhandle, params, 2);
 if (err < 0) {
     con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err));
     return -1;
 }
 tmp = 11025;
 err = snd_pcm_hw_params_set_rate_near(snd_devhandle, params, &tmp, NULL);
 if (err < 0) {
     con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err));
     return -1;
 }
 snd_pcm_hw_params_set_periods(snd_devhandle, params, 3, 0);
 snd_pcm_hw_params_set_buffer_size(snd_devhandle,params, (SOUND_BUFFER_SIZE*3)/2);

 err = snd_pcm_hw_params(snd_devhandle, params);
 if (err < 0) {
     con_printf(CON_CRITICAL,"ALSA: Error %s\n", snd_strerror(err));
     return -1;
 }

 /* Start the mixer thread */

 /* We really should check the results of these */
 pthread_mutexattr_init(&mutexattr);
 pthread_mutex_init(&mutex,&mutexattr);
 pthread_mutexattr_destroy(&mutexattr);
 
 if (pthread_attr_init(&attr) != 0) {
  con_printf(CON_CRITICAL, "failed to init attr\n");
  snd_pcm_close( snd_devhandle ); 
  return -1;
 }

 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

 pthread_create(&thread_id,&attr,mixer_thread,NULL);
 pthread_attr_destroy(&attr);

 digi_initialised = 1;
 return 0;
}
Пример #15
0
int audioStreamer_ALSA::Open(char *devname, int is_write, int srate, int nch, int bps, int fragsize, int nfrags, int dosleep)
{
	m_sleep=dosleep;

        /* Playback stream */
        snd_pcm_stream_t stream = is_write?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE;

	/* This structure contains information about    */
	/* the hardware and can be used to specify the  */      
	/* configuration to be used for the PCM stream. */ 
	snd_pcm_hw_params_t *hwparams;

	/* Allocate the snd_pcm_hw_params_t structure on the stack. */
	snd_pcm_hw_params_alloca(&hwparams);

    	if (snd_pcm_open(&pcm_handle, devname, stream, 0) < 0) 
	{
 		fprintf(stderr, "Error opening PCM device %s\n", devname);
	        return(-1);
    	}

        /* Init hwparams with full configuration space */
        if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) 
	{
		fprintf(stderr, "Can not configure this PCM device.\n");
		return(-1);
        }

	if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) 
	{
		fprintf(stderr, "Error setting access.\n");
		return(-1);
        }
	  
    	/* Set sample format */
	m_bps=bps==32?32:bps==24?24:16;
    	if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, 
				bps==32?SND_PCM_FORMAT_S32_LE:bps==24?SND_PCM_FORMAT_S24_3LE:SND_PCM_FORMAT_S16_LE) < 0) {
		fprintf(stderr, "Error setting format.\n");
		fprintf(stderr, "Try -bps 16, -bps 24, or -bps 32\n");
		return(-1);
	}

  int dir=0;          /* exact_rate == rate --> dir = 0 */
                          /* exact_rate < rate  --> dir = -1 */
                          /* exact_rate > rate  --> dir = 1 */
	unsigned int usrate=srate;

        /* Set sample rate. If the exact rate is not supported */
        /* by the hardware, use nearest possible rate.         */ 
	m_srate=srate;
  int exact_rate = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &usrate, &dir);
	if (dir != 0) 
	{
		fprintf(stderr, "The rate %d Hz is not supported by your hardware. Using %d Hz instead.\n", srate, exact_rate);
  		m_srate=exact_rate;
      	}

       	/* Set number of channels */
        if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, nch) < 0) 
	{
		fprintf(stderr, "Error setting channels.\n");
		fprintf(stderr, "Try -nch 1 or -nch 2\n");
		return(-1);
        }
	m_nch=nch;
	
	int periods=m_nfrags=(is_write?nfrags:nfrags*3);
	int periodsize=fragsize;

	/* Set number of periods. Periods used to be called fragments. */ 
	if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) 
	{
		fprintf(stderr, "Error setting periods.\n");
		fprintf(stderr, "Try -nbufs 2 through -nbufs 16\n");
		return(-1);
	}

    	/* Set buffer size (in frames). The resulting latency is given by */
    	/* latency = periodsize * periods / (rate * bytes_per_frame)     */
    	if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, m_bufsize = (periodsize * periods)/(m_nch * m_bps/8)) < 0) 
	{
		fprintf(stderr, "Error setting buffersize.\n");
		fprintf(stderr, "Try -bufsize 256 through -bufsize 2048\n");
		return(-1);
	}

     	/* Apply HW parameter settings to */
        /* PCM device and prepare device  */
        if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) 
	{
		fprintf(stderr, "Error setting HW params.\n");
		return(-1);
	}

	return 0;
}
Пример #16
0
int AlsaAudioPlugin::init(shared_ptr<t_CPC> cpc, shared_ptr<t_PSG> psg)
{
	if(!cpc->snd_enabled)
	{
		InfoLogMessage("[ALSA Audio Plugin] Not opening audio because disabled in the config");
		return 0;
	}
    /*  TODO */
    unsigned int rate = cpc->snd_playback_rate;
    int channels = cpc->snd_stereo ? 2 : 1;

	snd_pcm_format_t format = SND_PCM_FORMAT_S16;
	switch(cpc->snd_bits)
	{
		case 8:
			format = SND_PCM_FORMAT_U8;
			break;
		case 16:
			format = SND_PCM_FORMAT_S16;
			break;
		case 24:
			format = SND_PCM_FORMAT_S24;
			break;
		case 32:
			format = SND_PCM_FORMAT_S32;
			break;
		default:
			WarningLogMessage("[ALSA Audio Plugin] Warning, %d bits format unknown, fallback to %s.", cpc->snd_bits, snd_pcm_format_name(format));
	}

    int periods = 2;
    periodsize = 4096;

    unsigned int exact_rate;
    int dir, err;

    /* Handle for the PCM device */ 
    //snd_pcm_t *pcm_handle;          

    /* Playback stream */
    snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;

    /* This structure contains information about    */
    /* the hardware and can be used to specify the  */      
    /* configuration to be used for the PCM stream. */ 
    snd_pcm_hw_params_t *hwparams;

    /* Name of the PCM device, like plughw:0,0          */
    /* The first number is the number of the soundcard, */
    /* the second number is the number of the device.   */
    char *pcm_name = strdup("plughw:0,0");
	WarningLogMessage("TODO [%s:%d]: pcm_name need to be configurable.", __FILE__, __LINE__);
  
    /* Allocate the snd_pcm_hw_params_t structure on the stack. */
    snd_pcm_hw_params_alloca(&hwparams);

    /* Open PCM. The last parameter of this function is the mode. */
    /* If this is set to 0, the standard mode is used. Possible   */
    /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */ 
    /* If SND_PCM_NONBLOCK is used, read / write access to the    */
    /* PCM device will return immediately. If SND_PCM_ASYNC is    */
    /* specified, SIGIO will be emitted whenever a period has     */
    /* been completely processed by the soundcard.                */
    if(err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error opening PCM device %s (Error: %s)", pcm_name, snd_strerror(err));
        return 1;
    }

    /* Init hwparams with full configuration space */
    if(err = snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Can not configure PCM device %s. (Error: %s)", pcm_name, snd_strerror(err));
        return 1;
    }

    /* Set access type. This can be either    */
    /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
    /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
    /* There are also access types for MMAPed */
    /* access, but this is beyond the scope   */
    /* of this introduction.                  */
    if(err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting access on device %s. (Error: %s)", pcm_name, snd_strerror(err));
        return 1;
    }
  
    /* Set sample format */ 
    if(err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting format %s on device %s. (Error: %s)", snd_pcm_format_name(format), pcm_name, snd_strerror(err));
        return 1;
    }
    
    /* Set sample rate. If the exact rate is not supported */
    /* by the hardware, use nearest possible rate.         */ 
#if 0 // Segfault... Humf... TODO
    exact_rate = rate;
    if(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, &dir) < 0)
    {
        ErrorLogMessage("Error setting rate (%d) on device %s.", rate, pcm_name);
    }
    if(dir != 0) {
        WarningLogMessage("The rate %d Hz is not supported by your hardware on device %s.\n" \
                "==> Using %d Hz instead.", pcm_name, rate, exact_rate);
    }
#else
	exact_rate = rate;
    if(err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, exact_rate, 0) < 0)
    {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting rate (%d) on device %s. (Error: %s)", rate, pcm_name, snd_strerror(err));
    }
#endif
    
    /* Set number of channels */
    if(err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting channels (%d) on device %s. (Error: %s)", channels, pcm_name, snd_strerror(err));
        return 1;
    }

    /* Set number of periods. Periods used to be called fragments. */ 
    if(err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting periods (%d) on device %s. (Error: %s)", periods, pcm_name, snd_strerror(err));
        return 1;
    }

    /* Set buffer size (in frames). The resulting latency is given by */
    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
    int buffer_size = (periodsize * periods) >> 2;
    if(err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, buffer_size) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting buffersize (%d) on device %s. (Error: %s)", buffer_size, pcm_name, snd_strerror(err));
        return 1;
    }
    
    /* Apply HW parameter settings to */
    /* PCM device and prepare device  */
    if(err = snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
        ErrorLogMessage("[ALSA Audio Plugin] Error setting HW params on device %s. (Error: %s)", pcm_name, snd_strerror(err));
        return 1;
    }

	sndBuffer = new uint8_t[periodsize*4*2];
	if(!sndBuffer)
	{
		ErrorLogMessage("[ALSA Audio Plugin] sndBuffer allocation error.");
		return 1;
	}
    sndBufferPtr = sndBuffer;

	InfoLogMessage("[ALSA Audio Plugin] PCM device %s open at %d Hz %s, %d channels.", pcm_name, rate, snd_pcm_format_name(format), channels);

    return 0;
}
Пример #17
0
static int set_hwparams(snd_pcm_t *handle,
snd_pcm_hw_params_t *params,
snd_pcm_access_t access)
{
    unsigned int rrate;
    int err;
    /* choose all parameters */
    err = snd_pcm_hw_params_any(handle, params);
    if (err < 0) {
    printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
    return err;
    }
    /* set hardware resampling */
    err = snd_pcm_hw_params_set_rate_resample(handle, params, 0);
    if (err < 0) {
        printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
        return err;
    }
    /* set the interleaved read/write format */
    err = snd_pcm_hw_params_set_access(handle, params, access);
    if (err < 0) {
        printf("Access type not available for playback: %s\n", snd_strerror(err));
        return err;
    }
    /* set the sample format */
    err = snd_pcm_hw_params_set_format(handle, params, format);
    if (err < 0) {
        printf("Sample format not available for playback: %s\n", snd_strerror(err));
        return err;
    }
    /* set the count of channels */
    err = snd_pcm_hw_params_set_channels(handle, params, channels);
    if (err < 0) {
        printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
        return err;
    }
    /* set the stream rate */
    // rrate = rate;
    err = snd_pcm_hw_params_set_rate(handle, params, rate, 0);
    if (err < 0) {
        printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
        return err;
    }


    err = snd_pcm_hw_params_set_buffer_size(handle, params, BUFFER_SIZE);
    if (err < 0) {
        printf("Unable to set buffer size %lu for playback: %s\n", PERIOD_SIZE, snd_strerror(err));
        return err;
    }

    int dir;
    err = snd_pcm_hw_params_set_period_size(handle, params, PERIOD_SIZE, 0);
    if (err < 0) {
        printf("Unable to set period size %lu for playback: %s\n", PERIOD_SIZE, snd_strerror(err));
        return err;
    }

    /* write the parameters to device */
    err = snd_pcm_hw_params(handle, params);
    if (err < 0) {
        printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
        return err;
    }

    return 0;
}
Пример #18
0
static int audio_open(audiodevice_t *dev, chanfmt_t fmt) {
	audio_alsa09_t *alsa = (audio_alsa09_t *)dev->data_pcm;
	struct pollfd pfds;
	snd_pcm_hw_params_t *hwparams;
#if SND_LIB_VERSION >= SND_PROTOCOL_VERSION(1,0,0)
	snd_pcm_uframes_t len;
#else
	snd_pcm_sframes_t len;
#endif
	int err, periods;
	
	if (0 > snd_pcm_open(&alsa->handle, alsa->dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC)) {
		WARNING("Opening audio device %d failed\n", alsa->dev);
		goto _err_exit;
	}
	snd_pcm_hw_params_alloca(&hwparams);
	
	if (0 > snd_pcm_hw_params_any(alsa->handle, hwparams)) {
		WARNING("param get failed\n");
		goto _err_exit;
	}
	
	if (0 > snd_pcm_hw_params_set_access(alsa->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) {
		WARNING("set access fail\n");
		goto _err_exit;
	}
	
	if (0 > snd_pcm_hw_params_set_format(alsa->handle, hwparams, fmt.bit == 16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8)) {
		WARNING("set format fail\n");
		goto _err_exit;
	}
	
	if (0 > snd_pcm_hw_params_set_channels(alsa->handle, hwparams, fmt.ch)) {
		WARNING("set channel fail\n");
		goto _err_exit;
	}
	
#if SND_LIB_VERSION >= SND_PROTOCOL_VERSION(1,0,0)
	int tmp = fmt.rate;
	err = snd_pcm_hw_params_set_rate_near(alsa->handle, hwparams, &tmp, 0);
#else
	err = snd_pcm_hw_params_set_rate_near(alsa->handle, hwparams, fmt.rate, 0);
#endif
	if (err < 0) {
		WARNING("set rate fail\n");
		goto _err_exit;
	}

	if (tmp != fmt.rate) {
		WARNING("set rate fail\n");
		goto _err_exit;
	}

	if (0 > snd_pcm_hw_params_set_periods_integer(alsa->handle, hwparams)) {
		WARNING("set periods fail\n");
		goto _err_exit;
	}
	
	periods = 2;
	if (0 > snd_pcm_hw_params_set_periods_min(alsa->handle, hwparams, &periods, 0)) {
		WARNING("set priods min fail\n");
		goto _err_exit;
	}
	
	if (0 > snd_pcm_hw_params_set_buffer_size(alsa->handle, hwparams, BUFFERSIZE)) {
		WARNING("set buffer fail\n");
		goto _err_exit;
	}	  
	
	if (0 > snd_pcm_hw_params(alsa->handle, hwparams)) {
		WARNING("set hw parmas fail\n");
		goto _err_exit;
	}	  
#if SND_LIB_VERSION >= SND_PROTOCOL_VERSION(1,0,0)
	
        snd_pcm_hw_params_get_buffer_size(hwparams, &len);
#else
	len = snd_pcm_hw_params_get_buffer_size(hwparams);
#endif
	dev->buf.len = (int)len;
	snd_pcm_poll_descriptors(alsa->handle, &pfds, 1);
	dev->fd = pfds.fd;
	return OK;
	
 _err_exit:
	if (alsa->handle) {
		snd_pcm_close(alsa->handle);
	}
	dev->fd = -1;
	return NG;
}
Пример #19
0
int AlsaIO::Initialize(uint Channels, uint Samplerate, uint Fragments, uint FragmentSize, String Card) {
    this->uiChannels           = Channels;
    this->uiSamplerate         = Samplerate;
    this->uiMaxSamplesPerCycle = FragmentSize;
    this->bInterleaved         = true;

    if (HardwareParametersSupported(Channels, Samplerate, Fragments, FragmentSize)) {
        pcm_name = "hw:" + Card;
    }
    else {
        printf("Warning: your soundcard doesn't support chosen hardware parameters; ");
        printf("trying to compensate support lack with plughw...");
        fflush(stdout);
        pcm_name = "plughw:" + Card;
    }

    int err;

    snd_pcm_hw_params_alloca(&hwparams);  // Allocate the snd_pcm_hw_params_t structure on the stack.

    /* Open PCM. The last parameter of this function is the mode. */
    /* If this is set to 0, the standard mode is used. Possible   */
    /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
    /* If SND_PCM_NONBLOCK is used, read / write access to the    */
    /* PCM device will return immediately. If SND_PCM_ASYNC is    */
    /* specified, SIGIO will be emitted whenever a period has     */
    /* been completely processed by the soundcard.                */
    if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
        fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_name.c_str(), snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
        fprintf(stderr, "Error, cannot initialize hardware parameter structure: %s.\n", snd_strerror(err));
        return -1;
    }

    /* Set access type. This can be either    */
    /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
    /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
    if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_access: %s.\n", snd_strerror(err));
        return -1;
    }

    /* Set sample format */
    #if WORDS_BIGENDIAN
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0) {
    #else // little endian
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) {
    #endif
        fprintf(stderr, "Error setting sample format. : %s\n", snd_strerror(err));
        return -1;
    }

    int dir = 0;

    /* Set sample rate. If the exact rate is not supported */
    /* by the hardware, use nearest possible rate.         */
    #if ALSA_MAJOR > 0
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &Samplerate, &dir)) < 0) {
    #else
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, Samplerate, &dir)) < 0) {
    #endif
        fprintf(stderr, "Error setting sample rate. : %s\n", snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, Channels)) < 0) {
        fprintf(stderr, "Error setting number of channels. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Set number of periods. Periods used to be called fragments. */
    if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
        fprintf(stderr, "Error setting number of periods. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Set buffer size (in frames). The resulting latency is given by */
    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
    if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
        fprintf(stderr, "Error setting buffersize. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Apply HW parameter settings to */
    /* PCM device and prepare device  */
    if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
        fprintf(stderr, "Error setting HW params. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_malloc(&swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_malloc. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_current. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_set_stop_threshold. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params. : %s\n", snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
        fprintf(stderr, "Error snd_pcm_prepare : %s\n", snd_strerror(err));
        return -1;
    }

    // allocate the audio output buffer
    pOutputBuffer = new int16_t[Channels * FragmentSize];
    
    this->bInitialized = true;

    return 0;
}

/**
 *  Checks if sound card supports the chosen parameters.
 *
 *  @returns  true if hardware supports it
 */
bool AlsaIO::HardwareParametersSupported(uint channels, int samplerate, uint numfragments, uint fragmentsize) {
    pcm_name = "hw:0,0";
    if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;
    snd_pcm_hw_params_alloca(&hwparams);
    if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    #if WORDS_BIGENDIAN
    if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0) {
    #else // little endian
    if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
    #endif
        snd_pcm_close(pcm_handle);
        return false;
    }
    int dir = 0;
    if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }

    snd_pcm_close(pcm_handle);
    return true;
}

void AlsaIO::Activate() {
    this->StartThread();
}

int AlsaIO::Main() {
    if (!pEngine) {
        fprintf(stderr, "AlsaIO: No Sampler Engine assigned, exiting.\n");
        exit(EXIT_FAILURE);
    }
    if (!bInitialized) {
        fprintf(stderr, "AlsaIO: Not yet intitialized, exiting.\n");
        exit(EXIT_FAILURE);
    }

    while (true) {

        // let the engine render audio for the current audio fragment
        pEngine->RenderAudio(uiMaxSamplesPerCycle);


        // check clipping in the audio sum, convert to sample_type
        // (from 32bit to 16bit sample) and copy to output buffer
        float sample_point; uint o = 0;
        for (uint s = 0; s < uiMaxSamplesPerCycle; s++) {
            for (uint c = 0; c < uiChannels; c++) {
                sample_point = pEngine->GetAudioSumBuffer(c)[s] * pEngine->Volume;
                if (sample_point < -32768.0) sample_point = -32768.0;
                if (sample_point >  32767.0) sample_point =  32767.0;
                this->pOutputBuffer[o++] = (int32_t) sample_point;
            }
        }


        // output sound
        int res = Output();
        if (res < 0) {
            fprintf(stderr, "AlsaIO: Audio output error, exiting.\n");
            exit(EXIT_FAILURE);
        }
    }
}

/**
 *  Will be called after every audio fragment cycle, to output the audio data
 *  of the current fragment to the soundcard.
 *
 *  @returns  0 on success
 */
int AlsaIO::Output() {
    int err = snd_pcm_writei(pcm_handle, pOutputBuffer, uiMaxSamplesPerCycle);
    if (err < 0) {
        fprintf(stderr, "Error snd_pcm_writei failed. : %s\n", snd_strerror(err));
        return -1;
    }
    return 0;
}

void AlsaIO::Close() {
    if (bInitialized) {
        //dmsg(0,("Stopping Alsa Thread..."));
        //StopThread();  //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
        //dmsg(0,("OK\n"));
        if (pcm_handle) {
            //FIXME: currently commented out due to segfault
            //snd_pcm_close(pcm_handle);
            pcm_handle = NULL;
        }
        if (pOutputBuffer) {
            //FIXME: currently commented out due to segfault
            //delete[] pOutputBuffer;
            pOutputBuffer = NULL;
        }
        bInitialized = false;
    }
}

void* AlsaIO::GetInterleavedOutputBuffer() {
    return pOutputBuffer;
}

void* AlsaIO::GetChannelOutputBufer(uint Channel) {
    fprintf(stderr, "AlsaIO::GetChannelOutputBufer(): Only interleaved access allowed so far, exiting.\n");
    exit(EXIT_FAILURE);
    // just to avoid compiler warnings
    return NULL;
}
Пример #20
0
void
ags_devout_alsa_init(AgsSoundcard *soundcard,
		     GError **error)
{
  AgsDevout *devout;
  
  int rc;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *hwparams;
  unsigned int val;
  snd_pcm_uframes_t frames;
  unsigned int rate;
  unsigned int rrate;
  unsigned int channels;
  snd_pcm_uframes_t size;
  snd_pcm_sframes_t buffer_size;
  snd_pcm_sframes_t period_size;
  snd_pcm_sw_params_t *swparams;
  int period_event = 0;
  int err, dir;

  static unsigned int period_time = 100000;
  static snd_pcm_format_t format = SND_PCM_FORMAT_S16;

  devout = AGS_DEVOUT(soundcard);
  
  /*  */
  devout->flags |= (AGS_DEVOUT_BUFFER3 |
		    AGS_DEVOUT_START_PLAY |
		    AGS_DEVOUT_PLAY |
		    AGS_DEVOUT_NONBLOCKING);

  devout->note_offset = 0;

  memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));
  memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));
  memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));
  memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));

  /* Open PCM device for playback. */
  if ((err = snd_pcm_open(&handle, devout->out.alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    printf("Playback open error: %s\n", snd_strerror(err));
    g_set_error(error,
		AGS_DEVOUT_ERROR,
		AGS_DEVOUT_ERROR_LOCKED_SOUNDCARD,
		"unable to open pcm device: %s\n\0",
		snd_strerror(err));
    return;
  }

  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_sw_params_alloca(&swparams);

  /* choose all parameters */
  err = snd_pcm_hw_params_any(handle, hwparams);
  if (err < 0) {
    printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
    return;
  }

  /* set hardware resampling */
  err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 1);
  if (err < 0) {
    printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
    return;
  }

  /* set the interleaved read/write format */
  err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0) {
    printf("Access type not available for playback: %s\n", snd_strerror(err));
    return;
  }

  /* set the sample format */
  err = snd_pcm_hw_params_set_format(handle, hwparams, format);
  if (err < 0) {
    printf("Sample format not available for playback: %s\n", snd_strerror(err));
    return;
  }

  /* set the count of channels */
  channels = devout->dsp_channels;
  err = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
  if (err < 0) {
    printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
    return;
  }

  /* set the stream rate */
  rate = devout->samplerate;
  rrate = rate;
  err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rrate, 0);
  if (err < 0) {
    printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
    return;
  }

  if (rrate != rate) {
    printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
    //    exit(-EINVAL);
    return;
  }

  /* set the buffer size */
  size = devout->buffer_size;
  err = snd_pcm_hw_params_set_buffer_size(handle, hwparams, size);
  if (err < 0) {
    printf("Unable to set buffer size %i for playback: %s\n", size, snd_strerror(err));
    return;
  }

  buffer_size = size;

  /* set the period time */
  period_time = MSEC_PER_SEC / devout->samplerate;
  dir = -1;
  err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
  if (err < 0) {
    printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
    return;
  }

  err = snd_pcm_hw_params_get_period_size(hwparams, &size, &dir);
  if (err < 0) {
    printf("Unable to get period size for playback: %s\n", snd_strerror(err));
    return;
  }
  period_size = size;

  /* write the parameters to device */
  err = snd_pcm_hw_params(handle, hwparams);
  if (err < 0) {
    printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
    return;
  }

  /* get the current swparams */
  err = snd_pcm_sw_params_current(handle, swparams);
  if (err < 0) {
    printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
    return;
  }

  /* start the transfer when the buffer is almost full: */
  /* (buffer_size / avail_min) * avail_min */
  err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
  if (err < 0) {
    printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
    return;
  }

  /* allow the transfer when at least period_size samples can be processed */
  /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
  err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size);
  if (err < 0) {
    printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
    return;
  }

  /* write the parameters to the playback device */
  err = snd_pcm_sw_params(handle, swparams);
  if (err < 0) {
    printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
    return;
  }

  /*  */
  devout->out.alsa.handle = handle;
  devout->delay_counter = 0.0;
  devout->tic_counter = 0;
}
Пример #21
0
static int audio_configure(snd_pcm_t *device) {
  snd_pcm_hw_params_t *hw_params;
  int err;
  unsigned int sr = SAMPLE_RATE;

  err = snd_pcm_hw_params_malloc(&hw_params);
  if (err) {
    fprintf(stderr, "can't allocate hw_params: %s\n", snd_strerror(err));
    return err;
  }

  err = snd_pcm_hw_params_any(device, hw_params);
  if (err) {
    fprintf(stderr, "can't initialize hw_params: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  err = snd_pcm_hw_params_set_access(device, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err) {
    fprintf(stderr, "can't set access mode: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  err = snd_pcm_hw_params_set_format(device, hw_params, SND_PCM_FORMAT_S16_LE);
  if (err) {
    fprintf(stderr, "can't set format: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  err = snd_pcm_hw_params_set_rate_near(device, hw_params, &sr, 0);
  if (err) {
    fprintf(stderr, "can't set samplerate: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  err = snd_pcm_hw_params_set_channels(device, hw_params, 1);
  if (err) {
    fprintf(stderr, "can't set channels: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }
  
  err = snd_pcm_hw_params_set_buffer_size(device, hw_params, BUFFER_SIZE);
  if (err) {
    fprintf(stderr, "can't set buffer size: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  err = snd_pcm_hw_params_set_period_size(device, hw_params, PERIOD_SIZE, 0);
  if (err) {
    fprintf(stderr, "can't set period size: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  err = snd_pcm_hw_params(device, hw_params);
  if (err) {
    fprintf(stderr, "can't set hw params: %s\n", snd_strerror(err));
    snd_pcm_hw_params_free(hw_params);
    return err;
  }

  snd_pcm_hw_params_free(hw_params);
  return 0;
}