scummvm/saga/sndres.cpp
Eugene Sandulenko f3d340fb0c WIP for SAGA engine.
o text formatting is not consistent with rules, just indent utility is too
   dumb for that
 o it does not use OSystem, i.e. it runs on direct SDL calls
 o it may not even compile on your box
 o if you enable it, expect zillions of warnings
 o no sound

Now it runs ITE intro as reinherit did

svn-id: r13564
2004-04-12 21:40:49 +00:00

354 lines
7.0 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 The ScummVM project
*
* The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
/*
Description:
Sound resource management module
Notes:
*/
#include "reinherit.h"
#include "yslib.h"
#include <limits.h>
/*
* Uses the following modules:
\*--------------------------------------------------------------------------*/
#include "game_mod.h"
#include "rscfile_mod.h"
/*
* Begin module component
\*--------------------------------------------------------------------------*/
#include "sndres_mod.h"
#include "sndres.h"
namespace Saga {
R_SNDRES_MODULE SndModule;
int SND_Init(void)
{
int result;
/* Load sound module resource file contexts
* \*------------------------------------------------------------- */
result = GAME_GetFileContext(&SndModule.sfx_ctxt, R_GAME_SOUNDFILE, 0);
if (result != R_SUCCESS) {
return R_FAILURE;
}
result = GAME_GetFileContext(&SndModule.voice_ctxt,
R_GAME_VOICEFILE, 0);
if (result != R_SUCCESS) {
return R_FAILURE;
}
/* Grab sound resource information for the current game
* \*------------------------------------------------------------- */
GAME_GetSoundInfo(&SndModule.snd_info);
SndModule.init = 1;
return R_SUCCESS;
}
int SND_PlayVoice(ulong voice_rn)
{
R_SOUNDBUFFER snd_buffer;
int result;
result = SND_Load(SndModule.voice_ctxt, voice_rn, &snd_buffer);
if (result != R_SUCCESS) {
return R_FAILURE;
}
SYSSOUND_PlayVoice(&snd_buffer);
return R_SUCCESS;
}
int
SND_Load(R_RSCFILE_CONTEXT * snd_ctxt, ulong snd_rn, R_SOUNDBUFFER * snd_buf_i)
{
uchar *snd_res;
size_t snd_res_len;
int result;
assert((snd_ctxt != NULL) && (snd_buf_i != NULL));
result = RSC_LoadResource(snd_ctxt, snd_rn, &snd_res, &snd_res_len);
if (result != R_SUCCESS) {
return R_FAILURE;
}
switch (SndModule.snd_info.res_type) {
case R_GAME_SOUND_PCM:
snd_buf_i->s_freq = SndModule.snd_info.freq;
snd_buf_i->s_samplebits = SndModule.snd_info.sample_size;
snd_buf_i->s_stereo = SndModule.snd_info.stereo;
snd_buf_i->res_data = snd_res;
snd_buf_i->res_len = snd_res_len;
snd_buf_i->s_buf = snd_res;
snd_buf_i->s_buf_len = snd_res_len;
snd_buf_i->s_signed = 1;
break;
case R_GAME_SOUND_VOC:
if (LoadVocSound(snd_res, snd_res_len, snd_buf_i) != R_SUCCESS) {
RSC_FreeResource(snd_res);
return R_FAILURE;
}
break;
default:
/* Unknown sound type */
RSC_FreeResource(snd_res);
return R_FAILURE;
break;
}
return R_SUCCESS;
}
int
LoadVocSound(const uchar * snd_res,
size_t snd_res_len, R_SOUNDBUFFER * snd_buf_i)
{
R_VOC_HEADER_BLOCK voc_hb;
R_VOC_GENBLOCK voc_gb;
R_VOC_BLOCK1 voc_b1;
long byte_rate;
const uchar *read_p;
size_t read_len;
read_p = snd_res;
read_len = snd_res_len;
if (read_len < R_VOC_HEADER_BLOCK_LEN) {
return R_FAILURE;
}
memcpy(voc_hb.ft_desc, read_p, R_VOC_FILE_DESC_LEN);
read_p += R_VOC_FILE_DESC_LEN;
read_len -= R_VOC_FILE_DESC_LEN;
if (memcmp(voc_hb.ft_desc, R_VOC_FILE_DESC, R_VOC_FILE_DESC_LEN) != 0) {
/* Voc file desc string not found */
return R_FAILURE;
}
voc_hb.db_offset = ys_read_u16_le(read_p, &read_p);
voc_hb.voc_version = ys_read_u16_le(read_p, &read_p);
voc_hb.voc_fileid = ys_read_u16_le(read_p, &read_p);
if (read_len < voc_hb.db_offset + R_VOC_GENBLOCK_LEN) {
return R_FAILURE;
}
read_p = snd_res + voc_hb.db_offset;
read_len = snd_res_len - voc_hb.db_offset;
for (;;) {
/* Read generic block header
* \*--------------------------------------------------------- */
if (read_len < R_VOC_GENBLOCK_LEN) {
return R_FAILURE;
}
voc_gb.block_id = ys_read_u8(read_p, &read_p);
if (voc_gb.block_id == 0) {
return R_FAILURE;
}
voc_gb.block_len = ys_read_u24_le(read_p, &read_p);
read_len -= R_VOC_GENBLOCK_LEN;
/* Process block
* \*--------------------------------------------------------- */
switch (voc_gb.block_id) {
case 1: /* Sound data block */
voc_b1.time_constant = ys_read_u8(read_p, &read_p);
voc_b1.pack_method = ys_read_u8(read_p, &read_p);
read_len -= 2;
if (voc_b1.pack_method != 0) {
/* Packed VOC files not supported */
return R_FAILURE;
}
byte_rate = R_VOC_TIME_BASE / (R_VOC_TIME_CBASE -
(voc_b1.time_constant << 8));
snd_buf_i->s_stereo = 0;
snd_buf_i->s_samplebits = 8;
snd_buf_i->s_freq = byte_rate;
snd_buf_i->res_data = (uchar *) snd_res;
snd_buf_i->res_len = snd_res_len;
snd_buf_i->s_buf = (uchar *) read_p;
snd_buf_i->s_buf_len = read_len - 1; /* -1 for end block */
snd_buf_i->s_signed = 0;
return R_SUCCESS;
break;
default:
read_p += voc_gb.block_len;
read_len -= voc_gb.block_len;
break;
}
}
return R_SUCCESS;
}
int SND_GetVoiceLength(ulong voice_rn)
{
ulong length;
double ms_f;
int ms_i = -1;
int result;
assert(SndModule.init);
result = RSC_GetResourceSize(SndModule.voice_ctxt, voice_rn, &length);
if (result != R_SUCCESS) {
return -1;
}
if (SndModule.snd_info.res_type == R_GAME_SOUND_PCM) {
ms_f = (double)length /
(SndModule.snd_info.sample_size / CHAR_BIT) /
(SndModule.snd_info.freq) * 1000.0;
ms_i = (int)ms_f;
} else if (SndModule.snd_info.res_type == R_GAME_SOUND_VOC) {
/* Rough hack, fix this to be accurate */
ms_f = (double)length / 14705 * 1000.0;
ms_i = (int)ms_f;
} else {
return -1;
}
return ms_i;
}
int
SND_ITEVOC_Resample(long src_freq,
long dst_freq,
uchar * src_buf,
size_t src_buf_len, uchar ** dst_buf, size_t * dst_buf_len)
{
uchar *resamp_buf;
size_t resamp_len;
uchar src_samp_a;
uchar src_samp_b;
const uchar *read_pa;
const uchar *read_pb;
uchar *write_pa;
uchar *write_pb;
uchar *write_pc;
size_t src_i;
assert(src_freq == 14705);
assert(dst_freq == 22050);
resamp_len = (size_t) (src_buf_len * 1.5);
resamp_buf = (uchar *)malloc(resamp_len);
if (resamp_buf == NULL) {
return R_FAILURE;
}
read_pa = src_buf;
read_pb = src_buf + 1;
write_pa = resamp_buf;
write_pb = resamp_buf + 1;
write_pc = resamp_buf + 2;
for (src_i = 0; src_i < src_buf_len / 2; src_i++) {
src_samp_a = *read_pa;
src_samp_b = *read_pb;
read_pa += 2;
read_pb += 2;
*write_pa = src_samp_a;
*write_pb = (uchar) ((src_samp_a / 2) + (src_samp_b / 2));
*write_pc = src_samp_b;
write_pa += 3;
write_pb += 3;
write_pc += 3;
}
*dst_buf = resamp_buf;
*dst_buf_len = resamp_len;
return R_SUCCESS;
}
} // End of namespace Saga