rename VM_hash to VM_crc16, and the extension to DP_QC_CRC16. That way, it is specifi...
[divverent/darkplaces.git] / snd_bsd.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 #include "quakedef.h"
21
22 #include <sys/param.h>
23 #include <sys/audioio.h>
24 #ifndef SUNOS
25 #       include <sys/endian.h>
26 #endif
27 #include <sys/ioctl.h>
28
29 #include <fcntl.h>
30 #ifndef SUNOS
31 #       include <paths.h>
32 #endif
33 #include <unistd.h>
34
35 #include "snd_main.h"
36
37
38 static int audio_fd = -1;
39
40
41 /*
42 ====================
43 SndSys_Init
44
45 Create "snd_renderbuffer" with the proper sound format if the call is successful
46 May return a suggested format if the requested format isn't available
47 ====================
48 */
49 qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
50 {
51         unsigned int i;
52         const char *snddev;
53         audio_info_t info;
54
55         // Open the audio device
56 #ifdef _PATH_SOUND
57         snddev = _PATH_SOUND;
58 #elif defined(SUNOS)
59         snddev = "/dev/audio";
60 #else
61         snddev = "/dev/sound";
62 #endif
63         audio_fd = open (snddev, O_WRONLY | O_NDELAY | O_NONBLOCK);
64         if (audio_fd < 0)
65         {
66                 Con_Printf("Can't open the sound device (%s)\n", snddev);
67                 return false;
68         }
69
70         AUDIO_INITINFO (&info);
71 #ifdef AUMODE_PLAY      // NetBSD / OpenBSD 
72         info.mode = AUMODE_PLAY;
73 #endif
74         info.play.sample_rate = requested->speed;
75         info.play.channels = requested->channels;
76         info.play.precision = requested->width * 8;
77         if (requested->width == 1)
78 #ifdef SUNOS
79                 info.play.encoding = AUDIO_ENCODING_LINEAR8;
80 #else
81                 info.play.encoding = AUDIO_ENCODING_ULINEAR;
82 #endif
83         else
84 #ifdef SUNOS
85                 info.play.encoding = AUDIO_ENCODING_LINEAR;
86 #else
87 #       if BYTE_ORDER == BIG_ENDIAN
88                 info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
89 #       else
90                 info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
91 #       endif
92 #endif
93
94         if (ioctl (audio_fd, AUDIO_SETINFO, &info) == 0)
95                 break;
96
97         // TODO: check the parameters with AUDIO_GETINFO
98         // TODO: check AUDIO_ENCODINGFLAG_EMULATED with AUDIO_GETENC
99
100         snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL);
101         return true;
102 }
103
104
105 /*
106 ====================
107 SndSys_Shutdown
108
109 Stop the sound card, delete "snd_renderbuffer" and free its other resources
110 ====================
111 */
112 void SndSys_Shutdown (void)
113 {
114         if (audio_fd >= 0)
115         {
116                 close(audio_fd);
117                 audio_fd = -1;
118         }
119
120         if (snd_renderbuffer != NULL)
121         {
122                 Mem_Free(snd_renderbuffer->ring);
123                 Mem_Free(snd_renderbuffer);
124                 snd_renderbuffer = NULL;
125         }
126 }
127
128
129 /*
130 ====================
131 SndSys_Submit
132
133 Submit the contents of "snd_renderbuffer" to the sound card
134 ====================
135 */
136 void SndSys_Submit (void)
137 {
138         unsigned int startoffset, factor, limit, nbframes;
139         int written;
140         
141         if (audio_fd < 0 ||
142                 snd_renderbuffer->startframe == snd_renderbuffer->endframe)
143                 return;
144
145         startoffset = snd_renderbuffer->startframe % snd_renderbuffer->maxframes;
146         factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
147         limit = snd_renderbuffer->maxframes - startoffset;
148         nbframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
149         if (nbframes > limit)
150         {
151                 written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], limit * factor);
152                 if (written < 0)
153                 {
154                         Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
155                         return;
156                 }
157
158                 if (written % factor != 0)
159                         Sys_Error("SndSys_Submit: nb of bytes written (%d) isn't aligned to a frame sample!\n", written);
160
161                 snd_renderbuffer->startframe += written / factor;
162
163                 if ((unsigned int)written < limit * factor)
164                 {
165                         Con_Printf("SndSys_Submit: audio can't keep up! (%u < %u)\n", written, limit * factor);
166                         return;
167                 }
168                 
169                 nbframes -= limit;
170                 startoffset = 0;
171         }
172
173         written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], nbframes * factor);
174         if (written < 0)
175         {
176                 Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
177                 return;
178         }
179         snd_renderbuffer->startframe += written / factor;
180 }
181
182
183 /*
184 ====================
185 SndSys_GetSoundTime
186
187 Returns the number of sample frames consumed since the sound started
188 ====================
189 */
190 unsigned int SndSys_GetSoundTime (void)
191 {
192         audio_info_t info;
193
194         if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
195         {
196                 Con_Print("Error: can't get audio info\n");
197                 SNDDMA_Shutdown ();
198                 return 0;
199         }
200
201         return info.play.samples;
202 }
203
204
205 /*
206 ====================
207 SndSys_LockRenderBuffer
208
209 Get the exclusive lock on "snd_renderbuffer"
210 ====================
211 */
212 qboolean SndSys_LockRenderBuffer (void)
213 {
214         // Nothing to do
215         return true;
216 }
217
218
219 /*
220 ====================
221 SndSys_UnlockRenderBuffer
222
223 Release the exclusive lock on "snd_renderbuffer"
224 ====================
225 */
226 void SndSys_UnlockRenderBuffer (void)
227 {
228         // Nothing to do
229 }