1 /*
2  * Copyright (C) 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 /* aRts driver using the simpler plain C API */
23 
24 #include <unistd.h>
25 #include <artsc.h>
26 
27 static int mharts_init_status;
28 static arts_stream_t mharts_play_stream=NULL,mharts_record_stream=NULL;
29 static Dataformat mharts_format;
30 
mharts_check_init_status(void)31 static gboolean mharts_check_init_status(void)
32 {
33      gchar *c;
34      if (mharts_init_status != 0) {
35 	  c = g_strdup_printf(_("Unable to connect to aRts server: %s"),
36 			      arts_error_text(mharts_init_status));
37 	  user_error(c);
38 	  g_free(c);
39 	  return TRUE;
40      }
41      return FALSE;
42 }
43 
mharts_init(gboolean silent)44 static gboolean mharts_init(gboolean silent)
45 {
46      mharts_init_status = arts_init();
47      if (!silent)
48 	  mharts_check_init_status();
49      return (mharts_init_status == 0);
50 }
51 
mharts_quit(void)52 static void mharts_quit(void)
53 {
54      if (mharts_init_status == 0) arts_free();
55 }
56 
mharts_perror(gchar * msg,int errcode)57 static void mharts_perror(gchar *msg, int errcode)
58 {
59      gchar *c;
60      c = g_strdup_printf("aRts: %s: %s",msg,arts_error_text(errcode));
61      console_message(c);
62      g_free(c);
63 }
64 
mharts_set_nonblock(arts_stream_t stream)65 static void mharts_set_nonblock(arts_stream_t stream)
66 {
67      int i;
68      i = arts_stream_set(stream,ARTS_P_BLOCKING,0);
69      if (i < 0)
70 	  mharts_perror(_("Failed to set non-blocking mode"),i);
71      else if (i != 0)
72 	  console_message(_("Warning: aRts refuses to set non-blocking mode"));
73 }
74 
mharts_output_select_format(Dataformat * format,gboolean silent)75 static gint mharts_output_select_format(Dataformat *format, gboolean silent)
76 {
77      if (format->type != DATAFORMAT_PCM || format->samplesize > 2 ||
78 	 format->channels > 2)
79 	  return -1;
80      mharts_play_stream = arts_play_stream(format->samplerate,
81 					   format->samplesize*8,
82 					   format->channels, "mhwaveedit");
83      if (mharts_play_stream == NULL) {
84 	  if (!silent) {
85 	       user_error(_("Failed to start playback"));
86 	       return 1;
87 	  }
88 	  else
89 	       return -1;
90      }
91      mharts_set_nonblock(mharts_play_stream);
92      memcpy(&mharts_format,format,sizeof(Dataformat));
93      return 0;
94 }
95 
mharts_input_select_format(Dataformat * format,gboolean silent)96 static gint mharts_input_select_format(Dataformat *format, gboolean silent)
97 {
98      if (format->type != DATAFORMAT_PCM || format->samplesize > 2 ||
99 	 format->channels > 2)
100 	  return -1;
101      mharts_record_stream = arts_record_stream(format->samplerate,
102 					       format->samplesize*8,
103 					       format->channels,
104 					       "mhwaveedit_rec");
105      if (mharts_record_stream == NULL) {
106 	  if (!silent) {
107 	       user_error(_("Failed to start recording"));
108 	       return 1;
109 	  } else
110 	       return -1;
111      }
112      mharts_set_nonblock(mharts_record_stream);
113      memcpy(&mharts_format,format,sizeof(Dataformat));
114      return 0;
115 }
116 
mharts_output_suggest_format(Dataformat * format,Dataformat * result)117 static gboolean mharts_output_suggest_format(Dataformat *format,
118 					     Dataformat *result)
119 {
120      if (format->channels > 2)
121 	  return FALSE;
122 
123      memcpy(result,format,sizeof(Dataformat));
124 
125      if (format->type != DATAFORMAT_PCM || format->samplesize > 2) {
126 	  result->type = DATAFORMAT_PCM;
127 	  result->samplesize = 2;
128 	  return TRUE;
129      } else if (format->samplerate != 44100) {
130 	  result->samplerate = 44100;
131 	  return TRUE;
132      } else
133 	  return FALSE;
134 }
135 
mharts_buffer_size(void)136 static gint mharts_buffer_size(void)
137 {
138      int i;
139      i = arts_stream_get(mharts_play_stream,ARTS_P_BUFFER_SIZE);
140      if (i<0) {
141 	  mharts_perror(_("Failed to get buffer size"),i);
142 	  return 65536;
143      }
144      return i;
145 }
146 
mharts_buffer_space(void)147 static gint mharts_buffer_space(void)
148 {
149      int i;
150      i = arts_stream_get(mharts_play_stream,ARTS_P_BUFFER_SPACE);
151      if (i<0) {
152 	  mharts_perror(_("Failed to get buffer space"),i);
153 	  return mharts_buffer_size();
154      }
155      return i;
156 }
157 
mharts_output_stop(gboolean must_flush)158 static gboolean mharts_output_stop(gboolean must_flush)
159 {
160      int i,j,k;
161      float f;
162      if (mharts_play_stream == NULL) return TRUE;
163      if (must_flush) {
164 	  /* Flush buffers */
165 	  k = mharts_buffer_size();
166 	  i = mharts_buffer_space();
167 	  while (i < k) {
168 	       f = (float)(k-i) / (float)mharts_format.samplerate;
169 	       usleep((unsigned int)(f*1000000.0));
170 	       j = i;
171 	       i = mharts_buffer_space();
172 	       /* To avoid eternal loops in case of buggy behaviour */
173 	       if (j == i) break;
174 	  }
175      }
176      arts_close_stream(mharts_play_stream);
177      return must_flush;
178 }
179 
mharts_output_want_data(void)180 static gboolean mharts_output_want_data(void)
181 {
182      return (mharts_buffer_size()>0);
183 }
184 
mharts_output_play(gchar * buffer,guint bufsize)185 static guint mharts_output_play(gchar *buffer, guint bufsize)
186 {
187      gint i,j;
188      i = mharts_buffer_space();
189      if (bufsize == 0) {
190 	  j = mharts_buffer_size() - i;
191 	  if (j<0) return 0;
192 	  else return j;
193      }
194      if (i == 0) return 0;
195      if (bufsize > i) bufsize = i;
196      j = arts_write(mharts_play_stream, buffer, bufsize);
197      if (j<0) {
198 	  mharts_perror(_("write failed"),j);
199 	  return 0;
200      } else
201 	  return j;
202 }
203 
mharts_output_clear_buffers(void)204 static void mharts_output_clear_buffers(void)
205 {
206      arts_stream_t s;
207      Dataformat f;
208      int i;
209      s = mharts_play_stream;
210      memcpy(&f,&mharts_format,sizeof(f));
211      i = mharts_output_select_format(&f,TRUE);
212      if (i == 0) {
213 	  arts_close_stream(s);
214      } else {
215 	  mharts_play_stream = s;
216      }
217 }
218 
mharts_input_stop(void)219 static void mharts_input_stop(void)
220 {
221      arts_close_stream(mharts_record_stream);
222      mharts_record_stream = NULL;
223 }
224 
mharts_input_store(Ringbuf * buffer)225 static void mharts_input_store(Ringbuf *buffer)
226 {
227      gchar buf[4096];
228      int i,j;
229      j = ringbuf_freespace(buffer);
230      if (j > sizeof(buf)) j = sizeof(buf);
231      j -= j % mharts_format.samplebytes;
232      i = arts_read(mharts_record_stream, buf, j);
233      if (i < 0)
234 	  mharts_perror(_("read failed"),i);
235 }
236