initial import
[dosrtxon] / libs / mikmod / drivers / drv_wss.c
1 /*      MikMod sound library
2         (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
3         complete list.
4
5         This library is free software; you can redistribute it and/or modify
6         it under the terms of the GNU Library General Public License as
7         published by the Free Software Foundation; either version 2 of
8         the License, or (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU Library General Public License for more details.
14
15         You should have received a copy of the GNU Library General Public
16         License along with this library; if not, write to the Free Software
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18         02111-1307, USA.
19 */
20
21 /*==============================================================================
22
23   $Id$
24
25   Driver for Windows Sound System under DOS
26
27 ==============================================================================*/
28
29 /*
30
31         Written by Andrew Zabolotny <bit@eltech.ru>
32
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #ifdef DRV_WSS
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #ifdef HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47
48 #include "mikmod_internals.h"
49
50 #include "doswss.h"
51
52 static void WSS_CommandLine(const CHAR *cmdline)
53 {
54         char *ptr, *end;
55
56         if ((ptr=MD_GetAtom("port",cmdline,0)) != NULL) {
57                 wss.port = strtol(ptr, &end, 16);
58                 MikMod_free(ptr);
59         }
60         if ((ptr=MD_GetAtom("irq",cmdline,0)) != NULL) {
61                 wss.irq = strtol(ptr, &end, 10);
62                 MikMod_free(ptr);
63         }
64         if ((ptr=MD_GetAtom("dma",cmdline,0)) != NULL) {
65                 wss.dma = strtol(ptr, &end, 10);
66                 MikMod_free(ptr);
67         }
68 }
69
70 static BOOL WSS_IsThere(void)
71 {
72         return wss_detect();
73 }
74
75 static int WSS_Init(void)
76 {
77         if (!wss_open()) {
78                 _mm_errno = MMERR_INVALID_DEVICE;
79                 return 1;
80         }
81
82         /* Adjust mixing frequency according to card capabilities */
83         md_mixfreq = wss_adjust_freq(md_mixfreq);
84
85         return VC_Init();
86 }
87
88 static void WSS_Exit(void)
89 {
90         VC_Exit();
91         wss_close();
92 }
93
94 /* The last buffer byte filled with sound */
95 static unsigned int buff_tail = 0;
96
97 static void WSS_Callback(void)
98 {
99         unsigned int dma_size, dma_pos;
100         ULONG (*mixer)(SBYTE *buf, ULONG todo);
101
102         wss_query_dma(&dma_size, &dma_pos);
103         /* There isn't much sense in filling less than 256 bytes */
104         dma_pos &= ~255;
105
106         /* If nothing to mix, quit */
107         if (buff_tail == dma_pos)
108                 return;
109
110         if (Player_Paused_internal())
111                 mixer = VC_SilenceBytes;
112         else
113                 mixer = VC_WriteBytes;
114
115         /* If DMA pointer still didn't wrapped around ... */
116         if (dma_pos > buff_tail) {
117                 buff_tail += mixer ((SBYTE *)(wss.dma_buff->linear + buff_tail), dma_pos - buff_tail);
118                 /* If we arrived right to the DMA buffer end, jump to the beginning */
119                 if (buff_tail >= dma_size)
120                         buff_tail = 0;
121         } else {
122                 /* If wrapped around, fill first to the end of buffer */
123                 mixer ((SBYTE *)(wss.dma_buff->linear + buff_tail), dma_size - buff_tail);
124                 /* Now fill from buffer beginning to current DMA pointer */
125                 buff_tail = mixer ((SBYTE *)wss.dma_buff->linear, dma_pos);
126         }
127 }
128
129 static void WSS_Update(void)
130 {
131         /* Do nothing: the real update is done during SB interrupts */
132 }
133
134 static int WSS_PlayStart(void)
135 {
136         if (VC_PlayStart())
137                 return 1;
138
139         /* Set our routine to be called during WSS IRQs */
140         buff_tail = 0;
141         wss.timer_callback = WSS_Callback;
142
143         /* Start cyclic DMA transfer */
144         if (!wss_start_dma(((md_mode & DMODE_16BITS) ? WSSMODE_16BITS | WSSMODE_SIGNED : 0) |
145                 ((md_mode & DMODE_STEREO) ? WSSMODE_STEREO : 0), md_mixfreq))
146         {
147                 _mm_errno = MMERR_DOSWSS_STARTDMA;
148                 return 1;
149         }
150
151         /* Enable speaker output */
152         wss_output(TRUE);
153
154         return 0;
155 }
156
157 static int WSS_Reset(void)
158 {
159         wss_reset();
160         VC_Exit();
161         return VC_Init();
162 }
163
164 static void WSS_PlayStop(void)
165 {
166         wss.timer_callback = NULL;
167         wss_output(FALSE);
168         wss_stop_dma();
169         VC_PlayStop();
170 }
171
172 MDRIVER drv_wss =
173 {
174         NULL,
175         "Windows Sound System",
176         "Windows Sound System (CS423*,ESS*) v1.0",
177         0, 255,
178         "wss",
179         "port:c:32C,530,604,E80,F40,530:Windows Sound System base I/O port\n"
180         "irq:c:2,3,5,7,10,5:Windows Sound System IRQ\n"
181         "dma:c:0,1,3,0:Windows Sound System DMA channel\n",
182
183         WSS_CommandLine,
184         WSS_IsThere,
185         VC_SampleLoad,
186         VC_SampleUnload,
187         VC_SampleSpace,
188         VC_SampleLength,
189         WSS_Init,
190         WSS_Exit,
191         WSS_Reset,
192         VC_SetNumVoices,
193         WSS_PlayStart,
194         WSS_PlayStop,
195         WSS_Update,
196         NULL,
197         VC_VoiceSetVolume,
198         VC_VoiceGetVolume,
199         VC_VoiceSetFrequency,
200         VC_VoiceGetFrequency,
201         VC_VoiceSetPanning,
202         VC_VoiceGetPanning,
203         VC_VoicePlay,
204         VC_VoiceStop,
205         VC_VoiceStopped,
206         VC_VoiceGetPosition,
207         VC_VoiceRealVolume
208 };
209
210 #else /* ifdef DRV_WSS */
211
212 #include "mikmod_internals.h"
213 MISSING(drv_wss);
214
215 #endif
216
217 /* ex:set ts=4: */