These files have been contributed by Christopher ML Zumwalt May
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1401 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,95 +1,105 @@
|
||||
/*******************************************************************************
|
||||
/
|
||||
/ File: FileGameSound.h
|
||||
/
|
||||
/ Description: BFileGameSound is a class that streams data out of a file.
|
||||
/
|
||||
/ Copyright 1999, Be Incorporated, All Rights Reserved
|
||||
/
|
||||
*******************************************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: FileGameSound.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BFileGameSound is a class that streams data out of a file.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_FILE_GAME_SOUND_H)
|
||||
#define _FILE_GAME_SOUND_H
|
||||
#ifndef _FILEGAMESOUND_H
|
||||
#define _FILEGAMESOUND_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <StreamingGameSound.h>
|
||||
|
||||
class BMediaFile;
|
||||
namespace BPrivate {
|
||||
class BTrackReader;
|
||||
}
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
struct _gs_media_tracker;
|
||||
struct _gs_ramp;
|
||||
|
||||
// FileGameSound -------------------------------------------------------------
|
||||
class BFileGameSound : public BStreamingGameSound
|
||||
{
|
||||
public:
|
||||
BFileGameSound(
|
||||
const entry_ref * file,
|
||||
bool looping = true,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BFileGameSound(
|
||||
const char * file,
|
||||
bool looping = true,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BFileGameSound(const entry_ref * file,
|
||||
bool looping = true,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BFileGameSound(const char * file,
|
||||
bool looping = true,
|
||||
BGameSoundDevice * device = NULL);
|
||||
|
||||
virtual ~BFileGameSound();
|
||||
virtual ~BFileGameSound();
|
||||
|
||||
virtual BGameSound * Clone() const;
|
||||
virtual BGameSound * Clone() const;
|
||||
|
||||
virtual status_t StartPlaying();
|
||||
virtual status_t StopPlaying();
|
||||
status_t Preload(); // if you have stopped and want to start quickly again
|
||||
virtual status_t StartPlaying();
|
||||
virtual status_t StopPlaying();
|
||||
status_t Preload(); // if you have stopped and want to start quickly again
|
||||
|
||||
virtual void FillBuffer(
|
||||
void * inBuffer,
|
||||
size_t inByteCount);
|
||||
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
|
||||
virtual status_t SetPaused(
|
||||
bool isPaused,
|
||||
bigtime_t rampTime);
|
||||
enum {
|
||||
B_NOT_PAUSED,
|
||||
B_PAUSE_IN_PROGRESS,
|
||||
B_PAUSED
|
||||
};
|
||||
int32 IsPaused();
|
||||
virtual void FillBuffer(void * inBuffer,
|
||||
size_t inByteCount);
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
virtual status_t SetPaused(bool isPaused,
|
||||
bigtime_t rampTime);
|
||||
enum {
|
||||
B_NOT_PAUSED,
|
||||
B_PAUSE_IN_PROGRESS,
|
||||
B_PAUSED
|
||||
};
|
||||
int32 IsPaused();
|
||||
|
||||
private:
|
||||
|
||||
BMediaFile * _m_soundFile;
|
||||
BPrivate::BTrackReader * _m_trackReader;
|
||||
bool _m_looping;
|
||||
bool _m_stopping;
|
||||
uchar _m_zero;
|
||||
uchar _m_reserved_u;
|
||||
|
||||
// cruft for read-ahead goes here
|
||||
thread_id _m_streamThread;
|
||||
port_id _m_streamPort;
|
||||
enum {
|
||||
cmdStartPlaying = 1,
|
||||
cmdStopPlaying,
|
||||
cmdUsedBytes,
|
||||
cmdPreload
|
||||
};
|
||||
int32 _m_loopCount;
|
||||
char * _m_buffer;
|
||||
size_t _m_bufferSize;
|
||||
int32 _m_stopCount;
|
||||
int32 _m_pauseState;
|
||||
float _m_pauseGain;
|
||||
float _m_pausePan;
|
||||
|
||||
static status_t stream_thread(
|
||||
void * that);
|
||||
void LoadFunc();
|
||||
size_t Load(
|
||||
size_t & offset,
|
||||
size_t bytes);
|
||||
void read_data(
|
||||
char * dest,
|
||||
size_t bytes);
|
||||
|
||||
_gs_media_tracker * fAudioStream;
|
||||
|
||||
bool fStopping;
|
||||
bool fLooping;
|
||||
char fReserved;
|
||||
char * fBuffer;
|
||||
|
||||
size_t fFrameSize;
|
||||
size_t fBufferSize;
|
||||
size_t fPlayPosition;
|
||||
|
||||
thread_id fReadThread;
|
||||
port_id fPort;
|
||||
|
||||
_gs_ramp * fPausing;
|
||||
bool fPaused;
|
||||
float fPauseGain;
|
||||
|
||||
status_t Init(const entry_ref* file);
|
||||
|
||||
static int32 ReadThread(void* arg);
|
||||
|
||||
bool Load();
|
||||
bool Read(void * buffer, size_t bytes);
|
||||
|
||||
/* leave these declarations private unless you plan on actually implementing and using them. */
|
||||
BFileGameSound();
|
||||
BFileGameSound(const BFileGameSound&);
|
||||
@@ -97,7 +107,7 @@ static status_t stream_thread(
|
||||
|
||||
/* fbc data and virtuals */
|
||||
|
||||
uint32 _reserved_BFileGameSound_[8];
|
||||
uint32 _reserved_BFileGameSound_[9];
|
||||
|
||||
status_t _Reserved_BFileGameSound_0(int32 arg, ...); /* SetPaused(bool paused, bigtime_t ramp); */
|
||||
virtual status_t _Reserved_BFileGameSound_1(int32 arg, ...);
|
||||
|
||||
+86
-87
@@ -1,110 +1,109 @@
|
||||
/*******************************************************************************
|
||||
/
|
||||
/ File: GameGameSound.h
|
||||
/
|
||||
/ Description: BGameSound is an abstract base class for all sounds being
|
||||
/ played using the gamesound kit. Use one of the concrete
|
||||
/ subclasses for actually playing sound.
|
||||
/
|
||||
/ Copyright 1999, Be Incorporated, All Rights Reserved
|
||||
/
|
||||
*******************************************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSound.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Base class for play sounds using the game kit
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GAMESOUND_H
|
||||
#define _GAMESOUND_H
|
||||
|
||||
#if !defined(_GAME_SOUND_H)
|
||||
#define _GAME_SOUND_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <GameSoundDefs.h>
|
||||
#include <new>
|
||||
|
||||
struct gs_audio_format;
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
class BGameSoundDevice;
|
||||
|
||||
namespace BPrivate {
|
||||
class PrivGameSound;
|
||||
}
|
||||
|
||||
// BGameSound class -------------------------------------------------------------
|
||||
class BGameSound
|
||||
{
|
||||
public:
|
||||
BGameSound(
|
||||
BGameSoundDevice * device = NULL);
|
||||
virtual ~BGameSound();
|
||||
BGameSound(BGameSoundDevice * device = NULL);
|
||||
virtual ~BGameSound();
|
||||
|
||||
virtual BGameSound * Clone() const = 0;
|
||||
status_t InitCheck() const;
|
||||
virtual BGameSound * Clone() const = 0;
|
||||
status_t InitCheck() const;
|
||||
|
||||
// BGameSound attributes
|
||||
BGameSoundDevice * Device() const;
|
||||
gs_id ID() const;
|
||||
const gs_audio_format & Format() const; // only valid after Init()
|
||||
|
||||
BGameSoundDevice * Device() const;
|
||||
gs_id ID() const;
|
||||
const gs_audio_format &
|
||||
Format() const; // only valid after Init()
|
||||
// Playing sounds
|
||||
virtual status_t StartPlaying();
|
||||
virtual bool IsPlaying();
|
||||
virtual status_t StopPlaying();
|
||||
|
||||
virtual status_t StartPlaying();
|
||||
virtual bool IsPlaying();
|
||||
virtual status_t StopPlaying();
|
||||
|
||||
// Modifing the playback
|
||||
status_t SetGain(float gain,
|
||||
bigtime_t duration = 0); // ramp duration in seconds
|
||||
status_t SetPan(float pan,
|
||||
bigtime_t duration = 0); // ramp duration in seconds
|
||||
float Gain();
|
||||
float Pan();
|
||||
|
||||
status_t SetGain(
|
||||
float gain,
|
||||
bigtime_t duration = 0); // ramp duration in seconds
|
||||
status_t SetPan(
|
||||
float pan,
|
||||
bigtime_t duration = 0); // ramp duration in seconds
|
||||
float Gain();
|
||||
float Pan();
|
||||
virtual status_t SetAttributes(gs_attribute * inAttributes,
|
||||
size_t inAttributeCount);
|
||||
virtual status_t GetAttributes(gs_attribute * outAttributes,
|
||||
size_t inAttributeCount);
|
||||
|
||||
virtual status_t SetAttributes(
|
||||
gs_attribute * inAttributes,
|
||||
size_t inAttributeCount);
|
||||
virtual status_t GetAttributes(
|
||||
gs_attribute * outAttributes,
|
||||
size_t inAttributeCount);
|
||||
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
|
||||
void * operator new(
|
||||
size_t size);
|
||||
void * operator new(
|
||||
size_t size,
|
||||
const nothrow_t &) throw();
|
||||
void operator delete(
|
||||
void * ptr);
|
||||
#if !__MWERKS__
|
||||
// there's a bug in MWCC under R4.1 and earlier
|
||||
void operator delete(
|
||||
void * ptr,
|
||||
const nothrow_t &) throw();
|
||||
#endif
|
||||
|
||||
static status_t SetMemoryPoolSize( // implemented in PrivGameSound.cpp
|
||||
size_t in_poolSize);
|
||||
static status_t LockMemoryPool( // implemented in PrivGameSound.cpp
|
||||
bool in_lockInCore);
|
||||
static int32 SetMaxSoundCount( // implemented in PrivGameSound.cpp
|
||||
int32 in_maxCount);
|
||||
// void * operator new(size_t size);
|
||||
// void * operator new(size_t size, const nothrow_t &) throw();
|
||||
// void operator delete(void * ptr);
|
||||
//#if !__MWERKS__
|
||||
// there's a bug in MWCC under R4.1 and earlier
|
||||
// void operator delete(void * ptr,
|
||||
// const nothrow_t &) throw();
|
||||
//#endif
|
||||
|
||||
static status_t SetMemoryPoolSize(size_t in_poolSize);
|
||||
static status_t LockMemoryPool(bool in_lockInCore);
|
||||
static int32 SetMaxSoundCount(int32 in_maxCount);
|
||||
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
protected:
|
||||
|
||||
status_t SetInitError(
|
||||
status_t in_initError);
|
||||
status_t Init(
|
||||
gs_id handle);
|
||||
|
||||
BGameSound(
|
||||
const BGameSound & other);
|
||||
BGameSound & operator=(
|
||||
const BGameSound & other);
|
||||
status_t SetInitError(status_t in_initError);
|
||||
status_t Init(gs_id handle);
|
||||
|
||||
BGameSound(const BGameSound & other);
|
||||
BGameSound & operator=(const BGameSound & other);
|
||||
|
||||
private:
|
||||
|
||||
friend class BPrivate::PrivGameSound;
|
||||
|
||||
gs_id _m_handle;
|
||||
BGameSoundDevice * _m_device;
|
||||
gs_audio_format
|
||||
_m_format;
|
||||
status_t _m_initError;
|
||||
|
||||
BGameSoundDevice* fDevice;
|
||||
status_t fInitError;
|
||||
|
||||
gs_audio_format fFormat;
|
||||
gs_id fSound;
|
||||
|
||||
/* leave these declarations private unless you plan on actually implementing and using them. */
|
||||
BGameSound();
|
||||
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
/*******************************************************************************
|
||||
/
|
||||
/ File: GameSoundDefs.h
|
||||
/
|
||||
/ Description: Definitions of common types and constants for the gamesound kit.
|
||||
/
|
||||
/ Copyright 1999, Be Incorporated, All Rights Reserved
|
||||
/
|
||||
*******************************************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSound.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Declerations for game sounds
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_GAME_SOUND_DEFS_H)
|
||||
#define _GAME_SOUND_DEFS_H
|
||||
|
||||
@@ -1,30 +1,54 @@
|
||||
/*******************************************************************************
|
||||
/
|
||||
/ File: PushGameSound.h
|
||||
/
|
||||
/ Description: BPushGameSound is a class for games that want to push data
|
||||
/ at the system, rather than have a callback get called.
|
||||
/
|
||||
/ Copyright 1999, Be Incorporated, All Rights Reserved
|
||||
/
|
||||
*******************************************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: FileGameSound.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BFileGameSound is a class that streams data out of a file.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PUSHGAMESOUND_H
|
||||
#define _PUSHGAMESOUND_H
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
#if !defined(_PUSH_GAME_SOUND_H)
|
||||
#define _PUSH_GAME_SOUND_H
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <StreamingGameSound.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
|
||||
// FileGameSound -------------------------------------------------------------
|
||||
class BPushGameSound : public BStreamingGameSound
|
||||
{
|
||||
public:
|
||||
BPushGameSound(
|
||||
size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount = 2,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BPushGameSound(size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount = 2,
|
||||
BGameSoundDevice * device = NULL);
|
||||
|
||||
virtual ~BPushGameSound();
|
||||
virtual ~BPushGameSound();
|
||||
|
||||
enum lock_status {
|
||||
lock_failed = -1, // not yet time to do more
|
||||
@@ -32,56 +56,57 @@ virtual ~BPushGameSound();
|
||||
lock_ok_frames_dropped // you may have missed some buffers
|
||||
};
|
||||
|
||||
virtual lock_status LockNextPage(
|
||||
void ** out_pagePtr,
|
||||
size_t * out_pageSize);
|
||||
virtual status_t UnlockPage(
|
||||
void * in_pagePtr);
|
||||
virtual lock_status LockNextPage(void ** out_pagePtr,
|
||||
size_t * out_pageSize);
|
||||
virtual status_t UnlockPage(void * in_pagePtr);
|
||||
|
||||
virtual lock_status LockForCyclic(
|
||||
void ** out_basePtr,
|
||||
size_t * out_size);
|
||||
virtual status_t UnlockCyclic();
|
||||
virtual size_t CurrentPosition();
|
||||
virtual lock_status LockForCyclic(void ** out_basePtr,
|
||||
size_t * out_size);
|
||||
virtual status_t UnlockCyclic();
|
||||
virtual size_t CurrentPosition();
|
||||
|
||||
virtual BGameSound * Clone() const;
|
||||
virtual BGameSound * Clone() const;
|
||||
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
|
||||
protected:
|
||||
|
||||
BPushGameSound(BGameSoundDevice * device);
|
||||
|
||||
virtual status_t SetParameters( // will allocate handle and call Init()
|
||||
size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount);
|
||||
virtual status_t SetParameters(size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount);
|
||||
|
||||
virtual status_t SetStreamHook(
|
||||
void (*hook)(void * inCookie, void * inBuffer, size_t inByteCount, BStreamingGameSound * me),
|
||||
void * cookie);
|
||||
virtual void FillBuffer( // default is to call stream hook, if any
|
||||
void * inBuffer,
|
||||
size_t inByteCount);
|
||||
virtual status_t SetStreamHook(void (*hook)(void * inCookie, void * inBuffer, size_t inByteCount, BStreamingGameSound * me),
|
||||
void * cookie);
|
||||
|
||||
virtual void FillBuffer(void * inBuffer,
|
||||
size_t inByteCount);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/* leave these declarations private unless you plan on actually implementing and using them. */
|
||||
BPushGameSound();
|
||||
BPushGameSound(const BPushGameSound&);
|
||||
BPushGameSound& operator=(const BPushGameSound&);
|
||||
/* leave these declarations private unless you plan on actually implementing and using them. */
|
||||
BPushGameSound();
|
||||
BPushGameSound(const BPushGameSound&);
|
||||
BPushGameSound& operator=(const BPushGameSound&);
|
||||
|
||||
int32 _m_benCount;
|
||||
sem_id _m_benSem;
|
||||
char * _m_lockedPtr;
|
||||
char * _m_playedPtr;
|
||||
size_t _m_pageSize;
|
||||
int32 _m_pageCount;
|
||||
size_t _m_bufSize;
|
||||
char * _m_buffer;
|
||||
bool BytesReady(size_t * bytes);
|
||||
|
||||
sem_id fLock;
|
||||
BList * fPageLocked;
|
||||
|
||||
size_t fLockPos;
|
||||
size_t fPlayPos;
|
||||
|
||||
char * fBuffer;
|
||||
size_t fPageSize;
|
||||
int32 fPageCount;
|
||||
size_t fBufferSize;
|
||||
|
||||
/* fbc data and virtuals */
|
||||
/* fbc data and virtuals */
|
||||
|
||||
uint32 _reserved_BPushGameSound_[12];
|
||||
uint32 _reserved_BPushGameSound_[12];
|
||||
|
||||
virtual status_t _Reserved_BPushGameSound_0(int32 arg, ...);
|
||||
virtual status_t _Reserved_BPushGameSound_1(int32 arg, ...);
|
||||
|
||||
@@ -1,50 +1,78 @@
|
||||
/* SimpleGameSound.h */
|
||||
/*******************************************************************************
|
||||
/
|
||||
/ File: SimpleGameSound.h
|
||||
/
|
||||
/ Description: BSimpleGameSound is a class for sound effects that are
|
||||
/ short, and consists of non-changing samples in memory.
|
||||
/
|
||||
/ Copyright 1999, Be Incorporated, All Rights Reserved
|
||||
/
|
||||
*******************************************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: SimpleGameSound.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BSimpleGameSound is a class for sound effects that are
|
||||
// short, and consists of non-changing samples in memory.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_SIMPLE_GAME_SOUND_H)
|
||||
#define _SIMPLE_GAME_SOUND_H
|
||||
|
||||
#ifndef _SIMPLEGAMESOUND_H
|
||||
#define _SIMPLEGAMESOUND_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <GameSoundDefs.h>
|
||||
#include <GameSound.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
|
||||
// BGameSound class -------------------------------------------------------------
|
||||
class BSimpleGameSound : public BGameSound
|
||||
{
|
||||
public:
|
||||
BSimpleGameSound(
|
||||
const entry_ref * inFile,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BSimpleGameSound(
|
||||
const char * inFile,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BSimpleGameSound(
|
||||
const void * inData,
|
||||
size_t inFrameCount,
|
||||
const gs_audio_format * format,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BSimpleGameSound(const entry_ref * inFile,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BSimpleGameSound(const char * inFile,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BSimpleGameSound(const void * inData,
|
||||
size_t inFrameCount,
|
||||
const gs_audio_format * format,
|
||||
BGameSoundDevice * device = NULL);
|
||||
|
||||
BSimpleGameSound(
|
||||
const BSimpleGameSound & other);
|
||||
BSimpleGameSound(const BSimpleGameSound & other);
|
||||
|
||||
virtual ~BSimpleGameSound();
|
||||
virtual ~BSimpleGameSound();
|
||||
|
||||
virtual BGameSound * Clone() const;
|
||||
virtual BGameSound * Clone() const;
|
||||
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
|
||||
status_t SetIsLooping(
|
||||
bool looping); // whether to go back to beginning
|
||||
bool IsLooping() const;
|
||||
status_t SetIsLooping(bool looping);
|
||||
bool IsLooping() const;
|
||||
|
||||
private:
|
||||
|
||||
status_t Init(const entry_ref * inFile);
|
||||
status_t Init(const void* inData,
|
||||
int64 inFrameCount,
|
||||
const gs_audio_format* format);
|
||||
|
||||
/* leave these declarations private unless you plan on actually implementing and using them. */
|
||||
BSimpleGameSound();
|
||||
BSimpleGameSound& operator=(const BSimpleGameSound&);
|
||||
|
||||
@@ -1,67 +1,87 @@
|
||||
/*******************************************************************************
|
||||
/
|
||||
/ File: StreamingGameSound.h
|
||||
/
|
||||
/ Description: BStreamingGameSound is a class for all kinds of streaming
|
||||
/ (data not known beforehand) game sounds.
|
||||
/
|
||||
/ Copyright 1999, Be Incorporated, All Rights Reserved
|
||||
/
|
||||
*******************************************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: StreamingGameSound.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BStreamingGameSound is a class for all kinds of streaming
|
||||
// (data not known beforehand) game sounds.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if !defined(_STREAMING_GAME_SOUND_H)
|
||||
#define _STREAMING_GAME_SOUND_H
|
||||
#ifndef _STREAMINGGAMESOUND_H
|
||||
#define _STREAMINGGAMESOUND_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <SupportDefs.h>
|
||||
#include <GameSound.h>
|
||||
#include <Locker.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
|
||||
class BStreamingGameSound : public BGameSound
|
||||
{
|
||||
public:
|
||||
BStreamingGameSound(
|
||||
size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount = 2,
|
||||
BGameSoundDevice * device = NULL);
|
||||
BStreamingGameSound(size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount = 2,
|
||||
BGameSoundDevice * device = NULL);
|
||||
|
||||
virtual ~BStreamingGameSound();
|
||||
virtual ~BStreamingGameSound();
|
||||
|
||||
virtual BGameSound * Clone() const;
|
||||
virtual BGameSound * Clone() const;
|
||||
|
||||
virtual status_t SetStreamHook(
|
||||
void (*hook)(void * inCookie, void * inBuffer, size_t inByteCount, BStreamingGameSound * me),
|
||||
void * cookie);
|
||||
virtual void FillBuffer( // default is to call stream hook, if any
|
||||
void * inBuffer,
|
||||
size_t inByteCount);
|
||||
virtual status_t SetStreamHook(void (*hook)(void * inCookie, void * inBuffer, size_t inByteCount, BStreamingGameSound * me),
|
||||
void * cookie);
|
||||
virtual void FillBuffer(void * inBuffer,
|
||||
size_t inByteCount);
|
||||
|
||||
virtual status_t SetAttributes(
|
||||
gs_attribute * inAttributes,
|
||||
size_t inAttributeCount);
|
||||
virtual status_t SetAttributes(gs_attribute * inAttributes,
|
||||
size_t inAttributeCount);
|
||||
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
virtual status_t Perform(int32 selector, void * data);
|
||||
|
||||
protected:
|
||||
|
||||
BStreamingGameSound(
|
||||
BGameSoundDevice * device);
|
||||
virtual status_t SetParameters( // will allocate handle and call Init()
|
||||
size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount);
|
||||
|
||||
bool Lock();
|
||||
void Unlock();
|
||||
BStreamingGameSound(BGameSoundDevice * device);
|
||||
|
||||
virtual status_t SetParameters(size_t inBufferFrameCount,
|
||||
const gs_audio_format * format,
|
||||
size_t inBufferCount);
|
||||
|
||||
bool Lock();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
|
||||
void (*_m_streamHook)(void * cookie, void * buffer, size_t bytes, BStreamingGameSound * sound);
|
||||
void * _m_streamCookie;
|
||||
BLocker _m_lock;
|
||||
|
||||
static void stream_callback(void * cookie, gs_id handle, void * buffer, int32 offset, int32 size, size_t bufSize);
|
||||
void (*fStreamHook)(void * cookie, void * buffer, size_t bytes, BStreamingGameSound * sound);
|
||||
void * fStreamCookie;
|
||||
BLocker fLock;
|
||||
|
||||
/* leave these declarations private unless you plan on actually implementing and using them. */
|
||||
BStreamingGameSound();
|
||||
|
||||
+400
-28
@@ -1,32 +1,199 @@
|
||||
/*
|
||||
* Copyright 2002, Marcus Overhagen. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: FileGameSound.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BFileGameSound is a class that streams data out of a file.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <memory.h>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <Entry.h>
|
||||
#include <MediaFile.h>
|
||||
#include <MediaTrack.h>
|
||||
#include <scheduler.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundDevice.h>
|
||||
#include <GSUtility.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <FileGameSound.h>
|
||||
|
||||
static const size_t default_in_buffer_frame_count = 4096; // XXX change this
|
||||
static const gs_audio_format default_format = {}; // XXX change this
|
||||
static const size_t default_in_buffer_count = 2; // XXX change this
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
const int32 kPages = 20;
|
||||
struct _gs_media_tracker
|
||||
{
|
||||
BMediaFile * file;
|
||||
BMediaTrack * stream;
|
||||
int64 frames;
|
||||
size_t position;
|
||||
};
|
||||
|
||||
// Locale utility functions -----------------------------------------------
|
||||
bool FillBuffer(_gs_ramp * ramp, uint8 * data, uint8 * buffer, size_t * bytes)
|
||||
{
|
||||
int32 samples = *bytes / sizeof(int16);
|
||||
|
||||
for(int32 byte = 0; byte < samples; byte++)
|
||||
{
|
||||
float gain = *ramp->value;
|
||||
data[byte] = uint8(float(buffer[byte]) * gain);
|
||||
|
||||
if (ChangeRamp(ramp))
|
||||
{
|
||||
*bytes = byte * sizeof(int16);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FillBuffer(_gs_ramp * ramp, int16 * data, int16 * buffer, size_t * bytes)
|
||||
{
|
||||
int32 samples = *bytes / sizeof(int16);
|
||||
|
||||
for(int32 byte = 0; byte < samples; byte++)
|
||||
{
|
||||
float gain = *ramp->value;
|
||||
data[byte] = int16(float(buffer[byte]) * gain);
|
||||
|
||||
if (ChangeRamp(ramp))
|
||||
{
|
||||
*bytes = byte * sizeof(int16);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FillBuffer(_gs_ramp * ramp, int32 * data, int32 * buffer, size_t * bytes)
|
||||
{
|
||||
size_t byte = 0;
|
||||
bool bytesAreReady = (*bytes > 0);
|
||||
|
||||
while(bytesAreReady)
|
||||
{
|
||||
float gain = *ramp->value;
|
||||
data[byte] = int32(float(buffer[byte]) * gain);
|
||||
|
||||
if (ChangeRamp(ramp))
|
||||
{
|
||||
*bytes = byte;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte++;
|
||||
bytesAreReady = (byte >= *bytes);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FillBuffer(_gs_ramp * ramp, float * data, float * buffer, size_t * bytes)
|
||||
{
|
||||
size_t byte = 0;
|
||||
bool bytesAreReady = (*bytes > 0);
|
||||
|
||||
while(bytesAreReady)
|
||||
{
|
||||
float gain = *ramp->value;
|
||||
data[byte] = buffer[byte] * gain;
|
||||
|
||||
if (ChangeRamp(ramp))
|
||||
{
|
||||
*bytes = byte;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte++;
|
||||
bytesAreReady = (byte >= *bytes);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// BFileGameSound -------------------------------------------------------
|
||||
BFileGameSound::BFileGameSound(const entry_ref *file,
|
||||
bool looping,
|
||||
BGameSoundDevice *device)
|
||||
: BStreamingGameSound(default_in_buffer_frame_count, &default_format, default_in_buffer_count, device)
|
||||
: BStreamingGameSound(device),
|
||||
fAudioStream(NULL),
|
||||
fStopping(false),
|
||||
fLooping(looping),
|
||||
fBuffer(NULL),
|
||||
fPlayPosition(0),
|
||||
fPausing(NULL),
|
||||
fPaused(false),
|
||||
fPauseGain(1.0)
|
||||
{
|
||||
if (InitCheck() == B_OK) SetInitError(Init(file));
|
||||
}
|
||||
|
||||
|
||||
BFileGameSound::BFileGameSound(const char *file,
|
||||
bool looping,
|
||||
BGameSoundDevice *device)
|
||||
: BStreamingGameSound(default_in_buffer_frame_count, &default_format, default_in_buffer_count, device)
|
||||
: BStreamingGameSound(device),
|
||||
fAudioStream(NULL),
|
||||
fStopping(false),
|
||||
fLooping(looping),
|
||||
fBuffer(NULL),
|
||||
fPlayPosition(0),
|
||||
fPausing(NULL),
|
||||
fPaused(false),
|
||||
fPauseGain(1.0)
|
||||
{
|
||||
if (InitCheck() == B_OK)
|
||||
{
|
||||
entry_ref node;
|
||||
|
||||
if (get_ref_for_path(file, &node) != B_OK)
|
||||
SetInitError(B_ENTRY_NOT_FOUND);
|
||||
else
|
||||
SetInitError(Init(&node));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BFileGameSound::~BFileGameSound()
|
||||
{
|
||||
if (fReadThread >= 0) kill_thread(fReadThread);
|
||||
|
||||
if (fAudioStream)
|
||||
{
|
||||
if (fAudioStream->stream) fAudioStream->file->ReleaseTrack(fAudioStream->stream);
|
||||
|
||||
fAudioStream->file->CloseFile();
|
||||
|
||||
//delete fAudioStream->stream;
|
||||
delete fAudioStream->file;
|
||||
}
|
||||
|
||||
delete [] fBuffer;
|
||||
delete fAudioStream;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,21 +207,53 @@ BFileGameSound::Clone() const
|
||||
status_t
|
||||
BFileGameSound::StartPlaying()
|
||||
{
|
||||
return B_ERROR;
|
||||
// restart playback if needed
|
||||
if (IsPlaying()) StopPlaying();
|
||||
|
||||
fPort = create_port(kPages, "audioque");
|
||||
|
||||
// create the thread that will read the file
|
||||
fReadThread = spawn_thread(ReadThread, "audiostream", B_NORMAL_PRIORITY, this);
|
||||
if (fReadThread < B_OK) return B_NO_MORE_THREADS;
|
||||
|
||||
status_t error = resume_thread(fReadThread);
|
||||
if (error != B_OK) return error;
|
||||
|
||||
// start playing the file
|
||||
return BStreamingGameSound::StartPlaying();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BFileGameSound::StopPlaying()
|
||||
{
|
||||
return B_ERROR;
|
||||
status_t error = BStreamingGameSound::StopPlaying();
|
||||
|
||||
// start reading next time from the start of the file
|
||||
int64 frame = 0;
|
||||
fAudioStream->stream->SeekToFrame(&frame);
|
||||
|
||||
fStopping = false;
|
||||
fAudioStream->position = 0;
|
||||
fPlayPosition = 0;
|
||||
|
||||
// we don't need to read any more
|
||||
kill_thread(fReadThread);
|
||||
delete_port(fPort);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BFileGameSound::Preload()
|
||||
{
|
||||
return B_ERROR;
|
||||
if (!IsPlaying())
|
||||
{
|
||||
for(int32 i = 0; i < kPages / 2; i++) Load();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +261,79 @@ void
|
||||
BFileGameSound::FillBuffer(void *inBuffer,
|
||||
size_t inByteCount)
|
||||
{
|
||||
int32 cookie;
|
||||
size_t bytes = inByteCount;
|
||||
|
||||
if (!fPaused || fPausing)
|
||||
{
|
||||
// time to read a new buffer
|
||||
if (fPlayPosition == 0) read_port_etc(fPort, &cookie, fBuffer, fBufferSize, B_TIMEOUT, 0);
|
||||
|
||||
if (fPausing)
|
||||
{
|
||||
Lock();
|
||||
|
||||
bool rampDone = false;
|
||||
|
||||
// Fill the requsted buffer, stopping if the paused flag is set
|
||||
switch(Format().format)
|
||||
{
|
||||
case gs_audio_format::B_GS_U8:
|
||||
rampDone = ::FillBuffer(fPausing, (uint8*)inBuffer, (uint8*)&fBuffer[fPlayPosition], &bytes);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_S16:
|
||||
rampDone = ::FillBuffer(fPausing, (int16*)inBuffer, (int16*)&fBuffer[fPlayPosition], &bytes);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_S32:
|
||||
rampDone = ::FillBuffer(fPausing, (int32*)inBuffer, (int32*)&fBuffer[fPlayPosition], &bytes);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_F:
|
||||
rampDone = ::FillBuffer(fPausing, (float*)inBuffer, (float*)&fBuffer[fPlayPosition], &bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
// We finished ramping
|
||||
if (rampDone)
|
||||
{
|
||||
if (bytes < inByteCount && !fPausing)
|
||||
{
|
||||
// Since are resumming play back, we need to copy any remaining samples
|
||||
char * buffer = (char*)inBuffer;
|
||||
memcpy(&buffer[bytes], &fBuffer[fPlayPosition + bytes], inByteCount - bytes);
|
||||
}
|
||||
|
||||
delete fPausing;
|
||||
fPausing = NULL;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t byte = 0;
|
||||
char * buffer = (char*)inBuffer;
|
||||
|
||||
// We need to be able to stop asap when the pause flag is flipped.
|
||||
while(byte < bytes && (!fPaused || fPausing))
|
||||
{
|
||||
buffer[byte] = fBuffer[fPlayPosition + byte];
|
||||
byte++;
|
||||
}
|
||||
|
||||
bytes = byte;
|
||||
}
|
||||
}
|
||||
|
||||
fPlayPosition += bytes;
|
||||
if (fPlayPosition >= fBufferSize)
|
||||
{
|
||||
// We have finished reading the buffer. Setup for the next buffer.
|
||||
fPlayPosition = 0;
|
||||
memset(fBuffer, 0, fBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,45 +349,145 @@ status_t
|
||||
BFileGameSound::SetPaused(bool isPaused,
|
||||
bigtime_t rampTime)
|
||||
{
|
||||
return B_ERROR;
|
||||
if (fPaused != isPaused)
|
||||
{
|
||||
Lock();
|
||||
|
||||
// Clear any old ramping
|
||||
delete fPausing;
|
||||
fPausing = NULL;
|
||||
|
||||
if (rampTime > 100000)
|
||||
{
|
||||
// Setup for ramping
|
||||
if (isPaused)
|
||||
fPausing = InitRamp(&fPauseGain, 0.0, Format().frame_rate, rampTime);
|
||||
else
|
||||
fPausing = InitRamp(&fPauseGain, 1.0, Format().frame_rate, rampTime);
|
||||
}
|
||||
|
||||
fPaused = isPaused;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
BFileGameSound::IsPaused()
|
||||
{
|
||||
return 0;
|
||||
if (fPausing) return B_PAUSE_IN_PROGRESS;
|
||||
|
||||
if (fPaused) return B_PAUSED;
|
||||
|
||||
return B_NOT_PAUSED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BFileGameSound::stream_thread(void *that)
|
||||
BFileGameSound::Init(const entry_ref* file)
|
||||
{
|
||||
return B_ERROR;
|
||||
fAudioStream = new _gs_media_tracker;
|
||||
memset(fAudioStream, 0, sizeof(_gs_media_tracker));
|
||||
|
||||
fAudioStream->file = new BMediaFile(file);
|
||||
status_t error = fAudioStream->file->InitCheck();
|
||||
if (error != B_OK) return error;
|
||||
|
||||
fAudioStream->stream = fAudioStream->file->TrackAt(0);
|
||||
|
||||
// is this is an audio file?
|
||||
media_format mformat;
|
||||
fAudioStream->stream->EncodedFormat(&mformat);
|
||||
if (!mformat.IsAudio()) return B_MEDIA_BAD_FORMAT;
|
||||
|
||||
gs_audio_format dformat = Device()->Format();
|
||||
|
||||
// request the format we want the sound
|
||||
memset(&mformat, 0, sizeof(media_format));
|
||||
mformat.type = B_MEDIA_RAW_AUDIO;
|
||||
fAudioStream->stream->DecodedFormat(&mformat);
|
||||
|
||||
// translate the format into a "GameKit" friendly one
|
||||
gs_audio_format gsformat;
|
||||
media_to_gs_format(&gsformat, &mformat.u.raw_audio);
|
||||
|
||||
// Since the buffer sized read from the file is most likely differnt
|
||||
// then the buffer used by the audio mixer, we must allocate a buffer
|
||||
// large enough to hold the largest request.
|
||||
fBufferSize = gsformat.buffer_size;
|
||||
if (fBufferSize < dformat.buffer_size) fBufferSize = dformat.buffer_size;
|
||||
|
||||
// create the buffer
|
||||
fBuffer = new char[fBufferSize * 2];
|
||||
memset(fBuffer, 0, fBufferSize * 2);
|
||||
|
||||
fFrameSize = gsformat.channel_count * get_sample_size(gsformat.format);
|
||||
fAudioStream->frames = fAudioStream->stream->CountFrames();
|
||||
|
||||
// Ask the device to attach our sound to it
|
||||
gs_id sound;
|
||||
error = Device()->CreateBuffer(&sound, this, &gsformat);
|
||||
if (error != B_OK) return error;
|
||||
|
||||
return BGameSound::Init(sound);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BFileGameSound::LoadFunc()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
BFileGameSound::Load(size_t &offset,
|
||||
size_t bytes)
|
||||
int32
|
||||
BFileGameSound::ReadThread(void* arg)
|
||||
{
|
||||
BFileGameSound* obj = (BFileGameSound*)arg;
|
||||
|
||||
while(true) obj->Load();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BFileGameSound::read_data(char *dest,
|
||||
size_t bytes)
|
||||
bool
|
||||
BFileGameSound::Load()
|
||||
{
|
||||
int64 frames;
|
||||
char * buffer = &fBuffer[fBufferSize + fAudioStream->position];
|
||||
fAudioStream->stream->ReadFrames(buffer, &frames);
|
||||
|
||||
int32 frame = fAudioStream->stream->CurrentFrame();
|
||||
|
||||
fAudioStream->position += fFrameSize * frames;
|
||||
if (fAudioStream->position >= fBufferSize)
|
||||
{
|
||||
// we have filled the enter buffer, time to send
|
||||
write_port(fPort, fBufferSize, &fBuffer[fBufferSize], fBufferSize);
|
||||
fAudioStream->position = 0;
|
||||
}
|
||||
|
||||
if (frame >= fAudioStream->frames)
|
||||
{
|
||||
if (fLooping)
|
||||
{
|
||||
// since we are looping, we need to start reading from
|
||||
// the begining of the file again.
|
||||
int64 firstFrame = 0;
|
||||
fAudioStream->stream->SeekToFrame(&firstFrame);
|
||||
|
||||
fStopping = true;
|
||||
}
|
||||
else fStopping = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BFileGameSound::Read(void * buffer, size_t bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* unimplemented for protection of the user:
|
||||
*
|
||||
* BFileGameSound::BFileGameSound()
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSoundDevice.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Utility functions used by sound system
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <MediaDefs.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundDefs.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <GSUtility.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Utility functions -----------------------------------------------------------
|
||||
_gs_ramp* InitRamp(float* value, float set, float frames, bigtime_t duration)
|
||||
{
|
||||
float diff = (set > *value) ? set - *value : *value - set;
|
||||
bigtime_t sec = bigtime_t(duration / 1000000.0);
|
||||
float inc = diff * 200;
|
||||
|
||||
_gs_ramp* ramp = new _gs_ramp;
|
||||
ramp->value = value;
|
||||
|
||||
ramp->frame_total = frames * sec;
|
||||
ramp->frame_inc = int(ramp->frame_total / inc);
|
||||
|
||||
ramp->inc = (set - *value) / inc;
|
||||
|
||||
ramp->frame_count = 0;
|
||||
ramp->frame_inc_count = 0;
|
||||
|
||||
ramp->duration = duration;
|
||||
|
||||
return ramp;
|
||||
}
|
||||
|
||||
bool ChangeRamp(_gs_ramp* ramp)
|
||||
{
|
||||
if (ramp->frame_count > ramp->frame_total) return true;
|
||||
|
||||
if (ramp->frame_inc_count >= ramp->frame_inc)
|
||||
{
|
||||
ramp->frame_inc_count = 0;
|
||||
*ramp->value += ramp->inc;
|
||||
}
|
||||
else ramp->frame_inc_count++;
|
||||
|
||||
ramp->frame_count++;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t get_sample_size(int32 format)
|
||||
{
|
||||
size_t sample;
|
||||
|
||||
switch(format)
|
||||
{
|
||||
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||
sample = sizeof(char);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_U8:
|
||||
sample = sizeof(uint8);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_S16:
|
||||
sample = sizeof(int16);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_S32:
|
||||
sample = sizeof(int32);
|
||||
break;
|
||||
|
||||
case gs_audio_format::B_GS_F:
|
||||
sample = sizeof(float);
|
||||
break;
|
||||
|
||||
default: sample = 0;
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
void media_to_gs_format(gs_audio_format* dest, media_raw_audio_format* source)
|
||||
{
|
||||
dest->format = source->format;
|
||||
dest->frame_rate = source->frame_rate;
|
||||
dest->channel_count = source->channel_count;
|
||||
dest->byte_order = source->byte_order;
|
||||
dest->buffer_size = source->buffer_size;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSoundDevice.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Utility functions used by sound system
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GAMESOUND_UTILITY_H
|
||||
#define _GAMESOUND_UTILITY_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundDefs.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
struct _gs_ramp
|
||||
{
|
||||
float inc;
|
||||
float orignal;
|
||||
float* value;
|
||||
|
||||
float frame_total;
|
||||
float frame_inc;
|
||||
|
||||
float frame_count;
|
||||
float frame_inc_count;
|
||||
|
||||
bigtime_t duration;
|
||||
};
|
||||
|
||||
_gs_ramp* InitRamp(float* value, float set, float frames, bigtime_t duration);
|
||||
bool ChangeRamp(_gs_ramp* ramp);
|
||||
size_t get_sample_size(int32 format);
|
||||
void media_to_gs_format(gs_audio_format * dest, media_raw_audio_format * source);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,562 @@
|
||||
/*****************************************************************************/
|
||||
// GameProdcure.h
|
||||
//
|
||||
// This produce creates audio buffer on behalf of the GameKit.
|
||||
//
|
||||
// Copyright (c) 2001 OpenBeOS Project
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameProducer.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: A MediaKit producer node which mixes sound from the GameKit
|
||||
// and sends them to the audio mixer
|
||||
/*****************************************************************************/
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <ByteOrder.h>
|
||||
#include <BufferGroup.h>
|
||||
#include <Buffer.h>
|
||||
#include <List.h>
|
||||
#include <TimeSource.h>
|
||||
#include <MediaDefs.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundBuffer.h>
|
||||
#include <GameSoundDevice.h>
|
||||
#include <GSUtility.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <GameProducer.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
struct _gs_play
|
||||
{
|
||||
gs_id sound;
|
||||
bool * hook;
|
||||
|
||||
_gs_play * next;
|
||||
_gs_play * previous;
|
||||
};
|
||||
|
||||
GameProducer::GameProducer(GameSoundBuffer * object,
|
||||
const gs_audio_format * format)
|
||||
: BMediaNode("GameProducer.h"),
|
||||
BBufferProducer(B_MEDIA_RAW_AUDIO),
|
||||
BMediaEventLooper(),
|
||||
fBufferGroup(NULL),
|
||||
fLatency(0),
|
||||
fInternalLatency(0),
|
||||
fOutputEnabled(true)
|
||||
{
|
||||
// initialize our preferred format object
|
||||
fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
|
||||
fPreferredFormat.u.raw_audio.format = format->format;
|
||||
fPreferredFormat.u.raw_audio.channel_count = format->channel_count;
|
||||
fPreferredFormat.u.raw_audio.frame_rate = format->frame_rate; // measured in Hertz
|
||||
fPreferredFormat.u.raw_audio.byte_order = format->byte_order;
|
||||
// fPreferredFormat.u.raw_audio.channel_mask = B_CHANNEL_LEFT & B_CHANNEL_RIGHT;
|
||||
// fPreferredFormat.u.raw_audio.valid_bits = 32;
|
||||
// fPreferredFormat.u.raw_audio.matrix_mask = B_MATRIX_AMBISONIC_WXYZ;
|
||||
|
||||
// we'll use the consumer's preferred buffer size, if any
|
||||
fPreferredFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size;
|
||||
|
||||
// we're not connected yet
|
||||
fOutput.destination = media_destination::null;
|
||||
fOutput.format = fPreferredFormat;
|
||||
|
||||
fFrameSize = get_sample_size(format->format) * format->channel_count;
|
||||
fObject = object;
|
||||
}
|
||||
|
||||
|
||||
GameProducer::~GameProducer()
|
||||
{
|
||||
// Stop the BMediaEventLooper thread
|
||||
Quit();
|
||||
}
|
||||
|
||||
|
||||
// BMediaNode methods
|
||||
BMediaAddOn *
|
||||
GameProducer::AddOn(int32 *internal_id) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// BBufferProducer methods
|
||||
status_t
|
||||
GameProducer::GetNextOutput(int32* cookie, media_output* out_output)
|
||||
{
|
||||
// we currently support only one output
|
||||
if (0 != *cookie) return B_BAD_INDEX;
|
||||
|
||||
*out_output = fOutput;
|
||||
*cookie += 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::DisposeOutputCookie(int32 cookie)
|
||||
{
|
||||
// do nothing because our cookie is only an integer
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::EnableOutput(const media_source& what, bool enabled, int32* _deprecated_)
|
||||
{
|
||||
// If I had more than one output, I'd have to walk my list of output records to see
|
||||
// which one matched the given source, and then enable/disable that one. But this
|
||||
// node only has one output, so I just make sure the given source matches, then set
|
||||
// the enable state accordingly.
|
||||
if (what == fOutput.source)
|
||||
{
|
||||
fOutputEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::FormatSuggestionRequested(media_type type, int32 /*quality*/, media_format* format)
|
||||
{
|
||||
// insure that we received a format
|
||||
if (!format)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// returning our preferred format
|
||||
*format = fPreferredFormat;
|
||||
|
||||
// our format is supported
|
||||
if (type == B_MEDIA_UNKNOWN_TYPE) return B_OK;
|
||||
|
||||
// we only support raw audo
|
||||
return (type != B_MEDIA_RAW_AUDIO) ? B_MEDIA_BAD_FORMAT : B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::FormatProposal(const media_source& output, media_format* format)
|
||||
{
|
||||
// doest the proposed output match our output?
|
||||
if (output != fOutput.source) return B_MEDIA_BAD_SOURCE;
|
||||
|
||||
// return our preferred format
|
||||
*format = fPreferredFormat;
|
||||
|
||||
// we will reject the proposal if the format is not audio
|
||||
media_type requestedType = format->type;
|
||||
if ((requestedType != B_MEDIA_UNKNOWN_TYPE) && (requestedType != B_MEDIA_RAW_AUDIO))
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
|
||||
return B_OK; // raw audio or wildcard type, either is okay by us
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::PrepareToConnect(const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name)
|
||||
{
|
||||
// The format has been processed by the consumer at this point. We need
|
||||
// to insure the format is still acceptable and any wild care are filled in.
|
||||
|
||||
// trying to connect something that isn't our source?
|
||||
if (what != fOutput.source) return B_MEDIA_BAD_SOURCE;
|
||||
|
||||
// are we already connected?
|
||||
if (fOutput.destination != media_destination::null) return B_MEDIA_ALREADY_CONNECTED;
|
||||
|
||||
// the format may not yet be fully specialized (the consumer might have
|
||||
// passed back some wildcards). Finish specializing it now, and return an
|
||||
// error if we don't support the requested format.
|
||||
if (format->type != B_MEDIA_RAW_AUDIO)
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
|
||||
if (format->u.raw_audio.format != fPreferredFormat.u.raw_audio.format)
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
|
||||
// check the buffer size, which may still be wildcarded
|
||||
if (format->u.raw_audio.buffer_size == media_raw_audio_format::wildcard.buffer_size)
|
||||
format->u.raw_audio.buffer_size = 2048; // pick something comfortable to suggest
|
||||
|
||||
// Now reserve the connection, and return information about it
|
||||
fOutput.destination = where;
|
||||
fOutput.format = *format;
|
||||
*out_source = fOutput.source;
|
||||
strncpy(out_name, fOutput.name, B_MEDIA_NAME_LENGTH);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name)
|
||||
{
|
||||
// If something earlier failed, Connect() might still be called, but with a non-zero
|
||||
// error code. When that happens we simply unreserve the connection and do
|
||||
// nothing else.
|
||||
if (error)
|
||||
{
|
||||
fOutput.destination = media_destination::null;
|
||||
fOutput.format = fPreferredFormat;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Okay, the connection has been confirmed. Record the destination and format
|
||||
// that we agreed on, and report our connection name again.
|
||||
fOutput.destination = destination;
|
||||
fOutput.format = format;
|
||||
strncpy(io_name, fOutput.name, B_MEDIA_NAME_LENGTH);
|
||||
|
||||
// Now that we're connected, we can determine our downstream latency.
|
||||
// Do so, then make sure we get our events early enough.
|
||||
media_node_id id;
|
||||
FindLatencyFor(fOutput.destination, &fLatency, &id);
|
||||
|
||||
// Use a dry run to see how long it takes me to fill a buffer of data
|
||||
|
||||
// The first step to setup the buffer
|
||||
bigtime_t start, produceLatency;
|
||||
int32 frames = int32(fOutput.format.u.raw_audio.buffer_size / fFrameSize);
|
||||
float* data = new float[frames * 2];
|
||||
|
||||
// Second, fill the buffer
|
||||
start = ::system_time();
|
||||
for(int32 i = 0; i < frames; i++)
|
||||
{
|
||||
data[i*2] = 0.8 * float(i/frames);
|
||||
data[i*2+1] = 0.8 * float(i/frames);
|
||||
}
|
||||
produceLatency = ::system_time();
|
||||
|
||||
// Thid, calculate the latency
|
||||
fInternalLatency = produceLatency - start;
|
||||
SetEventLatency(fLatency + fInternalLatency);
|
||||
|
||||
// Finaily, clean up
|
||||
delete [] data;
|
||||
|
||||
// reset our buffer duration, etc. to avoid later calculations
|
||||
bigtime_t duration = bigtime_t(1000000) * frames / bigtime_t(fOutput.format.u.raw_audio.frame_rate);
|
||||
SetBufferDuration(duration);
|
||||
|
||||
// Set up the buffer group for our connection, as long as nobody handed us a
|
||||
// buffer group (via SetBufferGroup()) prior to this.
|
||||
if (!fBufferGroup)
|
||||
{
|
||||
size_t size = fOutput.format.u.raw_audio.buffer_size;
|
||||
int32 count = int32(fLatency / BufferDuration() + 2);
|
||||
fBufferGroup = new BBufferGroup(size, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::Disconnect(const media_source& what, const media_destination& where)
|
||||
{
|
||||
// Make sure that our connection is the one being disconnected
|
||||
if ((where == fOutput.destination) && (what == fOutput.source))
|
||||
{
|
||||
fOutput.destination = media_destination::null;
|
||||
fOutput.format = fPreferredFormat;
|
||||
delete fBufferGroup;
|
||||
fBufferGroup = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::FormatChangeRequested(const media_source& source, const media_destination& destination, media_format* io_format, int32* _deprecated_)
|
||||
{
|
||||
// we don't support any other formats, so we just reject any format changes.
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup)
|
||||
{
|
||||
// verify that we didn't get bogus arguments before we proceed
|
||||
if (for_source != fOutput.source) return B_MEDIA_BAD_SOURCE;
|
||||
|
||||
// Are we being passed the buffer group we're already using?
|
||||
if (newGroup == fBufferGroup) return B_OK;
|
||||
|
||||
// Ahh, someone wants us to use a different buffer group. At this point we delete
|
||||
// the one we are using and use the specified one instead. If the specified group is
|
||||
// NULL, we need to recreate one ourselves, and use *that*. Note that if we're
|
||||
// caching a BBuffer that we requested earlier, we have to Recycle() that buffer
|
||||
// *before* deleting the buffer group, otherwise we'll deadlock waiting for that
|
||||
// buffer to be recycled!
|
||||
delete fBufferGroup; // waits for all buffers to recycle
|
||||
if (newGroup != NULL)
|
||||
{
|
||||
// we were given a valid group; just use that one from now on
|
||||
fBufferGroup = newGroup;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we were passed a NULL group pointer; that means we construct
|
||||
// our own buffer group to use from now on
|
||||
size_t size = fOutput.format.u.raw_audio.buffer_size;
|
||||
int32 count = int32(fLatency / BufferDuration() + 2);
|
||||
fBufferGroup = new BBufferGroup(size, count);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::GetLatency(bigtime_t* out_latency)
|
||||
{
|
||||
// report our *total* latency: internal plus downstream plus scheduling
|
||||
*out_latency = EventLatency() + SchedulingLatency();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::LateNoticeReceived(const media_source& what, bigtime_t how_much, bigtime_t performance_time)
|
||||
{
|
||||
// If we're late, we need to catch up. Respond in a manner appropriate to our
|
||||
// current run mode.
|
||||
if (what == fOutput.source)
|
||||
{
|
||||
if (RunMode() == B_RECORDING)
|
||||
{
|
||||
// A hardware capture node can't adjust; it simply emits buffers at
|
||||
// appropriate points. We (partially) simulate this by not adjusting
|
||||
// our behavior upon receiving late notices -- after all, the hardware
|
||||
// can't choose to capture "sooner"....
|
||||
}
|
||||
else if (RunMode() == B_INCREASE_LATENCY)
|
||||
{
|
||||
// We're late, and our run mode dictates that we try to produce buffers
|
||||
// earlier in order to catch up. This argues that the downstream nodes are
|
||||
// not properly reporting their latency, but there's not much we can do about
|
||||
// that at the moment, so we try to start producing buffers earlier to
|
||||
// compensate.
|
||||
fInternalLatency += how_much;
|
||||
SetEventLatency(fLatency + fInternalLatency);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The other run modes dictate various strategies for sacrificing data quality
|
||||
// in the interests of timely data delivery. The way *we* do this is to skip
|
||||
// a buffer, which catches us up in time by one buffer duration.
|
||||
size_t nSamples = fOutput.format.u.raw_audio.buffer_size / fFrameSize;
|
||||
fFramesSent += nSamples;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::LatencyChanged(const media_source& source, const media_destination& destination, bigtime_t new_latency, uint32 flags)
|
||||
{
|
||||
// something downstream changed latency, so we need to start producing
|
||||
// buffers earlier (or later) than we were previously. Make sure that the
|
||||
// connection that changed is ours, and adjust to the new downstream
|
||||
// latency if so.
|
||||
if ((source == fOutput.source) && (destination == fOutput.destination))
|
||||
{
|
||||
fLatency = new_latency;
|
||||
SetEventLatency(fLatency + fInternalLatency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::SetPlayRate(int32 numer, int32 denom)
|
||||
{
|
||||
// Play rates are weird. We don't support them
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameProducer::HandleMessage(int32 message, const void* data, size_t size)
|
||||
{
|
||||
// We currently do not handle private messages
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::AdditionalBufferRequested(const media_source& source, media_buffer_id prev_buffer, bigtime_t prev_time, const media_seek_tag* prev_tag)
|
||||
{
|
||||
// we don't support offline mode (yet...)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// BMediaEventLooper methods
|
||||
void
|
||||
GameProducer::NodeRegistered()
|
||||
{
|
||||
// Start the BMediaEventLooper thread
|
||||
SetPriority(B_REAL_TIME_PRIORITY);
|
||||
Run();
|
||||
|
||||
// set up as much information about our output as we can
|
||||
fOutput.source.port = ControlPort();
|
||||
fOutput.source.id = 0;
|
||||
fOutput.node = Node();
|
||||
::strcpy(fOutput.name, "GameProducer Output");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::SetRunMode(run_mode mode)
|
||||
{
|
||||
// We don't support offline run mode, so broadcast an error if we're set to
|
||||
// B_OFFLINE. Unfortunately, we can't actually reject the mode change...
|
||||
if (B_OFFLINE == mode)
|
||||
{
|
||||
ReportError(B_NODE_FAILED_SET_RUN_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, bool realTimeEvent)
|
||||
{
|
||||
// FPRINTF(stderr, "ToneProducer::HandleEvent\n");
|
||||
switch (event->type)
|
||||
{
|
||||
case BTimedEventQueue::B_START:
|
||||
// don't do anything if we're already running
|
||||
if (RunState() != B_STARTED)
|
||||
{
|
||||
// We are going to start sending buffers so setup the needed bookkeeping
|
||||
fFramesSent = 0;
|
||||
fStartTime = event->event_time;
|
||||
media_timed_event firstBufferEvent(fStartTime, BTimedEventQueue::B_HANDLE_BUFFER);
|
||||
|
||||
// Alternatively, we could call HandleEvent() directly with this event, to avoid a trip through
|
||||
// the event queue, like this:
|
||||
//
|
||||
// this->HandleEvent(&firstBufferEvent, 0, false);
|
||||
//
|
||||
EventQueue()->AddEvent(firstBufferEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
case BTimedEventQueue::B_STOP:
|
||||
// When we handle a stop, we must ensure that downstream consumers don't
|
||||
// get any more buffers from us. This means we have to flush any pending
|
||||
// buffer-producing events from the queue.
|
||||
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
|
||||
break;
|
||||
|
||||
case BTimedEventQueue::B_HANDLE_BUFFER:
|
||||
{
|
||||
// make sure we're both started *and* connected before delivering a buffer
|
||||
if ((RunState() == BMediaEventLooper::B_STARTED) && (fOutput.destination != media_destination::null))
|
||||
{
|
||||
// Get the next buffer of data
|
||||
BBuffer* buffer = FillNextBuffer(event->event_time);
|
||||
if (buffer)
|
||||
{
|
||||
// send the buffer downstream if and only if output is enabled
|
||||
status_t err = B_ERROR;
|
||||
if (fOutputEnabled) err = SendBuffer(buffer, fOutput.destination);
|
||||
if (err)
|
||||
{
|
||||
// we need to recycle the buffer ourselves if output is disabled or
|
||||
// if the call to SendBuffer() fails
|
||||
buffer->Recycle();
|
||||
}
|
||||
}
|
||||
|
||||
// track how much media we've delivered so far
|
||||
size_t nFrames = fOutput.format.u.raw_audio.buffer_size / fFrameSize;
|
||||
fFramesSent += nFrames;
|
||||
|
||||
// The buffer is on its way; now schedule the next one to go
|
||||
bigtime_t nextEvent = fStartTime + bigtime_t(double(fFramesSent) / double(fOutput.format.u.raw_audio.frame_rate) * 1000000.0);
|
||||
media_timed_event nextBufferEvent(nextEvent, BTimedEventQueue::B_HANDLE_BUFFER);
|
||||
EventQueue()->AddEvent(nextBufferEvent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------
|
||||
// GameProducer
|
||||
BBuffer*
|
||||
GameProducer::FillNextBuffer(bigtime_t event_time)
|
||||
{
|
||||
// get a buffer from our buffer group
|
||||
BBuffer* buf = fBufferGroup->RequestBuffer(fOutput.format.u.raw_audio.buffer_size, BufferDuration());
|
||||
|
||||
// if we fail to get a buffer (for example, if the request times out), we skip this
|
||||
// buffer and go on to the next, to avoid locking up the control thread
|
||||
if (!buf) return NULL;
|
||||
|
||||
// we need to discribe the buffer
|
||||
int64 frames = int64(fOutput.format.u.raw_audio.buffer_size / fFrameSize);
|
||||
memset(buf->Data(), 0, fOutput.format.u.raw_audio.buffer_size);
|
||||
|
||||
// now fill the buffer with data, continuing where the last buffer left off
|
||||
fObject->Play(buf->Data(), frames);
|
||||
|
||||
// fill in the buffer header
|
||||
media_header* hdr = buf->Header();
|
||||
hdr->type = B_MEDIA_RAW_AUDIO;
|
||||
hdr->size_used = fOutput.format.u.raw_audio.buffer_size;
|
||||
hdr->time_source = TimeSource()->ID();
|
||||
|
||||
bigtime_t stamp;
|
||||
if (RunMode() == B_RECORDING)
|
||||
{
|
||||
// In B_RECORDING mode, we stamp with the capture time. We're not
|
||||
// really a hardware capture node, but we simulate it by using the (precalculated)
|
||||
// time at which this buffer "should" have been created.
|
||||
stamp = event_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
// okay, we're in one of the "live" performance run modes. in these modes, we
|
||||
// stamp the buffer with the time at which the buffer should be rendered to the
|
||||
// output, not with the capture time. fStartTime is the cached value of the
|
||||
// first buffer's performance time; we calculate this buffer's performance time as
|
||||
// an offset from that time, based on the amount of media we've created so far.
|
||||
// Recalculating every buffer like this avoids accumulation of error.
|
||||
stamp = fStartTime + bigtime_t(double(fFramesSent) / double(fOutput.format.u.raw_audio.frame_rate) * 1000000.0);
|
||||
}
|
||||
hdr->start_time = stamp;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameProducer.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: A MediaKit producer node which mixes sound from the GameKit
|
||||
// and sends them to the audio mixer
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GAMEPRODUCER_H
|
||||
#define _GAMEPRODUCER_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <media/BufferProducer.h>
|
||||
#include <media/MediaEventLooper.h>
|
||||
#include <GameSoundDefs.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
class GameSoundBuffer;
|
||||
|
||||
// GameProducer class -------------------------------------------------------------
|
||||
class GameProducer : public BBufferProducer, public BMediaEventLooper
|
||||
{
|
||||
public:
|
||||
GameProducer(GameSoundBuffer * object,
|
||||
const gs_audio_format * format);
|
||||
~GameProducer();
|
||||
|
||||
// BMediaNode methods
|
||||
BMediaAddOn* AddOn(int32* internal_id) const;
|
||||
|
||||
// BBufferProducer methods
|
||||
status_t FormatSuggestionRequested(media_type type,
|
||||
int32 quality,
|
||||
media_format* format);
|
||||
|
||||
status_t FormatProposal(const media_source& output,
|
||||
media_format* format);
|
||||
|
||||
status_t FormatChangeRequested(const media_source& source,
|
||||
const media_destination& destination,
|
||||
media_format* io_format,
|
||||
int32* _deprecated_);
|
||||
|
||||
status_t GetNextOutput(int32* cookie,
|
||||
media_output* out_output);
|
||||
|
||||
status_t DisposeOutputCookie(int32 cookie);
|
||||
|
||||
status_t SetBufferGroup(const media_source& for_source,
|
||||
BBufferGroup* group);
|
||||
|
||||
|
||||
status_t GetLatency(bigtime_t* out_latency);
|
||||
|
||||
status_t PrepareToConnect(const media_source& what,
|
||||
const media_destination& where,
|
||||
media_format* format,
|
||||
media_source* out_source,
|
||||
char* out_name);
|
||||
|
||||
void Connect(status_t error,
|
||||
const media_source& source,
|
||||
const media_destination& destination,
|
||||
const media_format& format,
|
||||
char* io_name);
|
||||
|
||||
void Disconnect(const media_source& what,
|
||||
const media_destination& where);
|
||||
|
||||
void LateNoticeReceived(const media_source& what,
|
||||
bigtime_t how_much,
|
||||
bigtime_t performance_time);
|
||||
|
||||
void EnableOutput(const media_source & what,
|
||||
bool enabled,
|
||||
int32* _deprecated_);
|
||||
|
||||
status_t SetPlayRate(int32 numer,
|
||||
int32 denom);
|
||||
|
||||
status_t HandleMessage(int32 message,
|
||||
const void* data,
|
||||
size_t size);
|
||||
|
||||
void AdditionalBufferRequested(const media_source& source,
|
||||
media_buffer_id prev_buffer,
|
||||
bigtime_t prev_time,
|
||||
const media_seek_tag* prev_tag);
|
||||
|
||||
void LatencyChanged(const media_source& source,
|
||||
const media_destination& destination,
|
||||
bigtime_t new_latency,
|
||||
uint32 flags);
|
||||
|
||||
// BMediaEventLooper methods
|
||||
void NodeRegistered();
|
||||
void SetRunMode(run_mode mode);
|
||||
void HandleEvent(const media_timed_event* event,
|
||||
bigtime_t lateness,
|
||||
bool realTimeEvent = false);
|
||||
|
||||
// GameProducer
|
||||
status_t StartPlaying(GameSoundBuffer* sound);
|
||||
status_t StopPlaying(GameSoundBuffer* sound);
|
||||
bool IsPlaying(GameSoundBuffer* sound) const;
|
||||
|
||||
int32 SoundCount() const;
|
||||
|
||||
private:
|
||||
BBuffer* FillNextBuffer(bigtime_t event_time);
|
||||
|
||||
BBufferGroup * fBufferGroup;
|
||||
bigtime_t fLatency, fInternalLatency;
|
||||
media_output fOutput;
|
||||
bool fOutputEnabled;
|
||||
media_format fPreferredFormat;
|
||||
|
||||
bigtime_t fStartTime;
|
||||
size_t fFrameSize;
|
||||
int64 fFramesSent;
|
||||
GameSoundBuffer * fObject;
|
||||
};
|
||||
|
||||
#endif
|
||||
+118
-28
@@ -1,65 +1,120 @@
|
||||
/*
|
||||
* Copyright 2002, Marcus Overhagen. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSound.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Provides much of interfaces with BGameSoundDevice on behalf
|
||||
// of the rest of it's childern.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundBuffer.h>
|
||||
#include <GameSoundDevice.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <GameSound.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// BGameSound class ------------------------------------------------------------
|
||||
BGameSound::BGameSound(BGameSoundDevice *device)
|
||||
: fSound(-1)
|
||||
{
|
||||
fDevice = GetDefaultDevice();
|
||||
fInitError = fDevice->InitCheck();
|
||||
}
|
||||
|
||||
|
||||
BGameSound::BGameSound(const BGameSound &other)
|
||||
: fSound(-1)
|
||||
{
|
||||
memcpy(&fFormat, &other.fFormat, sizeof(gs_audio_format));
|
||||
fDevice = GetDefaultDevice();
|
||||
|
||||
fInitError = fDevice->InitCheck();
|
||||
}
|
||||
|
||||
|
||||
BGameSound::~BGameSound()
|
||||
{
|
||||
if (fSound >= 0)
|
||||
fDevice->ReleaseBuffer(fSound);
|
||||
|
||||
ReleaseDevice();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSound::InitCheck() const
|
||||
{
|
||||
return B_ERROR;
|
||||
return fInitError;
|
||||
}
|
||||
|
||||
|
||||
BGameSoundDevice *
|
||||
BGameSound::Device() const
|
||||
{
|
||||
return NULL;
|
||||
return fDevice;
|
||||
}
|
||||
|
||||
|
||||
gs_id
|
||||
BGameSound::ID() const
|
||||
{
|
||||
return 0;
|
||||
return fSound;
|
||||
}
|
||||
|
||||
|
||||
const gs_audio_format &
|
||||
BGameSound::Format() const
|
||||
{
|
||||
return fDevice->Format(fSound);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSound::StartPlaying()
|
||||
{
|
||||
return B_ERROR;
|
||||
fDevice->StartPlaying(fSound);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BGameSound::IsPlaying()
|
||||
{
|
||||
return false;
|
||||
return fDevice->IsPlaying(fSound);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSound::StopPlaying()
|
||||
{
|
||||
return B_ERROR;
|
||||
fDevice->StopPlaying(fSound);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +122,14 @@ status_t
|
||||
BGameSound::SetGain(float gain,
|
||||
bigtime_t duration)
|
||||
{
|
||||
return B_ERROR;
|
||||
gs_attribute attribute;
|
||||
|
||||
attribute.attribute = B_GS_GAIN;
|
||||
attribute.value = gain;
|
||||
attribute.duration = duration;
|
||||
attribute.flags = 0;
|
||||
|
||||
return fDevice->SetAttributes(fSound, &attribute, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,21 +137,44 @@ status_t
|
||||
BGameSound::SetPan(float pan,
|
||||
bigtime_t duration)
|
||||
{
|
||||
return B_ERROR;
|
||||
gs_attribute attribute;
|
||||
|
||||
attribute.attribute = B_GS_PAN;
|
||||
attribute.value = pan;
|
||||
attribute.duration = duration;
|
||||
attribute.flags = 0;
|
||||
|
||||
return fDevice->SetAttributes(fSound, &attribute, 1);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
BGameSound::Gain()
|
||||
{
|
||||
return 0.0f;
|
||||
gs_attribute attribute;
|
||||
|
||||
attribute.attribute = B_GS_GAIN;
|
||||
attribute.flags = 0;
|
||||
|
||||
if (fDevice->GetAttributes(fSound, &attribute, 1) != B_OK)
|
||||
return 0.0;
|
||||
|
||||
return attribute.value;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
BGameSound::Pan()
|
||||
{
|
||||
return 0.0f;
|
||||
gs_attribute attribute;
|
||||
|
||||
attribute.attribute = B_GS_PAN;
|
||||
attribute.flags = 0;
|
||||
|
||||
if (fDevice->GetAttributes(fSound, &attribute, 1) != B_OK)
|
||||
return 0.0;
|
||||
|
||||
return attribute.value;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +182,7 @@ status_t
|
||||
BGameSound::SetAttributes(gs_attribute *inAttributes,
|
||||
size_t inAttributeCount)
|
||||
{
|
||||
return B_ERROR;
|
||||
return fDevice->SetAttributes(fSound, inAttributes, inAttributeCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +190,7 @@ status_t
|
||||
BGameSound::GetAttributes(gs_attribute *outAttributes,
|
||||
size_t inAttributeCount)
|
||||
{
|
||||
return B_ERROR;
|
||||
return fDevice->GetAttributes(fSound, outAttributes, inAttributeCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +201,7 @@ BGameSound::Perform(int32 selector,
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void *
|
||||
BGameSound::operator new(size_t size)
|
||||
{
|
||||
@@ -128,7 +213,7 @@ void
|
||||
BGameSound::operator delete(void *ptr)
|
||||
{
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
status_t
|
||||
BGameSound::SetMemoryPoolSize(size_t in_poolSize)
|
||||
@@ -147,34 +232,39 @@ BGameSound::LockMemoryPool(bool in_lockInCore)
|
||||
int32
|
||||
BGameSound::SetMaxSoundCount(int32 in_maxCount)
|
||||
{
|
||||
return 0;
|
||||
return in_maxCount;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSound::SetInitError(status_t in_initError)
|
||||
{
|
||||
return B_ERROR;
|
||||
fInitError = in_initError;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSound::Init(gs_id handle)
|
||||
{
|
||||
return B_ERROR;
|
||||
if (fSound < 0) fSound = handle;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
BGameSound::BGameSound(const BGameSound &other)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
BGameSound &
|
||||
BGameSound::operator=(const BGameSound &other)
|
||||
{
|
||||
if (fSound)
|
||||
fDevice->ReleaseBuffer(fSound);
|
||||
|
||||
fSound = other.fSound;
|
||||
fInitError = other.fInitError;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/* unimplemented for protection of the user:
|
||||
*
|
||||
|
||||
@@ -0,0 +1,541 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSoundBuffer.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Interface to a single sound, managed by the GameSoundDevice.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <MediaAddOn.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <MediaTheme.h>
|
||||
#include <TimeSource.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundDevice.h>
|
||||
#include <GameProducer.h>
|
||||
#include <GSUtility.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <GameSoundBuffer.h>
|
||||
#include <StreamingGameSound.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Sound Buffer Utility functions ----------------------------------------
|
||||
inline void ApplyMod(uint8 * data, uint8 * buffer, int64 index, float gain, float * pan)
|
||||
{
|
||||
data[index*2] += uint8(float(buffer[index*2]) * gain * pan[0]);
|
||||
data[index*2+1] += uint8(float(buffer[index*2+1]) * gain * pan[1]);
|
||||
}
|
||||
|
||||
|
||||
inline void ApplyMod(int16 * data, int16 * buffer, int32 index, float gain, float * pan)
|
||||
{
|
||||
data[index*2] = int16(float(buffer[index*2]) * gain * pan[0]);
|
||||
data[index*2+1] = int16(float(buffer[index*2+1]) * gain * pan[1]);
|
||||
}
|
||||
|
||||
|
||||
inline void ApplyMod(int32 * data, int32 * buffer, int32 index, float gain, float * pan)
|
||||
{
|
||||
data[index*2] += int32(float(buffer[index*2]) * gain * pan[0]);
|
||||
data[index*2+1] += int32(float(buffer[index*2+1]) * gain * pan[1]);
|
||||
}
|
||||
|
||||
|
||||
inline void ApplyMod(float * data, float * buffer, int32 index, float gain, float * pan)
|
||||
{
|
||||
data[index*2] += buffer[index*2] * gain * pan[0];
|
||||
data[index*2+1] += buffer[index*2+1] * gain * pan[1];
|
||||
}
|
||||
|
||||
// GameSoundBuffer -------------------------------------------------------
|
||||
GameSoundBuffer::GameSoundBuffer(const gs_audio_format * format)
|
||||
: fLooping(false),
|
||||
fIsConnected(false),
|
||||
fIsPlaying(false),
|
||||
fGain(1.0),
|
||||
fPan(0.0),
|
||||
fPanLeft(1.0),
|
||||
fPanRight(1.0),
|
||||
fGainRamp(NULL),
|
||||
fPanRamp(NULL)
|
||||
{
|
||||
fConnection = new Connection;
|
||||
fNode = new GameProducer(this, format);
|
||||
|
||||
fFrameSize = get_sample_size(format->format) * format->channel_count;
|
||||
|
||||
memcpy(&fFormat, format, sizeof(gs_audio_format));
|
||||
}
|
||||
|
||||
|
||||
GameSoundBuffer::~GameSoundBuffer()
|
||||
{
|
||||
BMediaRoster* r = BMediaRoster::Roster();
|
||||
|
||||
if (fIsPlaying) r->StopNode(fConnection->producer, 0, true);
|
||||
|
||||
if (fIsConnected)
|
||||
{
|
||||
// Ordinarily we'd stop *all* of the nodes in the chain at this point. However,
|
||||
// one of the nodes is the System Mixer, and stopping the Mixer is a Bad Idea (tm).
|
||||
// So, we just disconnect from it, and release our references to the nodes that
|
||||
// we're using. We *are* supposed to do that even for global nodes like the Mixer.
|
||||
r->Disconnect(fConnection->producer.node, fConnection->source,
|
||||
fConnection->consumer.node, fConnection->destination);
|
||||
|
||||
r->ReleaseNode(fConnection->producer);
|
||||
r->ReleaseNode(fConnection->consumer);
|
||||
}
|
||||
|
||||
delete fGainRamp;
|
||||
delete fPanRamp;
|
||||
|
||||
delete fConnection;
|
||||
delete fNode;
|
||||
}
|
||||
|
||||
|
||||
const gs_audio_format &
|
||||
GameSoundBuffer::Format() const
|
||||
{
|
||||
return fFormat;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GameSoundBuffer::IsLooping() const
|
||||
{
|
||||
return fLooping;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameSoundBuffer::SetLooping(bool looping)
|
||||
{
|
||||
fLooping = looping;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
GameSoundBuffer::Gain() const
|
||||
{
|
||||
return fGain;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::SetGain(float gain, bigtime_t duration)
|
||||
{
|
||||
if (gain < 0.0 || gain > 1.0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fGainRamp) delete fGainRamp;
|
||||
|
||||
if (duration > 100000)
|
||||
fGainRamp = InitRamp(&fGain, gain, fFormat.frame_rate, duration);
|
||||
else
|
||||
fGain = gain;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
GameSoundBuffer::Pan() const
|
||||
{
|
||||
return fPan;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::SetPan(float pan, bigtime_t duration)
|
||||
{
|
||||
if (pan < -1.0 || pan > 1.0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fPanRamp) delete fPanRamp;
|
||||
|
||||
if (duration < 100000)
|
||||
{
|
||||
fPan = pan;
|
||||
|
||||
if (fPan < 0.0)
|
||||
{
|
||||
fPanLeft = 1.0;
|
||||
fPanRight = 1.0 + fPan;
|
||||
}
|
||||
else
|
||||
{
|
||||
fPanRight = 1.0;
|
||||
fPanLeft = 1.0 - fPan;
|
||||
}
|
||||
}
|
||||
else fPanRamp = InitRamp(&fPan, pan, fFormat.frame_rate, duration);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::GetAttributes(gs_attribute * attributes,
|
||||
size_t attributeCount)
|
||||
{
|
||||
for(size_t i = 0; i < attributeCount; i++)
|
||||
{
|
||||
switch(attributes[i].attribute)
|
||||
{
|
||||
case B_GS_GAIN:
|
||||
attributes[i].value = fGain;
|
||||
if (fGainRamp) attributes[i].duration = fGainRamp->duration;
|
||||
break;
|
||||
|
||||
case B_GS_PAN:
|
||||
attributes[i].value = fPan;
|
||||
if (fPanRamp) attributes[i].duration = fGainRamp->duration;
|
||||
|
||||
case B_GS_LOOPING:
|
||||
attributes[i].value = (fLooping) ? -1.0 : 0.0;
|
||||
attributes[i].duration = bigtime_t(0);
|
||||
|
||||
default:
|
||||
attributes[i].value = 0.0;
|
||||
attributes[i].duration = bigtime_t(0);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::SetAttributes(gs_attribute * attributes,
|
||||
size_t attributeCount)
|
||||
{
|
||||
status_t error = B_OK;
|
||||
|
||||
for(size_t i = 0; i < attributeCount; i++)
|
||||
{
|
||||
switch(attributes[i].attribute)
|
||||
{
|
||||
case B_GS_GAIN:
|
||||
error = SetGain(attributes[i].value, attributes[i].duration);
|
||||
break;
|
||||
|
||||
case B_GS_PAN:
|
||||
error = SetPan(attributes[i].value, attributes[i].duration);
|
||||
break;
|
||||
|
||||
case B_GS_LOOPING:
|
||||
fLooping = bool(attributes[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameSoundBuffer::Play(void * data, int64 frames)
|
||||
{
|
||||
float * pan = new float[1];
|
||||
pan[0] = fPanRight;
|
||||
pan[1] = fPanLeft;
|
||||
|
||||
char * buffer = new char[fFrameSize * frames];
|
||||
|
||||
FillBuffer(buffer, frames);
|
||||
|
||||
switch(fFormat.format)
|
||||
{
|
||||
case gs_audio_format::B_GS_U8:
|
||||
{
|
||||
for(int64 i = 0; i < frames; i++)
|
||||
{
|
||||
ApplyMod((uint8*)data, (uint8*)buffer, i, fGain, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gs_audio_format::B_GS_S16:
|
||||
{
|
||||
for(int64 i = 0; i < frames; i++)
|
||||
{
|
||||
ApplyMod((int16*)data, (int16*)buffer, i, fGain, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gs_audio_format::B_GS_S32:
|
||||
{
|
||||
for(int64 i = 0; i < frames; i++)
|
||||
{
|
||||
ApplyMod((int32*)data, (int32*)buffer, i, fGain, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gs_audio_format::B_GS_F:
|
||||
{
|
||||
for(int64 i = 0; i < frames; i++)
|
||||
{
|
||||
ApplyMod((float*)data, (float*)buffer, i, fGain, pan);
|
||||
UpdateMods();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] buffer;
|
||||
delete [] pan;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameSoundBuffer::UpdateMods()
|
||||
{
|
||||
// adjust the gain if needed
|
||||
if (fGainRamp)
|
||||
{
|
||||
if (ChangeRamp(fGainRamp))
|
||||
{
|
||||
delete fGainRamp;
|
||||
fGainRamp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust the ramp if needed
|
||||
if (fPanRamp)
|
||||
{
|
||||
if (ChangeRamp(fPanRamp))
|
||||
{
|
||||
delete fPanRamp;
|
||||
fPanRamp = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fPan < 0.0)
|
||||
{
|
||||
fPanLeft = 1.0;
|
||||
fPanRight = 1.0 + fPan;
|
||||
}
|
||||
else
|
||||
{
|
||||
fPanRight = 1.0;
|
||||
fPanLeft = 1.0 - fPan;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GameSoundBuffer::Reset()
|
||||
{
|
||||
fGain = 1.0;
|
||||
delete fGainRamp;
|
||||
fGainRamp = NULL;
|
||||
|
||||
fPan = 0.0;
|
||||
fPanLeft = 1.0;
|
||||
fPanRight = 1.0;
|
||||
delete fPanRamp;
|
||||
fPanRamp = NULL;
|
||||
|
||||
fLooping = false;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::Connect(media_node * consumer)
|
||||
{
|
||||
BMediaRoster* r = BMediaRoster::Roster();
|
||||
status_t err;
|
||||
|
||||
err = r->RegisterNode(fNode);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// make sure the Media Roster knows that we're using the node
|
||||
r->GetNodeFor(fNode->Node().node, &fConnection->producer);
|
||||
|
||||
// connect to the mixer
|
||||
fConnection->consumer = *consumer;
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// set the producer's time source to be the "default" time source, which
|
||||
// the Mixer uses too.
|
||||
r->GetTimeSource(&fConnection->timeSource);
|
||||
r->SetTimeSourceFor(fConnection->producer.node, fConnection->timeSource.node);
|
||||
|
||||
// got the nodes; now we find the endpoints of the connection
|
||||
media_input mixerInput;
|
||||
media_output soundOutput;
|
||||
int32 count = 1;
|
||||
err = r->GetFreeOutputsFor(fConnection->producer, &soundOutput, 1, &count);
|
||||
if (err != B_OK) return err;
|
||||
count = 1;
|
||||
err = r->GetFreeInputsFor(fConnection->consumer, &mixerInput, 1, &count);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// got the endpoints; now we connect it!
|
||||
media_format format;
|
||||
format.type = B_MEDIA_RAW_AUDIO;
|
||||
format.u.raw_audio = media_raw_audio_format::wildcard;
|
||||
err = r->Connect(soundOutput.source, mixerInput.destination, &format, &soundOutput, &mixerInput);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// the inputs and outputs might have been reassigned during the
|
||||
// nodes' negotiation of the Connect(). That's why we wait until
|
||||
// after Connect() finishes to save their contents.
|
||||
fConnection->format = format;
|
||||
fConnection->source = soundOutput.source;
|
||||
fConnection->destination = mixerInput.destination;
|
||||
|
||||
fIsConnected = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::StartPlaying()
|
||||
{
|
||||
if (fIsPlaying) return EALREADY;
|
||||
|
||||
BMediaRoster* r = BMediaRoster::Roster();
|
||||
BTimeSource* ts = r->MakeTimeSourceFor(fConnection->producer);
|
||||
|
||||
// make sure we give the producer enough time to run buffers through
|
||||
// the node chain, otherwise it'll start up already late
|
||||
bigtime_t latency = 0;
|
||||
r->GetLatencyFor(fConnection->producer, &latency);
|
||||
r->StartNode(fConnection->producer, ts->Now() + latency);
|
||||
ts->Release();
|
||||
|
||||
fIsPlaying = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GameSoundBuffer::StopPlaying()
|
||||
{
|
||||
if (!fIsPlaying) return EALREADY;
|
||||
|
||||
BMediaRoster* r = BMediaRoster::Roster();
|
||||
r->StopNode(fConnection->producer, 0, true); // synchronous stop
|
||||
|
||||
Reset();
|
||||
fIsPlaying = false;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GameSoundBuffer::IsPlaying()
|
||||
{
|
||||
return fIsPlaying;
|
||||
}
|
||||
|
||||
|
||||
// SimpleSoundBuffer ------------------------------------------------------
|
||||
SimpleSoundBuffer::SimpleSoundBuffer(const gs_audio_format * format,
|
||||
const void * data,
|
||||
int64 frames)
|
||||
: GameSoundBuffer(format),
|
||||
fPosition(0)
|
||||
|
||||
{
|
||||
fBuffer = new char[frames * fFrameSize];
|
||||
fBufferSize = frames * fFrameSize;
|
||||
}
|
||||
|
||||
|
||||
SimpleSoundBuffer::~SimpleSoundBuffer()
|
||||
{
|
||||
delete [] fBuffer;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleSoundBuffer::Reset()
|
||||
{
|
||||
GameSoundBuffer::Reset();
|
||||
fPosition = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleSoundBuffer::FillBuffer(void * data, int64 frames)
|
||||
{
|
||||
char * buffer = (char*)data;
|
||||
size_t bytes = fFrameSize * frames;
|
||||
|
||||
if (fPosition + bytes >= fBufferSize)
|
||||
{
|
||||
size_t remainder = fBufferSize - fPosition;
|
||||
memcpy(buffer, &fBuffer[fPosition], remainder);
|
||||
|
||||
if (fLooping) memcpy(&buffer[remainder], fBuffer, bytes - remainder);
|
||||
}
|
||||
else memcpy(buffer, &fBuffer[fPosition], bytes);
|
||||
}
|
||||
|
||||
|
||||
// StreamingSoundBuffer ------------------------------------------------------
|
||||
StreamingSoundBuffer::StreamingSoundBuffer(const gs_audio_format * format,
|
||||
const void * streamHook)
|
||||
: GameSoundBuffer(format)
|
||||
{
|
||||
fStreamHook = (void*)streamHook;
|
||||
}
|
||||
|
||||
|
||||
StreamingSoundBuffer::~StreamingSoundBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StreamingSoundBuffer::FillBuffer(void * buffer,
|
||||
int64 frames)
|
||||
{
|
||||
BStreamingGameSound* object = (BStreamingGameSound*)fStreamHook;
|
||||
|
||||
size_t bytes = fFrameSize * frames;
|
||||
object->FillBuffer(buffer, bytes);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSoundBuffer.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Interface to a single sound, managed by the GameSoundDevice.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GAMESOUNDBUFFER_H
|
||||
#define _GAMESOUNDBUFFER_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <GameSoundDefs.h>
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaNode.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
const int32 kPausedAttribute = B_GS_FIRST_PRIVATE_ATTRIBUTE;
|
||||
|
||||
class GameProducer;
|
||||
struct _gs_ramp;
|
||||
struct Connection
|
||||
{
|
||||
media_node producer, consumer;
|
||||
media_source source;
|
||||
media_destination destination;
|
||||
media_format format;
|
||||
media_node timeSource;
|
||||
};
|
||||
|
||||
// GameSoundBuffer -------------------------------------------------------------
|
||||
class GameSoundBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
GameSoundBuffer(const gs_audio_format* format);
|
||||
virtual ~GameSoundBuffer();
|
||||
|
||||
virtual status_t Connect(media_node * consumer);
|
||||
status_t StartPlaying();
|
||||
status_t StopPlaying();
|
||||
bool IsPlaying();
|
||||
|
||||
void Play(void * data, int64 frames);
|
||||
void UpdateMods();
|
||||
virtual void Reset();
|
||||
|
||||
virtual void * Data() { return NULL; }
|
||||
const gs_audio_format & Format() const;
|
||||
|
||||
bool IsLooping() const;
|
||||
void SetLooping(bool loop);
|
||||
float Gain() const;
|
||||
status_t SetGain(float gain, bigtime_t duration);
|
||||
float Pan() const;
|
||||
status_t SetPan(float pan, bigtime_t duration);
|
||||
|
||||
virtual status_t GetAttributes(gs_attribute * attributes,
|
||||
size_t attributeCount);
|
||||
virtual status_t SetAttributes(gs_attribute * attributes,
|
||||
size_t attributeCount);
|
||||
protected:
|
||||
|
||||
virtual void FillBuffer(void * data, int64 frames) = 0;
|
||||
|
||||
gs_audio_format fFormat;
|
||||
bool fLooping;
|
||||
|
||||
size_t fFrameSize;
|
||||
|
||||
private:
|
||||
|
||||
Connection * fConnection;
|
||||
GameProducer * fNode;
|
||||
bool fIsConnected;
|
||||
bool fIsPlaying;
|
||||
|
||||
float fGain;
|
||||
float fPan, fPanLeft, fPanRight;
|
||||
_gs_ramp* fGainRamp;
|
||||
_gs_ramp* fPanRamp;
|
||||
};
|
||||
|
||||
|
||||
class SimpleSoundBuffer : public GameSoundBuffer
|
||||
{
|
||||
public:
|
||||
SimpleSoundBuffer(const gs_audio_format* format,
|
||||
const void * data,
|
||||
int64 frames = 0);
|
||||
virtual ~SimpleSoundBuffer();
|
||||
|
||||
virtual void * Data() { return fBuffer; }
|
||||
virtual void Reset();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void FillBuffer(void * data, int64 frames);
|
||||
|
||||
private:
|
||||
char * fBuffer;
|
||||
size_t fBufferSize;
|
||||
size_t fPosition;
|
||||
};
|
||||
|
||||
class StreamingSoundBuffer : public GameSoundBuffer
|
||||
{
|
||||
public:
|
||||
StreamingSoundBuffer(const gs_audio_format * format,
|
||||
const void * streamHook);
|
||||
virtual ~StreamingSoundBuffer();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void FillBuffer(void * data, int64 frames);
|
||||
|
||||
private:
|
||||
|
||||
void * fStreamHook;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: BGameSoundDevice.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Manages the game producer. The class may change with out
|
||||
// notice and was only inteneded for use by the GameKit at
|
||||
// this time. Use at your own risk.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <List.h>
|
||||
#include <MediaAddOn.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <MediaTheme.h>
|
||||
#include <TimeSource.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundBuffer.h>
|
||||
#include <GameProducer.h>
|
||||
#include <GSUtility.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <GameSoundDevice.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// BGameSoundDevice definitions ------------------------------------
|
||||
const int32 kInitSoundCount = 32;
|
||||
const int32 kGrowth = 16;
|
||||
|
||||
static int32 deviceCount = 0;
|
||||
static BGameSoundDevice* theDevice = NULL;
|
||||
|
||||
BGameSoundDevice * GetDefaultDevice()
|
||||
{
|
||||
if (!theDevice)
|
||||
theDevice = new BGameSoundDevice();
|
||||
|
||||
deviceCount++;
|
||||
return theDevice;
|
||||
}
|
||||
|
||||
void ReleaseDevice()
|
||||
{
|
||||
deviceCount--;
|
||||
|
||||
if (deviceCount <= 0)
|
||||
{
|
||||
delete theDevice;
|
||||
theDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// BGameSoundDevice -------------------------------------------------------
|
||||
BGameSoundDevice::BGameSoundDevice()
|
||||
: fIsConnected(false),
|
||||
fSoundCount(kInitSoundCount)
|
||||
{
|
||||
fConnection = new Connection;
|
||||
memset(&fFormat, 0, sizeof(gs_audio_format));
|
||||
|
||||
fInitError = Connect();
|
||||
|
||||
fSounds = new GameSoundBuffer*[kInitSoundCount];
|
||||
for(int32 i = 0; i < kInitSoundCount; i++)
|
||||
fSounds[i] = NULL;
|
||||
}
|
||||
|
||||
|
||||
BGameSoundDevice::~BGameSoundDevice()
|
||||
{
|
||||
BMediaRoster* r = BMediaRoster::Roster();
|
||||
|
||||
// We need to stop all the sounds before we stop the mixer
|
||||
for(int32 i = 0; i < fSoundCount; i++)
|
||||
delete fSounds[i];
|
||||
|
||||
if (fIsConnected)
|
||||
{
|
||||
// stop the nodes if they are running
|
||||
r->StopNode(fConnection->producer, 0, true); // synchronous stop
|
||||
|
||||
// Ordinarily we'd stop *all* of the nodes in the chain at this point. However,
|
||||
// one of the nodes is the System Mixer, and stopping the Mixer is a Bad Idea (tm).
|
||||
// So, we just disconnect from it, and release our references to the nodes that
|
||||
// we're using. We *are* supposed to do that even for global nodes like the Mixer.
|
||||
r->Disconnect(fConnection->producer.node, fConnection->source,
|
||||
fConnection->consumer.node, fConnection->destination);
|
||||
|
||||
r->ReleaseNode(fConnection->producer);
|
||||
r->ReleaseNode(fConnection->consumer);
|
||||
}
|
||||
|
||||
delete [] fSounds;
|
||||
delete fConnection;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::InitCheck() const
|
||||
{
|
||||
return fInitError;
|
||||
}
|
||||
|
||||
|
||||
const gs_audio_format &
|
||||
BGameSoundDevice::Format() const
|
||||
{
|
||||
return fFormat;
|
||||
}
|
||||
|
||||
|
||||
const gs_audio_format &
|
||||
BGameSoundDevice::Format(gs_id sound) const
|
||||
{
|
||||
return fSounds[sound-1]->Format();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BGameSoundDevice::SetInitError(status_t error)
|
||||
{
|
||||
fInitError = error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::CreateBuffer(gs_id * sound,
|
||||
const gs_audio_format * format,
|
||||
const void * data,
|
||||
int64 frames)
|
||||
{
|
||||
if (frames <= 0 || !sound) return B_BAD_VALUE;
|
||||
|
||||
status_t err = B_MEDIA_TOO_MANY_BUFFERS;
|
||||
int32 position = AllocateSound();
|
||||
|
||||
if (position >= 0)
|
||||
{
|
||||
fSounds[position] = new SimpleSoundBuffer(format, data, frames);
|
||||
err = fSounds[position]->Connect(&fConnection->producer);
|
||||
}
|
||||
|
||||
*sound = gs_id(position+1);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::CreateBuffer(gs_id * sound,
|
||||
const void * object,
|
||||
const gs_audio_format * format)
|
||||
{
|
||||
if (!object || !sound) return B_BAD_VALUE;
|
||||
|
||||
status_t err = B_MEDIA_TOO_MANY_BUFFERS;
|
||||
int32 position = AllocateSound();
|
||||
|
||||
if (position >= 0)
|
||||
{
|
||||
fSounds[position] = new StreamingSoundBuffer(format, object);
|
||||
err = fSounds[position]->Connect(&fConnection->producer);
|
||||
}
|
||||
|
||||
*sound = gs_id(position+1);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BGameSoundDevice::ReleaseBuffer(gs_id sound)
|
||||
{
|
||||
delete fSounds[sound-1];
|
||||
fSounds[sound-1] = NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::Buffer(gs_id sound,
|
||||
gs_audio_format * format,
|
||||
void * data)
|
||||
{
|
||||
if (!format) return B_BAD_VALUE;
|
||||
|
||||
memcpy(format, &fSounds[sound-1]->Format(), sizeof(gs_audio_format));
|
||||
|
||||
if (fSounds[sound-1]->Data())
|
||||
{
|
||||
data = malloc(format->buffer_size);
|
||||
memcpy(data, fSounds[sound-1]->Data(), format->buffer_size);
|
||||
}
|
||||
else data = NULL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::StartPlaying(gs_id sound)
|
||||
{
|
||||
status_t error = EALREADY;
|
||||
|
||||
if (!fSounds[sound-1]->IsPlaying())
|
||||
{
|
||||
// tell the producer to start playing the sound
|
||||
error = fSounds[sound-1]->StartPlaying();
|
||||
}
|
||||
else fSounds[sound-1]->Reset();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::StopPlaying(gs_id sound)
|
||||
{
|
||||
status_t error = EALREADY;
|
||||
|
||||
if (fSounds[sound-1]->IsPlaying())
|
||||
{
|
||||
// Tell the producer to stop play this sound
|
||||
fSounds[sound-1]->Reset();
|
||||
error = fSounds[sound-1]->StopPlaying();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BGameSoundDevice::IsPlaying(gs_id sound)
|
||||
{
|
||||
return fSounds[sound-1]->IsPlaying();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::GetAttributes(gs_id sound,
|
||||
gs_attribute * attributes,
|
||||
size_t attributeCount)
|
||||
{
|
||||
if (!fSounds[sound-1]) return B_ERROR;
|
||||
|
||||
return fSounds[sound-1]->GetAttributes(attributes, attributeCount);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::SetAttributes(gs_id sound,
|
||||
gs_attribute * attributes,
|
||||
size_t attributeCount)
|
||||
{
|
||||
if (!fSounds[sound-1]) return B_ERROR;
|
||||
|
||||
return fSounds[sound-1]->SetAttributes(attributes, attributeCount);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BGameSoundDevice::Connect()
|
||||
{
|
||||
BMediaRoster* r = BMediaRoster::Roster();
|
||||
status_t err;
|
||||
|
||||
// create your own audio mixer
|
||||
dormant_node_info mixer_dormant_info;
|
||||
int32 mixer_count = 1; // for now, we only care about the first we find.
|
||||
err = r->GetDormantNodes(&mixer_dormant_info, &mixer_count, 0, 0, 0, B_SYSTEM_MIXER, 0);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
//fMixer = new media_node;
|
||||
err = r->InstantiateDormantNode(mixer_dormant_info, &fConnection->producer);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// retieve the system's audio mixer
|
||||
err = r->GetAudioMixer(&fConnection->consumer);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
int32 count = 1;
|
||||
media_input mixerInput;
|
||||
err = r->GetFreeInputsFor(fConnection->consumer, &mixerInput, 1, &count);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
count = 1;
|
||||
media_output mixerOutput;
|
||||
err = r->GetFreeOutputsFor(fConnection->producer, &mixerOutput, 1, &count);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
media_format format(mixerOutput.format);
|
||||
err = r->Connect(mixerOutput.source, mixerInput.destination, &format, &mixerOutput, &mixerInput);
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// set the producer's time source to be the "default" time source, which
|
||||
// the Mixer uses too.
|
||||
r->GetTimeSource(&fConnection->timeSource);
|
||||
r->SetTimeSourceFor(fConnection->producer.node, fConnection->timeSource.node);
|
||||
|
||||
// Start our mixer's time source if need be. Chances are, it won't need to be,
|
||||
// but if we forget to do this, our mixer might not do anything at all.
|
||||
BTimeSource* mixerTimeSource = r->MakeTimeSourceFor(fConnection->producer);
|
||||
if (! mixerTimeSource) return B_ERROR;
|
||||
|
||||
if (!mixerTimeSource->IsRunning())
|
||||
{
|
||||
status_t err = r->StartNode(mixerTimeSource->Node(), BTimeSource::RealTime());
|
||||
if (err != B_OK)
|
||||
{
|
||||
mixerTimeSource->Release();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Start up our mixer
|
||||
bigtime_t tpNow = mixerTimeSource->Now();
|
||||
err = r->StartNode(fConnection->producer, tpNow + 10000);
|
||||
mixerTimeSource->Release();
|
||||
if (err != B_OK) return err;
|
||||
|
||||
// the inputs and outputs might have been reassigned during the
|
||||
// nodes' negotiation of the Connect(). That's why we wait until
|
||||
// after Connect() finishes to save their contents.
|
||||
fConnection->format = format;
|
||||
fConnection->source = mixerOutput.source;
|
||||
fConnection->destination = mixerInput.destination;
|
||||
|
||||
// Set an appropriate run mode for the producer
|
||||
r->SetRunModeNode(fConnection->producer, BMediaNode::B_INCREASE_LATENCY);
|
||||
|
||||
media_to_gs_format(&fFormat, &format.u.raw_audio);
|
||||
fIsConnected = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
BGameSoundDevice::AllocateSound()
|
||||
{
|
||||
for(int32 i = 0; i < fSoundCount; i++)
|
||||
if (!fSounds[i])
|
||||
return i;
|
||||
|
||||
// we need to allocate new space for the sound
|
||||
GameSoundBuffer ** sounds = new GameSoundBuffer*[fSoundCount + kGrowth];
|
||||
for(int32 i = 0; i < fSoundCount; i++)
|
||||
sounds[i] = fSounds[i];
|
||||
|
||||
for(int32 i = fSoundCount; i < fSoundCount + kGrowth; i++)
|
||||
sounds[i] = NULL;
|
||||
|
||||
// replace the old list
|
||||
delete [] fSounds;
|
||||
fSounds = sounds;
|
||||
fSoundCount += kGrowth;
|
||||
|
||||
return fSoundCount - kGrowth;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSoundDevice.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: Manages the game producer. The class may change with out
|
||||
// notice and was only inteneded for use by the GameKit at
|
||||
// this time. Use at your own risk.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GAMESOUNDDEVICE_H
|
||||
#define _GAMESOUNDDEVICE_H
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <GameSoundDefs.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// Globals ---------------------------------------------------------------------
|
||||
class BMediaNode;
|
||||
class GameSoundBuffer;
|
||||
struct Connection;
|
||||
|
||||
// BGameSoundDevice ------------------------------------------------------------
|
||||
class BGameSoundDevice
|
||||
{
|
||||
public:
|
||||
BGameSoundDevice();
|
||||
virtual ~BGameSoundDevice();
|
||||
|
||||
status_t InitCheck() const;
|
||||
virtual const gs_audio_format & Format() const;
|
||||
virtual const gs_audio_format & Format(gs_id sound) const;
|
||||
|
||||
virtual status_t CreateBuffer(gs_id * sound,
|
||||
const gs_audio_format * format,
|
||||
const void * data,
|
||||
int64 frames);
|
||||
virtual status_t CreateBuffer(gs_id * sound,
|
||||
const void * object,
|
||||
const gs_audio_format * format);
|
||||
virtual void ReleaseBuffer(gs_id sound);
|
||||
|
||||
virtual status_t Buffer(gs_id sound,
|
||||
gs_audio_format * format,
|
||||
void * data);
|
||||
|
||||
virtual bool IsPlaying(gs_id sound);
|
||||
virtual status_t StartPlaying(gs_id sound);
|
||||
virtual status_t StopPlaying(gs_id sound);
|
||||
|
||||
virtual status_t GetAttributes(gs_id sound,
|
||||
gs_attribute * attributes,
|
||||
size_t attributeCount);
|
||||
virtual status_t SetAttributes(gs_id sound,
|
||||
gs_attribute * attributes,
|
||||
size_t attributeCount);
|
||||
|
||||
protected:
|
||||
void SetInitError(status_t error);
|
||||
|
||||
gs_audio_format fFormat;
|
||||
private:
|
||||
status_t Connect();
|
||||
int32 AllocateSound();
|
||||
|
||||
status_t fInitError;
|
||||
|
||||
Connection * fConnection;
|
||||
bool fIsConnected;
|
||||
|
||||
int32 fSoundCount;
|
||||
GameSoundBuffer ** fSounds;
|
||||
};
|
||||
|
||||
BGameSoundDevice* GetDefaultDevice();
|
||||
void ReleaseDevice();
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,7 @@ SubDir OBOS_TOP src kits game ;
|
||||
UsePublicHeaders game ;
|
||||
|
||||
SharedLibrary game :
|
||||
# Public Game Kit
|
||||
DirectWindow.cpp
|
||||
WindowScreen.cpp
|
||||
GameSound.cpp
|
||||
@@ -10,9 +11,14 @@ SharedLibrary game :
|
||||
FileGameSound.cpp
|
||||
PushGameSound.cpp
|
||||
StreamingGameSound.cpp
|
||||
|
||||
# Internal Functionality
|
||||
GameProducer.cpp
|
||||
GameSoundBuffer.cpp
|
||||
GameSoundDevice.cpp
|
||||
GSUtility.cpp
|
||||
;
|
||||
|
||||
LinkSharedOSLibs libgame.so :
|
||||
be
|
||||
be media
|
||||
;
|
||||
|
||||
|
||||
+162
-17
@@ -1,40 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002, Marcus Overhagen. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: GameSound.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BPushGameSound class
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <List.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GSUtility.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <PushGameSound.h>
|
||||
|
||||
static const size_t default_in_buffer_frame_count = 4096; // XXX change this
|
||||
static const gs_audio_format default_format = {}; // XXX change this
|
||||
static const size_t default_in_buffer_count = 2; // XXX change this
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// BPushGameSound --------------------------------------------------------------
|
||||
BPushGameSound::BPushGameSound(size_t inBufferFrameCount,
|
||||
const gs_audio_format *format,
|
||||
size_t inBufferCount,
|
||||
BGameSoundDevice *device)
|
||||
: BStreamingGameSound(default_in_buffer_frame_count, &default_format, default_in_buffer_count, device)
|
||||
: BStreamingGameSound(inBufferFrameCount, format, inBufferCount, device)
|
||||
{
|
||||
if (InitCheck() == B_OK)
|
||||
{
|
||||
status_t error = SetParameters(inBufferFrameCount, format, inBufferCount);
|
||||
if (error != B_OK)
|
||||
fPageLocked = new BList;
|
||||
else
|
||||
SetInitError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BPushGameSound::BPushGameSound(BGameSoundDevice * device)
|
||||
: BStreamingGameSound(device),
|
||||
fLockPos(0),
|
||||
fPlayPos(0),
|
||||
fBuffer(NULL),
|
||||
fPageSize(0),
|
||||
fPageCount(0),
|
||||
fBufferSize(0)
|
||||
{
|
||||
fPageLocked = new BList;
|
||||
}
|
||||
|
||||
BPushGameSound::~BPushGameSound()
|
||||
{
|
||||
delete [] fBuffer;
|
||||
delete fPageLocked;
|
||||
}
|
||||
|
||||
|
||||
BPushGameSound::lock_status
|
||||
BPushGameSound::LockNextPage(void **out_pagePtr,
|
||||
size_t *out_pageSize)
|
||||
{
|
||||
return lock_failed;
|
||||
{
|
||||
// the user can not lock every page
|
||||
if (fPageLocked->CountItems() > fPageCount - 3) return lock_failed;
|
||||
|
||||
// the user cann't lock a page being played
|
||||
if (fLockPos < fPlayPos && fLockPos + fPageSize > fPlayPos) return lock_failed;
|
||||
|
||||
// lock the page
|
||||
char * lockPage = &fBuffer[fLockPos];
|
||||
fPageLocked->AddItem(lockPage);
|
||||
|
||||
// move the locker to the next page
|
||||
fLockPos += fPageSize;
|
||||
if (fLockPos > fBufferSize) fLockPos = 0;
|
||||
|
||||
*out_pagePtr = lockPage;
|
||||
*out_pageSize = fPageSize;
|
||||
|
||||
return lock_ok;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BPushGameSound::UnlockPage(void *in_pagePtr)
|
||||
{
|
||||
return B_ERROR;
|
||||
return (fPageLocked->RemoveItem(in_pagePtr)) ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,28 +110,34 @@ BPushGameSound::lock_status
|
||||
BPushGameSound::LockForCyclic(void **out_basePtr,
|
||||
size_t *out_size)
|
||||
{
|
||||
return lock_failed;
|
||||
*out_basePtr = fBuffer;
|
||||
*out_size = fBufferSize;
|
||||
return lock_ok;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BPushGameSound::UnlockCyclic()
|
||||
{
|
||||
return B_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
BPushGameSound::CurrentPosition()
|
||||
{
|
||||
return 0;
|
||||
return fPlayPos;
|
||||
}
|
||||
|
||||
|
||||
BGameSound *
|
||||
BPushGameSound::Clone() const
|
||||
{
|
||||
return NULL;
|
||||
gs_audio_format format = Format();
|
||||
size_t frameSize = get_sample_size(format.format) * format.channel_count;
|
||||
size_t bufferFrameCount = fPageSize / frameSize;
|
||||
|
||||
return new BPushGameSound(bufferFrameCount, &format, fPageCount, Device());
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +154,18 @@ BPushGameSound::SetParameters(size_t inBufferFrameCount,
|
||||
const gs_audio_format *format,
|
||||
size_t inBufferCount)
|
||||
{
|
||||
return B_ERROR;
|
||||
status_t error = BStreamingGameSound::SetParameters(inBufferFrameCount, format, inBufferCount);
|
||||
if (error != B_OK) return error;
|
||||
|
||||
size_t frameSize = get_sample_size(format->format) * format->channel_count;
|
||||
|
||||
fPageCount = inBufferCount;
|
||||
fPageSize = frameSize * inBufferFrameCount;
|
||||
fBufferSize = fPageSize * fPageCount;
|
||||
|
||||
fBuffer = new char[fBufferSize];
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,10 +180,70 @@ BPushGameSound::SetStreamHook(void (*hook)(void * inCookie, void * inBuffer, siz
|
||||
void
|
||||
BPushGameSound::FillBuffer(void *inBuffer,
|
||||
size_t inByteCount)
|
||||
{
|
||||
{
|
||||
size_t bytes = inByteCount;
|
||||
|
||||
if (BytesReady(&bytes))
|
||||
{
|
||||
if (fPlayPos + bytes > fBufferSize)
|
||||
{
|
||||
size_t remainder = fPlayPos + bytes - fBufferSize;
|
||||
char * buffer = (char*)inBuffer;
|
||||
|
||||
// fill the buffer with the samples left at the end of our buffer
|
||||
memcpy(buffer, &fBuffer[fPlayPos], remainder);
|
||||
fPlayPos = 0;
|
||||
|
||||
// fill the remainder of the buffer by looping to the start
|
||||
// of the buffer if it isn't locked
|
||||
bytes -= remainder;
|
||||
if (BytesReady(&bytes))
|
||||
{
|
||||
memcpy(&buffer[remainder], fBuffer, bytes);
|
||||
fPlayPos += bytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(inBuffer, &fBuffer[fPlayPos], bytes);
|
||||
fPlayPos += bytes;
|
||||
}
|
||||
|
||||
BStreamingGameSound::FillBuffer(inBuffer, inByteCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BPushGameSound::BytesReady(size_t * bytes)
|
||||
{
|
||||
if (fPageLocked->CountItems() > 0)
|
||||
{
|
||||
size_t start = fPlayPos;
|
||||
size_t ready = fPlayPos;
|
||||
int32 page = int32(start / fPageSize);
|
||||
|
||||
// return if there is nothing to do
|
||||
if (fPageLocked->HasItem(&fBuffer[page * fPageSize])) return false;
|
||||
|
||||
while (ready < *bytes)
|
||||
{
|
||||
ready += fPageSize;
|
||||
page = int32(ready / fPageSize);
|
||||
|
||||
if (fPageLocked->HasItem(&fBuffer[page * fPageSize]))
|
||||
{
|
||||
// we have found a locked page
|
||||
*bytes = ready - start - (ready - page * fPageSize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all of the bytes are ready
|
||||
return true;
|
||||
}
|
||||
|
||||
/* unimplemented for protection of the user:
|
||||
*
|
||||
* BPushGameSound::BPushGameSound()
|
||||
|
||||
@@ -1,21 +1,70 @@
|
||||
/*
|
||||
* Copyright 2002, Marcus Overhagen. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: SimpleGameSound.h
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BSimpleGameSound is a class for sound effects that are
|
||||
// short, and consists of non-changing samples in memory.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <Entry.h>
|
||||
#include <MediaFile.h>
|
||||
#include <MediaTrack.h>
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundBuffer.h>
|
||||
#include <GameSoundDevice.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <SimpleGameSound.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
|
||||
// BSimpleGameSound ------------------------------------------------------------
|
||||
BSimpleGameSound::BSimpleGameSound(const entry_ref *inFile,
|
||||
BGameSoundDevice *device)
|
||||
: BGameSound(device)
|
||||
: BGameSound(device)
|
||||
{
|
||||
if (InitCheck() == B_OK) SetInitError(Init(inFile));
|
||||
}
|
||||
|
||||
|
||||
BSimpleGameSound::BSimpleGameSound(const char *inFile,
|
||||
BGameSoundDevice *device)
|
||||
: BGameSound(device)
|
||||
: BGameSound(device)
|
||||
{
|
||||
if (InitCheck() == B_OK)
|
||||
{
|
||||
entry_ref file;
|
||||
|
||||
if (get_ref_for_path(inFile, &file) != B_OK)
|
||||
SetInitError(B_ENTRY_NOT_FOUND);
|
||||
else
|
||||
SetInitError(Init(&file));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +72,25 @@ BSimpleGameSound::BSimpleGameSound(const void *inData,
|
||||
size_t inFrameCount,
|
||||
const gs_audio_format *format,
|
||||
BGameSoundDevice *device)
|
||||
: BGameSound(device)
|
||||
: BGameSound(device)
|
||||
{
|
||||
if (InitCheck() == B_OK) SetInitError(Init(inData, inFrameCount, format));
|
||||
}
|
||||
|
||||
|
||||
BSimpleGameSound::BSimpleGameSound(const BSimpleGameSound &other)
|
||||
: BGameSound(other.Device())
|
||||
{
|
||||
: BGameSound(other)
|
||||
{
|
||||
gs_audio_format format;
|
||||
void * data;
|
||||
|
||||
status_t error = other.Device()->Buffer(other.ID(), &format, data);
|
||||
if (error != B_OK) SetInitError(error);
|
||||
|
||||
Init(data, 0, &format);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
BSimpleGameSound::~BSimpleGameSound()
|
||||
{
|
||||
}
|
||||
@@ -42,29 +99,176 @@ BSimpleGameSound::~BSimpleGameSound()
|
||||
BGameSound *
|
||||
BSimpleGameSound::Clone() const
|
||||
{
|
||||
return NULL;
|
||||
gs_audio_format format;
|
||||
void * data;
|
||||
|
||||
status_t error = Device()->Buffer(ID(), &format, data);
|
||||
if (error != B_OK) return NULL;
|
||||
|
||||
BSimpleGameSound * clone = new BSimpleGameSound(data, 0, &format, Device());
|
||||
|
||||
free(data);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BSimpleGameSound::Perform(int32 selector,
|
||||
void *data)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BSimpleGameSound::SetIsLooping(bool looping)
|
||||
{
|
||||
return B_ERROR;
|
||||
gs_attribute attribute;
|
||||
|
||||
attribute.attribute = B_GS_LOOPING;
|
||||
attribute.value = (looping) ? -1.0 : 0.0;
|
||||
attribute.duration = bigtime_t(0);
|
||||
attribute.flags = 0;
|
||||
|
||||
return Device()->SetAttributes(ID(), &attribute, 1);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BSimpleGameSound::IsLooping() const
|
||||
{
|
||||
return false;
|
||||
gs_attribute attribute;
|
||||
|
||||
attribute.attribute = B_GS_LOOPING;
|
||||
attribute.flags = 0;
|
||||
|
||||
if (Device()->GetAttributes(ID(), &attribute, 1) != B_OK)
|
||||
return false;
|
||||
|
||||
return bool(attribute.value);
|
||||
}
|
||||
|
||||
status_t
|
||||
BSimpleGameSound::Perform(int32 selector,
|
||||
void *data)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
status_t
|
||||
BSimpleGameSound::Init(const entry_ref* inFile)
|
||||
{
|
||||
BMediaFile file(inFile);
|
||||
gs_audio_format gsformat;
|
||||
media_format mformat;
|
||||
int64 framesRead, framesTotal = 0;
|
||||
|
||||
if (file.InitCheck() != B_OK) return file.InitCheck();
|
||||
|
||||
BMediaTrack* audioStream = file.TrackAt(0);
|
||||
audioStream->EncodedFormat(&mformat);
|
||||
if (!mformat.IsAudio()) return B_ERROR;
|
||||
|
||||
int64 frames = audioStream->CountFrames();
|
||||
|
||||
memset(&mformat, 0, sizeof(media_format));
|
||||
mformat.type = B_MEDIA_RAW_AUDIO;
|
||||
mformat.u.raw_audio.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
|
||||
audioStream->DecodedFormat(&mformat);
|
||||
|
||||
memset(&gsformat, 0, sizeof(gs_audio_format));
|
||||
gsformat.frame_rate = mformat.u.raw_audio.frame_rate;
|
||||
gsformat.channel_count = mformat.u.raw_audio.channel_count;
|
||||
gsformat.byte_order = mformat.u.raw_audio.byte_order;
|
||||
gsformat.buffer_size = mformat.u.raw_audio.buffer_size;
|
||||
|
||||
if (mformat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_CHAR)
|
||||
{
|
||||
// The GameKit doesnt support this format so we will have to reformat
|
||||
// the data into something the GameKit does support.
|
||||
char * buffer = new char[gsformat.buffer_size];
|
||||
uchar * data = new uchar[frames * gsformat.channel_count];
|
||||
|
||||
while (framesTotal < frames)
|
||||
{
|
||||
// read the next chunck from the stream
|
||||
memset(buffer, 0, gsformat.buffer_size);
|
||||
audioStream->ReadFrames(buffer, &framesRead);
|
||||
|
||||
// refomat the buffer from
|
||||
int64 position = framesTotal * gsformat.channel_count;
|
||||
for(int32 i = 0; i < (int32)gsformat.buffer_size; i++)
|
||||
data[i + position] = buffer[i] + 128;
|
||||
|
||||
framesTotal += framesRead;
|
||||
}
|
||||
|
||||
gsformat.format = gs_audio_format::B_GS_U8;
|
||||
|
||||
status_t error = Init(data, frames, &gsformat);
|
||||
|
||||
// free the buffers we no longer need
|
||||
delete [] buffer;
|
||||
delete [] data;
|
||||
|
||||
file.ReleaseTrack(audioStream);
|
||||
return error;
|
||||
}
|
||||
|
||||
// We need to detriman the size, in bytes, of a single sample.
|
||||
// At the same time, we will store the format of the audio buffer
|
||||
size_t sampleSize;
|
||||
switch(mformat.u.raw_audio.format)
|
||||
{
|
||||
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||
sampleSize = sizeof(uchar);
|
||||
gsformat.format = gs_audio_format::B_GS_U8;
|
||||
break;
|
||||
|
||||
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||
sampleSize = sizeof(int16);
|
||||
gsformat.format = gs_audio_format::B_GS_S16;
|
||||
break;
|
||||
|
||||
case media_raw_audio_format::B_AUDIO_INT:
|
||||
sampleSize = sizeof(int32);
|
||||
gsformat.format = gs_audio_format::B_GS_S32;
|
||||
break;
|
||||
|
||||
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||
sampleSize = sizeof(float);
|
||||
gsformat.format = gs_audio_format::B_GS_F;
|
||||
break;
|
||||
|
||||
default: return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
char * data = (char*)malloc(frames * gsformat.channel_count * sampleSize);
|
||||
gsformat.buffer_size = frames * gsformat.channel_count * sampleSize;
|
||||
|
||||
while(framesTotal < frames)
|
||||
{
|
||||
int64 position = framesTotal * gsformat.channel_count * sampleSize;
|
||||
audioStream->ReadFrames(&data[position], &framesRead);
|
||||
|
||||
framesTotal += framesRead;
|
||||
}
|
||||
|
||||
status_t error = Init(data, frames, &gsformat);
|
||||
|
||||
free(data);
|
||||
|
||||
file.ReleaseTrack(audioStream);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BSimpleGameSound::Init(const void* inData,
|
||||
int64 inFrameCount,
|
||||
const gs_audio_format* format)
|
||||
{
|
||||
gs_id sound;
|
||||
|
||||
status_t error = Device()->CreateBuffer(&sound, format, inData, inFrameCount);
|
||||
if (error != B_OK) return error;
|
||||
|
||||
BGameSound::Init(sound);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,61 @@
|
||||
/*
|
||||
* Copyright 2002, Marcus Overhagen. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2001-2002, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File Name: StreamingGameSound.cpp
|
||||
// Author: Christopher ML Zumwalt May ([email protected])
|
||||
// Description: BStreamingGameSound is a class for all kinds of streaming
|
||||
// (data not known beforehand) game sounds.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
|
||||
// Project Includes ------------------------------------------------------------
|
||||
#include <GameSoundDevice.h>
|
||||
|
||||
// Local Includes --------------------------------------------------------------
|
||||
#include <StreamingGameSound.h>
|
||||
|
||||
// Local Defines ---------------------------------------------------------------
|
||||
BStreamingGameSound::BStreamingGameSound(size_t inBufferFrameCount,
|
||||
const gs_audio_format *format,
|
||||
size_t inBufferCount,
|
||||
BGameSoundDevice *device)
|
||||
: BGameSound(device)
|
||||
: BGameSound(device),
|
||||
fStreamHook(NULL),
|
||||
fStreamCookie(NULL)
|
||||
{
|
||||
if (InitCheck() == B_OK)
|
||||
{
|
||||
status_t error = SetParameters(inBufferFrameCount, format, inBufferCount);
|
||||
SetInitError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BStreamingGameSound::BStreamingGameSound(BGameSoundDevice *device)
|
||||
: BGameSound(device),
|
||||
fStreamHook(NULL),
|
||||
fStreamCookie(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -30,7 +76,10 @@ status_t
|
||||
BStreamingGameSound::SetStreamHook(void (*hook)(void * inCookie, void * inBuffer, size_t inByteCount, BStreamingGameSound * me),
|
||||
void * cookie)
|
||||
{
|
||||
return B_ERROR;
|
||||
fStreamHook = hook;
|
||||
fStreamCookie = cookie;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,14 +87,8 @@ void
|
||||
BStreamingGameSound::FillBuffer(void *inBuffer,
|
||||
size_t inByteCount)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BStreamingGameSound::SetAttributes(gs_attribute *inAttributes,
|
||||
size_t inAttributeCount)
|
||||
{
|
||||
return B_ERROR;
|
||||
if (fStreamHook)
|
||||
(fStreamHook)(fStreamCookie, inBuffer, inByteCount, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,42 +100,38 @@ BStreamingGameSound::Perform(int32 selector,
|
||||
}
|
||||
|
||||
|
||||
BStreamingGameSound::BStreamingGameSound(BGameSoundDevice *device)
|
||||
: BGameSound(device)
|
||||
status_t
|
||||
BStreamingGameSound::SetAttributes(gs_attribute * inAttributes,
|
||||
size_t inAttributeCount)
|
||||
{
|
||||
return BGameSound::SetAttributes(inAttributes, inAttributeCount);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BStreamingGameSound::SetParameters(size_t inBufferFrameCount,
|
||||
const gs_audio_format *format,
|
||||
size_t inBufferCount)
|
||||
const gs_audio_format *format,
|
||||
size_t inBufferCount)
|
||||
{
|
||||
return B_ERROR;
|
||||
gs_id sound;
|
||||
status_t error = Device()->CreateBuffer(&sound, this, format);
|
||||
if (error != B_OK) return error;
|
||||
|
||||
return BGameSound::Init(sound);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BStreamingGameSound::Lock()
|
||||
{
|
||||
return false;
|
||||
return fLock.Lock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStreamingGameSound::Unlock()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStreamingGameSound::stream_callback(void *cookie,
|
||||
gs_id handle,
|
||||
void *buffer,
|
||||
int32 offset,
|
||||
int32 size,
|
||||
size_t bufSize)
|
||||
{
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user