|
|
1.1 root 1: /*
2: Hatari
3: */
4:
1.1.1.2 root 5: #include <SDL.h>
6:
1.1 root 7: #include "main.h"
8: #include "audio.h"
9: #include "debug.h"
10: #include "dialog.h"
11: #include "errlog.h"
12: #include "memAlloc.h"
13: #include "misc.h"
14: #include "sound.h"
15:
16: #define WRITE_INIT_POS ((SoundPlayBackFrequencies[OutputAudioFreqIndex]/50)*2) /* Write 2/50th ahead of write position */
17:
18: /* 11Khz, 22Khz, 44Khz playback */
19: int SoundPlayBackFrequencies[] = {
20: 11025, /* PLAYBACK_LOW */
21: 22050, /* PLAYBACK_MEDIUM */
22: 44100, /* PLAYBACK_HIGH */
23: };
24:
25: /* Bytes to download on each odd/even frame - as 11Khz does not divide by 50 exactly */
26: int SoundPlayBackFreqFrameLengths[][2] = {
27: 221,220, /* 220.5 */
28: 441,441, /* 441 */
29: 882,882, /* 882 */
30: };
31:
1.1.1.3 ! root 32: BOOL bDisableSound=FALSE;
1.1.1.2 root 33: BOOL bSoundWorking=TRUE; /* Is sound OK */
34: volatile BOOL bPlayingBuffer = FALSE; /* Is playing buffer? Start when start processing ST */
35: int WriteOffset=0; /* Write offset into buffer */
1.1.1.3 ! root 36: int OutputAudioFreqIndex=FREQ_22Khz; /* Playback rate (11Khz,22Khz or 44Khz) */
1.1 root 37: float PlayVolume=0.0f;
38: BOOL bAquireWritePosition=FALSE;
1.1.1.2 root 39: unsigned char *SoundBuffer1, *SoundBuffer2;
40: int SoundBufferSize=1024; /* Size of sound buffer */
41:
1.1.1.3 ! root 42: SDL_AudioSpec desiredAudioSpec; /* We fill in the desired SDL audio options here */
1.1.1.2 root 43:
1.1 root 44:
45:
1.1.1.2 root 46: /*-----------------------------------------------------------------------*/
47: /*
48: SDL audio callback function
49: */
50: void Audio_CallBack(void *userdata, Uint8 *stream, int len)
51: {
1.1.1.3 ! root 52: memcpy(stream, SoundBuffer2, len);
1.1.1.2 root 53: }
54:
1.1 root 55:
1.1.1.2 root 56: /*-----------------------------------------------------------------------*/
1.1 root 57: /*
1.1.1.3 ! root 58: Create object for sound. Return TRUE if all OK
1.1 root 59: We use direct access to the primary buffer, set to an unsigned 8-bit mono stream
60: */
1.1.1.2 root 61: void Audio_Init(void)
1.1 root 62: {
63:
1.1.1.2 root 64: /* Is enabled? */
65: if (bDisableSound) {
1.1.1.3 ! root 66: /* Stop any sound access */
1.1.1.2 root 67: ErrLog_File("Sound: Disabled\n");
68: bSoundWorking = FALSE;
1.1 root 69: return;
70: }
71:
1.1.1.2 root 72: /* Init SDL audio: */
1.1.1.3 ! root 73: desiredAudioSpec.freq = SoundPlayBackFrequencies[OutputAudioFreqIndex];
! 74: desiredAudioSpec.format = AUDIO_U8; /* 8 Bit unsigned */
! 75: desiredAudioSpec.channels = 1; /* Mono */
! 76: desiredAudioSpec.samples = SoundBufferSize; /* Buffer size */
! 77: desiredAudioSpec.callback = Audio_CallBack;
! 78: desiredAudioSpec.userdata = NULL;
! 79: if( SDL_OpenAudio(&desiredAudioSpec, NULL) ) /* Open audio device */
! 80: {
! 81: fprintf(stderr, "Can't use audio!\n");
1.1.1.2 root 82: bSoundWorking = FALSE;
1.1.1.3 ! root 83: ConfigureParams.Sound.bEnableSound = FALSE;
1.1.1.2 root 84: return;
1.1 root 85: }
1.1.1.3 ! root 86:
1.1.1.2 root 87: /* Create sound buffer, return if error */
88: Audio_CreateSoundBuffer();
1.1.1.3 ! root 89: SDL_PauseAudio(FALSE);
1.1 root 90: }
91:
1.1.1.2 root 92:
93: /*-----------------------------------------------------------------------*/
1.1 root 94: /*
95: Free object created for Direct Sound
96: */
1.1.1.2 root 97: void Audio_UnInit(void)
1.1 root 98: {
1.1.1.3 ! root 99: SDL_PauseAudio(TRUE);
1.1.1.2 root 100:
101: /* Free sound buffer */
102: Audio_FreeSoundBuffer();
103:
104: SDL_CloseAudio();
1.1 root 105: }
106:
1.1.1.2 root 107:
108: /*-----------------------------------------------------------------------*/
1.1 root 109: /*
110: Create sound buffer to write samples into
111: */
1.1.1.2 root 112: BOOL Audio_CreateSoundBuffer(void)
1.1 root 113: {
1.1.1.2 root 114: int bufferlen;
1.1 root 115:
1.1.1.2 root 116: /* Allocate memory for the 2 sound buffers: */
117: bufferlen = SoundBufferSize + SoundPlayBackFreqFrameLengths[FREQ_44Khz][0];
118: SoundBuffer1 = malloc( bufferlen );
119: if( !SoundBuffer1 ) {
120: bSoundWorking = FALSE;
1.1 root 121: return(FALSE);
122: }
1.1.1.2 root 123: memset(SoundBuffer1, 128, bufferlen);
124:
125: SoundBuffer2 = malloc( bufferlen );
126: if( !SoundBuffer2 ) {
127: bSoundWorking = FALSE;
128: free( SoundBuffer1 );
129: SoundBuffer1 = NULL;
1.1 root 130: return(FALSE);
131: }
1.1.1.2 root 132: memset(SoundBuffer2, 128, bufferlen);
1.1 root 133:
1.1.1.2 root 134: /* All OK */
135: bSoundWorking = TRUE;
136: /* And begin */
137: Audio_ResetBuffer();
1.1 root 138:
139: return(TRUE);
140: }
141:
1.1.1.2 root 142:
143: /*-----------------------------------------------------------------------*/
1.1 root 144: /*
145: Free sound buffer
146: */
1.1.1.2 root 147: void Audio_FreeSoundBuffer(void)
1.1 root 148: {
1.1.1.2 root 149: /* Stop */
150: Audio_StopBuffer();
151: /* And free */
152: if( SoundBuffer1 )
153: free(SoundBuffer1);
1.1.1.3 ! root 154: if( SoundBuffer2 )
1.1.1.2 root 155: free(SoundBuffer2);
1.1 root 156: }
157:
1.1.1.2 root 158:
159: /*-----------------------------------------------------------------------*/
1.1 root 160: /*
1.1.1.3 ! root 161: Set audio playback frequency variable, pass as PLAYBACK_xxxx
1.1 root 162: */
1.1.1.2 root 163: void Audio_SetOutputAudioFreq(int Frequency)
1.1 root 164: {
1.1.1.2 root 165: /* Set new frequency, index into SoundPlayBackFrequencies[] */
1.1 root 166: OutputAudioFreqIndex = Frequency;
1.1.1.3 ! root 167:
! 168: /* Re-open SDL audio interface... */
! 169: Audio_UnInit();
! 170: Audio_Init();
1.1 root 171: }
172:
1.1.1.2 root 173:
174: /*-----------------------------------------------------------------------*/
1.1 root 175: /*
176: Reset sound buffer, so plays from correct position
177: */
1.1.1.2 root 178: void Audio_ResetBuffer(void)
1.1 root 179: {
1.1.1.2 root 180: /* Get new 'write' position on next frame */
1.1 root 181: bAquireWritePosition = TRUE;
182: }
183:
1.1.1.2 root 184:
185: /*-----------------------------------------------------------------------*/
1.1 root 186: /*
187: Stop sound buffer
188: */
1.1.1.2 root 189: void Audio_StopBuffer(void)
1.1 root 190: {
1.1.1.2 root 191: /* Stop from playing */
1.1.1.3 ! root 192: SDL_PauseAudio(TRUE);
1.1 root 193: bPlayingBuffer = FALSE;
194: }
195:
1.1.1.2 root 196:
197: /*-----------------------------------------------------------------------*/
1.1 root 198: /*
199: Scale sample value(-128...127) according to 'PlayVolume' setting
200: */
1.1.1.2 root 201: char Audio_ModifyVolume(char Sample)
1.1 root 202: {
1.1.1.2 root 203: /* If full volume, just use current value */
1.1 root 204: if (PlayVolume==1.0f)
205: return(Sample);
206:
1.1.1.2 root 207: /* Else, scale volume */
1.1 root 208: Sample = (char)((float)Sample*PlayVolume);
209:
210: return(Sample);
211: }
212:
1.1.1.2 root 213:
214: /*-----------------------------------------------------------------------*/
1.1 root 215: /*
1.1.1.2 root 216: Write samples into Direct Sound buffer at 'Offset',
217: taking care to wrap around. Pass NULL to write zero's.
1.1 root 218: */
1.1.1.2 root 219: void Audio_WriteSamplesIntoBuffer(char *pSamples,int Index,int Length,int RampSetting)
1.1 root 220: {
1.1.1.2 root 221: void *lpWrite;
1.1 root 222: unsigned char *pBuffer;
1.1.1.2 root 223: short dwLenBytes;
224: int dsRetVal;
225: int i;
1.1 root 226:
1.1.1.2 root 227: /* Modify ramp volume - ramp down if sound not enabled or not in windows mouse mode */
1.1.1.3 ! root 228: if ( (((RampSetting==RAMP_DOWN) || (!ConfigureParams.Sound.bEnableSound)) && (PlayVolume>0.0f)) ) {
1.1 root 229: PlayVolume -= RAMP_DOWN_VOLUME_LEVEL;
230: if (PlayVolume<=0.0f)
231: PlayVolume = 0.0f;
232: }
233: else if ( (RampSetting==RAMP_UP) && (PlayVolume<1.0f) ) {
234: PlayVolume += RAMP_UP_VOLUME_LEVEL;
235: if (PlayVolume>=1.0f)
236: PlayVolume = 1.0f;
237: }
238:
1.1.1.2 root 239: if (SoundBuffer1) {
240:
241: /* Do need to reset 'write' position? */
1.1 root 242: if (bAquireWritePosition) {
1.1.1.2 root 243: WriteOffset = 0;
1.1 root 244: bAquireWritePosition = FALSE;
245: }
246:
1.1.1.2 root 247: lpWrite = SoundBuffer1 + WriteOffset;
248: dwLenBytes = Length;
1.1 root 249:
1.1.1.2 root 250: /* Write section, convert to 'unsigned' and write '128'(unsigned) if passed NULL */
251: if ( (dwLenBytes>0) && (lpWrite) ) {
252: if (pSamples) {
253: pBuffer = (unsigned char *)lpWrite;
254: for(i=0; i<(int)dwLenBytes; i++) {
255: *pBuffer++ = Audio_ModifyVolume(pSamples[Index])+128;
256: Index = (Index+1)&4095;
1.1 root 257: }
258: }
1.1.1.2 root 259: else
260: memset(lpWrite,128,dwLenBytes);
1.1 root 261: }
262:
1.1.1.2 root 263: /* Update write buffer */
1.1 root 264: if (pSamples) {
265: WriteOffset += Length;
1.1.1.2 root 266: if (WriteOffset>=SoundBufferSize) {
267: /* If the buffer is full, swap the buffers and copy overflow space to the new buffer. */
268: SDL_LockAudio();
269: WriteOffset -= SoundBufferSize;
270: memcpy(SoundBuffer2, SoundBuffer1+SoundBufferSize, WriteOffset); /* Copy overflow to the next buffer */
271: pBuffer = SoundBuffer2;
272: SoundBuffer2 = SoundBuffer1; /* Swap the buffers */
273: SoundBuffer1 = pBuffer;
274: SDL_UnlockAudio();
275: }
1.1 root 276: }
277:
1.1.1.2 root 278: /* Are we playing? */
1.1 root 279: if (!bPlayingBuffer) {
1.1.1.3 ! root 280: SDL_PauseAudio(FALSE);
1.1.1.2 root 281: Audio_ResetBuffer();
1.1 root 282: bPlayingBuffer = TRUE;
283: }
284: else {
1.1.1.2 root 285: /* Check here for play/write pointers getting away from each other and set 'bAquireWritePosition' to reset */
286: //lpDSBPrimBuffer->GetCurrentPosition(NULL,(DWORD *)&WriteCursor);
287: /* If the writecursor is too-far away from where we think it should be cause a reset */
288: //CursorDiff = WriteOffset-WriteCursor;
289: /* Check for overlap */
290: //if (CursorDiff<0)
291: // CursorDiff = (WriteOffset+PrimaryBufferSize)-WriteCursor;
292: /* So, does need reset? */
293: //if (abs(CursorDiff)>(WRITE_INIT_POS*2))
294: // Audio_ResetBuffer();
1.1 root 295: }
296: }
1.1.1.2 root 297:
1.1 root 298: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.