/[svn]/linuxsampler/tags/singlechannel/src/alsaio.cpp
ViewVC logotype

Annotation of /linuxsampler/tags/singlechannel/src/alsaio.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (hide annotations) (download)
Mon Feb 16 19:30:42 2004 UTC (20 years, 3 months ago) by schoenebeck
Original Path: linuxsampler/trunk/src/alsaio.cpp
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 schoenebeck 31 /***************************************************************************
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 schoenebeck 33 int AlsaIO::Initialize(uint Channels, uint Samplerate, uint Fragments, uint FragmentSize, String Card) {
32 schoenebeck 31 this->uiChannels = Channels;
33     this->uiSamplerate = Samplerate;
34     this->uiMaxSamplesPerCycle = FragmentSize;
35     this->bInterleaved = true;
36    
37     if (HardwareParametersSupported(Channels, Samplerate, Fragments, FragmentSize)) {
38 schoenebeck 33 pcm_name = "hw:" + Card;
39 schoenebeck 31 }
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 schoenebeck 33 pcm_name = "plughw:" + Card;
45 schoenebeck 31 }
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