/* write as many blocks as is currently possible */ static void sndio_update(int threaded) { struct pollfd pfd; nfds_t nfds; int i, nblocks, nbytes; /* make sure counters have been updated */ nfds = sio_pollfd(hdl, &pfd, POLLOUT); poll(&pfd, nfds, 0); if (!(sio_revents(hdl, &pfd) & POLLOUT)) return; nblocks = (sndio_play_appbufsz - (sndio_playpos - sndio_realpos)) / sndio_play_round; /* we got POLLOUT, so we can write something. if we don't * write anything, we could underrun. */ if (nblocks < 1) nblocks = 1; for (i = 0; i < nblocks; i++) { sio_write(hdl, sndio_play_bufdata, sndio_play_bufsize); sndio_playpos += sndio_play_round; if (sio_eof(hdl)) { /* print error message? */ return; } _mix_some_samples((uintptr_t) sndio_play_bufdata, 0, sndio_signed); } }
/* psp_audio_channel_thread: * This PSP thread manages the audio playing. */ static int psp_audio_channel_thread() { while (psp_audio_on) { void *bufptr = &sound_buffer[curr_buffer]; /* Asks to the Allegro mixer to fill the buffer */ _mix_some_samples((uintptr_t)bufptr, 0, IS_SIGNED); /* Send mixed buffer to sound card */ sceAudioOutputPannedBlocking(hw_channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, bufptr); curr_buffer = !curr_buffer; } sceKernelExitThread(0); return 0; }
/* jack_process: * The JACK processing functions. */ static int jack_process (jack_nframes_t nframes, void *arg) { jack_nframes_t i; /* TODO: Should be uint16_t and uint8_t? Endianess? */ unsigned short *buffer16 = jack_buffer; unsigned char *buffer8 = jack_buffer; _mix_some_samples((uintptr_t) jack_buffer, 0, jack_signed); jack_default_audio_sample_t *out_left = (jack_default_audio_sample_t *) jack_port_get_buffer (output_left, nframes); if (jack_stereo) { jack_default_audio_sample_t *out_right = (jack_default_audio_sample_t *) jack_port_get_buffer (output_right, nframes); if (jack_16bit) { for (i = 0; i < nframes; i++) { out_left[i] = ((sample_t) buffer16[i * 2] - AMP16) / AMP16; out_right[i] = ((sample_t) buffer16[i * 2 + 1] - AMP16) / AMP16; } } else { for (i = 0; i < nframes; i++) { out_left[i] = ((sample_t) buffer8[i * 2] - AMP8) / (sample_t) AMP8; out_right[i] = ((sample_t) buffer8[i * 2 + 1] - AMP8) / (sample_t) AMP8; } } } else { if (jack_16bit) { for (i = 0; i < nframes; i++) { out_left[i] = ((sample_t) buffer16[i] - AMP16) / AMP16; } } else { for (i = 0; i < nframes; i++) { out_left[i] = ((sample_t) buffer8[i] - AMP8) / AMP8; } } } return 0; }
/* alsa_mix * Mix and send some samples to ALSA. */ static void alsa_mix(void) { int ret, samples = alsa_bufsize; unsigned char *ptr = alsa_bufdata; while (samples > 0) { ret = snd_pcm_writei(pcm_handle, ptr, samples); if (ret == -EAGAIN) continue; if (ret < 0) { if (xrun_recovery(pcm_handle, ret) < 0) fprintf(stderr, "Write error: %s\n", snd_strerror(ret)); poll_next = 0; break; /* skip one period */ } if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_RUNNING) poll_next = 1; samples -= ret; ptr += ret * alsa_sample_size; } _mix_some_samples((uintptr_t)alsa_bufdata, 0, alsa_signed); }
/* jack_init: * JACK init routine. */ static int jack_init(int input, int voices) { const char **ports; char tmp[128]; if (!jack_detect(input)) return -1; jack_bufsize = get_config_int("sound", "jack_buffer_size", jack_bufsize); if (jack_bufsize == -1) jack_bufsize = jack_get_buffer_size (jack_client); /* Those are already read in from the config file by Allegro. */ jack_16bit = (_sound_bits == 16 ? 1 : 0); jack_stereo = (_sound_stereo ? 1 : 0); /* Let Allegro mix in its native unsigned format. */ jack_signed = 0; jack_set_process_callback (jack_client, jack_process, NULL); output_left = jack_port_register (jack_client, jack_stereo ? "left" : "mono", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (jack_stereo) output_right = jack_port_register (jack_client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); jack_rate = jack_get_sample_rate (jack_client); jack_buffer = _AL_MALLOC_ATOMIC(jack_bufsize * (1 + jack_16bit) * (1 + jack_stereo)); if (!jack_buffer) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text( "Cannot allocate audio buffer")); jack_exit (input); return -1; } digi_jack.voices = voices; if (_mixer_init(jack_bufsize * (1 + jack_stereo), jack_rate, jack_stereo, jack_16bit, &digi_jack.voices)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text( "Cannot init software mixer")); jack_exit (input); return -1; } _mix_some_samples((uintptr_t) jack_buffer, 0, jack_signed); if (jack_activate (jack_client)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text( "Cannot activate Jack client")); jack_exit (input); return 1; } /* Try to connect the ports. Failure to connect is not critical, since with * JACK, users may connect/disconnect ports anytime, without Allegro caring. */ if ((ports = jack_get_ports (jack_client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { TRACE (PREFIX_I "Cannot find any physical playback ports"); } if (ports) { if (ports[0]) { if (jack_connect (jack_client, jack_port_name (output_left), ports[0]) == 0) TRACE (PREFIX_I "Connected left playback port to %s", ports[0]); } if (jack_stereo && ports[1]) { if (jack_connect (jack_client, jack_port_name (output_right), ports[1]) == 0) TRACE (PREFIX_I "Connected right playback port to %s", ports[1]); } _AL_FREE (ports); } uszprintf(jack_desc, sizeof(jack_desc), get_config_text ("Jack, client '%s': %d bits, %s, %d bps, %s"), jack_client_name, jack_16bit ? 16 : 8, uconvert_ascii((jack_signed ? "signed" : "unsigned"), tmp), jack_rate, uconvert_ascii((jack_stereo ? "stereo" : "mono"), tmp)); return 0; }
static int sndio_init(int input, int voices) { char tmp1[128], tmp2[128]; if (input) { digi_driver->rec_cap_bits = 16; digi_driver->rec_cap_stereo = TRUE; return 0; } if (open_sndio_device(0) != 0) return -1; sndio_play_bufdata = _AL_MALLOC_ATOMIC(sndio_play_bufsize); if (sndio_play_bufdata == 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer")); sio_close(hdl); return -1; } sndio_realpos = sndio_playpos = 0; sio_onmove(hdl, movecb, NULL); sndio_volume = 127; sio_onvol(hdl, volcb, NULL); if (!sio_start(hdl)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not start sndio")); sio_close(hdl); return -1; } digi_sndio.voices = voices; /* first arg is total number of samples */ if (_mixer_init(sndio_play_round * (_sound_stereo ? 2 : 1), _sound_freq, _sound_stereo, ((_sound_bits == 16) ? 1 : 0), &digi_sndio.voices) != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer")); sio_close(hdl); return -1; } _mix_some_samples((uintptr_t) sndio_play_bufdata, 0, sndio_signed); /* Add audio interrupt. */ _unix_bg_man->register_func(sndio_update); uszprintf(sndio_desc, sizeof(sndio_desc), get_config_text("%s: %d bits, %s, %d Hz, %s"), "sndio device", _sound_bits, uconvert_ascii((sndio_signed ? "signed" : "unsigned"), tmp1), _sound_freq, uconvert_ascii((par.pchan == 2 ? "stereo" : "mono"), tmp2)); digi_driver->desc = sndio_desc; return 0; }
/* alsa_init: * ALSA init routine. */ static int alsa_init(int input, int voices) { int ret = 0; char tmp1[128], tmp2[128]; int format = 0; unsigned int numfrags = 0; snd_pcm_uframes_t fragsize; if (input) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported")); return -1; } ALSA9_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0)); alsa_device = get_config_string(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_device", tmp2), alsa_device); alsa_mixer_device = get_config_string(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_mixer_device", tmp2), alsa_mixer_device); fragsize = get_config_int(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_fragsize", tmp2), 0); numfrags = get_config_int(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_numfrags", tmp2), ALSA_DEFAULT_NUMFRAGS); ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (ret < 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device")); return -1; } snd_mixer_open(&alsa_mixer, 0); if (alsa_mixer && snd_mixer_attach(alsa_mixer, alsa_mixer_device) >= 0 && snd_mixer_selem_register (alsa_mixer, NULL, NULL) >= 0 && snd_mixer_load(alsa_mixer) >= 0) { const char *alsa_mixer_elem_name = get_config_string(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_mixer_elem", tmp2), "PCM"); alsa_mixer_elem = snd_mixer_first_elem(alsa_mixer); while (alsa_mixer_elem) { const char *name = snd_mixer_selem_get_name(alsa_mixer_elem); if (strcasecmp(name, alsa_mixer_elem_name) == 0) { snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem, &alsa_mixer_elem_min, &alsa_mixer_elem_max); alsa_mixer_allegro_ratio = (double) (alsa_mixer_elem_max - alsa_mixer_elem_min) / (double) 255; break; } alsa_mixer_elem = snd_mixer_elem_next(alsa_mixer_elem); } } /* Set format variables. */ alsa_bits = (_sound_bits == 8) ? 8 : 16; alsa_stereo = (_sound_stereo) ? 1 : 0; alsa_rate = (_sound_freq > 0) ? _sound_freq : 44100; alsa_signed = 0; format = ((alsa_bits == 16) ? SND_PCM_FORMAT_U16_NE : SND_PCM_FORMAT_U8); switch (format) { case SND_PCM_FORMAT_U8: alsa_bits = 8; break; case SND_PCM_FORMAT_U16_NE: if (sizeof(short) != 2) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format")); goto Error; } break; default: ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format")); goto Error; } alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1); if (fragsize == 0) { unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags; fragsize = 1; while (fragsize < size) fragsize <<= 1; } snd_pcm_hw_params_malloc(&hwparams); snd_pcm_sw_params_malloc(&swparams); ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams)); ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)); ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format)); ALSA9_CHECK(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, alsa_stereo + 1)); ALSA9_CHECK(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &alsa_rate, NULL)); ALSA9_CHECK(snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &fragsize, NULL)); ALSA9_CHECK(snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &numfrags, NULL)); ALSA9_CHECK(snd_pcm_hw_params(pcm_handle, hwparams)); ALSA9_CHECK(snd_pcm_hw_params_get_period_size(hwparams, &alsa_bufsize, NULL)); ALSA9_CHECK(snd_pcm_hw_params_get_periods(hwparams, &alsa_fragments, NULL)); TRACE (PREFIX_I "alsa_bufsize = %ld, alsa_fragments = %d\n", alsa_bufsize, alsa_fragments); ALSA9_CHECK(snd_pcm_sw_params_current(pcm_handle, swparams)); ALSA9_CHECK(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, alsa_bufsize)); ALSA9_CHECK(snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, fragsize)); ALSA9_CHECK(snd_pcm_sw_params_set_xfer_align(pcm_handle, swparams, 1)); ALSA9_CHECK(snd_pcm_sw_params(pcm_handle, swparams)); /* Allocate mixing buffer. */ alsa_bufdata = _AL_MALLOC_ATOMIC(alsa_bufsize * alsa_sample_size); if (!alsa_bufdata) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer")); goto Error; } /* Initialise mixer. */ digi_alsa.voices = voices; if (_mixer_init(alsa_bufsize * (alsa_stereo ? 2 : 1), alsa_rate, alsa_stereo, ((alsa_bits == 16) ? 1 : 0), &digi_alsa.voices) != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer")); goto Error; } snd_pcm_prepare(pcm_handle); pdc = snd_pcm_poll_descriptors_count (pcm_handle); if (pdc <= 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Invalid poll descriptors count")); goto Error; } ufds = _AL_MALLOC(sizeof(struct pollfd) * pdc); if (ufds == NULL) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory for poll descriptors")); goto Error; } ALSA9_CHECK(snd_pcm_poll_descriptors(pcm_handle, ufds, pdc)); poll_next = 0; _mix_some_samples((uintptr_t) alsa_bufdata, 0, alsa_signed); /* Add audio interrupt. */ _unix_bg_man->register_func(alsa_update); uszprintf(alsa_desc, sizeof(alsa_desc), get_config_text ("Alsa 0.9, Device '%s': %d bits, %s, %d bps, %s"), alsa_device, alsa_bits, uconvert_ascii((alsa_signed ? "signed" : "unsigned"), tmp1), alsa_rate, uconvert_ascii((alsa_stereo ? "stereo" : "mono"), tmp2)); digi_driver->desc = alsa_desc; return 0; Error: if (pcm_handle) { snd_pcm_close(pcm_handle); pcm_handle = NULL; } return -1; }