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