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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations) (download)
Fri Jan 2 00:02:56 2004 UTC (20 years, 3 months ago) by schoenebeck
File size: 9446 byte(s)
* src/gig.cpp: fixed looping informations ('LoopStart', 'LoopEnd' and
  'LoopSize')
* src/voice.cpp: pitch sample according to keyboard position only if
  keyrange > 1 key, this was the reason that some gig files were horrible
  detuned
* src/audioio.cpp: bigendian specific fix
* src/ringbuffer.h: removed kernel header dependency by adding own atomic.h

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 "audioio.h"
24
25 AudioIO::AudioIO() {
26 pcm_handle = NULL;
27 pOutputBuffer = NULL;
28 Initialized = false;
29 stream = SND_PCM_STREAM_PLAYBACK;
30 }
31
32 AudioIO::~AudioIO() {
33 Close();
34 }
35
36 int AudioIO::Initialize(uint channels, uint samplerate, uint numfragments, uint fragmentsize) {
37 this->Channels = channels;
38 this->Samplerate = samplerate;
39 this->Fragments = numfragments;
40 this->FragmentSize = fragmentsize;
41
42 if (HardwareParametersSupported(channels, samplerate, numfragments, fragmentsize)) {
43 pcm_name = "hw:0,0";
44 }
45 else {
46 printf("Warning: your soundcard doesn't support chosen hardware parameters; ");
47 printf("trying to compensate support lack with plughw...");
48 fflush(stdout);
49 pcm_name = "plughw:0,0";
50 }
51
52 int err;
53
54 snd_pcm_hw_params_alloca(&hwparams); // Allocate the snd_pcm_hw_params_t structure on the stack.
55
56 /* Open PCM. The last parameter of this function is the mode. */
57 /* If this is set to 0, the standard mode is used. Possible */
58 /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
59 /* If SND_PCM_NONBLOCK is used, read / write access to the */
60 /* PCM device will return immediately. If SND_PCM_ASYNC is */
61 /* specified, SIGIO will be emitted whenever a period has */
62 /* been completely processed by the soundcard. */
63 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
64 fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_name.c_str(), snd_strerror(err));
65 return EXIT_FAILURE;
66 }
67
68 if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
69 fprintf(stderr, "Error, cannot initialize hardware parameter structure: %s.\n", snd_strerror(err));
70 return EXIT_FAILURE;
71 }
72
73 /* Set access type. This can be either */
74 /* SND_PCM_ACCESS_RW_INTERLEAVED or */
75 /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
76 if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
77 fprintf(stderr, "Error snd_pcm_hw_params_set_access: %s.\n", snd_strerror(err));
78 return EXIT_FAILURE;
79 }
80
81 /* Set sample format */
82 #if WORDS_BIGENDIAN
83 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0) {
84 #else // little endian
85 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) {
86 #endif
87 fprintf(stderr, "Error setting sample format. : %s\n", snd_strerror(err));
88 return EXIT_FAILURE;
89 }
90
91 int dir = 0;
92
93 /* Set sample rate. If the exact rate is not supported */
94 /* by the hardware, use nearest possible rate. */
95 #if ALSA_MAJOR > 0
96 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &samplerate, &dir)) < 0) {
97 #else
98 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, samplerate, &dir)) < 0) {
99 #endif
100 fprintf(stderr, "Error setting sample rate. : %s\n", snd_strerror(err));
101 return EXIT_FAILURE;
102 }
103
104 if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels)) < 0) {
105 fprintf(stderr, "Error setting number of channels. : %s\n", snd_strerror(err));
106 return EXIT_FAILURE;
107 }
108
109 /* Set number of periods. Periods used to be called fragments. */
110 if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, numfragments, dir)) < 0) {
111 fprintf(stderr, "Error setting number of periods. : %s\n", snd_strerror(err));
112 return EXIT_FAILURE;
113 }
114
115 /* Set buffer size (in frames). The resulting latency is given by */
116 /* latency = periodsize * periods / (rate * bytes_per_frame) */
117 if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments))) < 0) {
118 fprintf(stderr, "Error setting buffersize. : %s\n", snd_strerror(err));
119 return EXIT_FAILURE;
120 }
121
122 /* Apply HW parameter settings to */
123 /* PCM device and prepare device */
124 if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
125 fprintf(stderr, "Error setting HW params. : %s\n", snd_strerror(err));
126 return EXIT_FAILURE;
127 }
128
129 if (snd_pcm_sw_params_malloc(&swparams) != 0) {
130 fprintf(stderr, "Error in snd_pcm_sw_params_malloc. : %s\n", snd_strerror(err));
131 return EXIT_FAILURE;
132 }
133
134 if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
135 fprintf(stderr, "Error in snd_pcm_sw_params_current. : %s\n", snd_strerror(err));
136 return EXIT_FAILURE;
137 }
138
139 if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
140 fprintf(stderr, "Error in snd_pcm_sw_params_set_stop_threshold. : %s\n", snd_strerror(err));
141 return EXIT_FAILURE;
142 }
143
144 if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
145 fprintf(stderr, "Error in snd_pcm_sw_params. : %s\n", snd_strerror(err));
146 return EXIT_FAILURE;
147 }
148
149 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
150 fprintf(stderr, "Error snd_pcm_prepare : %s\n", snd_strerror(err));
151 return EXIT_FAILURE;
152 }
153
154 // allocate the audio output buffer
155 pOutputBuffer = new int16_t[channels * fragmentsize];
156
157 this->Initialized = true;
158
159 return EXIT_SUCCESS;
160 }
161
162 /**
163 * Checks if sound card supports the chosen parameters.
164 *
165 * @returns true if hardware supports it
166 */
167 bool AudioIO::HardwareParametersSupported(uint channels, int samplerate, uint numfragments, uint fragmentsize) {
168 pcm_name = "hw:0,0";
169 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;
170 snd_pcm_hw_params_alloca(&hwparams);
171 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
172 snd_pcm_close(pcm_handle);
173 return false;
174 }
175 if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
176 snd_pcm_close(pcm_handle);
177 return false;
178 }
179 #if WORDS_BIGENDIAN
180 if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0) {
181 #else // little endian
182 if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
183 #endif
184 snd_pcm_close(pcm_handle);
185 return false;
186 }
187 int dir = 0;
188 if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
189 snd_pcm_close(pcm_handle);
190 return false;
191 }
192 if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
193 snd_pcm_close(pcm_handle);
194 return false;
195 }
196 if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
197 snd_pcm_close(pcm_handle);
198 return false;
199 }
200 if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
201 snd_pcm_close(pcm_handle);
202 return false;
203 }
204
205 snd_pcm_close(pcm_handle);
206 return true;
207 }
208
209 /**
210 * Will be called by the audio engine after every audio fragment cycle, to
211 * output the audio data of the current fragment to the soundcard.
212 *
213 * @returns 0 on success
214 */
215 int AudioIO::Output() {
216 int err = snd_pcm_writei(pcm_handle, pOutputBuffer, FragmentSize);
217 if (err < 0) {
218 fprintf(stderr, "Error snd_pcm_writei failed. : %s\n", snd_strerror(err));
219 return EXIT_FAILURE;
220 }
221 return EXIT_SUCCESS;
222 }
223
224 void AudioIO::Close(void) {
225 if (Initialized) {
226 if (pcm_handle) {
227 //FIXME: currently commented out due to segfault
228 //snd_pcm_close(pcm_handle);
229 pcm_handle = NULL;
230 }
231 if (pOutputBuffer) {
232 //FIXME: currently commented out due to segfault
233 //delete[] pOutputBuffer;
234 pOutputBuffer = NULL;
235 }
236 Initialized = false;
237 }
238 }

  ViewVC Help
Powered by ViewVC