Mercurial > hg > xemacs-beta
view src/alsaplay.c @ 5077:d372b17f63ce
clean up toolbar/gutter edge geometry
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-02-25 Ben Wing <ben@xemacs.org>
* EmacsFrame.c (EmacsFrameSetValues):
* frame-impl.h:
* frame-impl.h (struct frame):
* frame-impl.h (FRAME_THEORETICAL_TOP_TOOLBAR_HEIGHT):
* frame-impl.h (FRAME_THEORETICAL_TOP_TOOLBAR_BORDER_WIDTH):
* frame-impl.h (FRAME_REAL_TOP_TOOLBAR_HEIGHT):
* frame-impl.h (FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH):
* frame-impl.h (FRAME_REAL_TOP_TOOLBAR_VISIBLE):
* frame-impl.h (FRAME_REAL_TOP_TOOLBAR_BOUNDS):
* frame.h:
* frame.h (enum edge_pos):
* gutter.c:
* gutter.c (get_gutter_coords):
* gutter.c (display_boxes_in_gutter_p):
* gutter.c (construct_window_gutter_spec):
* gutter.c (calculate_gutter_size_from_display_lines):
* gutter.c (calculate_gutter_size):
* gutter.c (output_gutter):
* gutter.c (clear_gutter):
* gutter.c (mark_gutters):
* gutter.c (gutter_extent_signal_changed_region_maybe):
* gutter.c (update_gutter_geometry):
* gutter.c (update_frame_gutter_geometry):
* gutter.c (update_frame_gutters):
* gutter.c (reset_gutter_display_lines):
* gutter.c (redraw_exposed_gutter):
* gutter.c (redraw_exposed_gutters):
* gutter.c (free_frame_gutters):
* gutter.c (decode_gutter_position):
* gutter.c (Fset_default_gutter_position):
* gutter.c (Fgutter_pixel_width):
* gutter.c (Fgutter_pixel_height):
* gutter.c (recompute_overlaying_specifier):
* gutter.c (gutter_specs_changed_1):
* gutter.c (gutter_specs_changed):
* gutter.c (top_gutter_specs_changed):
* gutter.c (bottom_gutter_specs_changed):
* gutter.c (left_gutter_specs_changed):
* gutter.c (right_gutter_specs_changed):
* gutter.c (gutter_geometry_changed_in_window):
* gutter.c (init_frame_gutters):
* gutter.c (specifier_vars_of_gutter):
* gutter.h:
* gutter.h (WINDOW_REAL_TOP_GUTTER_BOUNDS):
* gutter.h (FRAME_TOP_GUTTER_BOUNDS):
* lisp.h (enum edge_style):
* native-gtk-toolbar.c:
* native-gtk-toolbar.c (gtk_output_toolbar):
* native-gtk-toolbar.c (gtk_clear_toolbar):
* native-gtk-toolbar.c (gtk_output_frame_toolbars):
* native-gtk-toolbar.c (gtk_initialize_frame_toolbars):
* toolbar-msw.c:
* toolbar-msw.c (TOOLBAR_HANDLE):
* toolbar-msw.c (allocate_toolbar_item_id):
* toolbar-msw.c (mswindows_clear_toolbar):
* toolbar-msw.c (mswindows_output_toolbar):
* toolbar-msw.c (mswindows_move_toolbar):
* toolbar-msw.c (mswindows_redraw_exposed_toolbars):
* toolbar-msw.c (mswindows_initialize_frame_toolbars):
* toolbar-msw.c (mswindows_output_frame_toolbars):
* toolbar-msw.c (mswindows_clear_frame_toolbars):
* toolbar-msw.c (DELETE_TOOLBAR):
* toolbar-msw.c (mswindows_free_frame_toolbars):
* toolbar-msw.c (mswindows_get_toolbar_button_text):
* toolbar-xlike.c:
* toolbar-xlike.c (__prepare_button_area):
* toolbar-xlike.c (XLIKE_OUTPUT_BUTTONS_LOOP):
* toolbar-xlike.c (xlike_output_toolbar):
* toolbar-xlike.c (xlike_clear_toolbar):
* toolbar-xlike.c (xlike_output_frame_toolbars):
* toolbar-xlike.c (xlike_clear_frame_toolbars):
* toolbar-xlike.c (xlike_redraw_exposed_toolbar):
* toolbar-xlike.c (xlike_redraw_exposed_toolbars):
* toolbar-xlike.c (xlike_redraw_frame_toolbars):
* toolbar.c:
* toolbar.c (decode_toolbar_position):
* toolbar.c (Fset_default_toolbar_position):
* toolbar.c (mark_frame_toolbar_buttons_dirty):
* toolbar.c (compute_frame_toolbar_buttons):
* toolbar.c (set_frame_toolbar):
* toolbar.c (compute_frame_toolbars_data):
* toolbar.c (update_frame_toolbars_geometry):
* toolbar.c (init_frame_toolbars):
* toolbar.c (get_toolbar_coords):
* toolbar.c (CHECK_TOOLBAR):
* toolbar.c (toolbar_buttons_at_pixpos):
* toolbar.c (CTB_ERROR):
* toolbar.c (recompute_overlaying_specifier):
* toolbar.c (specifier_vars_of_toolbar):
* toolbar.h:
* toolbar.h (SET_TOOLBAR_WAS_VISIBLE_FLAG):
Create new enum edge_pos with TOP_EDGE, BOTTOM_EDGE, LEFT_EDGE,
RIGHT_EDGE; subsume TOP_BORDER, TOP_GUTTER, enum toolbar_pos,
enum gutter_pos, etc.
Create EDGE_POS_LOOP, subsuming GUTTER_POS_LOOP.
Create NUM_EDGES, use in many places instead of hardcoded '4'.
Instead of top_toolbar_was_visible, bottom_toolbar_was_visible,
etc. make an array toolbar_was_visible[NUM_EDGES]. This increases
the frame size by 15 bytes or so (could be 3 if we use Boolbytes)
but hardly seems w to matter -- frames are heavy weight objects
anyway. Same with top_gutter_was_visible, etc.
Remove duplicated SET_TOOLBAR_WAS_VISIBLE_FLAG and put defn in
one place (toolbar.h).
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Thu, 25 Feb 2010 04:45:13 -0600 |
parents | 16112448d484 |
children | 308d34e9f07d |
line wrap: on
line source
/* Play sound with the ALSA library Copyright (C) 2006 Jerry James. This file is part of XEmacs. XEmacs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. XEmacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Synched up with: Not in FSF. */ /* TODO: Support asynchronous sound playing; see the NAS support in sound.c */ #include <config.h> #include "lisp.h" #include "sound.h" #include "sysfile.h" /* We can't just include <alsa/asoundlib.h> because it tries to redefine * several symbols defined by the previous header files. */ #include <alsa/version.h> #include <alsa/input.h> #include <alsa/output.h> #include <alsa/conf.h> #include <alsa/global.h> #include <alsa/pcm.h> #include <alsa/error.h> #include <alsa/hwdep.h> #include <alsa/rawmidi.h> #include <alsa/control.h> #include <alsa/mixer.h> #define ALSA_VERSION(major,minor,sub) (((major)<<16) | ((minor)<<8)| (sub)) struct mixer_state { snd_mixer_t *mixer; snd_mixer_elem_t *vol_ctl; /* Which channels need the old volume restored */ int reset_front_left; int reset_front_center; int reset_front_right; int reset_rear_left; int reset_rear_right; int reset_woofer; #if SND_LIB_VERSION >= ALSA_VERSION (1, 0, 10) int reset_rear_center; int reset_side_left; int reset_side_right; #endif /* Old volumes for the channels */ long front_left_vol; long front_center_vol; long front_right_vol; long rear_left_vol; long rear_right_vol; long woofer_vol; #if SND_LIB_VERSION >= ALSA_VERSION (1, 0, 10) long rear_center_vol; long side_left_vol; long side_right_vol; #endif }; /* Assemble a machine half-word in little-endian order */ #define HALF_LE(arr,start) (arr[start] + (arr[start + 1] << 8)) /* Assemble a machine word in little-endian order */ #define WORD_LE(arr,start) (arr[start] + (arr[start + 1] << 8) + \ (arr[start + 2] << 16) + (arr[start + 3] << 24)) /* Assemble a machine word in big-endian order */ #define WORD_BE(arr,start) ((arr[start] << 24) + (arr[start + 1] << 16) + \ (arr[start + 2] << 8) + arr[start + 3]) /* This function was inspired by miscplay.c. * Examine sound data to determine its format. * * TODO: Detect other formats that ALSA can play, such as GSM and MPEG. */ static snd_pcm_format_t analyze_format (const Binbyte *format, int *speed, int *tracks) { if (!memcmp (format, "Creative Voice File\x1A\x1A\x00", 22) && HALF_LE (format, 22) == ((0x1233 - HALF_LE (format, 24)) & 0xFFFF)) { /* VOC */ *speed = 8000; *tracks = 2; return SND_PCM_FORMAT_U8; } else if (!memcmp (format, "RIFF", 4) && !memcmp (format + 8, "WAVEfmt ", 8)) { /* WAVE */ *speed = WORD_LE (format, 24); *tracks = format[22]; return format[32] / format[22] == 1 ? SND_PCM_FORMAT_U8 : SND_PCM_FORMAT_S16_LE; } else if (!memcmp (format, ".snd", 4)) { /* Sun/NeXT Audio (big endian) */ if (WORD_BE (format, 4) < 24) { *speed = 8000; *tracks = 1; return SND_PCM_FORMAT_MU_LAW; } *speed = WORD_BE (format, 16); *tracks = format[23]; if (!memcmp (format + 12, "\000\000\000", 3)) { switch (format[15]) { case 1: case 17: case 29: return SND_PCM_FORMAT_MU_LAW; case 2: return SND_PCM_FORMAT_S8; case 3: return SND_PCM_FORMAT_S16_BE; case 4: return SND_PCM_FORMAT_S24_BE; case 5: return SND_PCM_FORMAT_S32_BE; case 23: case 24: case 25: case 26: return SND_PCM_FORMAT_IMA_ADPCM; case 27: return SND_PCM_FORMAT_A_LAW; default: break; } } return SND_PCM_FORMAT_UNKNOWN; } else if (!memcmp (format, ".sd", 4)) { /* DEC Audio (little endian) */ if (WORD_LE (format, 4) < 24) { *speed = 8000; *tracks = 1; return SND_PCM_FORMAT_MU_LAW; } *speed = WORD_LE (format, 16); *tracks = format[20]; if (!memcmp (format + 13, "\000\000\000", 3)) { switch (format[12]) { case 1: case 17: case 29: return SND_PCM_FORMAT_MU_LAW; case 2: return SND_PCM_FORMAT_S8; case 3: return SND_PCM_FORMAT_S16_LE; case 4: return SND_PCM_FORMAT_S24_LE; case 5: return SND_PCM_FORMAT_S32_LE; case 23: case 24: case 25: case 26: return SND_PCM_FORMAT_IMA_ADPCM; case 27: return SND_PCM_FORMAT_A_LAW; default: break; } } return SND_PCM_FORMAT_UNKNOWN; } else { /* We don't know what it is. Guess that it is mono audio in unsigned * byte format. Maybe we should error if we reach this point. */ *speed = 8000; *tracks = 1; return SND_PCM_FORMAT_U8; } } /* Set the volume: if any errors occur, we accept the existing volume */ static void set_volume (struct mixer_state *mix, int volume) { snd_mixer_selem_id_t *volume_id; long min_vol, max_vol, dev_vol; if (snd_mixer_open (&mix->mixer, 0) < 0) return; if (snd_mixer_attach (mix->mixer, "default") < 0) return; if (snd_mixer_selem_register (mix->mixer, NULL, NULL) < 0) return; if (snd_mixer_load (mix->mixer) < 0) return; snd_mixer_selem_id_alloca (&volume_id); snd_mixer_selem_id_set_name (volume_id, "PCM"); if ((mix->vol_ctl = snd_mixer_find_selem (mix->mixer, volume_id)) == NULL) { snd_mixer_selem_id_set_name (volume_id, "Master"); if ((mix->vol_ctl = snd_mixer_find_selem (mix->mixer, volume_id)) == NULL) return; } /* Translate the Lisp volume range to the device volume range */ #if SND_LIB_VERSION < ALSA_VERSION (1, 0, 10) snd_mixer_selem_get_playback_volume_range (mix->vol_ctl, &min_vol, &max_vol); #else if (snd_mixer_selem_get_playback_volume_range (mix->vol_ctl, &min_vol, &max_vol) < 0) return; #endif dev_vol = volume * (max_vol - min_vol) / 100 + min_vol; /* Record the old volumes */ if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_FRONT_LEFT, &mix->front_left_vol) >= 0) mix->reset_front_left = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_FRONT_CENTER, &mix->front_center_vol) >= 0) mix->reset_front_center = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_FRONT_RIGHT, &mix->front_right_vol) >= 0) mix->reset_front_right = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_REAR_LEFT, &mix->rear_left_vol) >= 0) mix->reset_rear_left = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_REAR_RIGHT, &mix->rear_right_vol) >= 0) mix->reset_rear_right = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_WOOFER, &mix->woofer_vol) >= 0) mix->reset_woofer = 1; #if SND_LIB_VERSION >= ALSA_VERSION (1, 0, 10) if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_REAR_CENTER, &mix->rear_center_vol) >= 0) mix->reset_rear_center = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_SIDE_LEFT, &mix->side_left_vol) >= 0) mix->reset_side_left = 1; if (snd_mixer_selem_get_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_SIDE_RIGHT, &mix->side_right_vol) >= 0) mix->reset_side_right = 1; #endif /* Set the volume */ snd_mixer_selem_set_playback_volume_all (mix->vol_ctl, dev_vol); } static void reset_volume (const struct mixer_state *mix) { if (mix->reset_front_left) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_FRONT_LEFT, mix->front_left_vol); if (mix->reset_front_center) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_FRONT_CENTER, mix->front_center_vol); if (mix->reset_front_right) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_FRONT_RIGHT, mix->front_right_vol); if (mix->reset_rear_left) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_REAR_LEFT, mix->rear_left_vol); if (mix->reset_rear_right) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_REAR_RIGHT, mix->rear_right_vol); if (mix->reset_woofer) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_WOOFER, mix->woofer_vol); #if SND_LIB_VERSION >= ALSA_VERSION (1, 0, 10) if (mix->reset_rear_center) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_REAR_CENTER, mix->rear_center_vol); if (mix->reset_side_left) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_SIDE_LEFT, mix->side_left_vol); if (mix->reset_side_right) snd_mixer_selem_set_playback_volume (mix->vol_ctl, SND_MIXER_SCHN_SIDE_RIGHT, mix->side_right_vol); #endif snd_mixer_close (mix->mixer); } int alsa_play_sound_data (const Binbyte *data, int length, int volume) { snd_pcm_t *pcm_handle; snd_pcm_hw_params_t *hwparams; snd_pcm_format_t format; struct mixer_state mix; int speed, tracks, err; /* Set the PCM parameters */ if ((err = snd_pcm_open (&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) goto error_pcm_open; snd_pcm_hw_params_alloca (&hwparams); if ((err = snd_pcm_hw_params_any (pcm_handle, hwparams)) < 0) goto error_pcm; format = analyze_format (data, &speed, &tracks); if ((err = snd_pcm_hw_params_set_access (pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) goto error_pcm; if ((err = snd_pcm_hw_params_set_format (pcm_handle, hwparams, format)) < 0) goto error_pcm; if ((err = snd_pcm_hw_params_set_rate (pcm_handle, hwparams, speed, 0)) < 0) goto error_pcm; if ((err = snd_pcm_hw_params_set_channels (pcm_handle, hwparams, tracks)) < 0) goto error_pcm; if ((err = snd_pcm_hw_params (pcm_handle, hwparams)) < 0) goto error_pcm; /* Set the volume */ memset (&mix, 0, sizeof (mix)); set_volume (&mix, volume); /* Play the sound */ if ((err = snd_pcm_writei (pcm_handle, data, length)) < 0) goto error_mixer; /* Put the volume back the way it used to be */ reset_volume (&mix); /* Release resources */ snd_pcm_close (pcm_handle); return 1; error_mixer: reset_volume (&mix); error_pcm: snd_pcm_close (pcm_handle); error_pcm_open: sound_perror (snd_strerror (err)); return 0; } /* Read the sound file into an internal buffer, then call * alsa_play_sound_data. */ int alsa_play_sound_file (const Extbyte *sound_file, int volume) { Binbyte *data; int fd, retval; struct stat st; fd = retry_open (sound_file, O_RDONLY, 0); if (fd < 0) { sound_perror (sound_file); return 0; } qxe_fstat (fd, &st); data = xnew_array (Binbyte, st.st_size); retry_read (fd, data, st.st_size); retry_close (fd); retval = alsa_play_sound_data (data, st.st_size, volume); xfree (data); return retval; }