1 /*
2  * Copyright (C) 2002 2003 2005, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mhWaveEdit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <gtk/gtk.h>
25 #include "SDL.h"
26 #include "sound.h"
27 #include "ringbuf.h"
28 #include "gettext.h"
29 
30 static struct {
31      Ringbuf *output_buffer;
32 } sdl_data;
33 
sdl_init(gboolean silent)34 static gboolean sdl_init(gboolean silent)
35 {
36      gchar *c;
37      if (SDL_Init(SDL_INIT_AUDIO) == -1) {
38 	  c = g_strdup_printf(_("Could not initialize SDL: %s"),
39 			      SDL_GetError());
40 	  console_message(c);
41 	  g_free(c);
42 	  exit(1);
43      }
44      sdl_data.output_buffer = ringbuf_new (
45 	  inifile_get_guint32(INI_SETTING_SOUNDBUFSIZE,
46                               INI_SETTING_SOUNDBUFSIZE_DEFAULT) );
47      return TRUE;
48 }
49 
sdl_quit(void)50 static void sdl_quit(void)
51 {
52      SDL_Quit();
53 }
54 
sdl_output_callback(void * userdata,Uint8 * stream,int len)55 static void sdl_output_callback(void *userdata, Uint8 *stream, int len)
56 {
57      guint32 ui;
58      ui = ringbuf_dequeue ( sdl_data.output_buffer, stream, len );
59      if (ui < len) memset(stream+ui, 0, len-ui);
60 }
61 
sdl_output_select_format(Dataformat * format,gboolean silent,GVoidFunc ready_func)62 static gint sdl_output_select_format(Dataformat *format, gboolean silent,
63 				     GVoidFunc ready_func)
64 {
65      gchar *c;
66      SDL_AudioSpec desired;
67      if (format->type == DATAFORMAT_FLOAT || format->samplesize > 2 ||
68 	 format->channels > 2) return -1;
69      desired.freq = format->samplerate;
70      if (format->sign) {
71 	  if (format->samplesize == 1)
72 	       desired.format = AUDIO_S8;
73 	  else if (format->bigendian)
74 	       desired.format = AUDIO_S16MSB;
75 	  else
76 	       desired.format = AUDIO_S16LSB;
77      } else {
78 	  if (format->samplesize == 1)
79 	       desired.format = AUDIO_U8;
80 	  else if (format->bigendian)
81 	       desired.format = AUDIO_U16MSB;
82 	  else
83 	       desired.format = AUDIO_U16LSB;
84      }
85      desired.channels = format->channels;
86      desired.samples = 512;
87      desired.callback = sdl_output_callback;
88      if (SDL_OpenAudio(&desired,NULL) < 0) {
89 	  c = g_strdup_printf(_("SDL: Couldn't open audio: %s"),
90 			      SDL_GetError());
91 	  console_message(c);
92 	  g_free(c);
93 	  return -1;
94      }
95      return 0;
96 }
97 
sdl_output_stop(gboolean must_flush)98 static gboolean sdl_output_stop(gboolean must_flush)
99 {
100      if (must_flush)
101 	  while (ringbuf_available(sdl_data.output_buffer) > 0) do_yield(TRUE);
102      if (SDL_GetAudioStatus() != SDL_AUDIO_STOPPED)
103 	  SDL_CloseAudio();
104      ringbuf_drain(sdl_data.output_buffer);
105      return must_flush;
106 }
107 
sdl_output_clear_buffers(void)108 static void sdl_output_clear_buffers(void)
109 {
110      SDL_PauseAudio(1);
111      ringbuf_drain(sdl_data.output_buffer);
112 }
113 
sdl_output_play(gchar * buffer,guint bufsize)114 static guint sdl_output_play(gchar *buffer, guint bufsize)
115 {
116      guint i;
117      if (!bufsize) return ringbuf_available(sdl_data.output_buffer);
118      SDL_LockAudio();
119      /* printf("output_play: before: %d,%d\n",ringbuf_available(
120 	sdl_data.output_buffer),ringbuf_freespace(sdl_data.output_buffer)); */
121      i = (guint)ringbuf_enqueue( sdl_data.output_buffer, buffer, bufsize );
122      /* printf("output_play: after: %d,%d\n",
123 	ringbuf_available(sdl_data.output_buffer),
124 	ringbuf_freespace(sdl_data.output_buffer)); */
125      SDL_UnlockAudio();
126      if (SDL_GetAudioStatus() == SDL_AUDIO_PAUSED)
127 	  SDL_PauseAudio(0);
128      return i;
129 }
130 
sdl_output_want_data(void)131 static gboolean sdl_output_want_data(void)
132 {
133      return !ringbuf_isfull(sdl_data.output_buffer);
134 }
135 
136