File:  [UNIX Amiga Emulator] / uae / src / od-win32 / sound.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:59:27 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, BSchmidt
CVS tags: uae0817, uae0816, HEAD
uae-0.8.16

/*
 * UAE - The Un*x Amiga Emulator
 *
 * Win32 interface
 *
 * Copyright 1997 Mathias Ortmann
 */

#include <windows.h>
#include <ddraw.h>
#include <dsound.h>
#include <stdlib.h>
#include <stdarg.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>

#include "config.h"
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "sounddep/sound.h"
#include "events.h"
#include "uae.h"
#include "include/memory.h"
#include "events.h"
#include "custom.h"
#include "osdep/win32gui.h"
#include "osdep/resource.h"
#include "osdep/win32.h"

/* Sound emulation, Win32 interface */
char *sndptr, *sndptrmax, soundneutral;

static WAVEFORMATEX wavfmt;

LPSTR lpData;
static frame_time_t basevsynctime;
signed long bufsamples;
unsigned int samplecount;
DWORD soundbufsize;

int setup_sound (void)
{
    sound_available = 1;
    return 1;
}

int use_direct_sound = 1;

static HINSTANCE hDSound = NULL;

static HRESULT (WINAPI *pDirectSoundCreate) (GUID FAR *, LPDIRECTSOUND FAR *, IUnknown FAR *);

extern HWND hAmigaWnd;

LPDIRECTSOUND lpDS = NULL;
LPDIRECTSOUNDBUFFER lpDSBprimary = NULL;
LPDIRECTSOUNDBUFFER lpDSB = NULL;

char *DSError( HRESULT error )
{
    switch( error )
    {
    case DSERR_ALLOCATED:
        return "Allocated";

    case DSERR_UNINITIALIZED:
        return "Uninitialized";

    case DSERR_BADFORMAT:
        return "Bad Format";

    case DSERR_INVALIDCALL:
        return "Invalid Call";

    case DSERR_INVALIDPARAM:
        return "Invalid Parameter";

    case DSERR_OUTOFMEMORY:
        return "Out of Memory";

    case DSERR_PRIOLEVELNEEDED:
        return "Priority Level Needed";

    case DSERR_UNSUPPORTED:
        return "Unsupported";

    default:
        return "Unknown";
    }
}

LPWAVEHDR lpWaveHdr;
HANDLE hWaveOut;

MMTIME mmtime;

void close_sound (void)
{
    if( use_direct_sound )
    {
        if( lpDSB )
        {
            IDirectSoundBuffer_Release( lpDSB );
            lpDSB = NULL;
        }
        if( lpDSBprimary )
        {
            IDirectSoundBuffer_Release( lpDSBprimary );
            lpDSBprimary = NULL;
        }
        if( lpDS )
        {
            IDirectSound_Release( lpDS );
            lpDS = NULL;
        }
        if( hDSound )
            FreeLibrary( hDSound );
    }
    else
    {
        if( hWaveOut )
        {
	        waveOutReset( hWaveOut );
	        waveOutUnprepareHeader( hWaveOut, lpWaveHdr, sizeof( WAVEHDR ) );
	        GlobalFree( lpWaveHdr );
	        waveOutClose( hWaveOut );

	        hWaveOut = NULL;
        }
    }
    GlobalFree( lpData );
}

static __inline__ void direct_sound_play (LPSTR buffer)
{
    HRESULT hr;
    LPVOID lpvPtr1, lpvPtr2;
    DWORD dwBytes1, dwBytes2, status = 0;

    hr = IDirectSoundBuffer_Lock( lpDSB, 0, soundbufsize, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0 );
    if( hr == DSERR_BUFFERLOST )
    {
        IDirectSoundBuffer_Restore( lpDSB );
        hr = IDirectSoundBuffer_Lock( lpDSB, 0, soundbufsize, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0 );
    }
    if (hr == DS_OK) {
        memcpy (lpvPtr1, buffer, dwBytes1);
        if (lpvPtr2 != NULL) {
            memcpy (lpvPtr2, buffer+dwBytes1, dwBytes2);
        }
        hr = IDirectSoundBuffer_Unlock( lpDSB, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2 );
        hr = IDirectSoundBuffer_SetCurrentPosition( lpDSB, 0 );
        hr = IDirectSoundBuffer_GetStatus (lpDSB, &status);
        if (status & DSBSTATUS_PLAYING)
        {
            /* Already playing */
        }
        else
        {
            /* We took too long to fill in the buffer - get it playing again */
            hr = IDirectSoundBuffer_Play( lpDSB, 0, 0, 0 );
	    if (hr != DS_OK) {
		write_log( "SoundBuffer_Play() failure: %s", DSError( hr ) );
	    }
        }
    }
    else
    {
        write_log( "SoundLock() failure: %s", DSError( hr ) );
    }
}
    
void flush_sound_buffer( void )
{
    if (use_direct_sound)
        direct_sound_play (lpData);
}

void startsound( void )
{
    HRESULT hr;

    if (use_direct_sound)
    {
#if 0
        hr = IDirectSoundBuffer_Play (lpDSBprimary, 0, 0, DSBPLAY_LOOPING);
	if (hr != DS_OK) {
            write_log( "SoundPlay() failure: %s", DSError( hr ) );
        }
        hr = IDirectSoundBuffer_Play( lpDSB, 0, 0, 0 );

        if( hr == DS_OK )
        {
            write_log( "Sound Started...\n" );
            hr = IDirectSoundBuffer_SetVolume( lpDSB, 0 );
        } else {
            write_log( "SoundPlay() failure: %s", DSError( hr ) );
        }
#endif
    }
    else
    {
        lpWaveHdr->lpData = lpData;
        lpWaveHdr->dwBufferLength = soundbufsize;
        lpWaveHdr->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
        lpWaveHdr->dwLoops = 0x7fffffffL;
        waveOutPrepareHeader( hWaveOut, lpWaveHdr, sizeof(WAVEHDR) ); 

        if( waveOutWrite( hWaveOut, lpWaveHdr, sizeof(WAVEHDR) ) )
        { 
            write_log( "Failed to write to sound card\n" );
        } 
    }
}

void stopsound (void)
{
    HRESULT hr;

    sndptr = lpData;
    samplecount = 0;

    if( use_direct_sound )
    {
#if 0
        hr = IDirectSoundBuffer_Stop( lpDSB );
        if( hr != DS_OK )
        {
            write_log( "SoundStop() failure: %s", DSError( hr ) );
        }
        else
            write_log( "Sound Stopped...\n" );
#endif
    }
    else
    {
        memset( lpData, soundneutral, soundbufsize );
        waveOutReset( hWaveOut );
        waveOutUnprepareHeader( hWaveOut, lpWaveHdr, sizeof( WAVEHDR ) );
    }
}

static HWND dsound_tmpw;

int dsound_newwindow (HWND w)
{
    HRESULT hr;

    if (lpDS == 0)
	return 1;

    if (w == 0)
	w = dsound_tmpw;

    hr = IDirectSound_SetCooperativeLevel (lpDS, w, DSSCL_PRIORITY);
    if (hr != DS_OK) {
	write_log( "SetCooperativeLevel() failure: %s", DSError (hr));
	return 0;
    }
    return 1;
}

static int init_sound_win32 (void)
{
    HRESULT hr;
    DSBUFFERDESC sound_buffer;
    MMRESULT mmres;
    static int first_time = 1;

    if( currprefs.produce_sound < 0 ) 
    {
	    currprefs.produce_sound = 0;
	    write_log( "FrameSync disabled.\n" );
    }
    else
    {
#ifdef FRAME_RATE_HACK
        if (first_time)
        {
	        figure_processor_speed ();
            first_time = 0;
        }
#endif
    }

    if (currprefs.produce_sound < 2) {
	write_log ("Sound output disabled.\n");
	return 1;
    }

    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
    wavfmt.nChannels = 1 + currprefs.stereo;
    wavfmt.nSamplesPerSec = currprefs.sound_freq;
    wavfmt.nBlockAlign = currprefs.sound_bits / 8 * wavfmt.nChannels;
    wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * currprefs.sound_freq;
    wavfmt.wBitsPerSample = currprefs.sound_bits;

    soundneutral = currprefs.sound_bits == 8 ? 128 : 0;
    bufsamples = use_direct_sound ? 4096:2048 * currprefs.sound_freq / 11025;
    soundbufsize = bufsamples * wavfmt.nBlockAlign;

    if( !( lpData = (LPSTR)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, soundbufsize ) ) )
    {
	    write_log( "Failed to allocate sound buffer!\n" );
	    return 0;
    }

    if( use_direct_sound )
    {
	hDSound = LoadLibrary( "DSOUND.DLL" );
        if (hDSound == 0) {
    	    write_log ("You have to install DirectX on your system before you can use UAE.\n"
		       "Refer to the documentation for further details.\n");
	    return 0;
        }
	pDirectSoundCreate = GetProcAddress (hDSound, "DirectSoundCreate");

	basevsynctime = vsynctime;
	sndptrmax = lpData+soundbufsize;
	hr = pDirectSoundCreate( NULL, &lpDS, NULL );
	if (hr != DS_OK) {
	    write_log( "DirectSoundCreate() failure: %s", DSError (hr));
	    return 0;
	}

	dsound_tmpw = CreateWindowEx (WS_EX_ACCEPTFILES,
				      "PCsuxRox",
				      "Argh",
				      WS_CAPTION,
				      CW_USEDEFAULT, CW_USEDEFAULT,
				      10, 10,
				      NULL,
				      NULL,
				      0,
				      NULL);

	if (! dsound_newwindow (0))
	    return 0;

	memset (&sound_buffer, 0, sizeof( DSBUFFERDESC ));
	sound_buffer.dwSize = sizeof( DSBUFFERDESC );
	sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER;
	sound_buffer.dwBufferBytes = 0;
	sound_buffer.lpwfxFormat = NULL;

	hr = IDirectSound_CreateSoundBuffer (lpDS, &sound_buffer, &lpDSBprimary, NULL);
	if (hr != DS_OK) {
	    write_log( "CreateSoundBuffer() failure: %s", DSError( hr ) );
	    return 0;
	}

	hr = IDirectSoundBuffer_SetFormat (lpDSBprimary, &wavfmt);
	if (hr != DS_OK) {
	    write_log( "SetFormat() failure: %s", DSError (hr));
	    return 0;
	}
#if 0
	hr = IDirectSoundBuffer_SetVolume (lpDSBprimary, 0);
	if (hr != DS_OK) {
	    write_log( "SetVolume() 1 failure: %s", DSError (hr));
	    return 0;
	}
#endif
	sound_buffer.dwBufferBytes = soundbufsize;
	sound_buffer.lpwfxFormat = &wavfmt;
	sound_buffer.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC;
	hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &lpDSB, NULL );
	if (hr != DS_OK) {
	    write_log ("CreateSoundBuffer() failure: %s", DSError (hr));
	    return 0;
	}
	hr = IDirectSoundBuffer_SetVolume (lpDSB, 0);
	if (hr != DS_OK) {
	    write_log( "SetVolume() 2 failure: %s", DSError (hr));
	    return 0;
	}
    } else {
        mmtime.wType = TIME_SAMPLES;

        if( !( lpWaveHdr = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, (DWORD)sizeof( WAVEHDR ) ) ) )
        {
	        write_log( "Failed to allocate wave header!\n" );
	        return 0;
        }

        if( mmres = waveOutOpen( &hWaveOut, WAVE_MAPPER, &wavfmt, 0, 0, CALLBACK_NULL ) )
        {
	        write_log( "Sound device failed to open with error code %d.\n", mmres );
	        return 0;
        }
    }
    basevsynctime = vsynctime;
    sndptrmax = lpData + soundbufsize;

    stopsound();
    startsound();

    return currprefs.sound_freq;
}

void adjust_sound_timing (void)
{
    static DWORD last;
    signed long diff;

    if( use_direct_sound )
        return;

    waveOutGetPosition (hWaveOut, &mmtime, sizeof (mmtime));
    if (!mmtime.u.sample)
	mmtime.u.sample++;

    if (last == mmtime.u.sample)
	return;
    last = mmtime.u.sample;

    diff = samplecount - mmtime.u.sample;

    if (diff < -bufsamples || diff > bufsamples) {
	samplecount = mmtime.u.sample;
	sndptr = lpData + (samplecount % bufsamples) * wavfmt.nBlockAlign;
    }

/*
    if (diff < 0)
	vsynctime = basevsynctime * 5 / 6;
    else if (diff > 0)
	vsynctime = basevsynctime * 7 / 6;
*/
    return;
}

int init_sound (void)
{
    int rate;

    if ((rate = init_sound_win32 ()) < 2)
	return rate;

    scaled_sample_evtime = (unsigned long) maxhpos * maxvpos * vblank_hz * CYCLE_UNIT / rate;
    scaled_sample_evtime_ok = 1;

    if (currprefs.sound_bits == 16) {
	init_sound_table16 ();
	sample_handler = currprefs.stereo ? sample16s_handler : sample16_handler;
    } else {
	init_sound_table8 ();
	sample_handler = currprefs.stereo ? sample8s_handler : sample8_handler;
    }

    write_log ("Sound driver found and configured for %d bits at %d Hz %s\n",
			 currprefs.sound_bits, rate, currprefs.stereo ? "stereo" : "");

    return 1;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.