/[svn]/linuxsampler/trunk/src/alsaio.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/alsaio.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (show annotations) (download)
Mon Feb 16 19:30:42 2004 UTC (20 years, 2 months ago) by schoenebeck
File size: 11031 byte(s)
* implemented bidirectional voice state transition, means voice state can
  switch arbitrary times between 'Sustained'<-->'Released' within it's life
  time, thus the release process of a voice can be cancelled
* src/eg_vca.cpp: extended envelope generator by additional states
  ('Attack_Hold', 'Decay_1' and 'Decay_2')
* applied patch from Vladimir Senkov which adds new command line parameters
  ('--jackout', '--alsaout' and '--samplerate')
* configure.in: fixed compiler warning

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "alsaio.h"
24
25 AlsaIO::AlsaIO() : AudioIO(), Thread(true, 1, 0) {
26 pcm_handle = NULL;
27 pOutputBuffer = NULL;
28 stream = SND_PCM_STREAM_PLAYBACK;
29 }
30
31 int AlsaIO::Initialize(uint Channels, uint Samplerate, uint Fragments, uint FragmentSize, String Card) {
32 this->uiChannels = Channels;
33 this->uiSamplerate = Samplerate;
34 this->uiMaxSamplesPerCycle = FragmentSize;
35 this->bInterleaved = true;
36
37 if (HardwareParametersSupported(Channels, Samplerate, Fragments, FragmentSize)) {
38 pcm_name = "hw:" + Card;
39 }
40 else {
41 printf("Warning: your soundcard doesn't support chosen hardware parameters; ");
42 printf("trying to compensate support lack with plughw...");
43 fflush(stdout);
44 pcm_name = "plughw:" + Card;
45 }
46
47 int err;
48
49 snd_pcm_hw_params_alloca(&hwparams); // Allocate the snd_pcm_hw_params_t structure on the stack.
50
51 /* Open PCM. The last parameter of this function is the mode. */
52 /* If this is set to 0, the standard mode is used. Possible */
53 /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
54 /* If SND_PCM_NONBLOCK is used, read / write access to the */
55 /* PCM device will return immediately. If SND_PCM_ASYNC is */
56 /* specified, SIGIO will be emitted whenever a period has */
57 /* been completely processed by the soundcard. */
58 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
59 fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_name.c_str(), snd_strerror(err));
60 return -1;
61 }
62
63 if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
64 fprintf(stderr, "Error, cannot initialize hardware parameter structure: %s.\n", snd_strerror(err));
65 return -1;
66 }
67
68 /* Set access type. This can be either */
69 /* SND_PCM_ACCESS_RW_INTERLEAVED or */
70 /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
71 if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
72 fprintf(stderr, "Error snd_pcm_hw_params_set_access: %s.\n", snd_strerror(err));
73 return -1;
74 }
75
76 /* Set sample format */
77 #if WORDS_BIGENDIAN
78 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0) {
79 #else // little endian
80 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) {
81 #endif
82 fprintf(stderr, "Error setting sample format. : %s\n", snd_strerror(err));
83 return -1;
84 }
85
86 int dir = 0;
87
88 /* Set sample rate. If the exact rate is not supported */
89 /* by the hardware, use nearest possible rate. */
90 #if ALSA_MAJOR > 0
91 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &Samplerate, &dir)) < 0) {
92 #else
93 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, Samplerate, &dir)) < 0) {
94 #endif
95 fprintf(stderr, "Error setting sample rate. : %s\n", snd_strerror(err));
96 return -1;
97 }
98
99 if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, Channels)) < 0) {
100 fprintf(stderr, "Error setting number of channels. : %s\n", snd_strerror(err));
101 return -1;
102 }
103
104 /* Set number of periods. Periods used to be called fragments. */
105 if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
106 fprintf(stderr, "Error setting number of periods. : %s\n", snd_strerror(err));
107 return -1;
108 }
109
110 /* Set buffer size (in frames). The resulting latency is given by */
111 /* latency = periodsize * periods / (rate * bytes_per_frame) */
112 if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
113 fprintf(stderr, "Error setting buffersize. : %s\n", snd_strerror(err));
114 return -1;
115 }
116
117 /* Apply HW parameter settings to */
118 /* PCM device and prepare device */
119 if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
120 fprintf(stderr, "Error setting HW params. : %s\n", snd_strerror(err));
121 return -1;
122 }
123
124 if (snd_pcm_sw_params_malloc(&swparams) != 0) {
125 fprintf(stderr, "Error in snd_pcm_sw_params_malloc. : %s\n", snd_strerror(err));
126 return -1;
127 }
128
129 if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
130 fprintf(stderr, "Error in snd_pcm_sw_params_current. : %s\n", snd_strerror(err));
131 return -1;
132 }
133
134 if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
135 fprintf(stderr, "Error in snd_pcm_sw_params_set_stop_threshold. : %s\n", snd_strerror(err));
136 return -1;
137 }
138
139 if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
140 fprintf(stderr, "Error in snd_pcm_sw_params. : %s\n", snd_strerror(err));
141 return -1;
142 }
143
144 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
145 fprintf(stderr, "Error snd_pcm_prepare : %s\n", snd_strerror(err));
146 return -1;
147 }
148
149 // allocate the audio output buffer
150 pOutputBuffer = new int16_t[Channels * FragmentSize];
151
152 this->bInitialized = true;
153
154 return 0;
155 }
156
157 /**
158 * Checks if sound card supports the chosen parameters.
159 *
160 * @returns true if hardware supports it
161 */
162 bool AlsaIO::HardwareParametersSupported(uint channels, int samplerate, uint numfragments, uint fragmentsize) {
163 pcm_name = "hw:0,0";
164 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;
165 snd_pcm_hw_params_alloca(&hwparams);
166 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
167 snd_pcm_close(pcm_handle);
168 return false;
169 }
170 if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
171 snd_pcm_close(pcm_handle);
172 return false;
173 }
174 #if WORDS_BIGENDIAN
175 if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0) {
176 #else // little endian
177 if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
178 #endif
179 snd_pcm_close(pcm_handle);
180 return false;
181 }
182 int dir = 0;
183 if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
184 snd_pcm_close(pcm_handle);
185 return false;
186 }
187 if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
188 snd_pcm_close(pcm_handle);
189 return false;
190 }
191 if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
192 snd_pcm_close(pcm_handle);
193 return false;
194 }
195 if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
196 snd_pcm_close(pcm_handle);
197 return false;
198 }
199
200 snd_pcm_close(pcm_handle);
201 return true;
202 }
203
204 void AlsaIO::Activate() {
205 this->StartThread();
206 }
207
208 int AlsaIO::Main() {
209 if (!pEngine) {
210 fprintf(stderr, "AlsaIO: No Sampler Engine assigned, exiting.\n");
211 exit(EXIT_FAILURE);
212 }
213 if (!bInitialized) {
214 fprintf(stderr, "AlsaIO: Not yet intitialized, exiting.\n");
215 exit(EXIT_FAILURE);
216 }
217
218 while (true) {
219
220 // let the engine render audio for the current audio fragment
221 pEngine->RenderAudio(uiMaxSamplesPerCycle);
222
223
224 // check clipping in the audio sum, convert to sample_type
225 // (from 32bit to 16bit sample) and copy to output buffer
226 float sample_point; uint o = 0;
227 for (uint s = 0; s < uiMaxSamplesPerCycle; s++) {
228 for (uint c = 0; c < uiChannels; c++) {
229 sample_point = pEngine->GetAudioSumBuffer(c)[s] * pEngine->Volume;
230 if (sample_point < -32768.0) sample_point = -32768.0;
231 if (sample_point > 32767.0) sample_point = 32767.0;
232 this->pOutputBuffer[o++] = (int32_t) sample_point;
233 }
234 }
235
236
237 // output sound
238 int res = Output();
239 if (res < 0) {
240 fprintf(stderr, "AlsaIO: Audio output error, exiting.\n");
241 exit(EXIT_FAILURE);
242 }
243 }
244 }
245
246 /**
247 * Will be called after every audio fragment cycle, to output the audio data
248 * of the current fragment to the soundcard.
249 *
250 * @returns 0 on success
251 */
252 int AlsaIO::Output() {
253 int err = snd_pcm_writei(pcm_handle, pOutputBuffer, uiMaxSamplesPerCycle);
254 if (err < 0) {
255 fprintf(stderr, "Error snd_pcm_writei failed. : %s\n", snd_strerror(err));
256 return -1;
257 }
258 return 0;
259 }
260
261 void AlsaIO::Close() {
262 if (bInitialized) {
263 //dmsg(0,("Stopping Alsa Thread..."));
264 //StopThread(); //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
265 //dmsg(0,("OK\n"));
266 if (pcm_handle) {
267 //FIXME: currently commented out due to segfault
268 //snd_pcm_close(pcm_handle);
269 pcm_handle = NULL;
270 }
271 if (pOutputBuffer) {
272 //FIXME: currently commented out due to segfault
273 //delete[] pOutputBuffer;
274 pOutputBuffer = NULL;
275 }
276 bInitialized = false;
277 }
278 }
279
280 void* AlsaIO::GetInterleavedOutputBuffer() {
281 return pOutputBuffer;
282 }
283
284 void* AlsaIO::GetChannelOutputBufer(uint Channel) {
285 fprintf(stderr, "AlsaIO::GetChannelOutputBufer(): Only interleaved access allowed so far, exiting.\n");
286 exit(EXIT_FAILURE);
287 // just to avoid compiler warnings
288 return NULL;
289 }

  ViewVC Help
Powered by ViewVC