|
|
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] = {
1.1.1.4 ! root 27: { 221,220 }, /* 220.5 */
! 28: { 441,441 }, /* 441 */
! 29: { 882,882 }, /* 882 */
1.1 root 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: {
1.1.1.2 root 63: /* Is enabled? */
1.1.1.4 ! root 64: if(bDisableSound)
! 65: {
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.4 ! root 72: /* Init the SDL's audio subsystem: */
! 73: if( SDL_WasInit(SDL_INIT_AUDIO)==0 )
! 74: {
! 75: if( SDL_InitSubSystem(SDL_INIT_AUDIO)<0 )
! 76: {
! 77: fprintf(stderr, "Could not init audio: %s\n", SDL_GetError() );
! 78: bSoundWorking = FALSE;
! 79: return;
! 80: }
! 81: }
! 82:
! 83: /* Set up SDL audio: */
1.1.1.3 root 84: desiredAudioSpec.freq = SoundPlayBackFrequencies[OutputAudioFreqIndex];
85: desiredAudioSpec.format = AUDIO_U8; /* 8 Bit unsigned */
86: desiredAudioSpec.channels = 1; /* Mono */
87: desiredAudioSpec.samples = SoundBufferSize; /* Buffer size */
88: desiredAudioSpec.callback = Audio_CallBack;
89: desiredAudioSpec.userdata = NULL;
90: if( SDL_OpenAudio(&desiredAudioSpec, NULL) ) /* Open audio device */
91: {
1.1.1.4 ! root 92: fprintf(stderr, "Can't use audio: %s\n", SDL_GetError());
1.1.1.2 root 93: bSoundWorking = FALSE;
1.1.1.3 root 94: ConfigureParams.Sound.bEnableSound = FALSE;
1.1.1.2 root 95: return;
1.1 root 96: }
1.1.1.3 root 97:
1.1.1.2 root 98: /* Create sound buffer, return if error */
99: Audio_CreateSoundBuffer();
1.1.1.3 root 100: SDL_PauseAudio(FALSE);
1.1 root 101: }
102:
1.1.1.2 root 103:
104: /*-----------------------------------------------------------------------*/
1.1 root 105: /*
106: Free object created for Direct Sound
107: */
1.1.1.2 root 108: void Audio_UnInit(void)
1.1 root 109: {
1.1.1.3 root 110: SDL_PauseAudio(TRUE);
1.1.1.2 root 111:
112: /* Free sound buffer */
113: Audio_FreeSoundBuffer();
114:
115: SDL_CloseAudio();
1.1 root 116: }
117:
1.1.1.2 root 118:
119: /*-----------------------------------------------------------------------*/
1.1 root 120: /*
121: Create sound buffer to write samples into
122: */
1.1.1.2 root 123: BOOL Audio_CreateSoundBuffer(void)
1.1 root 124: {
1.1.1.2 root 125: int bufferlen;
1.1 root 126:
1.1.1.2 root 127: /* Allocate memory for the 2 sound buffers: */
128: bufferlen = SoundBufferSize + SoundPlayBackFreqFrameLengths[FREQ_44Khz][0];
129: SoundBuffer1 = malloc( bufferlen );
130: if( !SoundBuffer1 ) {
131: bSoundWorking = FALSE;
1.1 root 132: return(FALSE);
133: }
1.1.1.2 root 134: memset(SoundBuffer1, 128, bufferlen);
135:
136: SoundBuffer2 = malloc( bufferlen );
137: if( !SoundBuffer2 ) {
138: bSoundWorking = FALSE;
139: free( SoundBuffer1 );
140: SoundBuffer1 = NULL;
1.1 root 141: return(FALSE);
142: }
1.1.1.2 root 143: memset(SoundBuffer2, 128, bufferlen);
1.1 root 144:
1.1.1.2 root 145: /* All OK */
146: bSoundWorking = TRUE;
147: /* And begin */
148: Audio_ResetBuffer();
1.1 root 149:
150: return(TRUE);
151: }
152:
1.1.1.2 root 153:
154: /*-----------------------------------------------------------------------*/
1.1 root 155: /*
156: Free sound buffer
157: */
1.1.1.2 root 158: void Audio_FreeSoundBuffer(void)
1.1 root 159: {
1.1.1.2 root 160: /* Stop */
161: Audio_StopBuffer();
162: /* And free */
163: if( SoundBuffer1 )
164: free(SoundBuffer1);
1.1.1.3 root 165: if( SoundBuffer2 )
1.1.1.2 root 166: free(SoundBuffer2);
1.1 root 167: }
168:
1.1.1.2 root 169:
170: /*-----------------------------------------------------------------------*/
1.1 root 171: /*
1.1.1.3 root 172: Set audio playback frequency variable, pass as PLAYBACK_xxxx
1.1 root 173: */
1.1.1.2 root 174: void Audio_SetOutputAudioFreq(int Frequency)
1.1 root 175: {
1.1.1.2 root 176: /* Set new frequency, index into SoundPlayBackFrequencies[] */
1.1 root 177: OutputAudioFreqIndex = Frequency;
1.1.1.3 root 178:
179: /* Re-open SDL audio interface... */
180: Audio_UnInit();
181: Audio_Init();
1.1 root 182: }
183:
1.1.1.2 root 184:
185: /*-----------------------------------------------------------------------*/
1.1 root 186: /*
187: Reset sound buffer, so plays from correct position
188: */
1.1.1.2 root 189: void Audio_ResetBuffer(void)
1.1 root 190: {
1.1.1.2 root 191: /* Get new 'write' position on next frame */
1.1 root 192: bAquireWritePosition = TRUE;
193: }
194:
1.1.1.2 root 195:
196: /*-----------------------------------------------------------------------*/
1.1 root 197: /*
198: Stop sound buffer
199: */
1.1.1.2 root 200: void Audio_StopBuffer(void)
1.1 root 201: {
1.1.1.2 root 202: /* Stop from playing */
1.1.1.3 root 203: SDL_PauseAudio(TRUE);
1.1 root 204: bPlayingBuffer = FALSE;
205: }
206:
1.1.1.2 root 207:
208: /*-----------------------------------------------------------------------*/
1.1 root 209: /*
210: Scale sample value(-128...127) according to 'PlayVolume' setting
211: */
1.1.1.2 root 212: char Audio_ModifyVolume(char Sample)
1.1 root 213: {
1.1.1.2 root 214: /* If full volume, just use current value */
1.1 root 215: if (PlayVolume==1.0f)
216: return(Sample);
217:
1.1.1.2 root 218: /* Else, scale volume */
1.1 root 219: Sample = (char)((float)Sample*PlayVolume);
220:
221: return(Sample);
222: }
223:
1.1.1.2 root 224:
225: /*-----------------------------------------------------------------------*/
1.1 root 226: /*
1.1.1.2 root 227: Write samples into Direct Sound buffer at 'Offset',
228: taking care to wrap around. Pass NULL to write zero's.
1.1 root 229: */
1.1.1.2 root 230: void Audio_WriteSamplesIntoBuffer(char *pSamples,int Index,int Length,int RampSetting)
1.1 root 231: {
1.1.1.2 root 232: void *lpWrite;
1.1 root 233: unsigned char *pBuffer;
1.1.1.2 root 234: short dwLenBytes;
235: int i;
1.1 root 236:
1.1.1.2 root 237: /* Modify ramp volume - ramp down if sound not enabled or not in windows mouse mode */
1.1.1.3 root 238: if ( (((RampSetting==RAMP_DOWN) || (!ConfigureParams.Sound.bEnableSound)) && (PlayVolume>0.0f)) ) {
1.1 root 239: PlayVolume -= RAMP_DOWN_VOLUME_LEVEL;
240: if (PlayVolume<=0.0f)
241: PlayVolume = 0.0f;
242: }
243: else if ( (RampSetting==RAMP_UP) && (PlayVolume<1.0f) ) {
244: PlayVolume += RAMP_UP_VOLUME_LEVEL;
245: if (PlayVolume>=1.0f)
246: PlayVolume = 1.0f;
247: }
248:
1.1.1.2 root 249: if (SoundBuffer1) {
250:
251: /* Do need to reset 'write' position? */
1.1 root 252: if (bAquireWritePosition) {
1.1.1.2 root 253: WriteOffset = 0;
1.1 root 254: bAquireWritePosition = FALSE;
255: }
256:
1.1.1.2 root 257: lpWrite = SoundBuffer1 + WriteOffset;
258: dwLenBytes = Length;
1.1 root 259:
1.1.1.2 root 260: /* Write section, convert to 'unsigned' and write '128'(unsigned) if passed NULL */
261: if ( (dwLenBytes>0) && (lpWrite) ) {
262: if (pSamples) {
263: pBuffer = (unsigned char *)lpWrite;
264: for(i=0; i<(int)dwLenBytes; i++) {
265: *pBuffer++ = Audio_ModifyVolume(pSamples[Index])+128;
266: Index = (Index+1)&4095;
1.1 root 267: }
268: }
1.1.1.2 root 269: else
270: memset(lpWrite,128,dwLenBytes);
1.1 root 271: }
272:
1.1.1.2 root 273: /* Update write buffer */
1.1 root 274: if (pSamples) {
275: WriteOffset += Length;
1.1.1.2 root 276: if (WriteOffset>=SoundBufferSize) {
277: /* If the buffer is full, swap the buffers and copy overflow space to the new buffer. */
278: SDL_LockAudio();
279: WriteOffset -= SoundBufferSize;
280: memcpy(SoundBuffer2, SoundBuffer1+SoundBufferSize, WriteOffset); /* Copy overflow to the next buffer */
281: pBuffer = SoundBuffer2;
282: SoundBuffer2 = SoundBuffer1; /* Swap the buffers */
283: SoundBuffer1 = pBuffer;
284: SDL_UnlockAudio();
285: }
1.1 root 286: }
287:
1.1.1.2 root 288: /* Are we playing? */
1.1 root 289: if (!bPlayingBuffer) {
1.1.1.3 root 290: SDL_PauseAudio(FALSE);
1.1.1.2 root 291: Audio_ResetBuffer();
1.1 root 292: bPlayingBuffer = TRUE;
293: }
294: else {
1.1.1.2 root 295: /* Check here for play/write pointers getting away from each other and set 'bAquireWritePosition' to reset */
296: //lpDSBPrimBuffer->GetCurrentPosition(NULL,(DWORD *)&WriteCursor);
297: /* If the writecursor is too-far away from where we think it should be cause a reset */
298: //CursorDiff = WriteOffset-WriteCursor;
299: /* Check for overlap */
300: //if (CursorDiff<0)
301: // CursorDiff = (WriteOffset+PrimaryBufferSize)-WriteCursor;
302: /* So, does need reset? */
303: //if (abs(CursorDiff)>(WRITE_INIT_POS*2))
304: // Audio_ResetBuffer();
1.1 root 305: }
306: }
1.1.1.2 root 307:
1.1 root 308: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.