mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
878 lines
32 KiB
C++
878 lines
32 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <Errors.h>
|
|
#include <Resources.h>
|
|
#include <Sound.h>
|
|
#include <SoundSprocket.h>
|
|
#include <SoundComponents.h>
|
|
#include <math.h>
|
|
#include "pstypes.h"
|
|
#define SOUND_ON
|
|
#define MAX_VOLUME 256
|
|
#define MAX_SOUND_CHANNELS 16
|
|
Boolean have_descent_cd = false;
|
|
int sndsprk_lomem = 0;
|
|
int master_save;
|
|
int sndsprk_initialized = 0;
|
|
ubyte sndsprk_paused = 0;
|
|
ubyte sndsprk_cd_started = 0; // have we started a disc that is not the Descent cd?
|
|
int midi_volume = 256;
|
|
int sndsprk_volume = MAX_VOLUME;
|
|
int sndsprk_midi_song_playing = 0;
|
|
int sndsprk_last_midi_song = 0;
|
|
int sndsprk_last_midi_song_loop = 0;
|
|
int sndsprk_max_channels = MAX_SOUND_CHANNELS;
|
|
ushort num_sounds = 0;
|
|
ushort num_channels = 0;
|
|
ushort near_channel = 0;
|
|
ushort far_channel = 0;
|
|
extern ubyte Config_master_volume;
|
|
static int CD_volume;
|
|
static SSpListenerReference gListener = nil;
|
|
// sound object stuff -- used for fans and the boss only??
|
|
#define SOF_USED 1 // Set if this sample is used
|
|
#define SOF_PLAYING 2 // Set if this sample is playing on a channel
|
|
#define SOF_LINK_TO_OBJ 4 // Sound is linked to a moving object. If object dies, then finishes play and quits.
|
|
#define SOF_LINK_TO_POS 8 // Sound is linked to segment, pos
|
|
#define SOF_PLAY_FOREVER 16 // Play forever (or until level is stopped), otherwise plays once
|
|
#define SOUND_PLAYING 1
|
|
#define SOUND_OBJECT_PLAYING 2
|
|
typedef struct song_resource {
|
|
short midi_id;
|
|
ubyte lead_inst;
|
|
ubyte buffer_ahead;
|
|
ushort tempo;
|
|
ushort pitch_shift;
|
|
ubyte sound_voices;
|
|
ubyte max_notes;
|
|
ushort norm_voices;
|
|
} song_resource;
|
|
typedef struct sound_object {
|
|
short signature; // A unique signature to this sound
|
|
ubyte flags; // Used to tell if this slot is used and/or currently playing, and how long.
|
|
fix max_volume; // Max volume that this sound is playing at
|
|
fix max_distance; // The max distance that this sound can be heard at...
|
|
fix distance; // The distance that this sound is from the player
|
|
int volume; // Volume that this sound is playing at
|
|
int pan; // Pan value that this sound is playing at
|
|
short handle; // What handle this sound is playing on. Valid only if SOF_PLAYING is set.
|
|
short soundnum; // The sound number that is playing
|
|
union {
|
|
struct {
|
|
short segnum; // Used if SOF_LINK_TO_POS field is used
|
|
short sidenum;
|
|
vms_vector position;
|
|
} pos;
|
|
struct {
|
|
short objnum; // Used if SOF_LINK_TO_OBJ field is used
|
|
short objsignature;
|
|
} obj;
|
|
} link_type;
|
|
} sound_object;
|
|
int num_sound_objects = 0;
|
|
sound_object SoundObjects[MAX_SOUND_OBJECTS];
|
|
short next_signature = 0;
|
|
int old_sndnum[3] = {-1, -1, -1};
|
|
#define SOUND_OFFSET 10000
|
|
#define MIN_SOUND_DISTANCE 10
|
|
#define MAX_SOUND_DISTANCE 100
|
|
Ptr sound_ptr[MAX_SOUNDS + 1];
|
|
SndChannelPtr snd_channel_near[MAX_SOUND_CHANNELS];
|
|
SndChannelPtr snd_channel_far[MAX_SOUND_CHANNELS];
|
|
SndChannelPtr snd_channel_ambient[3] = {0, 0, 0};
|
|
SSpLocalizationData farLocalization, nearLocalization, ambientLocalization;
|
|
void calc_polar_sound(vms_vector *sound_pos, float *azimuth, float *elevation);
|
|
void sndsprk_reset_sndsprk_sounds() {
|
|
int i;
|
|
SndCommand sndCommand;
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
|
|
// DAJ EndAllSound();
|
|
// num_sound_objects = 0;
|
|
// stop_redbook();
|
|
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = 0L;
|
|
|
|
sndCommand.cmd = flushCmd;
|
|
for (i = 0; i < num_channels; i++)
|
|
SndDoImmediate(snd_channel_near[i], &sndCommand);
|
|
sndCommand.cmd = quietCmd;
|
|
for (i = num_channels; i < num_channels; i++)
|
|
SndDoImmediate(snd_channel_far[i], &sndCommand);
|
|
|
|
sndCommand.cmd = flushCmd;
|
|
for (i = 0; i < num_channels; i++)
|
|
SndDoImmediate(snd_channel_far[i], &sndCommand);
|
|
sndCommand.cmd = quietCmd;
|
|
for (i = num_channels; i < num_channels; i++)
|
|
SndDoImmediate(snd_channel_near[i], &sndCommand);
|
|
|
|
sndsprk_stop_loop(0);
|
|
sndsprk_stop_loop(1);
|
|
sndsprk_stop_loop(2);
|
|
}
|
|
void sndsprk_play_sample_3d(int sndnum, float distance, float elevation, float azimuth) {
|
|
SndCommand sndCommand;
|
|
OSStatus err;
|
|
|
|
if (Newdemo_state == ND_STATE_RECORDING)
|
|
newdemo_record_sound_3d_once(sndnum, elevation, distance);
|
|
#ifdef SOUND_ON
|
|
if (sound_ptr[sndnum] && snd_channel_far[far_channel]) {
|
|
farLocalization.currentLocation.elevation = elevation;
|
|
farLocalization.currentLocation.azimuth = azimuth;
|
|
farLocalization.currentLocation.distance = distance;
|
|
err = SndSetInfo(snd_channel_far[far_channel], siSSpLocalization, &farLocalization);
|
|
// if(err != noErr)
|
|
// Error("Far SndSetInfo siSSpLocalization channel %d", far_channel);
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = 0L;
|
|
|
|
sndCommand.cmd = flushCmd;
|
|
err = SndDoImmediate(snd_channel_far[far_channel], &sndCommand);
|
|
// if(err != noErr)
|
|
// Error("Far Sound Channel %d is corrupt: flushCmd", far_channel);
|
|
|
|
sndCommand.cmd = quietCmd; // Send quietCmd to stop any current sound.
|
|
err = SndDoImmediate(snd_channel_far[far_channel], &sndCommand);
|
|
// if(err != noErr)
|
|
// Error("Far Sound Channel %d is corrupt: quietCmd", far_channel);
|
|
sndCommand.cmd = bufferCmd;
|
|
sndCommand.param2 = (long)(sound_ptr[sndnum]);
|
|
err = SndDoCommand(snd_channel_far[far_channel], &sndCommand, true);
|
|
// if(err != noErr)
|
|
// Error("Far Sound Channel %d is corrupt: bufferCmd", far_channel);
|
|
|
|
far_channel++;
|
|
if (far_channel >= num_channels) {
|
|
far_channel = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
void sndsprk_play_loop_3d(int chan, int sndnum, float distance, float elevation, float azimuth) {
|
|
SndCommand sndCommand;
|
|
OSStatus err;
|
|
|
|
if (Newdemo_state == ND_STATE_RECORDING)
|
|
newdemo_record_sound_3d_once(sndnum, azimuth, distance);
|
|
#ifdef SOUND_ON
|
|
if (sound_ptr[sndnum]) {
|
|
ambientLocalization.currentLocation.elevation = elevation;
|
|
ambientLocalization.currentLocation.azimuth = azimuth;
|
|
ambientLocalization.currentLocation.distance = distance;
|
|
err = SndSetInfo(snd_channel_ambient[chan], siSSpLocalization, &ambientLocalization);
|
|
// if(err != noErr)
|
|
// Error("Ambient SndSetInfo siSSpLocalization channel %d", chan);
|
|
|
|
if (sndnum != old_sndnum[chan]) {
|
|
sndCommand.cmd = bufferCmd;
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = (long)(sound_ptr[sndnum]);
|
|
err = SndDoCommand(snd_channel_ambient[chan], &sndCommand, true);
|
|
// if(err != noErr)
|
|
// Error("Ambient Sound Channel %d is corrupt: bufferCmd", chan);
|
|
sndCommand.cmd = freqCmd;
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = 60;
|
|
err = SndDoCommand(snd_channel_ambient[chan], &sndCommand, true);
|
|
// if(err != noErr)
|
|
// Error("Ambient Sound Channel %d is corrupt: freqCmd", chan);
|
|
|
|
old_sndnum[chan] = sndnum;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
void sndsprk_play_sample(int sndnum, fix max_volume) {
|
|
SndCommand sndCommand;
|
|
OSStatus err;
|
|
|
|
if (Newdemo_state == ND_STATE_RECORDING)
|
|
newdemo_record_sound(sndnum);
|
|
#ifdef SOUND_ON
|
|
|
|
if (sound_ptr[sndnum] && snd_channel_near[near_channel]) {
|
|
// set in set_max_channels & does not change
|
|
SndSetInfo(snd_channel_near[near_channel], siSSpLocalization, &nearLocalization);
|
|
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = 0L;
|
|
|
|
sndCommand.cmd = flushCmd;
|
|
err = SndDoImmediate(snd_channel_near[near_channel], &sndCommand);
|
|
// if(err != noErr)
|
|
// Error("Near Sound Channel %d is corrupt: flushCmd", near_channel);
|
|
|
|
sndCommand.cmd = quietCmd; // Send quietCmd to stop any current sound.
|
|
err = SndDoImmediate(snd_channel_near[near_channel], &sndCommand);
|
|
// if(err != noErr)
|
|
// Error("Near Sound Channel %d is corrupt: quietCmd", near_channel);
|
|
|
|
sndCommand.cmd = bufferCmd;
|
|
sndCommand.param2 = (long)(sound_ptr[sndnum]);
|
|
err = SndDoCommand(snd_channel_near[near_channel], &sndCommand, true);
|
|
// if(err != noErr)
|
|
// Error("Near Sound Channel %d is corrupt: bufferCmd", near_channel);
|
|
|
|
near_channel++;
|
|
if (near_channel >= num_channels) {
|
|
// mprintf((STDOUT, "near snd_channel roll over at %f\n", f2fl(GameTime)));
|
|
near_channel = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
void sndsprk_play_sample_once(int sndnum, fix max_volume) { sndsprk_play_sample(sndnum, max_volume); }
|
|
void sndsprk_set_sndsprk_volume(int volume) {
|
|
SndCommand sndCommand;
|
|
int i;
|
|
short one_side;
|
|
long both_side;
|
|
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
|
|
one_side = volume * 0x20;
|
|
both_side = (one_side << 16) | one_side;
|
|
sndCommand.cmd = volumeCmd;
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = both_side;
|
|
for (i = 0; i < num_channels; i++)
|
|
SndDoImmediate(snd_channel_near[i], &sndCommand);
|
|
for (i = 0; i < num_channels; i++)
|
|
SndDoImmediate(snd_channel_far[i], &sndCommand);
|
|
|
|
SndDoImmediate(snd_channel_ambient[0], &sndCommand);
|
|
SndDoImmediate(snd_channel_ambient[1], &sndCommand);
|
|
SndDoImmediate(snd_channel_ambient[2], &sndCommand);
|
|
}
|
|
void sndsprk_stop_current_song() {
|
|
stop_redbook();
|
|
sndsprk_midi_song_playing = 0;
|
|
}
|
|
void sndsprk_play_midi_song(int songnum, int loop) {
|
|
OSErr err;
|
|
song_resource *song;
|
|
ushort midi_id;
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
sndsprk_last_midi_song = songnum;
|
|
sndsprk_last_midi_song_loop = loop;
|
|
if (!have_descent_cd) {
|
|
if (!cd_playing && !sndsprk_cd_started)
|
|
redbook_start_play();
|
|
sndsprk_cd_started = 1;
|
|
return;
|
|
}
|
|
sndsprk_stop_current_song();
|
|
|
|
if (midi_volume < 1)
|
|
return;
|
|
play_redbook_track(songnum, loop);
|
|
sndsprk_midi_song_playing = 1;
|
|
}
|
|
void do_midi_stuff() {
|
|
if (sndsprk_last_midi_song_loop && !redbook_IsCDPlaying()) {
|
|
play_redbook_track(sndsprk_last_midi_song, 1);
|
|
}
|
|
}
|
|
void sndsprk_set_midi_volume(int volume) {
|
|
int old_volume = midi_volume;
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
// midi_volume = (volume*255)/8; //TOO LOUD
|
|
midi_volume = (volume * 0x10);
|
|
|
|
redbook_set_volume(midi_volume);
|
|
|
|
if (!old_volume && midi_volume) {
|
|
sndsprk_play_midi_song(sndsprk_last_midi_song, sndsprk_last_midi_song_loop);
|
|
} else if (old_volume && !midi_volume) {
|
|
sndsprk_stop_current_song();
|
|
}
|
|
}
|
|
void sndsprk_set_volume(int dvolume, int mvolume) {
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
sndsprk_set_sndsprk_volume(dvolume);
|
|
sndsprk_set_midi_volume(mvolume);
|
|
}
|
|
void sndsprk_set_master_volume(int volume) {
|
|
short one_side;
|
|
long both_side;
|
|
one_side = volume * 0x20;
|
|
both_side = (one_side << 16) | one_side;
|
|
SetDefaultOutputVolume(both_side);
|
|
// SetSoundVol(volume);
|
|
}
|
|
void sndsprk_reset() {
|
|
// num_sound_objects = 0;
|
|
}
|
|
void sndsprk_resume_all() {}
|
|
void sndsprk_pause_all() {}
|
|
void sndsprk_stop_all() {
|
|
SndCommand sndCommand;
|
|
int i;
|
|
sndsprk_stop_current_song();
|
|
sndsprk_stop_loop(0);
|
|
sndsprk_stop_loop(1);
|
|
sndsprk_stop_loop(2);
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = 0L;
|
|
for (i = 0; i < num_channels; i++) {
|
|
if (snd_channel_near[i]) {
|
|
sndCommand.cmd = flushCmd;
|
|
SndDoImmediate(snd_channel_near[i], &sndCommand);
|
|
sndCommand.cmd = quietCmd; // Send quietCmd to stop any current sound.
|
|
SndDoImmediate(snd_channel_near[i], &sndCommand);
|
|
}
|
|
}
|
|
for (i = 0; i < num_channels; i++) {
|
|
if (snd_channel_far[i]) {
|
|
sndCommand.cmd = flushCmd;
|
|
SndDoImmediate(snd_channel_far[i], &sndCommand);
|
|
sndCommand.cmd = quietCmd; // Send quietCmd to stop any current sound.
|
|
SndDoImmediate(snd_channel_far[i], &sndCommand);
|
|
}
|
|
}
|
|
}
|
|
void sndsprk_set_max_channels(int n) {
|
|
int i;
|
|
OSStatus err;
|
|
unsigned int cpuLoadLimit;
|
|
SoundComponentLink myLink;
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
if (sndsprk_midi_song_playing)
|
|
sndsprk_stop_current_song();
|
|
myLink.description.componentType = kSoundEffectsType;
|
|
myLink.description.componentSubType = kSSpLocalizationSubType;
|
|
myLink.description.componentManufacturer = kAnyComponentManufacturer;
|
|
myLink.description.componentFlags = 0;
|
|
myLink.description.componentFlagsMask = kAnyComponentFlagsMask;
|
|
myLink.mixerID = nil;
|
|
myLink.linkID = nil;
|
|
if (n > num_channels) {
|
|
|
|
for (i = num_channels; i < n; i++) {
|
|
snd_channel_near[i] = (SndChannelPtr)NewPtr(sizeof(SndChannel));
|
|
if (!snd_channel_near[i])
|
|
Error("Unable to allocate NewPtr snd_channel_near %d", i);
|
|
snd_channel_near[i]->qLength = 2;
|
|
err = SndNewChannel(&snd_channel_near[i], sampledSynth, initStereo /*initMono+initNoInterp*/, NULL);
|
|
if (err != noErr)
|
|
Error("Error %d Unable to allocate near sound channel %d", err, i);
|
|
|
|
err = SndSetInfo(snd_channel_near[i], siPreMixerSoundComponent, &myLink);
|
|
if (err != noErr)
|
|
Error("SndSetInfo siPreMixerSoundComponent near Error %d", err);
|
|
err = SndSetInfo(snd_channel_near[i], siSSpLocalization, &nearLocalization);
|
|
if (err != noErr)
|
|
Error("SndSetInfo siSSpLocalization near Error %d", err);
|
|
}
|
|
for (i = num_channels; i < n; i++) {
|
|
snd_channel_far[i] = (SndChannelPtr)NewPtr(sizeof(SndChannel));
|
|
if (!snd_channel_far[i])
|
|
Error("Unable to allocate NewPtr snd_channel_far %d", i);
|
|
snd_channel_far[i]->qLength = 2;
|
|
err = SndNewChannel(&snd_channel_far[i], sampledSynth, initStereo /*initMono+initNoInterp*/, NULL);
|
|
if (err != noErr)
|
|
Error("Error %d Unable to allocate far sound channel %d", err, i);
|
|
|
|
err = SndSetInfo(snd_channel_far[i], siPreMixerSoundComponent, &myLink);
|
|
if (err != noErr)
|
|
Error("SndSetInfo siPreMixerSoundComponent far Error %d", err);
|
|
}
|
|
} else if (n < num_channels) {
|
|
for (i = num_channels - 1; i >= n; i--) {
|
|
SndDisposeChannel(snd_channel_near[i], true);
|
|
snd_channel_near[i] = NULL;
|
|
SndDisposeChannel(snd_channel_far[i], true);
|
|
snd_channel_far[i] = NULL;
|
|
}
|
|
}
|
|
num_channels = n;
|
|
|
|
if (snd_channel_ambient[0] == 0) {
|
|
for (i = 0; i < 3; i++) {
|
|
snd_channel_ambient[i] = (SndChannelPtr)NewPtr(sizeof(SndChannel));
|
|
snd_channel_ambient[i]->qLength = 2;
|
|
err = SndNewChannel(&snd_channel_ambient[i], sampledSynth, initStereo /*initMono+initNoInterp*/, NULL);
|
|
if (err != noErr)
|
|
Error("Err %d Unable to allocate ambient Sound Channel %d", err, i);
|
|
|
|
err = SndSetInfo(snd_channel_ambient[i], siPreMixerSoundComponent, &myLink);
|
|
if (err != noErr)
|
|
Error("Error %d in SndSetInfo ambient chan %d", err, i);
|
|
}
|
|
}
|
|
}
|
|
int sndsprk_start_sound_object(int i) {
|
|
fix path_distance;
|
|
int num_search_segs = 20;
|
|
float distance, elevation, azimuth;
|
|
calc_polar_sound(&SoundObjects[i].link_type.pos.position, &azimuth, &elevation);
|
|
path_distance = find_connected_distance(&Viewer->pos, Viewer->segnum, &SoundObjects[i].link_type.pos.position,
|
|
SoundObjects[i].link_type.pos.segnum, num_search_segs, WID_RENDPAST_FLAG);
|
|
distance = f2fl(path_distance);
|
|
if (distance > 0) {
|
|
sndsprk_play_loop_3d(0, SoundObjects[i].soundnum, distance, elevation, azimuth);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
void sndsprk_stop_loop(int chan) {
|
|
SndCommand sndCommand;
|
|
if (old_sndnum[chan] != -1) {
|
|
old_sndnum[chan] = -1;
|
|
sndCommand.cmd = quietCmd; // Send quietCmd to stop any current sound.
|
|
sndCommand.param1 = 0;
|
|
sndCommand.param2 = 0L;
|
|
SndDoImmediate(snd_channel_ambient[chan], &sndCommand);
|
|
}
|
|
}
|
|
void sndsprk_get_sound_loc(vms_matrix *listener, vms_vector *listener_pos, int listener_seg, vms_vector *sound_pos,
|
|
int sound_seg, fix max_volume, int *volume, int *pan, fix max_distance) {
|
|
vms_vector vector_to_sound;
|
|
fix angle_from_ear, cosang, sinang;
|
|
fix distance;
|
|
fix path_distance;
|
|
*volume = 0;
|
|
*pan = 0;
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
|
|
max_distance = (max_distance * 5) / 4; // Make all sounds travel 1.25 times as far.
|
|
// Warning: Made the vm_vec_normalized_dir be vm_vec_normalized_dir_quick and got illegal values to acos in the
|
|
//fang computation.
|
|
distance = vm_vec_normalized_dir_quick(&vector_to_sound, sound_pos, listener_pos);
|
|
|
|
if (distance < max_distance) {
|
|
int num_search_segs = f2i(max_distance / 20);
|
|
if (num_search_segs < 1)
|
|
num_search_segs = 1;
|
|
path_distance =
|
|
find_connected_distance(listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG);
|
|
// path_distance = distance;
|
|
if (path_distance > -1) {
|
|
*volume = max_volume - (path_distance / f2i(max_distance));
|
|
// mprintf( (0, "Sound path distance %.2f, volume is %d / %d\n", f2fl(distance), *volume, max_volume ));
|
|
if (*volume > 0) {
|
|
angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec, &vector_to_sound, &listener->uvec);
|
|
fix_sincos(angle_from_ear, &sinang, &cosang);
|
|
// mprintf( (0, "volume is %.2f\n", f2fl(*volume) ));
|
|
if (Config_channels_reversed)
|
|
cosang *= -1;
|
|
*pan = fixmuldiv(cosang, 255, F1_0);
|
|
} else {
|
|
*volume = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int sndsprk_link_sound_to_object(int soundnum, short objnum, int forever, fix max_volume) { // 10 segs away
|
|
return sndsprk_link_sound_to_object2(soundnum, objnum, forever, max_volume, 256 * F1_0);
|
|
}
|
|
int sndsprk_link_sound_to_pos(int soundnum, short segnum, short sidenum, vms_vector *pos, int forever, fix max_volume) {
|
|
return sndsprk_link_sound_to_pos2(soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256);
|
|
}
|
|
int sndsprk_link_sound_to_object2(int org_soundnum, short objnum, int forever, fix max_volume, fix max_distance) {
|
|
fix path_distance;
|
|
float distance, elevation, azimuth;
|
|
int num_search_segs = 20;
|
|
|
|
calc_polar_sound(&Objects[objnum].pos, &azimuth, &elevation);
|
|
path_distance = find_connected_distance(&Viewer->pos, Viewer->segnum, &Objects[objnum].pos, Objects[objnum].segnum,
|
|
num_search_segs, WID_RENDPAST_FLAG);
|
|
distance = f2fl(path_distance);
|
|
if (!forever && distance > 0) {
|
|
clamp(distance, MIN_SOUND_DISTANCE, MAX_SOUND_DISTANCE);
|
|
sndsprk_play_sample_3d(org_soundnum, distance, elevation, azimuth);
|
|
}
|
|
}
|
|
int sndsprk_link_sound_to_pos2(int org_soundnum, short sound_seg, short sidenum, vms_vector *sound_pos, int forever,
|
|
fix max_volume, fix max_distance) {
|
|
fix path_distance;
|
|
float distance, elevation, azimuth;
|
|
int num_search_segs = 20;
|
|
int i;
|
|
|
|
if (num_sound_objects > MAX_SOUND_OBJECTS)
|
|
// Error("Max sound objects exceeded");
|
|
return -1;
|
|
|
|
path_distance =
|
|
find_connected_distance(&Viewer->pos, Viewer->segnum, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG);
|
|
if (!forever) {
|
|
if (path_distance >= 0) {
|
|
distance = f2fl(path_distance);
|
|
clamp(distance, MIN_SOUND_DISTANCE, MAX_SOUND_DISTANCE);
|
|
calc_polar_sound(sound_pos, &azimuth, &elevation);
|
|
sndsprk_play_sample_3d(org_soundnum, distance, elevation, azimuth);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
SoundObjects[num_sound_objects].signature = next_signature++;
|
|
SoundObjects[num_sound_objects].flags = SOF_USED | SOF_LINK_TO_POS;
|
|
if (forever)
|
|
SoundObjects[num_sound_objects].flags |= SOF_PLAY_FOREVER;
|
|
SoundObjects[num_sound_objects].link_type.pos.segnum = sound_seg;
|
|
SoundObjects[num_sound_objects].link_type.pos.sidenum = sidenum;
|
|
SoundObjects[num_sound_objects].link_type.pos.position = *sound_pos;
|
|
SoundObjects[num_sound_objects].soundnum = (short)org_soundnum;
|
|
SoundObjects[num_sound_objects].max_volume = max_volume;
|
|
SoundObjects[num_sound_objects].max_distance = max_distance;
|
|
SoundObjects[num_sound_objects].distance = path_distance;
|
|
SoundObjects[num_sound_objects].volume = 0;
|
|
SoundObjects[num_sound_objects].pan = 0;
|
|
num_sound_objects++;
|
|
|
|
// sndsprk_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum,
|
|
// &SoundObjects[i].link_type.pos.position, SoundObjects[i].link_type.pos.segnum,
|
|
// SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan,
|
|
// SoundObjects[i].max_distance );
|
|
|
|
// sndsprk_start_sound_object(i);
|
|
// sndsprk_play_loop_3d( org_soundnum, distance, elevation, azimuth);
|
|
return SoundObjects[num_sound_objects].signature;
|
|
}
|
|
void calc_polar_sound(vms_vector *sound_pos, float *azimuth, float *elevation) {
|
|
vms_vector vector_to_sound;
|
|
vms_vector cross_vec;
|
|
fix distfix;
|
|
fix fixdot;
|
|
// fix updot, rtdot;
|
|
// float float_dot;
|
|
fix cosang, sinang;
|
|
fixang ang_from_ear;
|
|
distfix = vm_vec_normalized_dir_quick(&vector_to_sound, sound_pos, &Viewer->pos);
|
|
// vm_vec_sub( &vector_to_sound, sound_pos, &Viewer->pos);
|
|
// distfix = vm_vec_normalize_quick(&vector_to_sound);
|
|
fixdot = vm_vec_dot(&(Viewer->orient.rvec), &vector_to_sound);
|
|
|
|
ang_from_ear = fix_acos(fixdot);
|
|
fix_sincos(ang_from_ear, &sinang, &cosang);
|
|
*azimuth = f2fl(cosang);
|
|
*elevation = f2fl(sinang);
|
|
// mprintf((0, "sndvec %f %f\n", *azimuth*57, *elevation*57));
|
|
/*
|
|
fixdot = vm_vec_dot(&(Viewer->orient.fvec), &vector_to_sound);
|
|
vm_vec_cross(&cross_vec, &(Viewer->orient.uvec), &vector_to_sound);
|
|
float_dot = f2fl(fixdot);
|
|
updot = vm_vec_dot(&cross_vec,&(Viewer->orient.fvec));
|
|
if (updot < 0)
|
|
*azimuth = -acosf(float_dot);
|
|
else
|
|
*azimuth = acosf(float_dot);
|
|
|
|
rtdot = vm_vec_dot(&cross_vec,&(Viewer->orient.rvec));
|
|
if (rtdot < 0)
|
|
*elevation = -asinf(float_dot);
|
|
else
|
|
*elevation = asinf(float_dot);
|
|
*/
|
|
#ifdef DEBUG_ON
|
|
// mprintf((0, "az %f ", *azimuth*57.295780));
|
|
// mprintf((0, "el %f ", *elevation*57.295780));
|
|
// mprintf((0, "| %f %f %", f2fl(angle_from_ear), f2fl(cosang)*57.295780,f2fl(sinang)*57.295780));
|
|
// mprintf((0, "\n"));
|
|
#endif
|
|
}
|
|
#define MAX_AMBIENT_DISTANCE 0xFF0000 // DAJ is 255
|
|
void sndsprk_sync_sounds() {
|
|
int i;
|
|
int oldvolume, oldpan;
|
|
SndCommand snd_cmd;
|
|
vms_vector pnt;
|
|
int set = 0;
|
|
fix path_distance;
|
|
fix closet_dist[3] = {MAX_AMBIENT_DISTANCE, MAX_AMBIENT_DISTANCE, MAX_AMBIENT_DISTANCE};
|
|
fix direct_distance;
|
|
fix found;
|
|
int num_search_segs = 4;
|
|
float elevation, azimuth;
|
|
int closet_sound[3] = {-1, -1, -1};
|
|
static byte was_playing[3] = {0, 0, 0};
|
|
int chan;
|
|
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
|
|
if (!num_sound_objects)
|
|
return;
|
|
|
|
// find the closest ambient sounds
|
|
for (i = 0; i < num_sound_objects; i++) {
|
|
if ((SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_PLAY_FOREVER)) {
|
|
//* first check to see if its even in the sound range
|
|
SoundObjects[i].distance = vm_vec_dist_quick(&Viewer->pos, &SoundObjects[i].link_type.pos.position);
|
|
if (SoundObjects[i].distance <= MAX_AMBIENT_DISTANCE) {
|
|
if (SoundObjects[i].soundnum == 224 || SoundObjects[i].soundnum == 41)
|
|
chan = 0;
|
|
else if (SoundObjects[i].soundnum == 235 || SoundObjects[i].soundnum == 150)
|
|
chan = 1;
|
|
else if (SoundObjects[i].soundnum == 121 || SoundObjects[i].soundnum == 42)
|
|
chan = 2;
|
|
else {
|
|
mprintf((STDOUT, "%d is not one of the standard ambient sounds\n", SoundObjects[i].soundnum));
|
|
continue;
|
|
}
|
|
found = find_connected_distance(&Viewer->pos, Viewer->segnum, &SoundObjects[i].link_type.pos.position,
|
|
SoundObjects[i].link_type.pos.segnum, num_search_segs, WID_RENDPAST_FLAG);
|
|
if (found > 0 && SoundObjects[i].distance < closet_dist[chan]) {
|
|
closet_dist[chan] = SoundObjects[i].distance;
|
|
closet_sound[chan] = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// now play them
|
|
for (i = 0; i < 3; i++) {
|
|
int segnum, sidenum, wallnum;
|
|
if ((closet_sound[i] != -1) && (closet_dist[i] > 0) && (closet_dist[i] < MAX_AMBIENT_DISTANCE)) {
|
|
// first is it a valid wall number then look to see if we turned off the force field
|
|
segnum = SoundObjects[closet_sound[i]].link_type.pos.segnum;
|
|
sidenum = SoundObjects[closet_sound[i]].link_type.pos.sidenum;
|
|
wallnum = Segments[segnum].sides[sidenum].wall_num;
|
|
if ((wallnum != -1) && (Walls[wallnum].flags & WALL_ILLUSION_OFF)) {
|
|
sndsprk_stop_loop(i);
|
|
was_playing[i] = 0;
|
|
} else {
|
|
calc_polar_sound(&SoundObjects[closet_sound[i]].link_type.pos.position, &azimuth, &elevation);
|
|
sndsprk_play_loop_3d(i, SoundObjects[closet_sound[i]].soundnum, f2fl(closet_dist[i]), elevation, azimuth);
|
|
was_playing[i] = 1;
|
|
}
|
|
} else if (was_playing[i]) {
|
|
sndsprk_stop_loop(i);
|
|
was_playing[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
void sndsprk_kill_sound_linked_to_segment(int segnum, int sidenum, int soundnum) { sndsprk_stop_loop(0); }
|
|
void sndsprk_kill_sound_linked_to_object(int objnum) {}
|
|
void sndsprk_close() {
|
|
int i;
|
|
if (!sndsprk_initialized)
|
|
return;
|
|
sndsprk_stop_current_song();
|
|
sndsprk_stop_loop(0);
|
|
sndsprk_stop_loop(1);
|
|
sndsprk_stop_loop(2);
|
|
for (i = 0; i < num_channels; i++) {
|
|
if (snd_channel_near[i]) {
|
|
SndDisposeChannel(snd_channel_near[i], true);
|
|
DisposePtr((char *)snd_channel_near[i]);
|
|
}
|
|
if (snd_channel_far[i]) {
|
|
SndDisposeChannel(snd_channel_far[i], true);
|
|
DisposePtr((char *)snd_channel_far[i]);
|
|
}
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
SndDisposeChannel(snd_channel_ambient[i], true);
|
|
// DisposePtr((char*)snd_channel_ambient[i]);
|
|
}
|
|
for (i = 0; i <= MAX_SOUNDS; i++) {
|
|
if (sound_ptr[i]) {
|
|
// UnHoldMemory(sound_ptr[i], soundDataSize);
|
|
DisposePtr(sound_ptr[i]);
|
|
}
|
|
}
|
|
redbook_set_volume(CD_volume);
|
|
SetDefaultOutputVolume(master_save);
|
|
}
|
|
void sndsprk_init_sounds() {}
|
|
void sndsprk_load_sounds() {
|
|
Handle theSound;
|
|
long soundDataSize, header;
|
|
short i;
|
|
SoundHeaderPtr sndhead;
|
|
OSStatus err;
|
|
NumVersion ver;
|
|
|
|
ver = SndSoundManagerVersion();
|
|
if (ver.majorRev != 3 && ver.minorAndBugRev != 33)
|
|
Error("Sound Manager 3.33 is required");
|
|
for (i = 0; i <= MAX_SOUNDS; i++) {
|
|
theSound = GetResource('snd ', i + SOUND_OFFSET);
|
|
if (theSound != NULL) {
|
|
HLock((Handle)theSound);
|
|
GetSoundHeaderOffset((SndListResource **)theSound, &header);
|
|
soundDataSize = GetHandleSize((Handle)theSound) - header;
|
|
sound_ptr[i] = NewPtr(soundDataSize);
|
|
if (sound_ptr[i] != NULL) {
|
|
BlockMove((Ptr)(*theSound + header), sound_ptr[i], soundDataSize);
|
|
HUnlock((Handle)theSound);
|
|
ReleaseResource((Handle)theSound);
|
|
if (i == 121) // skip fan tick
|
|
((SoundHeaderPtr)(sound_ptr[i]))->loopStart = 128;
|
|
else
|
|
((SoundHeaderPtr)(sound_ptr[i]))->loopStart = 0;
|
|
((SoundHeaderPtr)(sound_ptr[i]))->loopEnd = soundDataSize - 24;
|
|
((SoundHeaderPtr)(sound_ptr[i]))->baseFrequency = 60;
|
|
num_sounds++;
|
|
// HoldMemory(sound_ptr[i], soundDataSize);
|
|
} else {
|
|
Error("Unable to allocate sound_ptr %d", i);
|
|
}
|
|
} else {
|
|
sound_ptr[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
int sndsprk_init() {
|
|
int i;
|
|
OSStatus err;
|
|
extern UInt16 gNumTracks;
|
|
|
|
GetDefaultOutputVolume(&master_save);
|
|
|
|
RedbookHandlerInit();
|
|
if (RedbookIsCDInserted()) {
|
|
have_descent_cd = true;
|
|
gNumTracks = RedbookGetNumTracks();
|
|
}
|
|
CD_volume = redbook_get_volume();
|
|
|
|
sndsprk_initialized = 1;
|
|
|
|
for (i = 0; i < MAX_SOUND_CHANNELS; i++) {
|
|
snd_channel_near[i] = NULL;
|
|
snd_channel_far[i] = NULL;
|
|
}
|
|
farLocalization.cpuLoad = 0;
|
|
farLocalization.medium = kSSpMedium_Air;
|
|
farLocalization.humidity = 0;
|
|
farLocalization.roomSize = 100;
|
|
farLocalization.roomReflectivity = -100;
|
|
farLocalization.reverbAttenuation = 0;
|
|
farLocalization.sourceMode = kSSpSourceMode_Localized;
|
|
farLocalization.referenceDistance = 10;
|
|
farLocalization.coneAngleCos = 0;
|
|
farLocalization.coneAttenuation = 0;
|
|
farLocalization.currentLocation.elevation = 0;
|
|
farLocalization.currentLocation.azimuth = 0;
|
|
farLocalization.currentLocation.distance = 1;
|
|
farLocalization.currentLocation.projectionAngle = 1;
|
|
farLocalization.currentLocation.sourceVelocity = 0;
|
|
farLocalization.currentLocation.listenerVelocity = 0;
|
|
farLocalization.reserved0 = 0;
|
|
farLocalization.reserved1 = 0;
|
|
farLocalization.reserved2 = 0;
|
|
farLocalization.reserved3 = 0;
|
|
farLocalization.virtualSourceCount = 0;
|
|
nearLocalization.cpuLoad = 0;
|
|
nearLocalization.medium = kSSpMedium_Air;
|
|
nearLocalization.humidity = 0;
|
|
nearLocalization.roomSize = 0;
|
|
nearLocalization.roomReflectivity = 0;
|
|
nearLocalization.reverbAttenuation = 0;
|
|
nearLocalization.sourceMode = kSSpSourceMode_Ambient;
|
|
nearLocalization.referenceDistance = 5;
|
|
nearLocalization.coneAngleCos = 0;
|
|
nearLocalization.coneAttenuation = 0;
|
|
nearLocalization.currentLocation.elevation = 0;
|
|
nearLocalization.currentLocation.azimuth = 0;
|
|
nearLocalization.currentLocation.distance = 5;
|
|
nearLocalization.currentLocation.projectionAngle = 1;
|
|
nearLocalization.currentLocation.sourceVelocity = 0;
|
|
nearLocalization.currentLocation.listenerVelocity = 0;
|
|
nearLocalization.reserved0 = 0;
|
|
nearLocalization.reserved1 = 0;
|
|
nearLocalization.reserved2 = 0;
|
|
nearLocalization.reserved3 = 0;
|
|
nearLocalization.virtualSourceCount = 0;
|
|
ambientLocalization.cpuLoad = 0;
|
|
ambientLocalization.medium = kSSpMedium_Air;
|
|
ambientLocalization.humidity = 0;
|
|
ambientLocalization.roomSize = 0;
|
|
ambientLocalization.roomReflectivity = 0;
|
|
ambientLocalization.reverbAttenuation = 0;
|
|
ambientLocalization.sourceMode = kSSpSourceMode_Localized;
|
|
ambientLocalization.referenceDistance = 10;
|
|
ambientLocalization.coneAngleCos = 0;
|
|
ambientLocalization.coneAttenuation = 0;
|
|
ambientLocalization.currentLocation.elevation = 0;
|
|
ambientLocalization.currentLocation.azimuth = 0;
|
|
ambientLocalization.currentLocation.distance = 1;
|
|
ambientLocalization.currentLocation.projectionAngle = 1;
|
|
ambientLocalization.currentLocation.sourceVelocity = 0;
|
|
ambientLocalization.currentLocation.listenerVelocity = 0;
|
|
ambientLocalization.reserved0 = 0;
|
|
ambientLocalization.reserved1 = 0;
|
|
ambientLocalization.reserved2 = 0;
|
|
ambientLocalization.reserved3 = 0;
|
|
ambientLocalization.virtualSourceCount = 0;
|
|
atexit(sndsprk_close);
|
|
return 0;
|
|
}
|
|
OSErr ConvertFromWavToRawSound(void *inBufferP, UInt32 inBuffSize, void *outBufferP, UInt32 *outBuffSize) {
|
|
OSErr theErr;
|
|
SoundConverter theSC;
|
|
UInt32 numFrames, numBytes, outBytes;
|
|
UInt32 aditionalOutputFrames, additionalOutputSize;
|
|
SInt32 currentBytes, bytesLeft;
|
|
SoundComponentData input, output; // these hold info for the formats
|
|
input.flags = 0;
|
|
input.format = MicrosoftADPCMFormat; /*one of the wav formats*/
|
|
input.numChannels = 2;
|
|
input.sampleSize = 16; /*8 for eight bit sound*/
|
|
input.sampleRate = rate44khz; /* a constant defined in Sound.h*/
|
|
input.sampleCount = 0;
|
|
input.buffer = 0;
|
|
input.reserved = 0;
|
|
output.flags = 0;
|
|
output.format = kSoundNotCompressed; /*'raw ' */
|
|
output.numChannels = 2;
|
|
output.sampleSize = 16; /*8 for eight bit sound*/
|
|
output.sampleRate = rate44khz; /* a constant defined in Sound.h*/
|
|
output.sampleCount = 0;
|
|
output.buffer = 0;
|
|
output.reserved = 0;
|
|
/*This opens a SoundConverter component. the params are ...
|
|
output format, output format, and the sound converter*/
|
|
theErr = SoundConverterOpen(&input, &output, &theSC);
|
|
if (theErr)
|
|
return theErr;
|
|
/* so how to allocate the new buffer? */
|
|
theErr = SoundConverterGetBufferSize(theSC, inBuffSize, &numFrames, &numBytes, outBuffSize);
|
|
if (theErr)
|
|
return theErr;
|
|
|
|
outBuffer = mem_malloc(outBytes);
|
|
if (!outBuffer) {
|
|
mprintf((0, "ConvertFromWavToRawSound: unable to allocate %d bytes", outBytes));
|
|
Int3();
|
|
}
|
|
theErr = SoundConverterBeginConversion(theSC);
|
|
if (theErr)
|
|
return theErr;
|
|
|
|
if (inBuffSize <= outBytes) { /*we can do it in one big chunk...*/
|
|
theErr = SoundConverterConvertBuffer(theSC, inBufferP, numFrames, outBufferP, 0, 0);
|
|
if (theErr)
|
|
return theErr;
|
|
|
|
theErr = SoundConverterEndConversion(theSC, outBufferP, &aditionalOutputFrames, &additionalOutputSize);
|
|
if (theErr)
|
|
return theErr;
|
|
} else { /*we need to do it in chunks :( */
|
|
bytesLeft = *outBuffSize;
|
|
while (bytesLeft > 0) {
|
|
theErr = SoundConvertBuffer(theSC, inBufferP, numFrames, numBytes, outBufferP, 0, 0);
|
|
if (theErr)
|
|
return theErr;
|
|
|
|
bytesLeft -= numBytes;
|
|
}
|
|
theErr = SoundConverterEndConversion(theSC, outBufferP, &aditionalOutputFrames, &additionalOutputSize);
|
|
if (theErr)
|
|
return theErr;
|
|
}
|
|
return theErr;
|
|
}
|