mirror of https://github.com/stella-emu/stella.git
Updated the DOS port to use the new sound routines in the core. Also
switched to a new set of low-level Sound Blaster routines which appear to provide better Sound Blaster support and the ability to auto-detect sound card settings. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@142 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
b93d8d186d
commit
f9c3e778c8
|
@ -13,7 +13,7 @@
|
|||
## See the file "license" for information on usage and redistribution of
|
||||
## this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
##
|
||||
## $Id: makefile,v 1.26 2002-11-11 22:01:28 stephena Exp $
|
||||
## $Id: makefile,v 1.27 2002-11-13 03:47:55 bwmott Exp $
|
||||
##============================================================================
|
||||
|
||||
##============================================================================
|
||||
|
@ -185,7 +185,7 @@ dos:
|
|||
OPTIONS+="$(OPTS.DOS)" \
|
||||
LDFLAGS="" \
|
||||
LDLIBS="" \
|
||||
OBJS="mainDOS.o PCJoys.o SndDOS.o sbdrv.o"
|
||||
OBJS="mainDOS.o PCJoys.o SndDOS.o dos_sb.o"
|
||||
|
||||
unix-x:
|
||||
make stella.x11 \
|
||||
|
@ -428,8 +428,8 @@ PCJoys.o: $(UI)/dos/PCJoys.cxx
|
|||
SndDOS.o: $(UI)/dos/SndDOS.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/SndDOS.cxx
|
||||
|
||||
sbdrv.o: $(UI)/dos/sbdrv.c
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/sbdrv.c
|
||||
dos_sb.o: $(UI)/dos/dos_sb.c
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/dos_sb.c
|
||||
|
||||
TermX11.o: $(UI)/x11/TermX11.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/x11/TermX11.cxx
|
||||
|
|
|
@ -8,122 +8,257 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SndDOS.cxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
|
||||
// $Id: SndDOS.cxx,v 1.2 2002-11-13 03:47:55 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "SndDOS.hxx"
|
||||
#include "TIASound.h"
|
||||
#include "sbdrv.h"
|
||||
|
||||
/**
|
||||
Compute the buffer size to use based on the given sample rate
|
||||
|
||||
@param The sample rate to compute the buffer size for
|
||||
*/
|
||||
static unsigned long computeBufferSize(int sampleRate)
|
||||
{
|
||||
int t;
|
||||
|
||||
for(t = 7; t <= 12; ++t)
|
||||
{
|
||||
if((1 << t) > (sampleRate / 60))
|
||||
{
|
||||
return (1 << (t - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return 256;
|
||||
}
|
||||
#include "dos.h"
|
||||
#include "dos_sb.h"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::SoundDOS()
|
||||
SoundDOS::SoundDOS(bool activate)
|
||||
: myCurrentVolume(100),
|
||||
myFragmentSize(1024),
|
||||
myIsInitializedFlag(false),
|
||||
myUpdateLock(false),
|
||||
myIsMuted(false),
|
||||
mySampleRate(31400),
|
||||
mySampleQueue(mySampleRate)
|
||||
{
|
||||
int sampleRate = 15700;
|
||||
int DMABufferSize = computeBufferSize(sampleRate);
|
||||
|
||||
if(OpenSB(sampleRate, DMABufferSize))
|
||||
if(activate)
|
||||
{
|
||||
myEnabled = true;
|
||||
int bps = 8;
|
||||
int stereo = 0;
|
||||
int buffersize = myFragmentSize;
|
||||
int playback_freq = mySampleRate;
|
||||
|
||||
// Initialize TIA Sound Library
|
||||
Tia_sound_init(31400, sampleRate);
|
||||
if(sb_init(&playback_freq, &bps, &buffersize, &stereo) < 0)
|
||||
{
|
||||
cerr << "WARNING: Couldn't initialize audio system! " << endl;
|
||||
myIsInitializedFlag = false;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mySampleRate = playback_freq;
|
||||
myFragmentSize = buffersize;
|
||||
|
||||
myIsInitializedFlag = true;
|
||||
myIsMuted = false;
|
||||
|
||||
// Start playing audio
|
||||
Start_audio_output(AUTO_DMA,
|
||||
(void (*)(unsigned char*, short unsigned int))Tia_process);
|
||||
sb_startoutput((sbmix_t)callback, (void*)this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oops, couldn't open SB so we're not enabled :-(
|
||||
myEnabled = false;
|
||||
return;
|
||||
myIsInitializedFlag = false;
|
||||
myIsMuted = true;
|
||||
mySampleRate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::~SoundDOS()
|
||||
{
|
||||
if(myEnabled)
|
||||
{
|
||||
CloseSB();
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::set(Sound::Register reg, uInt8 value)
|
||||
uInt32 SoundDOS::getSampleRate() const
|
||||
{
|
||||
if(!myEnabled)
|
||||
return;
|
||||
return myIsInitializedFlag ? mySampleRate : 0;
|
||||
}
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case AUDC0:
|
||||
Update_tia_sound(0x15, value);
|
||||
break;
|
||||
|
||||
case AUDC1:
|
||||
Update_tia_sound(0x16, value);
|
||||
break;
|
||||
|
||||
case AUDF0:
|
||||
Update_tia_sound(0x17, value);
|
||||
break;
|
||||
|
||||
case AUDF1:
|
||||
Update_tia_sound(0x18, value);
|
||||
break;
|
||||
|
||||
case AUDV0:
|
||||
Update_tia_sound(0x19, value);
|
||||
break;
|
||||
|
||||
case AUDV1:
|
||||
Update_tia_sound(0x1A, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundDOS::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::mute(bool state)
|
||||
{
|
||||
if(state)
|
||||
if(!myIsInitializedFlag)
|
||||
{
|
||||
Stop_audio_output();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore multiple calls to do the same thing
|
||||
if(myIsMuted == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
myIsMuted = state;
|
||||
|
||||
if(myIsMuted)
|
||||
{
|
||||
sb_stopoutput();
|
||||
}
|
||||
else
|
||||
{
|
||||
Start_audio_output(AUTO_DMA,
|
||||
(void (*)(unsigned char*, short unsigned int))Tia_process);
|
||||
sb_startoutput((sbmix_t)callback, (void*)this);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::close()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
sb_shutdown();
|
||||
}
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::setSoundVolume(uInt32 percent)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
if((percent >= 0) && (percent <= 100))
|
||||
{
|
||||
// TODO: At some point we should support setting the volume...
|
||||
myCurrentVolume = percent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::updateSound(MediaSource& mediaSource)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
// Move all of the generated samples into our private sample queue
|
||||
uInt8 buffer[4096];
|
||||
while(mediaSource.numberOfAudioSamples() > 0)
|
||||
{
|
||||
uInt32 size = mediaSource.dequeueAudioSamples(buffer, 4096);
|
||||
mySampleQueue.enqueue(buffer, size);
|
||||
}
|
||||
|
||||
// Block until the sound interrupt has consumed all but 125 milliseconds
|
||||
// of the available audio samples
|
||||
uInt32 leave = mySampleRate / 8;
|
||||
while(mySampleQueue.size() > leave)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::callback(void* udata, void* stream, int len)
|
||||
{
|
||||
SoundDOS* sound = (SoundDOS*)udata;
|
||||
|
||||
if(!sound->myIsInitializedFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't use samples unless there's at least 100 milliseconds worth of data
|
||||
if(sound->mySampleQueue.size() < (sound->mySampleRate / 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sound->mySampleQueue.dequeue((uInt8*)stream, len);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::SampleQueue::SampleQueue(uInt32 capacity)
|
||||
: myCapacity(capacity),
|
||||
myBuffer(0),
|
||||
mySize(0),
|
||||
myHead(0),
|
||||
myTail(0)
|
||||
{
|
||||
myBuffer = new uInt8[myCapacity];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::SampleQueue::~SampleQueue()
|
||||
{
|
||||
delete[] myBuffer;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::SampleQueue::clear()
|
||||
{
|
||||
myHead = myTail = mySize = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundDOS::SampleQueue::dequeue(uInt8* buffer, uInt32 size)
|
||||
{
|
||||
// We can only dequeue up to the number of items in the queue
|
||||
if(size > mySize)
|
||||
{
|
||||
size = mySize;
|
||||
}
|
||||
|
||||
if((myHead + size) < myCapacity)
|
||||
{
|
||||
memcpy((void*)buffer, (const void*)(myBuffer + myHead), size);
|
||||
myHead += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
uInt32 s1 = myCapacity - myHead;
|
||||
uInt32 s2 = size - s1;
|
||||
memcpy((void*)buffer, (const void*)(myBuffer + myHead), s1);
|
||||
memcpy((void*)(buffer + s1), (const void*)myBuffer, s2);
|
||||
myHead = (myHead + size) % myCapacity;
|
||||
}
|
||||
|
||||
mySize -= size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::SampleQueue::enqueue(uInt8* buffer, uInt32 size)
|
||||
{
|
||||
disable();
|
||||
if((mySize + size) > myCapacity)
|
||||
{
|
||||
size = myCapacity - mySize;
|
||||
}
|
||||
enable();
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if((myTail + size) < myCapacity)
|
||||
{
|
||||
memcpy((void*)(myBuffer + myTail), (const void*)buffer, size);
|
||||
myTail += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
uInt32 s1 = myCapacity - myTail;
|
||||
uInt32 s2 = size - s1;
|
||||
memcpy((void*)(myBuffer + myTail), (const void*)buffer, s1);
|
||||
memcpy((void*)myBuffer, (const void*)(buffer + s1), s2);
|
||||
myTail = (myTail + size) % myCapacity;
|
||||
}
|
||||
|
||||
disable();
|
||||
mySize += size;
|
||||
enable();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundDOS::SampleQueue::size() const
|
||||
{
|
||||
return mySize;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,34 +8,34 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SndDOS.hxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
|
||||
// $Id: SndDOS.hxx,v 1.2 2002-11-13 03:47:55 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDDOS_HXX
|
||||
#define SOUNDDOS_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Sound.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
|
||||
/**
|
||||
This class implements the sound API for the DOS operating system
|
||||
using a sound-blaster card.
|
||||
This class implements aa sound class for the DOS front-end. It supports
|
||||
SoundBlaster compatible sound cards.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: SndDOS.hxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
|
||||
@version $Id: SndDOS.hxx,v 1.2 2002-11-13 03:47:55 bwmott Exp $
|
||||
*/
|
||||
class SoundDOS : public Sound
|
||||
class SoundDOS
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundDOS();
|
||||
SoundDOS(bool activate = true);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
|
@ -44,23 +44,128 @@ class SoundDOS : public Sound
|
|||
|
||||
public:
|
||||
/**
|
||||
Set the value of the specified sound register
|
||||
|
||||
@param reg The sound register to set
|
||||
@param val The new value for the sound registers
|
||||
Closes the sound device
|
||||
*/
|
||||
virtual void set(Sound::Register reg, uInt8 val);
|
||||
void close();
|
||||
|
||||
/**
|
||||
Set the mute state of the sound object
|
||||
Return the playback sample rate for the sound device.
|
||||
|
||||
@param state Mutes sound iff true
|
||||
@return The playback sample rate
|
||||
*/
|
||||
virtual void mute(bool state);
|
||||
uInt32 getSampleRate() const;
|
||||
|
||||
/**
|
||||
Return true iff the sound device was successfully initialized.
|
||||
|
||||
@return true iff the sound device was successfully initialized
|
||||
*/
|
||||
bool isSuccessfullyInitialized() const;
|
||||
|
||||
/**
|
||||
Set the mute state of the sound object.
|
||||
|
||||
@param state Mutes sound if true, unmute if false
|
||||
*/
|
||||
void mute(bool state);
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
volume is given as a precentage from 0 to 100.
|
||||
|
||||
@param volume The new volume for the sound device
|
||||
*/
|
||||
void setSoundVolume(uInt32 volume);
|
||||
|
||||
/**
|
||||
Update the sound device using the audio sample from the specified
|
||||
media source.
|
||||
|
||||
@param mediaSource The media source to get audio samples from.
|
||||
*/
|
||||
void updateSound(MediaSource& mediaSource);
|
||||
|
||||
private:
|
||||
// Indicates if the sound system was initialized
|
||||
bool myEnabled;
|
||||
/**
|
||||
A bounded queue class used to hold audio samples after they are
|
||||
produced by the MediaSource.
|
||||
*/
|
||||
class SampleQueue
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new SampleQueue instance which can hold the specified
|
||||
number of samples. If the queue ever reaches its capacity then
|
||||
older samples are discarded.
|
||||
*/
|
||||
SampleQueue(uInt32 capacity);
|
||||
|
||||
/**
|
||||
Destroy this SampleQueue instance.
|
||||
*/
|
||||
virtual ~SampleQueue();
|
||||
|
||||
public:
|
||||
/**
|
||||
Clear any samples stored in the queue.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
Dequeue the upto the specified number of samples and store them
|
||||
in the buffer. Returns the actual number of samples removed from
|
||||
the queue.
|
||||
|
||||
@return the actual number of samples removed from the queue.
|
||||
*/
|
||||
uInt32 dequeue(uInt8* buffer, uInt32 size);
|
||||
|
||||
/**
|
||||
Enqueue the specified number of samples from the buffer.
|
||||
*/
|
||||
void enqueue(uInt8* buffer, uInt32 size);
|
||||
|
||||
/**
|
||||
Answers the number of samples currently in the queue.
|
||||
|
||||
@return The number of samples in the queue.
|
||||
*/
|
||||
uInt32 size() const;
|
||||
|
||||
private:
|
||||
const uInt32 myCapacity;
|
||||
uInt8* myBuffer;
|
||||
volatile uInt32 mySize;
|
||||
volatile uInt32 myHead;
|
||||
volatile uInt32 myTail;
|
||||
};
|
||||
|
||||
private:
|
||||
// Current volume
|
||||
uInt32 myCurrentVolume;
|
||||
|
||||
// SDL fragment size
|
||||
uInt32 myFragmentSize;
|
||||
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// Mutex
|
||||
bool myUpdateLock;
|
||||
bool myCallbackLock;
|
||||
|
||||
// Indicates if the sound is currently muted
|
||||
bool myIsMuted;
|
||||
|
||||
// DSP sample rate
|
||||
uInt32 mySampleRate;
|
||||
|
||||
// Queue which holds samples from the media source before they are played
|
||||
SampleQueue mySampleQueue;
|
||||
|
||||
private:
|
||||
// Callback function invoked by the sound library when it needs data
|
||||
static void callback(void* udata, void* stream, int len);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of version 2 of the GNU Library General
|
||||
** Public License as published by the Free Software Foundation.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Library General Public License for more details. To obtain a
|
||||
** copy of the GNU Library General Public License, write to the Free
|
||||
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**
|
||||
** Any permitted reproduction of these routines, in whole or in part,
|
||||
** must bear this legend.
|
||||
**
|
||||
** dos_sb.h
|
||||
**
|
||||
** DOS Sound Blaster header file
|
||||
** $Id: dos_sb.h,v 1.1 2002-11-13 03:47:55 bwmott Exp $
|
||||
*/
|
||||
|
||||
#ifndef DOS_SB_H
|
||||
#define DOS_SB_H
|
||||
|
||||
/* Thanks, Allegro! */
|
||||
#define BPS_TO_TIMER(x) (1193182L / (long)(x))
|
||||
#define END_OF_FUNCTION(x) void x##_end(void) {}
|
||||
#define END_OF_STATIC_FUNCTION(x) static void x##_end(void) {}
|
||||
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void*)&x, sizeof(x))
|
||||
#define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x, (long)x##_end - (long)x)
|
||||
|
||||
#define DISABLE_INTS() __asm__ __volatile__ ("cli")
|
||||
#define ENABLE_INTS() __asm__ __volatile__ ("sti")
|
||||
|
||||
typedef void (*sbmix_t)(void *userdata, void *buffer, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int sb_init(int *sample_rate, int *bps, int *buf_size, int *stereo);
|
||||
extern void sb_shutdown(void);
|
||||
extern int sb_startoutput(sbmix_t fillbuf, void *userdata);
|
||||
extern void sb_stopoutput(void);
|
||||
extern void sb_setrate(int rate);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* DOS_SB_H */
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: mainDOS.cxx,v 1.7 2002-04-28 18:06:56 bwmott Exp $
|
||||
// $Id: mainDOS.cxx,v 1.8 2002-11-13 03:47:55 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <go32.h>
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <strstream>
|
||||
#include <sstream>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
@ -848,6 +848,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
// Create a sound object for use with the console
|
||||
SoundDOS sound;
|
||||
// sound.setSoundVolume(settings->theDesiredVolume);
|
||||
|
||||
// Get just the filename of the file containing the ROM image
|
||||
const char* filename = (!strrchr(file, '\\')) ?
|
||||
|
@ -855,7 +856,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
// Create the 2600 game console
|
||||
theConsole = new Console(image, size, filename,
|
||||
theEvent, propertiesSet, sound);
|
||||
theEvent, propertiesSet, sound.getSampleRate());
|
||||
|
||||
// Free the image since we don't need it any longer
|
||||
delete[] image;
|
||||
|
@ -875,6 +876,7 @@ int main(int argc, char* argv[])
|
|||
if(!thePauseIndicator)
|
||||
{
|
||||
theConsole->mediaSource().update();
|
||||
sound.updateSound(theConsole->mediaSource());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -912,6 +914,9 @@ int main(int argc, char* argv[])
|
|||
// Get the ending time in case we need to print statistics
|
||||
uclock_t endingTime = uclock();
|
||||
|
||||
// Close the sound device
|
||||
sound.close();
|
||||
|
||||
uInt32 scanlines = theConsole->mediaSource().scanlines();
|
||||
string cartName = theConsole->properties().get("Cartridge.Name");
|
||||
string cartMD5 = theConsole->properties().get("Cartridge.MD5");
|
||||
|
|
|
@ -1,988 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: SBDRV */
|
||||
/* Purpose: Sound Blaster DAC DMA Driver V1.3 */
|
||||
/* Author(s): Ron Fries, Neil Bradley and Bradford Mott */
|
||||
/* */
|
||||
/* 02/20/97 - Initial Release */
|
||||
/* */
|
||||
/* 08/19/97 - V1.1 - Corrected problem with the auto-detect of older SB */
|
||||
/* cards and problem with DSP shutdown which left the auto-init */
|
||||
/* mode active. Required creating a function to reset the DSP. */
|
||||
/* Also, added checks on the BLASTER settings to verify they */
|
||||
/* are possible values for either SB or SB compatibles. */
|
||||
/* Added several helpful information/error messages. These can */
|
||||
/* be disabled by removing the SBDRV_SHOW_ERR definition. */
|
||||
/* */
|
||||
/* 12/24/97 - V1.2 - Added support for DJGPP (by Bradford Mott). */
|
||||
/* */
|
||||
/* 02/04/99 - V1.3 - Cleaned up DJGPP support, locking code and data. */
|
||||
/* Fixed a bug with the reading of the BLASTER= environment */
|
||||
/* variable, which caused a segfault if one was not set. Alst */
|
||||
/* added a timeout to dsp_out() and some other minor */
|
||||
/* modifications (Matthew Conte) */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* License Information and Copyright Notice */
|
||||
/* ======================================== */
|
||||
/* */
|
||||
/* SBDrv is Copyright(c) 1997-1999 by Ron Fries, Neil Bradley and */
|
||||
/* Bradford Mott */
|
||||
/* */
|
||||
/* This library is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of version 2 of the GNU Library General Public License */
|
||||
/* as published by the Free Software Foundation. */
|
||||
/* */
|
||||
/* This library is distributed in the hope that it will be useful, but */
|
||||
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */
|
||||
/* General Public License for more details. */
|
||||
/* To obtain a copy of the GNU Library General Public License, write to the */
|
||||
/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
/* */
|
||||
/* Any permitted reproduction of these routines, in whole or in part, must */
|
||||
/* bear this legend. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef DJGPP
|
||||
#include <go32.h>
|
||||
#include <dpmi.h>
|
||||
#include <sys/movedata.h>
|
||||
|
||||
/* Handy macros (care of Allegro) to lock code / data */
|
||||
#define END_OF_FUNCTION(x) static void x##_end(void) {}
|
||||
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void*)&x,sizeof(x))
|
||||
#define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x,(long)x##_end-(long)x)
|
||||
#endif
|
||||
|
||||
#include <dos.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include "sbdrv.h"
|
||||
|
||||
#define DSP_RESET 0x06
|
||||
#define DSP_READ 0x0a
|
||||
#define DSP_WRITE 0x0c
|
||||
#define DSP_ACK 0x0e
|
||||
|
||||
#define DMA_BASE 0x00
|
||||
#define DMA_COUNT 0x01
|
||||
#define DMA_MASK 0x0a
|
||||
#define DMA_MODE 0x0b
|
||||
#define DMA_FF 0x0c
|
||||
|
||||
#define MASTER_VOLUME 0x22
|
||||
#define LINE_VOLUME 0x2e
|
||||
#define FM_VOLUME 0x26
|
||||
|
||||
/* declare local global variables */
|
||||
#ifdef DJGPP
|
||||
static int theDOSBufferSegment;
|
||||
static int theDOSBufferSelector;
|
||||
#endif
|
||||
static uint8 *Sb_buffer;
|
||||
static uint16 Sb_buf_size = 200;
|
||||
static uint16 Sb_offset;
|
||||
static uint16 Playback_freq;
|
||||
static uint8 Sb_init = 0;
|
||||
static uint8 Count_low;
|
||||
static uint8 Count_high;
|
||||
|
||||
static uint16 IOaddr = 0x220;
|
||||
static uint16 Irq = 7;
|
||||
static uint16 Dma = 1;
|
||||
static uint8 DMAmode = AUTO_DMA;
|
||||
/*static*/ uint8 DMAcount;
|
||||
static void (*FillBuffer)(uint8 *buf, uint16 buf_size);
|
||||
|
||||
#ifdef DJGPP
|
||||
static _go32_dpmi_seginfo OldIntVectInfo;
|
||||
static _go32_dpmi_seginfo NewIntVectInfo;
|
||||
#else
|
||||
static void (__interrupt *OldIntVect)(void);
|
||||
#endif
|
||||
|
||||
/* function prototypes */
|
||||
static void setNewIntVect (uint16 irq);
|
||||
static void setOldIntVect (uint16 irq);
|
||||
static void dsp_out (uint16 port, uint8 val);
|
||||
static uint8 hextodec (char c);
|
||||
static void logErr (char *st);
|
||||
static uint8 getBlasterEnv (void);
|
||||
static uint8 dsp_in (uint16 port);
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: newIntVect */
|
||||
/* Purpose: The interrupt vector to handle the DAC DMAC completed interrupt */
|
||||
/* Sends the next buffer to the SB and re-fills the current buffer. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
#ifdef DJGPP
|
||||
static void newIntVect(void)
|
||||
#else
|
||||
static void interrupt newIntVect (void)
|
||||
#endif
|
||||
{
|
||||
uint16 addr;
|
||||
|
||||
if (DMAmode == STANDARD_DMA)
|
||||
{
|
||||
/* restart standard DMA transfer */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0x14);
|
||||
dsp_out (IOaddr + DSP_WRITE, Count_low);
|
||||
dsp_out (IOaddr + DSP_WRITE, Count_high);
|
||||
}
|
||||
|
||||
DMAcount++;
|
||||
|
||||
/* acknowledge the DSP interrupt */
|
||||
inp (IOaddr + DSP_ACK);
|
||||
|
||||
/* determine the current playback position */
|
||||
addr = inp (DMA_BASE + (Dma << 1)); /* get low byte ptr */
|
||||
addr |= inp (DMA_BASE + (Dma << 1)) << 8; /* and high byte ptr */
|
||||
|
||||
addr -= Sb_offset; /* subtract the offset */
|
||||
|
||||
/* if we're currently playing the first half of the buffer */
|
||||
if (addr < Sb_buf_size)
|
||||
{
|
||||
/* reload the second half of the buffer */
|
||||
FillBuffer(Sb_buffer + Sb_buf_size, Sb_buf_size);
|
||||
|
||||
#ifdef DJGPP
|
||||
/* Copy data to DOS memory buffer */
|
||||
dosmemput(Sb_buffer + Sb_buf_size, Sb_buf_size,
|
||||
(theDOSBufferSegment << 4) + Sb_buf_size);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else reload the first half of the buffer */
|
||||
FillBuffer(Sb_buffer, Sb_buf_size);
|
||||
|
||||
#ifdef DJGPP
|
||||
/* Copy data to DOS memory buffer */
|
||||
dosmemput(Sb_buffer, Sb_buf_size, theDOSBufferSegment << 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* indicate end of interrupt */
|
||||
outp (0x20, 0x20);
|
||||
|
||||
if (Irq > 7)
|
||||
{
|
||||
outp (0xa0, 0x20);
|
||||
}
|
||||
}
|
||||
#ifdef DJGPP
|
||||
END_OF_FUNCTION(newIntVect);
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: setNewIntVect */
|
||||
/* Purpose: To set the specified interrupt vector to the sound output */
|
||||
/* processing interrupt. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void setNewIntVect (uint16 irq)
|
||||
{
|
||||
#ifdef DJGPP
|
||||
/* Lock code / data */
|
||||
LOCK_VARIABLE(DMAmode);
|
||||
LOCK_VARIABLE(IOaddr);
|
||||
LOCK_VARIABLE(Count_low);
|
||||
LOCK_VARIABLE(DMAcount);
|
||||
LOCK_VARIABLE(Dma);
|
||||
LOCK_VARIABLE(Sb_offset);
|
||||
LOCK_VARIABLE(Sb_buf_size);
|
||||
LOCK_VARIABLE(theDOSBufferSegment);
|
||||
LOCK_FUNCTION(newIntVect);
|
||||
#endif
|
||||
|
||||
if (irq > 7)
|
||||
{
|
||||
#ifdef DJGPP
|
||||
_go32_dpmi_get_protected_mode_interrupt_vector(irq + 0x68,
|
||||
&OldIntVectInfo);
|
||||
NewIntVectInfo.pm_selector = _my_cs();
|
||||
NewIntVectInfo.pm_offset = (int)newIntVect;
|
||||
_go32_dpmi_allocate_iret_wrapper(&NewIntVectInfo);
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x68,
|
||||
&NewIntVectInfo);
|
||||
#else
|
||||
OldIntVect = _dos_getvect (irq + 0x68);
|
||||
_dos_setvect (irq + 0x68, newIntVect);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DJGPP
|
||||
_go32_dpmi_get_protected_mode_interrupt_vector(irq + 0x08,
|
||||
&OldIntVectInfo);
|
||||
NewIntVectInfo.pm_selector = _my_cs();
|
||||
NewIntVectInfo.pm_offset = (int)newIntVect;
|
||||
_go32_dpmi_allocate_iret_wrapper(&NewIntVectInfo);
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x08,
|
||||
&NewIntVectInfo);
|
||||
#else
|
||||
OldIntVect = _dos_getvect (irq + 0x08);
|
||||
_dos_setvect (irq + 0x08, newIntVect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: setOldIntVect */
|
||||
/* Purpose: To restore the original vector */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void setOldIntVect (uint16 irq)
|
||||
{
|
||||
if (irq > 7)
|
||||
{
|
||||
#ifdef DJGPP
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x68,
|
||||
&OldIntVectInfo);
|
||||
_go32_dpmi_free_iret_wrapper(&NewIntVectInfo);
|
||||
#else
|
||||
_dos_setvect (irq + 0x68, OldIntVect);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DJGPP
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(irq + 0x08,
|
||||
&OldIntVectInfo);
|
||||
_go32_dpmi_free_iret_wrapper(&NewIntVectInfo);
|
||||
#else
|
||||
_dos_setvect (irq + 0x08, OldIntVect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: dsp_out */
|
||||
/* Purpose: To send a byte to the SB's DSP */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: September 10, 1996 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void dsp_out(uint16 port, uint8 val)
|
||||
{
|
||||
uint32 timeout = 60000; /* set timeout */
|
||||
|
||||
/* wait for buffer to be free */
|
||||
while((timeout--) && (inp(IOaddr + DSP_WRITE) & 0x80))
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/* transmit the next byte */
|
||||
outp(port,val);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: dsp_in */
|
||||
/* Purpose: To read a byte from the SB's DSP */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 26, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static uint8 dsp_in(uint16 port)
|
||||
{
|
||||
uint16 x=10000; /* set timeout */
|
||||
|
||||
/* wait for buffer to be free */
|
||||
while(((inp(IOaddr + 0x0E) & 0x80) == 0) && (x>0))
|
||||
{
|
||||
/* decrement the timeout */
|
||||
x--;
|
||||
}
|
||||
|
||||
if (x>0)
|
||||
{
|
||||
/* read the data byte */
|
||||
return(inp(port));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: hextodec */
|
||||
/* Purpose: Convert the input character to hex */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: September 10, 1996 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8 hextodec (char c)
|
||||
{
|
||||
uint8 retval = 0;
|
||||
|
||||
c = toupper (c);
|
||||
|
||||
if ((c>='0') && (c<='9'))
|
||||
{
|
||||
retval = c - '0';
|
||||
}
|
||||
else if ((c>='A') && (c<='F'))
|
||||
{
|
||||
retval = c - 'A' + 10;
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: logErr */
|
||||
/* Purpose: Displays an error message. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: September 24, 1996 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void logErr (char *st)
|
||||
{
|
||||
#ifdef SBDRV_SHOW_ERR
|
||||
printf ("%s",st);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: getBlasterEnv */
|
||||
/* Purpose: Read the BLASTER environment variable and set the local globals */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: September 10, 1996 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static uint8 getBlasterEnv (void)
|
||||
{
|
||||
char *env;
|
||||
char *ptr;
|
||||
uint16 count = 0;
|
||||
|
||||
env = getenv("BLASTER");
|
||||
|
||||
/* if the environment variable exists */
|
||||
if (env)
|
||||
{
|
||||
strupr(env);
|
||||
|
||||
/* search for the address setting */
|
||||
ptr = strchr(env, 'A');
|
||||
if (ptr)
|
||||
{
|
||||
/* if valid, read and convert the IO address */
|
||||
IOaddr = (hextodec (ptr[1]) << 8) +
|
||||
(hextodec (ptr[2]) << 4) +
|
||||
(hextodec (ptr[3]));
|
||||
|
||||
/* verify the IO address is one of the possible SB settings */
|
||||
switch (IOaddr)
|
||||
{
|
||||
case 0x210:
|
||||
case 0x220:
|
||||
case 0x230:
|
||||
case 0x240:
|
||||
case 0x250:
|
||||
case 0x260:
|
||||
case 0x280:
|
||||
case 0x2A0:
|
||||
case 0x2C0:
|
||||
case 0x2E0:
|
||||
/* IO address OK so indicate one more valid item found */
|
||||
count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
logErr ("Invalid Sound Blaster I/O address specified.\n");
|
||||
logErr ("Possible values are: ");
|
||||
logErr ("210, 220, 230, 240, 250, 260, 280, 2A0, 2C0, 2E0.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logErr ("Unable to read Sound Blaster I/O address.\n");
|
||||
}
|
||||
|
||||
/* search for the IRQ setting */
|
||||
ptr = strchr(env, 'I');
|
||||
if (ptr)
|
||||
{
|
||||
/* if valid, read and convert the IRQ */
|
||||
/* if the IRQ has two digits */
|
||||
if ((ptr[1] == '1') && ((ptr[2] >= '0') && (ptr[2] <='5')))
|
||||
{
|
||||
/* then convert accordingly (using decimal) */
|
||||
Irq = hextodec (ptr[1]) * 10 + hextodec (ptr[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else convert as a single hex digit */
|
||||
Irq = hextodec (ptr[1]);
|
||||
}
|
||||
|
||||
/* verify the IRQ setting is one of the possible SB settings */
|
||||
switch (Irq)
|
||||
{
|
||||
case 2: /* two is actually the interrupt cascade for IRQs > 7 */
|
||||
/* IRQ nine is the cascase for 2 */
|
||||
Irq = 9;
|
||||
|
||||
/* IRQ OK so indicate one more valid item found */
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 7:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 15:
|
||||
|
||||
/* IRQ OK so indicate one more valid item found */
|
||||
count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
logErr ("Invalid Sound Blaster IRQ specified.\n");
|
||||
logErr ("Possible values are: ");
|
||||
logErr ("2, 3, 4, 5, 7, 9, 10, 11, 12, 15.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logErr ("Unable to read Sound Blaster IRQ.\n");
|
||||
}
|
||||
|
||||
/* search for the DMA setting */
|
||||
ptr = strchr(env, 'D');
|
||||
if (ptr)
|
||||
{
|
||||
/* if valid, read and convert the DMA */
|
||||
Dma = hextodec (ptr[1]);
|
||||
|
||||
/* verify the DMA setting is one of the possible 8-bit SB settings */
|
||||
switch (Dma)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
/* DMA OK so indicate one more valid item found */
|
||||
count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
logErr ("Invalid Sound Blaster 8-bit DMA specified.\n");
|
||||
logErr ("Possible values are: ");
|
||||
logErr ("0, 1, 3.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logErr ("Unable to read Sound Blaster DMA setting.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logErr ("BLASTER enviroment variable not configured.");
|
||||
}
|
||||
|
||||
return (count != 3);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: low_malloc */
|
||||
/* Purpose: To allocate memory in the first 640K of memory */
|
||||
/* Author: Neil Bradley */
|
||||
/* Date: December 16, 1996 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
void dos_memalloc(unsigned short int para, unsigned short int *seg, unsigned short int *sel);
|
||||
#pragma aux dos_memalloc = \
|
||||
"push ecx" \
|
||||
"push edx" \
|
||||
"mov ax, 0100h" \
|
||||
"int 31h" \
|
||||
"pop ebx" \
|
||||
"mov [ebx], dx" \
|
||||
"pop ebx" \
|
||||
"mov [ebx], ax" \
|
||||
parm [bx] [ecx] [edx] \
|
||||
modify [ax ebx ecx edx];
|
||||
|
||||
void dos_memfree(short int sel);
|
||||
#pragma aux dos_memfree = \
|
||||
"mov ax, 0101h" \
|
||||
"int 31h" \
|
||||
parm [dx] \
|
||||
modify [ax dx];
|
||||
|
||||
void *low_malloc(int size)
|
||||
{
|
||||
unsigned short int seg;
|
||||
unsigned short int i=0;
|
||||
|
||||
dos_memalloc((size >> 4) + 1, &seg, &i);
|
||||
return((char *)(seg << 4));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: Set_master_volume */
|
||||
/* Purpose: To set the Sound Blaster's master volume */
|
||||
/* Author: Neil Bradley */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
void Set_master_volume(uint8 left, uint8 right)
|
||||
|
||||
{
|
||||
/* if the SB was initialized */
|
||||
if (Sb_init)
|
||||
{
|
||||
outp(IOaddr + 0x04, MASTER_VOLUME);
|
||||
outp(IOaddr + 0x05, ((left & 0xf) << 4) + (right & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: Set_line_volume */
|
||||
/* Purpose: To set the Sound Blaster's line level volume */
|
||||
/* Author: Neil Bradley */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
void Set_line_volume(uint8 left, uint8 right)
|
||||
{
|
||||
/* if the SB was initialized */
|
||||
if (Sb_init)
|
||||
{
|
||||
outp(IOaddr + 0x04, LINE_VOLUME);
|
||||
outp(IOaddr + 0x05, ((left & 0xf) << 4) + (right & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: Set_FM_volume */
|
||||
/* Purpose: To set the Sound Blaster's FM volume */
|
||||
/* Author: Neil Bradley */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
void Set_FM_volume(uint8 left, uint8 right)
|
||||
|
||||
{
|
||||
/* if the SB was initialized */
|
||||
if (Sb_init)
|
||||
{
|
||||
outp(IOaddr + 0x04, FM_VOLUME);
|
||||
outp(IOaddr + 0x05, ((left & 0xf) << 4) + (right & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: ResetDSP */
|
||||
/* Purpose: To reset the SB DSP. Returns a value of zero if unsuccessful. */
|
||||
/* This function requires as input the SB base port address. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: August 5, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8 ResetDSP(uint16 ioaddr)
|
||||
{
|
||||
uint8 x;
|
||||
uint16 y;
|
||||
|
||||
/* assume the init was not successful */
|
||||
Sb_init = 0;
|
||||
|
||||
/* send a DSP reset to the SB */
|
||||
outp (ioaddr + DSP_RESET, 1);
|
||||
|
||||
/* wait a few microsec */
|
||||
x = inp(ioaddr + DSP_RESET);
|
||||
x = inp(ioaddr + DSP_RESET);
|
||||
x = inp(ioaddr + DSP_RESET);
|
||||
x = inp(ioaddr + DSP_RESET);
|
||||
|
||||
/* clear the DSP reset */
|
||||
outp (ioaddr + DSP_RESET,0);
|
||||
|
||||
/* wait a bit until the SB indicates good status */
|
||||
y = 0;
|
||||
|
||||
do
|
||||
{
|
||||
x = inp (ioaddr + DSP_READ);
|
||||
y++;
|
||||
} while ((y < 1000) && (x != 0xaa));
|
||||
|
||||
/* if we were able to successfully reset the SB */
|
||||
if (x == 0xaa)
|
||||
{
|
||||
/* turn on speaker */
|
||||
dsp_out (ioaddr + DSP_WRITE, 0xd1);
|
||||
|
||||
/* read to make sure DSP register is clear */
|
||||
dsp_in (ioaddr + DSP_READ);
|
||||
|
||||
/* set time constant */
|
||||
dsp_out (ioaddr + DSP_WRITE, 0x40);
|
||||
dsp_out (ioaddr + DSP_WRITE,
|
||||
(unsigned char)(256 - 1000000L/Playback_freq));
|
||||
|
||||
/* indicate successful initialization */
|
||||
Sb_init = 1;
|
||||
}
|
||||
|
||||
return (Sb_init);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: OpenSB */
|
||||
/* Purpose: To reset the SB and prepare all buffers and other global */
|
||||
/* global variables for sound output. Allows the user to select */
|
||||
/* the playback frequency, number of buffers, and size of each */
|
||||
/* buffer. Returns a value of zero if unsuccessful. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8 OpenSB(uint16 playback_freq, uint16 buffer_size)
|
||||
{
|
||||
/* initialize local globals */
|
||||
if (buffer_size > 0)
|
||||
{
|
||||
Sb_buf_size = buffer_size;
|
||||
}
|
||||
|
||||
Playback_freq = playback_freq;
|
||||
|
||||
/* assume the init was not successful */
|
||||
Sb_init = 0;
|
||||
|
||||
/* attempt to read the Blaster Environment Variable */
|
||||
if (getBlasterEnv() == 0)
|
||||
{
|
||||
/* if the DSP could be successfully reset */
|
||||
if (ResetDSP(IOaddr) != 0 )
|
||||
{
|
||||
/* setup the DSP interrupt service routine */
|
||||
setNewIntVect(Irq);
|
||||
|
||||
/* Enable the interrupt used */
|
||||
if (Irq > 7)
|
||||
{
|
||||
outp (0xa1,inp(0xa1) & (~(1<<(Irq-8))));
|
||||
}
|
||||
else
|
||||
{
|
||||
outp (0x21,inp(0x21) & (~(1<<Irq)));
|
||||
}
|
||||
|
||||
/* make sure interrupts are enabled */
|
||||
_enable();
|
||||
|
||||
/* create a buffer to hold the data */
|
||||
#ifdef __WATCOMC__
|
||||
Sb_buffer = low_malloc (Sb_buf_size*2);
|
||||
#elif defined(DJGPP)
|
||||
Sb_buffer = (uint8 *)malloc(Sb_buf_size*2);
|
||||
theDOSBufferSegment = __dpmi_allocate_dos_memory((Sb_buf_size*2+15) >> 4,
|
||||
&theDOSBufferSelector);
|
||||
#else
|
||||
Sb_buffer = malloc (Sb_buf_size*2);
|
||||
#endif
|
||||
|
||||
/* if we were unable to successfully allocate the buffer */
|
||||
#ifdef DJGPP
|
||||
if ((Sb_buffer == 0) || (theDOSBufferSegment == -1))
|
||||
#else
|
||||
if (Sb_buffer == 0)
|
||||
#endif
|
||||
{
|
||||
logErr ("Unable to allocate buffer for audio output.\n");
|
||||
|
||||
/* close the SB */
|
||||
CloseSB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logErr ("Unable to initialize the Sound Card.\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (Sb_init);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: CloseSB */
|
||||
/* Purpose: Closes the SB and disables the interrupts. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 1, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
void CloseSB(void)
|
||||
{
|
||||
#ifdef __WATCOMC__
|
||||
uint32 addr;
|
||||
#endif
|
||||
|
||||
/* if the SB was initialized */
|
||||
if (Sb_init)
|
||||
{
|
||||
/* stop all DMA transfer */
|
||||
Stop_audio_output();
|
||||
ResetDSP(IOaddr);
|
||||
|
||||
/* turn the speaker off */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0xd3);
|
||||
|
||||
/* indicate SB no longer active */
|
||||
Sb_init = 0;
|
||||
|
||||
/* Disable the interrupt used */
|
||||
if (Irq > 7)
|
||||
{
|
||||
outp (0xa1,inp(0xa1) | (1<<(Irq-8)));
|
||||
}
|
||||
else
|
||||
{
|
||||
outp (0x21,inp(0x21) | (1<<Irq));
|
||||
}
|
||||
|
||||
/* restore the original interrupt routine */
|
||||
setOldIntVect(Irq);
|
||||
|
||||
/* free any memory that had been allocated */
|
||||
if (Sb_buffer != 0)
|
||||
{
|
||||
#ifdef __WATCOMC__
|
||||
addr = (uint32) Sb_buffer;
|
||||
dos_memfree((uint16)(addr >> 4));
|
||||
#elif defined(DJGPP)
|
||||
free(Sb_buffer);
|
||||
__dpmi_free_dos_memory(theDOSBufferSelector);
|
||||
#else
|
||||
free (Sb_buffer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: Stop_audio_output */
|
||||
/* Purpose: Stops the SB's DMA transfer. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: January 17, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
void Stop_audio_output (void)
|
||||
{
|
||||
/* stop any transfer that may be in progress */
|
||||
|
||||
/* if the SB was initialized */
|
||||
if (Sb_init)
|
||||
{
|
||||
/* halt DMA */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0xd0);
|
||||
|
||||
/* exit DMA operation*/
|
||||
dsp_out (IOaddr + DSP_WRITE, 0xda);
|
||||
|
||||
/* halt DMA */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0xd0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: Start_audio_output */
|
||||
/* Purpose: Fills all configured buffers and outputs the first. */
|
||||
/* Author: Ron Fries */
|
||||
/* Date: February 20, 1997 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8 Start_audio_output (uint8 dma_mode,
|
||||
void (*fillBuffer)(uint8 *buf,uint16 n))
|
||||
{
|
||||
uint8 ret_val = 1;
|
||||
static uint8 pagePort[8] = { 0x87, 0x83, 0x81, 0x82 };
|
||||
uint8 offset_low;
|
||||
uint8 offset_high;
|
||||
uint8 page_no;
|
||||
uint8 count_low;
|
||||
uint8 count_high;
|
||||
uint32 addr;
|
||||
clock_t start_time;
|
||||
|
||||
/* if the SB initialized properly */
|
||||
if (Sb_init)
|
||||
{
|
||||
/* set the fill buffer routine */
|
||||
FillBuffer = fillBuffer;
|
||||
|
||||
/* keep track of the DMA selection */
|
||||
DMAmode = dma_mode;
|
||||
|
||||
/* stop any transfer that may be in progress */
|
||||
Stop_audio_output();
|
||||
|
||||
/* fill the buffer */
|
||||
FillBuffer (Sb_buffer, Sb_buf_size*2);
|
||||
|
||||
#ifdef DJGPP
|
||||
/* Copy data to DOS memory buffer */
|
||||
dosmemput(Sb_buffer, Sb_buf_size * 2, theDOSBufferSegment << 4);
|
||||
#endif
|
||||
|
||||
/* calculate high, low and page addresses of buffer */
|
||||
#ifdef __WATCOMC__
|
||||
addr = (uint32) Sb_buffer;
|
||||
#elif defined(DJGPP)
|
||||
addr = ((uint32) theDOSBufferSegment) << 4;
|
||||
#else
|
||||
addr = ((uint32)FP_SEG(Sb_buffer) << 4) +
|
||||
(uint32)FP_OFF(Sb_buffer);
|
||||
#endif
|
||||
Sb_offset = (uint16)(addr & 0x0ffff);
|
||||
offset_low = (uint8)(addr & 0x0ff);
|
||||
offset_high = (uint8)((addr >> 8) & 0x0ff);
|
||||
page_no = (uint8)(addr >> 16);
|
||||
|
||||
count_low = (uint8) ((Sb_buf_size*2)-1) & 0x0ff;
|
||||
count_high = (uint8) (((Sb_buf_size*2)-1) >> 8) & 0x0ff;
|
||||
|
||||
/* program the DMAC for output transfer */
|
||||
outp (DMA_MASK , 0x04 | Dma );
|
||||
outp (DMA_FF , 0 );
|
||||
|
||||
/* select auto-initialize DMA mode */
|
||||
outp (DMA_MODE , 0x58 | Dma );
|
||||
outp (DMA_BASE + (Dma << 1) , offset_low );
|
||||
outp (DMA_BASE + (Dma << 1) , offset_high );
|
||||
outp (pagePort[Dma] , page_no );
|
||||
outp (DMA_COUNT + (Dma << 1), count_low );
|
||||
outp (DMA_COUNT + (Dma << 1), count_high );
|
||||
outp (DMA_MASK , Dma );
|
||||
|
||||
/* calculate the high/low buffer size counts */
|
||||
Count_low = (uint8) (Sb_buf_size-1) & 0x0ff;
|
||||
Count_high = (uint8) ((Sb_buf_size-1) >> 8) & 0x0ff;
|
||||
|
||||
if (DMAmode == STANDARD_DMA)
|
||||
{
|
||||
/* start the standard DMA transfer */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0x14);
|
||||
dsp_out (IOaddr + DSP_WRITE, Count_low);
|
||||
dsp_out (IOaddr + DSP_WRITE, Count_high);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset the DMA counter */
|
||||
DMAcount = 0;
|
||||
|
||||
/* set the auto-initialize buffer size */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0x48);
|
||||
dsp_out (IOaddr + DSP_WRITE, Count_low);
|
||||
dsp_out (IOaddr + DSP_WRITE, Count_high);
|
||||
|
||||
/* and start the auto-initialize DMA transfer */
|
||||
dsp_out (IOaddr + DSP_WRITE, 0x1c);
|
||||
|
||||
start_time = clock();
|
||||
|
||||
/* Delay for a bit and wait for DMAcount to change. */
|
||||
/* Wait for the DMA to be called twice to make sure */
|
||||
/* auto-init mode is working properly. */
|
||||
while ((clock()-start_time < (int)(CLK_TCK/2)) && (DMAcount < 2))
|
||||
{
|
||||
/* This routine will wait for up to 1/2 second for DMAcount */
|
||||
/* to change. The value in CLK_TCK is the number of times */
|
||||
/* the clock will tick in one second. */
|
||||
}
|
||||
|
||||
/* if the auto-init DMA is not active */
|
||||
if (DMAcount < 2)
|
||||
{
|
||||
/* Reset the SB DSP */
|
||||
ResetDSP(IOaddr);
|
||||
|
||||
/* then try again with STANDARD_DMA */
|
||||
Start_audio_output (STANDARD_DMA, fillBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
ret_val = 0;
|
||||
}
|
||||
|
||||
return (ret_val);
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: SBDRV.H */
|
||||
/* Purpose: Define function prototypes and structures required for the */
|
||||
/* SB DRV routines, V1.3. */
|
||||
/* Author(s): Ron Fries and Neil Bradley */
|
||||
/* */
|
||||
/* 01/30/97 - Initial Release */
|
||||
/* 08/24/97 - V1.1 - Added defintion of SBDRV_SHOW_ERR to cause the SBDRV */
|
||||
/* to display error messages. Comment line to supress */
|
||||
/* 01/12/98 - V1.2 - Added support for DJGPP. */
|
||||
/* 02/04/99 - V1.3 - Cleaned up DJGPP support, fixed a possible segfault */
|
||||
/* in the reading of the BLASTER= env. variable, and */
|
||||
/* added timeout to dsp_out(). */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* License Information and Copyright Notice */
|
||||
/* ======================================== */
|
||||
/* */
|
||||
/* SBDrv is Copyright(c) 1997-1999 by Ron Fries, Neil Bradley and */
|
||||
/* Bradford Mott */
|
||||
/* */
|
||||
/* This library is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of version 2 of the GNU Library General Public License */
|
||||
/* as published by the Free Software Foundation. */
|
||||
/* */
|
||||
/* This library is distributed in the hope that it will be useful, but */
|
||||
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */
|
||||
/* General Public License for more details. */
|
||||
/* To obtain a copy of the GNU Library General Public License, write to the */
|
||||
/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
/* */
|
||||
/* Any permitted reproduction of these routines, in whole or in part, must */
|
||||
/* bear this legend. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _SBDRV_H
|
||||
#define _SBDRV_H
|
||||
|
||||
#ifndef _TYPEDEF_H
|
||||
#define _TYPEDEF_H
|
||||
|
||||
#define SBDRV_SHOW_ERR /* delete line to supress error message printing */
|
||||
|
||||
/* define some data types to keep it platform independent */
|
||||
#ifdef COMP16 /* if 16-bit compiler defined */
|
||||
#define int8 char
|
||||
#define int16 int
|
||||
#define int32 long
|
||||
#else /* else default to 32-bit compiler */
|
||||
#define int8 char
|
||||
#define int16 short
|
||||
#define int32 int
|
||||
#endif
|
||||
|
||||
#define uint8 unsigned int8
|
||||
#define uint16 unsigned int16
|
||||
#define uint32 unsigned int32
|
||||
|
||||
#endif
|
||||
|
||||
/* CONSTANT DEFINITIONS */
|
||||
|
||||
#define AUTO_DMA 0 /* selects auto-initialize DMA mode */
|
||||
#define STANDARD_DMA 1 /* selects standard DMA mode */
|
||||
|
||||
/* global function prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint8 OpenSB(uint16 playback_freq, uint16 buffer_size);
|
||||
void CloseSB(void);
|
||||
uint8 Start_audio_output (uint8 dma_mode,
|
||||
void (*fillBuffer)(uint8 *buf,uint16 n));
|
||||
void Stop_audio_output (void);
|
||||
|
||||
void Set_master_volume(uint8 left, uint8 right);
|
||||
void Set_line_volume(uint8 left, uint8 right);
|
||||
void Set_FM_volume(uint8 left, uint8 right);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,218 +0,0 @@
|
|||
SBDRV.C - SB DRIVER FUNCTIONS V1.3
|
||||
==================================
|
||||
|
||||
NOTE: There is some important information in the COMPILER REQUIREMENTS
|
||||
section.
|
||||
|
||||
The SBDRV.C file includes a set of simple routines for generating audio
|
||||
output through a basic SB card, which should include all SB compatible cards.
|
||||
The routines are designed to use the low-speed DMA output feature of the SB
|
||||
card. The routines will automatically create the necessary buffers. The
|
||||
audio processing/mixing function will automatically be called from the ISR
|
||||
to provide a continuous stream of output.
|
||||
|
||||
These functions have been designed to work with multiple compilers.
|
||||
They have already been tested with Borland C++ V3.1, MSVC V1.52,
|
||||
WATCOM V10.6 and DJGPP. The Borland and MSVC compilers used were 16-bit,
|
||||
while the WATCOM and DJGPP were 32-bit.
|
||||
|
||||
A header file 'SBDRV.H' has been included for use in other modules, and
|
||||
provides the necessary function prototypes.
|
||||
|
||||
The routines are easy to use. Detailed descriptions on the function calls
|
||||
are listed below.
|
||||
|
||||
|
||||
FEATURES
|
||||
--------
|
||||
|
||||
1) Full support for IRQs 0-15.
|
||||
|
||||
2) Ability to adjust the Master, FM and VOC/WAV volumes (note: not supported
|
||||
by all cards).
|
||||
|
||||
2) Once started, the the sound IRQ automatically calls the audio processing
|
||||
function. No additional calls are required.
|
||||
|
||||
3) The audio processing/mixing function is passed in as a initialization
|
||||
parameter. This should allow the routines to be used in most applications
|
||||
without modification.
|
||||
|
||||
4) The routines support AUTO-INITIALIZE and STANDARD DMA modes of operation.
|
||||
This will allow good sound reproduction on the newer cards but still
|
||||
support the old cards.
|
||||
|
||||
|
||||
LIMITATIONS
|
||||
-----------
|
||||
|
||||
The SB Driver routines have several limitations.
|
||||
|
||||
1) The routines can support any DMA channel from 0 to 3. If any other DMA
|
||||
channel is needed, changes are required. This may need to be changed to
|
||||
support all SB cards. This should not be much of a concern, though,
|
||||
since DMA channels 4-7 are only used for 16-bit DMA operation.
|
||||
|
||||
2) The routines only support the low-speed DMA output function of the SB
|
||||
card, which limits the maximum playback to approximately 22KHz.
|
||||
|
||||
3) The routines only support 8-bit mono audio output.
|
||||
|
||||
4) The routines require that the 'BLASTER' environment variable be configured.
|
||||
This can be accomplished by using "SET BLASTER = A220 I7 D1" from the
|
||||
command line. The 'A' value is the base address of the card, the 'I' value
|
||||
is the configured interrupt line, and the 'D' value is the configured DMA
|
||||
channel.
|
||||
|
||||
|
||||
GENERAL OVERVIEW
|
||||
----------------
|
||||
|
||||
On start-up of the system, a single call should be made to OpenSB.
|
||||
This routine will reset the SB, setup the interrupts and prepare the
|
||||
structures for sound output. This routine should not be called again
|
||||
until after the CloseSB function is called.
|
||||
|
||||
On system shut-down, a single call should be made to CloseSB. This routine
|
||||
will reset the SB, disable the interrupts and free the structures that were
|
||||
created.
|
||||
|
||||
Once the SB has been initialized, calling the Start_audio_output function
|
||||
will start the DMA operation. Once started, the sound output will be
|
||||
continuous; no other calls are required. The sound output will continue
|
||||
until either the Stop_audio_output or CloseSB functions are called.
|
||||
|
||||
The Stop_audio_output function can be used to pause the output temporarily.
|
||||
|
||||
|
||||
COMPILER REQUIREMENTS
|
||||
---------------------
|
||||
|
||||
*** Probably the most important compiler option is the selection of the data
|
||||
segment/stack segment relationship. Because the IRQ will be calling the
|
||||
fillBuffer function from within the IRQ, the data segment and stack segment
|
||||
may not be equal. The compiler should be set to DS != SS. Without this
|
||||
option, a stack overflow, system lockup or other unusual problem will occur.
|
||||
|
||||
|
||||
Borland C++ 3.1 Notes
|
||||
---------------------
|
||||
The memory model must be set to LARGE and the COMP16 logical must be defined.
|
||||
The DS/SS relationship can be left to 'default for memory model' since the
|
||||
LARGE model automatically sets DS != SS, or this option can be set to never.
|
||||
|
||||
|
||||
MSVC++ 1.5x
|
||||
-----------
|
||||
The memory model must be set to LARGE and the segment setup must be set to
|
||||
'DS != SS, DS loaded on function entry'. Extern and unitialized data should
|
||||
be assumed to be 'far'. Also, the COMP16 preprocessor symbol must be defined.
|
||||
|
||||
|
||||
WATCOM 10.6
|
||||
------------
|
||||
The segment relationship must be set to DS != SS and stack probes must be
|
||||
removed. This is accomplished by using the /zu and /s compiler options.
|
||||
|
||||
|
||||
DJGPP
|
||||
-----
|
||||
Actually, I'm not sure what's required. I just compiled it as
|
||||
GCC -o SBDRVTST.EXE SBDRVTST.C SBDRV.C and it worked. If you have problems
|
||||
you may want to contact Bradford Mott as he added DJGPP support.
|
||||
|
||||
|
||||
DETAILED FUNCTION DESCRIPTIONS
|
||||
------------------------------
|
||||
|
||||
OpenSB (uint16 playback_freq, uint16 buffer_size)
|
||||
-------------------------------------------------
|
||||
|
||||
This function resets and initializes the SB, initializes and enables the
|
||||
interrupts, and creates and initializes all local global structures.
|
||||
This function takes two parameters: the playback frequency and the size of
|
||||
each playback buffer.
|
||||
|
||||
The playback frequency can be any unsigned integer from 1-65535, though
|
||||
the maximum limit is currently set by the SB low-speed DMA audio routines
|
||||
(approx. 22KHz).
|
||||
|
||||
The system will automatically allocate two playback buffers. The size of
|
||||
each buffer can be any value from 1 to 65535. The actual size needed
|
||||
will depend on the playback frequency and the DMA mode.
|
||||
|
||||
If Auto-Initialize DMA mode will be used, the size of the buffer can be set
|
||||
as low as 35 or 40 with good output, though I don't recommend values lower
|
||||
than 100.
|
||||
|
||||
If Standard DMA mode will be used, the minimum size that will produce clear
|
||||
output varies based on the sample frequency. At maximum freq (22kHz), the
|
||||
buffer size must be between 500-600 to produce clear output. At lower sample
|
||||
frequencies, the size of the buffer can be much smaller.
|
||||
|
||||
If the call to OpenSB was unsuccessful, the function will return a value
|
||||
of 0. Otherwise, the return value will be non-zero.
|
||||
|
||||
|
||||
CloseSB (void)
|
||||
--------------
|
||||
|
||||
This function disables all interrupts, frees all buffers and stops all
|
||||
SB audio output. This function should be called before the program
|
||||
exits. This function has no input or output parameters.
|
||||
|
||||
|
||||
Set_FM_volume (uint8 left, uint8 right)
|
||||
Set_line_volume (uint8 left, uint8 right)
|
||||
Set_master_volume (uint8 left, uint8 right)
|
||||
-------------------------------------------
|
||||
|
||||
These functions set the left and right volume levels for the FM, line and
|
||||
master volume controls. These functions have no output parameters (void).
|
||||
|
||||
|
||||
Start_audio_output (uint8 dma_mode, void (*fillBuffer)(uint8 *buf, uint16 n))
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
This function starts the audio output. It takes two parameters, the dma mode
|
||||
to be used and the name of the function that generates the audio.
|
||||
|
||||
The possible selections for the dma_mode are AUTO_DMA and STANDARD_DMA.
|
||||
Normally, the AUTO_DMA option should always be used as the routines will
|
||||
attempt to auto-detect whether the AUTO_DMA option is supported. If AUTO_DMA
|
||||
is not supported, the routine will automatically switch to STANDARD_DMA mode.
|
||||
|
||||
It is possible (though unlikely) that the AUTO_DMA attempt will cause
|
||||
problems. Because of this possibility, the system can be forced to use the
|
||||
STANDARD_DMA mode by passing STANDARD_DMA to Start_audio_output. I recommend
|
||||
providing the user the option to force STANDARD_DMA operation. Note that the
|
||||
buffer size may need to be increased to support STANDARD_DMA (see OpenSB).
|
||||
|
||||
The fillBuffer function passed should be a function that takes two parameters,
|
||||
a pointer to an unsigned 8-bit buffer and an unsigned 16-bit integer. The
|
||||
fillBuffer routine should process the next 'n' bytes (specified by the 16-bit
|
||||
integer) and place them in the buffer pointed to starting with byte 0. Any
|
||||
function that meets these requirements can be used, which makes the SBDRV
|
||||
routines generic.
|
||||
|
||||
|
||||
|
||||
License Information and Copyright Notice
|
||||
========================================
|
||||
|
||||
SBDRV is Copyright(c) 1997-1999 by Ron Fries, Neil Bradley and Bradford Mott
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of version 2 of the GNU Library General Public License as published
|
||||
by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
|
||||
details.
|
||||
|
||||
To obtain a copy of the GNU Library General Public License, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Any permitted reproduction of these routines, in whole or in part, must bear
|
||||
this legend.
|
Loading…
Reference in New Issue