/* gfx_gdi_init: */ static struct BITMAP *gfx_gdi_init(int w, int h, int v_w, int v_h, int color_depth) { /* virtual screen are not supported */ if ((v_w!=0 && v_w!=w) || (v_h!=0 && v_h!=h)) return NULL; _enter_critical(); gfx_gdi.w = w; gfx_gdi.h = h; if (adjust_window(w, h) != 0) { _TRACE(PREFIX_E "window size not supported.\n"); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Resolution not supported")); goto Error; } /* the last flag serves as an end of loop delimiter */ gdi_dirty_lines = _AL_MALLOC_ATOMIC((h+1) * sizeof(char)); ASSERT(gdi_dirty_lines); memset(gdi_dirty_lines, 0, (h+1) * sizeof(char)); gdi_dirty_lines[h] = 1; /* create the screen surface */ screen_surf = _AL_MALLOC_ATOMIC(w * h * BYTES_PER_PIXEL(color_depth)); gdi_screen = _make_bitmap(w, h, (unsigned long)screen_surf, &gfx_gdi, color_depth, w * BYTES_PER_PIXEL(color_depth)); gdi_screen->write_bank = gfx_gdi_write_bank; _screen_vtable.acquire = gfx_gdi_lock; _screen_vtable.release = gfx_gdi_unlock; _screen_vtable.unwrite_bank = gfx_gdi_unwrite_bank; /* create render timer */ vsync_event = CreateEvent(NULL, FALSE, FALSE, NULL); install_int(render_proc, RENDER_DELAY); /* connect to the system driver */ win_gfx_driver = &win_gfx_driver_gdi; /* set the default switching policy */ set_display_switch_mode(SWITCH_PAUSE); /* grab input devices */ win_grab_input(); _exit_critical(); return gdi_screen; Error: _exit_critical(); gfx_gdi_exit(NULL); return NULL; }
/* sys_directx_get_executable_name: * Returns full path to the current executable. */ static void sys_directx_get_executable_name(char *output, int size) { char *temp = _AL_MALLOC_ATOMIC(size); if (GetModuleFileName(allegro_inst, temp, size)) do_uconvert(temp, U_ASCII, output, U_CURRENT, size); else usetc(output, 0); _AL_FREE(temp); }
/* sys_directx_message: * Displays a message. */ static void sys_directx_message(AL_CONST char *msg) { char *tmp1 = _AL_MALLOC_ATOMIC(ALLEGRO_MESSAGE_SIZE); char tmp2[WND_TITLE_SIZE*2]; HWND allegro_wnd = win_get_window(); while ((ugetc(msg) == '\r') || (ugetc(msg) == '\n')) msg += uwidth(msg); MessageBoxW(allegro_wnd, (unsigned short *)uconvert(msg, U_CURRENT, tmp1, U_UNICODE, ALLEGRO_MESSAGE_SIZE), (unsigned short *)uconvert(wnd_title, U_ASCII, tmp2, U_UNICODE, sizeof(tmp2)), MB_OK); _AL_FREE(tmp1); }
/* get_dib_from_bitmap_32: * Creates a Windows device-independent bitmap (DIB) from an Allegro BITMAP. * You have to free the memory allocated by this function. * * This version always creates a 32-bit DIB. */ static BYTE *get_dib_from_bitmap_32(ALLEGRO_BITMAP *bitmap) { int w, h; int x, y; int pitch; BYTE *pixels; BYTE *dst; w = al_get_bitmap_width(bitmap); h = al_get_bitmap_height(bitmap); pitch = w * 4; pixels = (BYTE *) _AL_MALLOC_ATOMIC(h * pitch); if (!pixels) return NULL; for (y = 0; y < h; y++) { dst = pixels + y * pitch; for (x = 0; x < w; x++) { ALLEGRO_COLOR col; unsigned char r, g, b, a; col = al_get_pixel(bitmap, x, y); al_unmap_rgba(col, &r, &g, &b, &a); /* BGR */ dst[0] = b; dst[1] = g; dst[2] = r; dst[3] = a; dst += 4; } } return pixels; }
/* Function: al_load_ogg_vorbis_f */ ALLEGRO_SAMPLE *al_load_ogg_vorbis_f(ALLEGRO_FILE* file) { /* Note: decoding library returns floats. I always return 16-bit (most * commonly supported). */ #ifdef ALLEGRO_LITTLE_ENDIAN const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ #else const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ #endif int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ int signedness = 1; /* 0 for unsigned, 1 for signed */ const int packet_size = 4096; /* suggestion for size to read at a time */ OggVorbis_File vf; vorbis_info* vi; char *buffer; long pos; ALLEGRO_SAMPLE *sample; int channels; long rate; long total_samples; int bitstream; long total_size; AL_OV_DATA ov; if (file == NULL) { ALLEGRO_WARN("Audio file failed to open.\n"); return NULL; } ov.file = file; if (ov_open_callbacks(&ov, &vf, NULL, 0, callbacks) < 0) { ALLEGRO_WARN("Audio file does not appear to be an Ogg bitstream.\n"); al_fclose(file); return NULL; } vi = ov_info(&vf, -1); channels = vi->channels; rate = vi->rate; total_samples = ov_pcm_total(&vf, -1); bitstream = -1; total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); buffer = _AL_MALLOC_ATOMIC(total_size); if (!buffer) { al_fclose(file); return NULL; } pos = 0; while (pos < total_size) { /* XXX error handling */ #if !defined(ALLEGRO_GP2XWIZ) && !defined(ALLEGRO_IPHONE) long read = ov_read(&vf, buffer + pos, packet_size, endian, word_size, signedness, &bitstream); #else (void)endian; (void)signedness; long read = ov_read(&vf, buffer + pos, packet_size, &bitstream); #endif pos += read; if (read == 0) break; } ov_clear(&vf); sample = al_create_sample(buffer, total_samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels), true); if (!sample) { _AL_FREE(buffer); } return sample; }
/* _unix_read_os_type: * Set the os_type variable to something sensible. */ void _unix_read_os_type(void) { #ifdef ALLEGRO_HAVE_SYS_UTSNAME_H struct utsname utsn; char *tmpstr, *tmpstr2; size_t pos; uname(&utsn); /* fetch OS version and revision */ tmpstr = _AL_MALLOC_ATOMIC(strlen(utsn.release)+1); _al_sane_strncpy(tmpstr, utsn.release, strlen(utsn.release)+1); tmpstr2 = NULL; for (pos = 0; pos <= strlen(utsn.release); pos++) { if (tmpstr[pos] == '.') { tmpstr[pos] = '\0'; if (!tmpstr2) tmpstr2 = tmpstr + pos + 1; } } os_version = atoi(tmpstr); os_revision = atoi(tmpstr2); _AL_FREE(tmpstr); /* try to detect Unix systems we know of */ if (!strcmp(utsn.sysname, "Linux")) { os_type = OSTYPE_LINUX; } else if (!strcmp(utsn.sysname, "SunOS")) { os_type = OSTYPE_SUNOS; } else if (!strcmp(utsn.sysname, "FreeBSD")) { os_type = OSTYPE_FREEBSD; } else if (!strcmp(utsn.sysname, "NetBSD")) { os_type = OSTYPE_NETBSD; } else if (!strcmp(utsn.sysname, "OpenBSD")) { os_type = OSTYPE_OPENBSD; } else if ((!strcmp(utsn.sysname, "IRIX")) || (!strcmp(utsn.sysname, "IRIX64"))) { os_type = OSTYPE_IRIX; } else if (!strcmp(utsn.sysname, "Darwin")) { os_type = OSTYPE_DARWIN; } else if (!strcmp(utsn.sysname, "QNX")) { os_type = OSTYPE_QNX; } else { os_type = OSTYPE_UNIX; /* that's all we can say for now */ } #else os_type = OSTYPE_UNIX; #endif os_multitasking = TRUE; }
/* 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; }
/* create_bitmap_ex * Creates a new memory bitmap in the specified color_depth */ BITMAP *create_bitmap_ex(int color_depth, int width, int height) { GFX_VTABLE *vtable; BITMAP *bitmap; int nr_pointers; int padding; int i; ASSERT(width >= 0); ASSERT(height > 0); ASSERT(system_driver); if (system_driver->create_bitmap) return system_driver->create_bitmap(color_depth, width, height); vtable = _get_vtable(color_depth); if (!vtable) return NULL; /* We need at least two pointers when drawing, otherwise we get crashes with * Electric Fence. We think some of the assembly code assumes a second line * pointer is always available. */ nr_pointers = MAX(2, height); bitmap = _AL_MALLOC(sizeof(BITMAP) + (sizeof(char *) * nr_pointers)); if (!bitmap) return NULL; /* This avoids a crash for assembler code accessing the last pixel, as it * read 4 bytes instead of 3. */ padding = (color_depth == 24) ? 1 : 0; bitmap->dat = _AL_MALLOC_ATOMIC(width * height * BYTES_PER_PIXEL(color_depth) + padding); if (!bitmap->dat) { _AL_FREE(bitmap); return NULL; } bitmap->w = bitmap->cr = width; bitmap->h = bitmap->cb = height; bitmap->clip = TRUE; bitmap->cl = bitmap->ct = 0; bitmap->vtable = vtable; bitmap->write_bank = bitmap->read_bank = _stub_bank_switch; bitmap->id = 0; bitmap->extra = NULL; bitmap->x_ofs = 0; bitmap->y_ofs = 0; bitmap->seg = _default_ds(); if (height > 0) { bitmap->line[0] = bitmap->dat; for (i=1; i<height; i++) bitmap->line[i] = bitmap->line[i-1] + width * BYTES_PER_PIXEL(color_depth); } if (system_driver->created_bitmap) system_driver->created_bitmap(bitmap); return bitmap; }
static int joy_init(void) { JOYSTICK_INFO *j; AL_CONST char *device_name = NULL; char tmp[128], tmp1[128], tmp2[128]; unsigned int raw_version; struct { unsigned char build, minor, major; } version; char num_axes, num_buttons; int throttle; int i, s, a, b; for (i = 0; i < MAX_JOYSTICKS; i++) { /* Check for a user override on the device to use. */ uszprintf(tmp, sizeof(tmp), uconvert_ascii("joystick_device_%d", tmp1), i); device_name = get_config_string(uconvert_ascii("joystick", tmp1), tmp, NULL); /* Special case for the first joystick. */ if (!device_name && (i == 0)) device_name = get_config_string(uconvert_ascii("joystick", tmp1), uconvert_ascii("joystick_device", tmp2), NULL); if (device_name) { joy_fd[i] = open(uconvert_toascii(device_name, tmp), O_RDONLY|O_NONBLOCK); if (joy_fd[i] == -1) break; } else { snprintf(tmp, sizeof(tmp), "/dev/input/js%d", i); tmp[sizeof(tmp)-1] = 0; joy_fd[i] = open(tmp, O_RDONLY|O_NONBLOCK); if (joy_fd[i] == -1) { snprintf(tmp, sizeof(tmp), "/dev/js%d", i); tmp[sizeof(tmp)-1] = 0; joy_fd[i] = open(tmp, O_RDONLY|O_NONBLOCK); if (joy_fd[i] == -1) break; } } if (ioctl(joy_fd[i], JSIOCGVERSION, &raw_version) < 0) { /* NOTE: IOCTL fails if the joystick API is version 0.x */ uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Your Linux joystick API is version 0.x which is unsupported.")); return -1; } version.major = (raw_version & 0xFF0000) >> 16; version.minor = (raw_version & 0xFF00) >> 8; version.build = (raw_version & 0xFF); ioctl(joy_fd[i], JSIOCGAXES, &num_axes); ioctl(joy_fd[i], JSIOCGBUTTONS, &num_buttons); if (num_axes > TOTAL_JOYSTICK_AXES) num_axes = TOTAL_JOYSTICK_AXES; if (num_buttons > MAX_JOYSTICK_BUTTONS) num_buttons = MAX_JOYSTICK_BUTTONS; /* User is allowed to override our simple assumption of which * axis number (kernel) the throttle is located at. */ uszprintf(tmp, sizeof(tmp), uconvert_ascii("throttle_axis_%d", tmp1), i); throttle = get_config_int(uconvert_ascii("joystick", tmp1), tmp, -1); if (throttle == -1) { throttle = get_config_int(uconvert_ascii("joystick", tmp1), uconvert_ascii("throttle_axis", tmp2), -1); } /* Each pair of axes is assumed to make up a stick unless it * is the sole remaining axis, or has been user specified, in * which case it is a throttle. */ j = &joy[i]; j->flags = JOYFLAG_ANALOGUE; for (s = 0, a = 0; (s < MAX_JOYSTICK_STICKS) && (a < num_axes); s++) { if ((a == throttle) || (a == num_axes-1)) { /* One axis throttle */ j->stick[s].flags = JOYFLAG_ANALOGUE | JOYFLAG_UNSIGNED; j->stick[s].num_axis = 1; j->stick[s].axis[0].name = get_config_text("Throttle"); j->stick[s].name = ustrdup(j->stick[s].axis[0].name); axis[i][a++] = &j->stick[s].axis[0]; } else { /* Two axis stick. */ j->stick[s].flags = JOYFLAG_ANALOGUE | JOYFLAG_SIGNED; j->stick[s].num_axis = 2; j->stick[s].axis[0].name = get_config_text("X"); j->stick[s].axis[1].name = get_config_text("Y"); j->stick[s].name = _AL_MALLOC_ATOMIC(32); ASSERT(j->stick[s].name); uszprintf((char *)j->stick[s].name, 32, get_config_text("Stick %d"), s+1); axis[i][a++] = &j->stick[s].axis[0]; axis[i][a++] = &j->stick[s].axis[1]; } } j->num_sticks = s; for (b = 0; b < num_buttons; b++) { j->button[b].name = _AL_MALLOC_ATOMIC(16); ASSERT(j->button[b].name); uszprintf((char *)j->button[b].name, 16, uconvert_ascii("%c", tmp), 'A' + b); } j->num_buttons = num_buttons; } num_joysticks = i; if (num_joysticks == 0) { uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unable to open %s: %s"), device_name ? device_name : uconvert_ascii("/dev/js0", tmp), ustrerror(errno)); return -1; } return 0; }
/* ljoy_get_joystick: [primary thread] * * Returns the address of a ALLEGRO_JOYSTICK structure for the device * number NUM. The top-level joystick functions will not call this * function if joystick number NUM was already gotten. If the * device cannot be opened, NULL is returned. */ static ALLEGRO_JOYSTICK *ljoy_get_joystick(int num) { ALLEGRO_JOYSTICK_LINUX *joy; int fd; /* Try to open the device. */ fd = try_open_joy_device(num); if (fd == -1) return NULL; /* Allocate a structure for the joystick. */ joy = _AL_MALLOC(sizeof *joy); if (!joy) { close(fd); return NULL; } memset(joy, 0, sizeof *joy); /* Initialise the event source part of it. */ _al_event_source_init(&joy->parent.es); /* Fill in the joystick information fields. */ { /* char tmp[128], tmp1[128], tmp2[128]; */ char num_axes; char num_buttons; int throttle; int s, a, b; ioctl(fd, JSIOCGAXES, &num_axes); ioctl(fd, JSIOCGBUTTONS, &num_buttons); if (num_axes > TOTAL_JOYSTICK_AXES) num_axes = TOTAL_JOYSTICK_AXES; if (num_buttons > _AL_MAX_JOYSTICK_BUTTONS) num_buttons = _AL_MAX_JOYSTICK_BUTTONS; /* XXX use configuration system when we get one */ throttle = -1; #if 0 /* User is allowed to override our simple assumption of which * axis number (kernel) the throttle is located at. */ snprintf(tmp, sizeof(tmp), "throttle_axis_%d", num); throttle = get_config_int("joystick", tmp, -1); if (throttle == -1) { throttle = get_config_int("joystick", "throttle_axis", -1); } #endif /* Each pair of axes is assumed to make up a stick unless it * is the sole remaining axis, or has been user specified, in * which case it is a throttle. */ for (s = 0, a = 0; s < _AL_MAX_JOYSTICK_STICKS && a < num_axes; s++) { if ((a == throttle) || (a == num_axes-1)) { /* One axis throttle. */ joy->parent.info.stick[s].flags = ALLEGRO_JOYFLAG_ANALOGUE; joy->parent.info.stick[s].num_axes = 1; joy->parent.info.stick[s].axis[0].name = "Throttle"; char *name = joy->parent.info.stick[s].axis[0].name; joy->parent.info.stick[s].name = _AL_MALLOC_ATOMIC(strlen(name) + 1); strcpy(joy->parent.info.stick[s].name, name); joy->axis_mapping[a].stick = s; joy->axis_mapping[a].axis = 0; a++; } else { /* Two axis stick. */ joy->parent.info.stick[s].flags = ALLEGRO_JOYFLAG_ANALOGUE; joy->parent.info.stick[s].num_axes = 2; joy->parent.info.stick[s].axis[0].name = "X"; joy->parent.info.stick[s].axis[1].name = "Y"; joy->parent.info.stick[s].name = _AL_MALLOC_ATOMIC (32); snprintf((char *)joy->parent.info.stick[s].name, 32, "Stick %d", s+1); joy->axis_mapping[a].stick = s; joy->axis_mapping[a].axis = 0; a++; joy->axis_mapping[a].stick = s; joy->axis_mapping[a].axis = 1; a++; } } joy->parent.info.num_sticks = s; /* Do the buttons. */ for (b = 0; b < num_buttons; b++) { joy->parent.info.button[b].name = _AL_MALLOC_ATOMIC (32); snprintf((char *)joy->parent.info.button[b].name, 32, "B%d", b+1); } joy->parent.info.num_buttons = num_buttons; } joy->parent.num = num; joy->fd = fd; /* Register the joystick with the fdwatch subsystem. */ _al_unix_start_watching_fd(joy->fd, ljoy_process_new_data, joy); return (ALLEGRO_JOYSTICK *) joy; }
/* 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; }