Files
fs2open.github.com/code/sound/rtvoice.cpp
T
Zacam 4952b70488 Trunk Sync - r10911
There are a lot of changes here that should probably be examined, namely the Debug Console (which had conflicts) and Yarn's "any resolution" mainhalls code (Which also had conflicts) but for the most part this should be fairly clean.

git-svn-id: svn://svn.icculus.org/fs2open/branches/antipodes@10912 387891d4-d844-0410-90c0-e4c51a9137d3
2014-09-11 19:22:13 +10:00

458 lines
11 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include "globalincs/pstypes.h"
#include "sound/sound.h"
#include "sound/ds.h"
#include "sound/dscap.h"
#include "sound/rtvoice.h"
typedef struct rtv_format
{
int nchannels;
int bits_per_sample;
int frequency;
} rtv_format;
#define MAX_RTV_FORMATS 5
static rtv_format Rtv_formats[MAX_RTV_FORMATS] =
{
{1, 8, 11025},
{1, 16, 11025},
{1, 8, 22050},
{1, 16, 22050},
{1, 8, 44100},
};
static int Rtv_recording_format; // recording format, index into Rtv_formats[]
static int Rtv_playback_format; // playback format, index into Rtv_formats[]
#define RTV_BUFFER_TIME 8 // length of buffer in seconds
static int Rtv_recording_inited=0; // The input stream has been inited
static int Rtv_playback_inited=0; // The output stream has been inited
static int Rtv_recording=0; // Voice is currently being recorded
#define MAX_RTV_OUT_BUFFERS 1
#define RTV_OUT_FLAG_USED (1<<0)
typedef struct rtv_out_buffer
{
int ds_handle; // handle to directsound buffer
int flags; // see RTV_OUT_FLAG_ #defines above
} rtv_out_buffer;
static rtv_out_buffer Rtv_output_buffers[MAX_RTV_OUT_BUFFERS]; // data for output buffers
//static struct t_CodeInfo Rtv_code_info; // Parms will need to be transmitted with packets
// recording timer data
#ifdef _WIN32
static int Rtv_record_timer_id; // unique id for callback timer
#else
static SDL_TimerID Rtv_record_timer_id;
#endif
static int Rtv_callback_time; // callback time in ms
void (*Rtv_callback)();
// recording/encoding buffers
static unsigned char *Rtv_capture_raw_buffer;
static unsigned char *Rtv_capture_compressed_buffer;
//static int Rtv_capture_compressed_buffer_size;
static int Rtv_capture_raw_buffer_size;
// playback/decoding buffers
static unsigned char *Rtv_playback_uncompressed_buffer;
static int Rtv_playback_uncompressed_buffer_size;
/////////////////////////////////////////////////////////////////////////////////////////////////
// RECORD/ENCODE
/////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
void CALLBACK TimeProc(unsigned int id, unsigned int msg, unsigned long userdata, unsigned long dw1, unsigned long dw2)
{
if ( !Rtv_callback ) {
return;
}
nprintf(("Alan","In callback\n"));
Rtv_callback();
}
#else
Uint32 CALLBACK TimeProc(Uint32 interval, void *param)
{
if ( !Rtv_callback ) {
SDL_RemoveTimer(Rtv_record_timer_id);
Rtv_record_timer_id = NULL;
return 0;
}
mprintf(("In callback\n"));
Rtv_callback();
if (Rtv_callback_time) {
return interval;
} else {
SDL_RemoveTimer(Rtv_record_timer_id);
Rtv_record_timer_id = NULL;
return 0;
}
}
#endif
// Try to pick the most appropriate recording format
//
// exit: 0 => success
// !0 => failure
int rtvoice_pick_record_format()
{
int i;
for (i=0; i<MAX_RTV_FORMATS; i++) {
if ( dscap_create_buffer(Rtv_formats[i].frequency, Rtv_formats[i].bits_per_sample, 1, RTV_BUFFER_TIME) == 0 ) {
dscap_release_buffer();
Rtv_recording_format=i;
break;
}
}
if ( i == MAX_RTV_FORMATS ) {
return -1;
}
return 0;
}
// input: qos => new quality of service (1..10)
void rtvoice_set_qos(int qos)
{
// TODO: Speex stuff
}
// Init the recording portion of the real-time voice system
// input: qos => quality of service (1..10) 1 is highest compression, 10 is highest quality
// exit: 0 => success
// !0 => failure, recording not possible
int rtvoice_init_recording(int qos)
{
#if 0
if ( !Rtv_recording_inited ) {
if ( rtvoice_pick_record_format() ) {
return -1;
}
Rtv_capture_raw_buffer_size = Rtv_formats[Rtv_recording_format].frequency * (RTV_BUFFER_TIME) * fl2i(Rtv_formats[Rtv_recording_format].bits_per_sample/8.0f);
if ( dscap_create_buffer(Rtv_formats[Rtv_recording_format].frequency, Rtv_formats[Rtv_recording_format].bits_per_sample, 1, RTV_BUFFER_TIME) ) {
return -1;
}
// malloc out the voice data buffer for raw (uncompressed) recorded sound
if ( Rtv_capture_raw_buffer ) {
vm_free(Rtv_capture_raw_buffer);
Rtv_capture_raw_buffer=NULL;
}
Rtv_capture_raw_buffer = (unsigned char*)vm_malloc(Rtv_capture_raw_buffer_size);
// malloc out voice data buffer for compressed recorded sound
if ( Rtv_capture_compressed_buffer ) {
vm_free(Rtv_capture_compressed_buffer);
Rtv_capture_compressed_buffer=NULL;
}
Rtv_capture_compressed_buffer_size=Rtv_capture_raw_buffer_size; // be safe and allocate same as uncompressed
Rtv_capture_compressed_buffer = (unsigned char*)vm_malloc(Rtv_capture_compressed_buffer_size);
Rtv_recording_inited=1;
}
return 0;
#else
return -1;
#endif
}
// Stop a stream from recording
void rtvoice_stop_recording()
{
if ( !Rtv_recording ) {
return;
}
dscap_stop_record();
if ( Rtv_record_timer_id ) {
#ifndef _WIN32
SDL_RemoveTimer(Rtv_record_timer_id);
Rtv_record_timer_id = NULL;
#else
timeKillEvent(Rtv_record_timer_id);
Rtv_record_timer_id = 0;
#endif
}
Rtv_recording=0;
}
// Close down the real-time voice recording system
void rtvoice_close_recording()
{
if ( Rtv_recording ) {
rtvoice_stop_recording();
}
if ( Rtv_capture_raw_buffer ) {
vm_free(Rtv_capture_raw_buffer);
Rtv_capture_raw_buffer=NULL;
}
if ( Rtv_capture_compressed_buffer ) {
vm_free(Rtv_capture_compressed_buffer);
Rtv_capture_compressed_buffer=NULL;
}
dscap_release_buffer();
Rtv_recording_inited=0;
}
// Open a stream for recording (recording begins immediately)
// exit: 0 => success
// !0 => failure
int rtvoice_start_recording( void (*user_callback)(), int callback_time )
{
if ( !dscap_supported() ) {
return -1;
}
Assert(Rtv_recording_inited);
if ( Rtv_recording ) {
return -1;
}
if ( dscap_start_record() ) {
return -1;
}
if ( user_callback ) {
#ifndef _WIN32
Rtv_record_timer_id = SDL_AddTimer(callback_time, TimeProc, NULL);
#else
Rtv_record_timer_id = timeSetEvent(callback_time, callback_time, TimeProc, 0, TIME_PERIODIC);
#endif
if ( !Rtv_record_timer_id ) {
dscap_stop_record();
return -1;
}
Rtv_callback = user_callback;
Rtv_callback_time = callback_time;
} else {
Rtv_callback = NULL;
Rtv_record_timer_id = 0;
}
Rtv_recording=1;
return 0;
}
// Retrieve the recorded voice data
// input: outbuf => output parameter, recorded voice stored here
// compressed_size => output parameter, size in bytes of recorded voice after compression
// uncompressed_size => output parameter, size in bytes of recorded voice before compression
// gain => output parameter, gain value which must be passed to decoder
// outbuf_raw => output optional parameter, pointer to the raw sound data making up the compressed chunk
// outbuf_size_raw => output optional parameter, size of the outbuf_raw buffer
//
// NOTE: function converts voice data into compressed format
void rtvoice_get_data(unsigned char **outbuf, int *size, double *gain)
{
int max_size __attribute__((__unused__)), raw_size;
max_size = dscap_max_buffersize();
*outbuf=NULL;
raw_size = dscap_get_raw_data(Rtv_capture_raw_buffer, Rtv_capture_raw_buffer_size);
// TODO: compress voice data
// *gain = Rtv_code_info.Gain;
*size = raw_size;
*outbuf = Rtv_capture_raw_buffer;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// DECODE/PLAYBACK
/////////////////////////////////////////////////////////////////////////////////////////////////
// uncompress the data into PCM format
void rtvoice_uncompress(unsigned char *data_in, int size_in, double gain, unsigned char *data_out, int size_out)
{
if ( (data_in == NULL) || (size_in <= 0) ) {
return;
}
}
// Close down the real-time voice playback system
void rtvoice_close_playback()
{
if ( Rtv_playback_uncompressed_buffer ) {
vm_free(Rtv_playback_uncompressed_buffer);
Rtv_playback_uncompressed_buffer=NULL;
}
Rtv_playback_inited=0;
}
// Clear out the Rtv_output_buffers[] array
void rtvoice_reset_out_buffers()
{
int i;
for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
Rtv_output_buffers[i].flags=0;
Rtv_output_buffers[i].ds_handle=-1;
}
}
// Init the playback portion of the real-time voice system
// exit: 0 => success
// !0 => failure, playback not possible
int rtvoice_init_playback()
{
rtv_format *rtvf=NULL;
if ( !Rtv_playback_inited ) {
rtvoice_reset_out_buffers();
Rtv_playback_format=0;
rtvf = &Rtv_formats[Rtv_playback_format];
if ( Rtv_playback_uncompressed_buffer ) {
vm_free(Rtv_playback_uncompressed_buffer);
Rtv_playback_uncompressed_buffer=NULL;
}
Rtv_playback_uncompressed_buffer_size = rtvf->frequency * (RTV_BUFFER_TIME) * fl2i(rtvf->bits_per_sample/8.0f);
Rtv_playback_uncompressed_buffer = (unsigned char*)vm_malloc(Rtv_playback_uncompressed_buffer_size);
Assert(Rtv_playback_uncompressed_buffer);
Rtv_playback_inited=1;
}
return 0;
}
int rtvoice_find_free_output_buffer()
{
int i;
for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
if ( !(Rtv_output_buffers[i].flags & RTV_OUT_FLAG_USED) ) {
break;
}
}
if ( i == MAX_RTV_OUT_BUFFERS ) {
return -1;
}
Rtv_output_buffers[i].flags |= RTV_OUT_FLAG_USED;
return i;
}
// Open a stream for real-time voice output
int rtvoice_create_playback_buffer()
{
int index;
rtv_format *rtvf=NULL;
rtvf = &Rtv_formats[Rtv_playback_format];
index = rtvoice_find_free_output_buffer();
if ( index == -1 ) {
Int3();
return -1;
}
Rtv_output_buffers[index].ds_handle = ds_create_buffer(rtvf->frequency, rtvf->bits_per_sample, 1, RTV_BUFFER_TIME);
if ( Rtv_output_buffers[index].ds_handle == -1 ) {
return -1;
}
return index;
}
void rtvoice_stop_playback(int index)
{
Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
if ( Rtv_output_buffers[index].ds_handle != -1 ) {
ds_stop_easy(Rtv_output_buffers[index].ds_handle);
}
}
}
void rtvoice_stop_playback_all()
{
int i;
for ( i = 0; i < MAX_RTV_OUT_BUFFERS; i++ ) {
rtvoice_stop_playback(i);
}
}
// Close a stream that was opened for real-time voice output
void rtvoice_free_playback_buffer(int index)
{
Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
Rtv_output_buffers[index].flags=0;
if ( Rtv_output_buffers[index].ds_handle != -1 ) {
ds_stop_easy(Rtv_output_buffers[index].ds_handle);
ds_unload_buffer(Rtv_output_buffers[index].ds_handle);
}
Rtv_output_buffers[index].ds_handle=-1;
}
}
// Play sound data
// exit: >=0 => handle to playing sound
// -1 => error, voice not played
int rtvoice_play(int index, unsigned char *data, int size)
{
int ds_handle, rval;
ds_handle = Rtv_output_buffers[index].ds_handle;
// Stop any currently playing voice output
ds_stop_easy(ds_handle);
// TODO: uncompress the data into PCM format
// lock the data in
if ( ds_lock_data(ds_handle, data, size) ) {
return -1;
}
// play the voice
rval = ds_play(ds_handle, -100, DS_MUST_PLAY, Master_voice_volume, 0, 0);
return rval;
}