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