2 * Soundblaster Emulation
4 * Copyright 2002 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(sblaster
);
35 /* Board Configuration */
36 /* FIXME: Should be in a config file */
41 /* Soundblaster state */
42 static int SampleMode
; /* Mono / Stereo */
43 static int SampleRate
;
44 static int SamplesCount
;
45 static BYTE DSP_Command
[256]; /* Store param numbers in bytes for each command */
46 static BYTE DSP_InBuffer
[10]; /* Store DSP command bytes parameters from host */
47 static int InSize
; /* Nb of bytes in InBuffer */
48 static BYTE DSP_OutBuffer
[10]; /* Store DSP information bytes to host */
49 static int OutSize
; /* Nb of bytes in InBuffer */
50 static int command
; /* Current command */
51 static int end_sound_loop
= 0;
52 static int dma_enable
= 0;
54 /* The maximum size of a dma transfer can be 65536 */
55 #define DMATRFSIZE 1024
57 /* DMA can perform 8 or 16-bit transfer */
58 static BYTE dma_buffer
[DMATRFSIZE
*2];
60 /* Direct Sound buffer config */
61 #define DSBUFLEN 4096 /* FIXME: Only this value seems to work */
63 /* Direct Sound playback stuff */
64 static HMODULE hmodule
;
65 typedef HRESULT (WINAPI
* fnDirectSoundCreate
) (LPGUID
,LPDIRECTSOUND
*,LPUNKNOWN
);
66 static fnDirectSoundCreate lpDirectSoundCreate
;
67 static LPDIRECTSOUND lpdsound
;
68 static LPDIRECTSOUNDBUFFER lpdsbuf
;
69 static DSBUFFERDESC buf_desc
;
70 static WAVEFORMATEX wav_fmt
;
71 static HANDLE SB_Thread
;
75 /* SB_Poll performs DMA transfers and fills the Direct Sound Buffer */
76 static DWORD CALLBACK
SB_Poll( void *dummy
)
83 DWORD dwbyteswritten1
= 0;
84 DWORD dwbyteswritten2
= 0;
87 /* FIXME: this loop must be improved */
88 while(!end_sound_loop
)
93 size
= DMA_Transfer(SB_DMA
,min(DMATRFSIZE
,SamplesCount
),dma_buffer
);
97 result
= IDirectSoundBuffer_Lock(lpdsbuf
,buf_off
,size
,(LPVOID
*)&lpbuf1
,&dwsize1
,(LPVOID
*)&lpbuf2
,&dwsize2
,0);
98 if (result
!= DS_OK
) {
99 ERR("Unable to lock sound buffer !\n");
103 dwbyteswritten1
= min(size
,dwsize1
);
104 memcpy(lpbuf1
,dma_buffer
,dwbyteswritten1
);
106 dwbyteswritten2
= min(size
- dwbyteswritten1
,dwsize2
);
107 memcpy(lpbuf2
,dma_buffer
+dwbyteswritten1
,dwbyteswritten2
);
109 buf_off
= (buf_off
+ dwbyteswritten1
+ dwbyteswritten2
) % DSBUFLEN
;
111 result
= IDirectSoundBuffer_Unlock(lpdsbuf
,lpbuf1
,dwbyteswritten1
,lpbuf2
,dwbyteswritten2
);
113 ERR("Unable to unlock sound buffer !\n");
115 SamplesCount
-= size
;
117 DOSVM_QueueEvent(SB_IRQ
,SB_IRQ_PRI
,NULL
,NULL
);
124 static BOOL
SB_Init(void)
129 hmodule
= LoadLibraryA("dsound.dll");
131 ERR("Can't load dsound.dll !\n");
134 lpDirectSoundCreate
= (fnDirectSoundCreate
)GetProcAddress(hmodule
,"DirectSoundCreate");
135 if (!lpDirectSoundCreate
) {
136 /* CloseHandle(hmodule); */
137 ERR("Can't find DirectSoundCreate function !\n");
140 result
= (*lpDirectSoundCreate
)(NULL
,&lpdsound
,NULL
);
141 if (result
!= DS_OK
) {
142 ERR("Unable to initialize Sound Subsystem err = %x !\n",result
);
146 /* FIXME: To uncomment when :
147 - SetCooperative level is correctly implemented
148 - an always valid and non changing handle to a windows (vga_hwnd) is available
149 (this surely needs some work in vga.c)
150 result = IDirectSound_SetCooperativeLevel(lpdsound,vga_hwnd,DSSCL_EXCLUSIVE|DSSCL_PRIORITY);
151 if (result != DS_OK) {
152 ERR("Can't set cooperative level !\n");
158 wav_fmt
.wFormatTag
= WAVE_FORMAT_PCM
;
159 wav_fmt
.nChannels
= 1;
160 wav_fmt
.nSamplesPerSec
= 22050;
161 wav_fmt
.nAvgBytesPerSec
= 22050;
162 wav_fmt
.nBlockAlign
= 1;
163 wav_fmt
.wBitsPerSample
= 8;
166 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
167 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
168 buf_desc
.dwBufferBytes
= DSBUFLEN
;
169 buf_desc
.lpwfxFormat
= &wav_fmt
;
170 result
= IDirectSound_CreateSoundBuffer(lpdsound
,&buf_desc
,&lpdsbuf
,NULL
);
171 if (result
!= DS_OK
) {
172 ERR("Can't create sound buffer !\n");
176 result
= IDirectSoundBuffer_Play(lpdsbuf
,0, 0, DSBPLAY_LOOPING
);
177 if (result
!= DS_OK
) {
178 ERR("Can't start playing !\n");
184 SB_Thread
= CreateThread(NULL
, 0, SB_Poll
, NULL
, 0, NULL
);
187 ERR("Can't create thread !\n");
194 static void SB_Reset(void)
201 /* Set Time Constant */
207 /* Generic DAC/ADC DMA (16-bit, 8-bit) */
208 for(i
=0xB0;i
<=0xCF;i
++)
210 /* DSP Indentification */
213 /* Clear command and input buffer */
217 /* Put a garbage value in the output buffer */
220 /* All right, let's put the magic value for autodetection */
221 DSP_OutBuffer
[0] = 0xaa;
223 /* Something is wrong, put 0 to failed autodetection */
224 DSP_OutBuffer
[0] = 0x00;
227 /* Find a standard sampling rate for DirectSound */
228 static int SB_StdSampleRate(int SampleRate
)
230 if (SampleRate
>((44100+48000)/2)) return 48000;
231 if (SampleRate
>((32000+44100)/2)) return 44100;
232 if (SampleRate
>((24000+32000)/2)) return 32000;
233 if (SampleRate
>((22050+24000)/2)) return 24000;
234 if (SampleRate
>((16000+22050)/2)) return 22050;
235 if (SampleRate
>((12000+16000)/2)) return 16000;
236 if (SampleRate
>((11025+12000)/2)) return 12000;
237 if (SampleRate
>((8000+11025)/2)) return 11025;
241 void SB_ioport_out( WORD port
, BYTE val
)
247 TRACE("Resetting DSP.\n");
250 /* DSP - Write Data or Command */
252 TRACE("val=%x\n",val
);
254 /* Clear input buffer and set the current command */
258 if (InSize
!=DSP_Command
[command
])
259 /* Fill the input buffer the command parameters if any */
260 DSP_InBuffer
[InSize
++]=val
;
262 /* Process command */
266 FIXME("Direct DAC (8-bit) - Not Implemented\n");
269 SamplesCount
= DSP_InBuffer
[1]+(val
<<8)+1;
270 TRACE("DMA DAC (8-bit) for %x samples\n",SamplesCount
);
274 FIXME("Direct ADC (8-bit) - Not Implemented\n");
277 FIXME("DMA ADC (8-bit) - Not Implemented\n");
280 SampleRate
= 1000000/(256-val
);
281 TRACE("Set Time Constant (%d <-> %d Hz => %d Hz)\n",DSP_InBuffer
[0],
282 SampleRate
,SB_StdSampleRate(SampleRate
));
283 SampleRate
= SB_StdSampleRate(SampleRate
);
284 wav_fmt
.nSamplesPerSec
= SampleRate
;
285 wav_fmt
.nAvgBytesPerSec
= SampleRate
;
286 IDirectSoundBuffer_SetFormat(lpdsbuf
,&wav_fmt
);
288 /* case 0xBX/0xCX -> See below */
290 TRACE("Halt DMA operation (8-bit)\n");
294 FIXME("Enable Speaker - Not Implemented\n");
297 FIXME("Disable Speaker - Not Implemented\n");
300 FIXME("Continue DMA operation (8-bit) - Not Implemented\n");
303 FIXME("Speaker Status - Not Implemented\n");
305 case 0xE0: /* SB 2.0 */
306 TRACE("DSP Identification\n");
307 DSP_OutBuffer
[OutSize
++] = ~val
;
310 TRACE("DSP Version\n");
312 DSP_OutBuffer
[0]=0; /* returns version 1.0 */
316 TRACE("IRQ Request (8-bit)\n");
317 DOSVM_QueueEvent(SB_IRQ
,SB_IRQ_PRI
,NULL
,NULL
);
320 if (((command
&0xF0)==0xB0)||((DSP_InBuffer
[0]&0xF0)==0xC0)) {
322 FIXME("Generic DAC/ADC DMA (16-bit, 8-bit) - %d % d\n",command
,DSP_InBuffer
[1]);
324 FIXME("Generic DAC/ADC fifo mode not supported\n");
326 FIXME("Generic DAC/ADC autoinit dma mode not supported\n");
328 FIXME("Generic DAC/ADC adc mode not supported\n");
331 FIXME("Generic DAC/ADC 8-bit not supported\n");
335 FIXME("Generic DAC/ADC 16-bit not supported\n");
339 ERR("Generic DAC/ADC resolution unknown\n");
342 if (DSP_InBuffer
[1]&0x010)
343 FIXME("Generic DAC/ADC signed sample mode not supported\n");
344 if (DSP_InBuffer
[1]&0x020)
345 FIXME("Generic DAC/ADC stereo mode not supported\n");
346 SamplesCount
= DSP_InBuffer
[2]+(val
<<8)+1;
347 TRACE("Generic DMA for %x samples\n",SamplesCount
);
351 FIXME("DSP command %x not supported\n",val
);
353 /* Empty the input buffer and end the command */
360 BYTE
SB_ioport_in( WORD port
)
368 /* Value in the read buffer */
370 res
= DSP_OutBuffer
[--OutSize
];
372 /* return the last byte */
373 res
= DSP_OutBuffer
[0];
375 /* DSP - Write Buffer Status */
377 /* DSP always ready for writing */
380 /* DSP - Data Available Status */
381 /* DSP - IRQ Acknowledge, 8-bit */
383 /* DSP data availability check */