|
|
1.1 root 1: /*
2: Hatari
3: */
4:
5: #include "main.h"
6: #include "audio.h"
7: #include "debug.h"
8: #include "dialog.h"
9: #include "errlog.h"
10: #include "memAlloc.h"
11: #include "misc.h"
12: #include "sound.h"
13: #include "view.h"
14:
15: #define WRITE_INIT_POS ((SoundPlayBackFrequencies[OutputAudioFreqIndex]/50)*2) /* Write 2/50th ahead of write position */
16:
17: /* 11Khz, 22Khz, 44Khz playback */
18: int SoundPlayBackFrequencies[] = {
19: 11025, /* PLAYBACK_LOW */
20: 22050, /* PLAYBACK_MEDIUM */
21: 44100, /* PLAYBACK_HIGH */
22: };
23:
24: /* Bytes to download on each odd/even frame - as 11Khz does not divide by 50 exactly */
25: int SoundPlayBackFreqFrameLengths[][2] = {
26: 221,220, /* 220.5 */
27: 441,441, /* 441 */
28: 882,882, /* 882 */
29: };
30:
31: BOOL bDisableDirectSound=FALSE;
32: //LPDIRECTSOUND lpDS = NULL;
33: //LPDIRECTSOUNDBUFFER lpDSBPrimBuffer = NULL;
34: BOOL bDirectSoundWorking=FALSE; /* Is sound OK */
35: volatile BOOL bPlayingBuffer = FALSE; /* Is playing buffer? Start when start processing ST */
36: int WriteOffset=0; /* Write offset into buffer */
37: int OutputAudioFreqIndex=FREQ_44Khz; /* Playback rate(11Khz,22Khz or 44Khz) */
38: float PlayVolume=0.0f;
39: BOOL bAquireWritePosition=FALSE;
40: int PrimaryBufferSize; /* Size of primary buffer */
41:
42:
43: /* FIXME: Rewrite those functions: */
44:
45: //-----------------------------------------------------------------------
46: /*
47: Create object for Direct Sound. Return TRUE if all OK
48: We use direct access to the primary buffer, set to an unsigned 8-bit mono stream
49: */
50: void DAudio_Init(void)
51: {
52: #if 0
53: DSCAPS dscaps;
54: HRESULT dsRetVal;
55:
56: // Is enabled?
57: if (bDisableDirectSound) {
58: // Stop any Direct Sound access
59: ErrLog_File("DirectSound: Disabled\n");
60: bDirectSoundWorking = FALSE;
61: return;
62: }
63:
64: // Create the main DirectSound object, using default driver
65: dsRetVal = DirectSoundCreate(NULL, &lpDS, NULL);
66: if(dsRetVal!=DS_OK) {
67: ErrLog_File("ERROR DirectSound: Unable to 'DirectSoundCreate', error code %d\n",dsRetVal);
68: bDirectSoundWorking = FALSE;
69: return;
70: }
71: ErrLog_File("DirectSound: 'DirectSoundCreate' - OK\n");
72:
73: // Report capabilities of sound card/driver
74: dscaps.dwSize = sizeof(DSCAPS);
75: dsRetVal = lpDS->GetCaps(&dscaps);
76: if(dsRetVal==DS_OK) {
77: // Report general list which we may use
78: ErrLog_File("DirectSound: Capabilities:-\n");
79: if (dscaps.dwFlags&DSCAPS_EMULDRIVER)
80: ErrLog_File("\tEmulatedDriver(WARNING: This may cause Hatari to play back sounds incorrectly\n");
81: if (dscaps.dwFlags&DSCAPS_PRIMARY16BIT)
82: ErrLog_File("\t16-Bit\n");
83: if (dscaps.dwFlags&DSCAPS_PRIMARY8BIT)
84: ErrLog_File("\t8-Bit\n");
85: if (dscaps.dwFlags&DSCAPS_PRIMARYMONO)
86: ErrLog_File("\tMono\n");
87: if (dscaps.dwFlags&DSCAPS_PRIMARYSTEREO)
88: ErrLog_File("\tStereo\n");
89:
90: // Are good enough?
91: if ( !((dscaps.dwFlags&DSCAPS_PRIMARY8BIT) && (dscaps.dwFlags&DSCAPS_PRIMARYMONO)) ) {
92: // No, MUST have 8-Bit/Mono
93: ErrLog_File("ERROR DirectSound: Your sound card does not support the playback mode required(8-Bit/Mono)\n");
94: bDirectSoundWorking = FALSE;
95: return;
96: }
97: }
98:
99: // Create sound buffer, return if error
100: DAudio_CreateSoundBuffer();
101: #endif
102: }
103:
104: //-----------------------------------------------------------------------
105: /*
106: Free object created for Direct Sound
107: */
108: void DAudio_UnInit(void)
109: {
110: #if 0
111: // Free Direct Sound
112: DAudio_FreeSoundBuffer();
113: if( lpDS ) {
114: lpDS->Release(); lpDS = NULL;
115: }
116: #endif
117: }
118:
119: //-----------------------------------------------------------------------
120: /*
121: Create sound buffer to write samples into
122: */
123: BOOL DAudio_CreateSoundBuffer(void)
124: {
125: #if 0
126: WAVEFORMATEX pwfx;
127: DSBUFFERDESC dsbdesc;
128: DSBCAPS dsbcaps;
129: HRESULT dsRetVal;
130:
131: // Set up wave format structure
132: memset(&pwfx, 0, sizeof(WAVEFORMATEX));
133: pwfx.wFormatTag = WAVE_FORMAT_PCM;
134: pwfx.nChannels = 1; // Mono
135: pwfx.nSamplesPerSec = SoundPlayBackFrequencies[OutputAudioFreqIndex];
136: pwfx.wBitsPerSample = 8; // 8 Bit unsigned
137: pwfx.nBlockAlign = (pwfx.nChannels*pwfx.wBitsPerSample)/8;
138: pwfx.nAvgBytesPerSec = pwfx.nSamplesPerSec*pwfx.nBlockAlign;
139: pwfx.cbSize = 0;
140: memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
141: dsbdesc.dwSize = sizeof(DSBUFFERDESC);
142: // Use direct access for Primary Buffer else sound drivers can cause corrupted sound and
143: // also declare 'STICKFOCUS' otherwise cannot continue sound when loose focus!
144: dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
145: // Buffer size is determined by sound hardware.
146: dsbdesc.dwBufferBytes = 0;
147: dsbdesc.lpwfxFormat = NULL; // Must be NULL for primary buffers
148:
149: // Obtain write-primary cooperative level
150: dsRetVal = lpDS->SetCooperativeLevel(hWnd, DSSCL_WRITEPRIMARY);
151: if(dsRetVal!=DS_OK) {
152: ErrLog_File("ERROR DirectSound: Unable to 'SetCooperativeLevel', error code %d\n",dsRetVal);
153: lpDS->Release(); lpDS = NULL;
154: bDirectSoundWorking = FALSE;
155: return(FALSE);
156: }
157:
158: // Create sound buffer
159: dsRetVal = lpDS->CreateSoundBuffer(&dsbdesc,&lpDSBPrimBuffer,NULL);
160: if(dsRetVal!=DS_OK) {
161: ErrLog_File("ERROR DirectSound: Unable to 'CreateSoundBuffer', error code %d\n",dsRetVal);
162: lpDS->Release(); lpDS = NULL;
163: bDirectSoundWorking = FALSE;
164: return(FALSE);
165: }
166:
167: // Succeeded. Set primary buffer to desired format.
168: dsRetVal = lpDSBPrimBuffer->SetFormat(&pwfx);
169: if(dsRetVal!=DS_OK) {
170: ErrLog_File("ERROR DirectSound: Unable to 'SetFormat', error code %d\n",dsRetVal);
171: lpDS->Release(); lpDS = NULL;
172: lpDSBPrimBuffer->Release(); lpDSBPrimBuffer = NULL;
173: bDirectSoundWorking = FALSE;
174: return(FALSE);
175: }
176:
177: // Get buffer size
178: dsbcaps.dwSize = sizeof(DSBCAPS);
179: lpDSBPrimBuffer->GetCaps(&dsbcaps);
180: PrimaryBufferSize = dsbcaps.dwBufferBytes;
181:
182: // All OK
183: bDirectSoundWorking = TRUE;
184: // And begin
185: DAudio_ResetBuffer();
186:
187: return(TRUE);
188: #endif
189: }
190:
191: //-----------------------------------------------------------------------
192: /*
193: Free sound buffer
194: */
195: void DAudio_FreeSoundBuffer(void)
196: {
197: #if 0
198: if (lpDSBPrimBuffer) {
199: // Stop
200: DAudio_StopBuffer();
201: // And free
202: lpDSBPrimBuffer->Release(); lpDSBPrimBuffer = NULL;
203: }
204: #endif
205: }
206:
207: //-----------------------------------------------------------------------
208: /*
209: Re-Create sound buffer to write samples into, will stop existing and restart with new frequency
210: */
211: void DAudio_ReCreateDirectSoundBuffer(void)
212: {
213: #if 0
214: if (lpDS) {
215: // Stop and delete old buffer
216: DAudio_FreeSoundBuffer();
217:
218: // Clear sample buffer, so plays silence
219: Sound_ClearMixBuffer();
220:
221: // And create new one(will use new 'OutputAudioFreq' value)
222: DAudio_CreateSoundBuffer();
223: }
224: #endif
225: }
226:
227: //-----------------------------------------------------------------------
228: /*
229: Set DirectSound playback frequency variable, pass as PLAYBACK_xxxx
230: */
231: void DAudio_SetOutputAudioFreq(int Frequency)
232: {
233: // Set new frequency, index into SoundPlayBackFrequencies[]
234: OutputAudioFreqIndex = Frequency;
235: }
236:
237: //-----------------------------------------------------------------------
238: /*
239: Reset sound buffer, so plays from correct position
240: */
241: void DAudio_ResetBuffer(void)
242: {
243: // Get new 'write' position on next frame
244: bAquireWritePosition = TRUE;
245: }
246:
247: //-----------------------------------------------------------------------
248: /*
249: Stop sound buffer
250: */
251: void DAudio_StopBuffer(void)
252: {
253: #if 0
254: // Stop from playing
255: if (lpDSBPrimBuffer)
256: lpDSBPrimBuffer->Stop();
257: bPlayingBuffer = FALSE;
258: #endif
259: }
260:
261: //-----------------------------------------------------------------------
262: /*
263: Scale sample value(-128...127) according to 'PlayVolume' setting
264: */
265: char DAudio_ModifyVolume(char Sample)
266: {
267: // If full volume, just use current value
268: if (PlayVolume==1.0f)
269: return(Sample);
270:
271: // Else, scale volume
272: Sample = (char)((float)Sample*PlayVolume);
273:
274: return(Sample);
275: }
276:
277: //-----------------------------------------------------------------------
278: /*
279: Write samples into Direct Sound buffer at 'Offset', taking care to wrap around. Pass NULL to write zero's
280: */
281: void DAudio_WriteSamplesIntoBuffer(char *pSamples,int Index,int Length,int RampSetting)
282: {
283: #if 0
284: void *lpWrite1, *lpWrite2;
285: unsigned char *pBuffer;
286: DWORD dwLenBytes1, dwLenBytes2;
287: HRESULT dsRetVal;
288: int i,WriteCursor,CursorDiff;
289:
290: // Modify ramp volume - ramp down if sound not enabled or not in windows mouse mode
291: if ( (((RampSetting==RAMP_DOWN) || (!ConfigureParams.Sound.bEnableSound)) && (PlayVolume>0.0f)) || bWindowsMouseMode ) {
292: PlayVolume -= RAMP_DOWN_VOLUME_LEVEL;
293: if (PlayVolume<=0.0f)
294: PlayVolume = 0.0f;
295: }
296: else if ( (RampSetting==RAMP_UP) && (PlayVolume<1.0f) ) {
297: PlayVolume += RAMP_UP_VOLUME_LEVEL;
298: if (PlayVolume>=1.0f)
299: PlayVolume = 1.0f;
300: }
301:
302: if (lpDSBPrimBuffer) {
303: // Do need to reset 'write' position?
304: if (bAquireWritePosition) {
305: // Get current write position
306: lpDSBPrimBuffer->GetCurrentPosition(NULL,(DWORD *)&WriteCursor);
307: WriteOffset = WriteCursor+WRITE_INIT_POS; // + little gap
308: bAquireWritePosition = FALSE;
309: }
310:
311: // Lock sound buffer to get pointers
312: lpWrite1 = lpWrite2 = NULL;
313: dwLenBytes1 = dwLenBytes2 = 0;
314: dsRetVal = lpDSBPrimBuffer->Lock( WriteOffset, Length, &lpWrite1, &dwLenBytes1, &lpWrite2, &dwLenBytes2, 0 );
315: if (dsRetVal==DSERR_BUFFERLOST) {
316: // Lost focus of buffer, restore and try to lock again
317: lpDSBPrimBuffer->Restore();
318: dsRetVal = lpDSBPrimBuffer->Lock( WriteOffset, Length, &lpWrite1, &dwLenBytes1, &lpWrite2, &dwLenBytes2, 0 );
319: }
320:
321: // All OK?
322: if (dsRetVal==DS_OK) {
323: // Write first section, convert to 'unsigned' and write '128'(unsigned) if passed NULL
324: if ( (dwLenBytes1>0) && (lpWrite1) ) {
325: if (pSamples) {
326: pBuffer = (unsigned char *)lpWrite1;
327: for(i=0; i<(int)dwLenBytes1; i++) {
328: *pBuffer++ = DAudio_ModifyVolume(pSamples[Index])+128;
329: Index = (Index+1)&4095;
330: }
331: }
332: else
333: memset(lpWrite1,128,dwLenBytes1);
334: }
335: // And second, if needed
336: if ( (dwLenBytes2>0) && (lpWrite2) ) {
337: if (pSamples) {
338: pBuffer = (unsigned char *)lpWrite2;
339: for(i=0; i<(int)dwLenBytes2; i++) {
340: *pBuffer++ = DAudio_ModifyVolume(pSamples[Index])+128;
341: Index = (Index+1)&4095;
342: }
343: }
344: else
345: memset(lpWrite2,128,dwLenBytes2);
346: }
347:
348: // Now unlock the buffer.
349: dsRetVal = lpDSBPrimBuffer->Unlock( (LPVOID)lpWrite1, dwLenBytes1,(LPVOID)lpWrite2, dwLenBytes2 );
350: }
351:
352: // Update write buffer
353: if (pSamples) {
354: WriteOffset += Length;
355: if (WriteOffset>=PrimaryBufferSize)
356: WriteOffset -= PrimaryBufferSize;
357: }
358:
359: // Are we playing?
360: if (!bPlayingBuffer) {
361: lpDSBPrimBuffer->Play( 0, 0, DSBPLAY_LOOPING );
362: DAudio_ResetBuffer();
363:
364: bPlayingBuffer = TRUE;
365: }
366: else {
367: // Check here for play/write pointers getting away from each other and set 'bAquireWritePosition' to reset
368: lpDSBPrimBuffer->GetCurrentPosition(NULL,(DWORD *)&WriteCursor);
369: // If the writecursor is too-far away from where we think it should be cause a reset
370: CursorDiff = WriteOffset-WriteCursor;
371: // Check for overlap
372: if (CursorDiff<0)
373: CursorDiff = (WriteOffset+PrimaryBufferSize)-WriteCursor;
374: // So, does need reset?
375: if (abs(CursorDiff)>(WRITE_INIT_POS*2))
376: DAudio_ResetBuffer();
377: }
378: }
379: #endif
380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.