mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-24 13:13:58 +00:00
moved file bundle stuff into class Bundle
svn-id: r4671
This commit is contained in:
parent
6dd5de48f9
commit
0b3c263857
@ -16,7 +16,7 @@ OBJS += util.o newgui.o gui/widget.o gui/dialog.o \
|
||||
v3/resource_v3.o v4/resource_v4.o scaler.o main.o \
|
||||
simon/midi.o simon/simon.o simon/simonsys.o simon/simonvga.o \
|
||||
simon/simondebug.o simon/simonres.o simon/simonitems.o simon/simonverb.o \
|
||||
sound/mididrv.o config-file.o
|
||||
sound/mididrv.o config-file.o bundle.o
|
||||
|
||||
DISTFILES=$(OBJS:.o=.cpp) Makefile scumm.h scummsys.h stdafx.h stdafx.cpp \
|
||||
debugrl.h whatsnew.txt readme.txt copying.txt \
|
||||
|
535
bundle.cpp
Normal file
535
bundle.cpp
Normal file
@ -0,0 +1,535 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2002 The ScummVM project
|
||||
*
|
||||
* 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:
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "scumm.h"
|
||||
#include "scummsys.h"
|
||||
#include "bundle.h"
|
||||
|
||||
Bundle::Bundle(Scumm * parent) {
|
||||
_voiceFile = NULL;
|
||||
_musicFile = NULL;
|
||||
_scumm = parent;
|
||||
}
|
||||
|
||||
Bundle::~Bundle() {
|
||||
if (_voiceFile != NULL)
|
||||
fclose (_voiceFile);
|
||||
|
||||
if (_musicFile != NULL)
|
||||
fclose (_musicFile);
|
||||
}
|
||||
|
||||
int32 Bundle::openVoiceFile(char * filename) {
|
||||
int32 tag, offset;
|
||||
|
||||
if (_voiceFile != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_voiceFile = fopen(filename, "rb");
|
||||
if (_voiceFile == NULL) {
|
||||
printf("Bundle: Can't open voice bundle file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
tag = _scumm->fileReadDwordBE(_voiceFile);
|
||||
offset = _scumm->fileReadDwordBE(_voiceFile);
|
||||
_numVoiceFiles = _scumm->fileReadDwordBE(_voiceFile);
|
||||
|
||||
_bundleVoiceTable = (BundleAudioTable *) malloc(_numVoiceFiles * sizeof(BundleAudioTable));
|
||||
|
||||
_scumm->fileSeek(_voiceFile, offset, SEEK_SET);
|
||||
|
||||
for (int32 i = 0; i < _numVoiceFiles; i++) {
|
||||
char name[13], c;
|
||||
int32 z = 0;
|
||||
int32 z2;
|
||||
|
||||
for (z2 = 0; z2 < 8; z2++)
|
||||
if ((c = _scumm->fileReadByte(_voiceFile)) != 0)
|
||||
name[z++] = c;
|
||||
name[z++] = '.';
|
||||
for (z2 = 0; z2 < 4; z2++)
|
||||
if ((c = _scumm->fileReadByte(_voiceFile)) != 0)
|
||||
name[z++] = c;
|
||||
name[z] = '\0';
|
||||
strcpy(_bundleVoiceTable[i].filename, name);
|
||||
_bundleVoiceTable[i].offset = _scumm->fileReadDwordBE(_voiceFile);
|
||||
_bundleVoiceTable[i].size = _scumm->fileReadDwordBE(_voiceFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 Bundle::openMusicFile(char * filename) {
|
||||
int32 tag, offset;
|
||||
|
||||
if (_musicFile != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_musicFile = fopen(filename, "rb");
|
||||
if (_musicFile == NULL) {
|
||||
printf("Bundle: Can't open music bundle file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
tag = _scumm->fileReadDwordBE(_musicFile);
|
||||
offset = _scumm->fileReadDwordBE(_musicFile);
|
||||
_numMusicFiles = _scumm->fileReadDwordBE(_musicFile);
|
||||
|
||||
_bundleMusicTable = (BundleAudioTable *) malloc(_numMusicFiles * sizeof(BundleAudioTable));
|
||||
|
||||
_scumm->fileSeek(_musicFile, offset, SEEK_SET);
|
||||
|
||||
for (int32 i = 0; i < _numMusicFiles; i++) {
|
||||
char name[13], c;
|
||||
int z = 0;
|
||||
int z2;
|
||||
|
||||
for (z2 = 0;z2 < 8; z2++)
|
||||
if ((c = _scumm->fileReadByte(_musicFile)) != 0)
|
||||
name[z++] = c;
|
||||
name[z++] = '.';
|
||||
for (z2 = 0;z2 < 4; z2++)
|
||||
if ((c = _scumm->fileReadByte(_musicFile)) != 0)
|
||||
name[z++] = c;
|
||||
name[z] = '\0';
|
||||
strcpy(_bundleVoiceTable[i].filename, name);
|
||||
_bundleVoiceTable[i].offset = _scumm->fileReadDwordBE(_musicFile);
|
||||
_bundleVoiceTable[i].size = _scumm->fileReadDwordBE(_musicFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 Bundle::decompressVoiceSampleByIndex(int32 index, byte * comp_final) {
|
||||
int32 i, tag, num, final_size, output_size;
|
||||
byte * comp_input, * comp_output;
|
||||
|
||||
if (_voiceFile == NULL) {
|
||||
printf("Bundle: voice file is not open !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_scumm->fileSeek(_voiceFile, _bundleVoiceTable[index].offset, SEEK_SET);
|
||||
tag = _scumm->fileReadDwordBE(_voiceFile);
|
||||
num = _scumm->fileReadDwordBE(_voiceFile);
|
||||
_scumm->fileReadDwordBE(_voiceFile);
|
||||
_scumm->fileReadDwordBE(_voiceFile);
|
||||
|
||||
if (tag != MKID_BE('COMP')) {
|
||||
warning("Bundle: Compressed sound %d invalid (%c%c%c%c)", index, tag>>24, tag>>16, tag>>8, tag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
_compVoiceTable[i].offset = _scumm->fileReadDwordBE(_voiceFile);
|
||||
_compVoiceTable[i].size = _scumm->fileReadDwordBE(_voiceFile);
|
||||
_compVoiceTable[i].codec = _scumm->fileReadDwordBE(_voiceFile);
|
||||
_scumm->fileReadDwordBE(_voiceFile);
|
||||
}
|
||||
|
||||
final_size = 0;
|
||||
|
||||
comp_output = (byte *)malloc(10000);
|
||||
for (i = 0; i < num; i++) {
|
||||
comp_input = (byte *)malloc(_compVoiceTable[i].size);
|
||||
|
||||
_scumm->fileSeek(_voiceFile, _bundleVoiceTable[index].offset + _compVoiceTable[i].offset, SEEK_SET);
|
||||
_scumm->fileRead(_voiceFile, comp_input, _compVoiceTable[i].size);
|
||||
|
||||
output_size = decompressCodec(_compVoiceTable[i].codec, comp_input, comp_output, _compVoiceTable[i].size);
|
||||
memcpy((byte *)&comp_final[final_size], comp_output, output_size);
|
||||
final_size += output_size;
|
||||
|
||||
free(comp_input);
|
||||
}
|
||||
free(comp_output);
|
||||
|
||||
return final_size;
|
||||
}
|
||||
|
||||
int32 Bundle::decompressMusicSampleByIndex(int32 index, int32 number, byte * comp_final) {
|
||||
int32 i, tag, num, final_size;
|
||||
byte * comp_input;
|
||||
|
||||
if (_musicFile == NULL) {
|
||||
printf("Bundle: music file is not open !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset, SEEK_SET);
|
||||
tag = _scumm->fileReadDwordBE(_musicFile);
|
||||
num = _scumm->fileReadDwordBE(_musicFile);
|
||||
_scumm->fileReadDwordBE(_musicFile);
|
||||
_scumm->fileReadDwordBE(_musicFile);
|
||||
|
||||
if (tag != MKID_BE('COMP')) {
|
||||
warning("Bundle: Compressed sound %d invalid (%c%c%c%c)", index, tag>>24, tag>>16, tag>>8, tag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
_compMusicTable[i].offset = _scumm->fileReadDwordBE(_musicFile);
|
||||
_compMusicTable[i].size = _scumm->fileReadDwordBE(_musicFile);
|
||||
_compMusicTable[i].codec = _scumm->fileReadDwordBE(_musicFile);
|
||||
_scumm->fileReadDwordBE(_musicFile);
|
||||
}
|
||||
|
||||
comp_input = (byte *)malloc(_compMusicTable[i].size);
|
||||
|
||||
_scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset + _compMusicTable[i].offset, SEEK_SET);
|
||||
_scumm->fileRead(_musicFile, comp_input, _compMusicTable[i].size);
|
||||
final_size = decompressCodec(_compMusicTable[i].codec, comp_input, comp_final, _compMusicTable[i].size);
|
||||
|
||||
free(comp_input);
|
||||
|
||||
return final_size;
|
||||
}
|
||||
|
||||
|
||||
int32 Bundle::decompressVoiceSampleByName(char * name, byte * comp_final) {
|
||||
int32 final_size = 0, i;
|
||||
|
||||
if (_voiceFile == NULL) {
|
||||
printf("Bundle: voice file is not open !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < _numVoiceFiles; i++) {
|
||||
if (!scumm_stricmp(name, _bundleVoiceTable[i].filename)) {
|
||||
final_size = decompressVoiceSampleByIndex(i, comp_final);
|
||||
return final_size;
|
||||
}
|
||||
}
|
||||
return final_size;
|
||||
}
|
||||
|
||||
int32 Bundle::decompressMusicSampleByName(char * name, int32 number, byte * comp_final) {
|
||||
int32 final_size = 0, i;
|
||||
|
||||
if (_voiceFile == NULL) {
|
||||
printf("Bundle: voice file is not open !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < _numMusicFiles; i++) {
|
||||
if (!scumm_stricmp(name, _bundleMusicTable[i].filename)) {
|
||||
final_size = decompressMusicSampleByIndex(i, number, comp_final);
|
||||
return final_size;
|
||||
}
|
||||
}
|
||||
return final_size;
|
||||
}
|
||||
|
||||
int32 Bundle::getNumberOfMusicSamplesByIndex(int32 index)
|
||||
{
|
||||
if (_musicFile == NULL) {
|
||||
printf("Bundle: music file is not open !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset, SEEK_SET);
|
||||
_scumm->fileReadDwordBE(_musicFile);
|
||||
return _scumm->fileReadDwordBE(_musicFile);
|
||||
}
|
||||
|
||||
int32 Bundle::getNumberOfMusicSamplesByName(char * name) {
|
||||
int32 number = 0, i;
|
||||
|
||||
if (_musicFile == NULL) {
|
||||
printf("Bundle: music file is not open !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < _numMusicFiles; i++) {
|
||||
if (!scumm_stricmp(name, _bundleMusicTable[i].filename)) {
|
||||
number = getNumberOfMusicSamplesByIndex (i);
|
||||
return number;
|
||||
}
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
#define NextBit bit = mask & 1; mask >>= 1; if (!--bitsleft) {mask = READ_LE_UINT16(srcptr); srcptr += 2; bitsleft=16;}
|
||||
|
||||
int32 Bundle::compDecode(byte * src, byte * dst) {
|
||||
byte * result, * srcptr = src, * dstptr = dst;
|
||||
int data, size, bit, bitsleft = 16, mask = READ_LE_UINT16(srcptr);
|
||||
srcptr += 2;
|
||||
|
||||
while(1) {
|
||||
NextBit
|
||||
if (bit) {
|
||||
*dstptr++ = *srcptr++;
|
||||
} else {
|
||||
NextBit
|
||||
if (!bit) {
|
||||
NextBit size = bit << 1;
|
||||
NextBit size = (size | bit) + 3;
|
||||
data = *srcptr++ | 0xffffff00;
|
||||
} else {
|
||||
data = *srcptr++;
|
||||
size = *srcptr++;
|
||||
|
||||
data |= 0xfffff000 + ((size & 0xf0) << 4);
|
||||
size = (size & 0x0f) + 3;
|
||||
|
||||
if (size == 3)
|
||||
if (((*srcptr++) + 1) == 1)
|
||||
return dstptr - dst;
|
||||
}
|
||||
result = dstptr+data;
|
||||
while (size--)
|
||||
*dstptr++ = *result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef NextBit
|
||||
|
||||
int32 Bundle::decompressCodec(int32 codec, byte * comp_input, byte * comp_output, int32 input_size) {
|
||||
int32 output_size = input_size;
|
||||
int32 offset1, offset2, offset3, length, k, c, s, j, r, t, z;
|
||||
byte * src, * t_table, * p;
|
||||
byte t_tmp1, t_tmp2;
|
||||
|
||||
switch(codec) {
|
||||
case 0:
|
||||
memcpy(comp_input, comp_output, output_size);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
p = comp_output;
|
||||
for (z = 1; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
p = comp_output;
|
||||
for (z = 2; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
break;
|
||||
|
||||
case 4:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
|
||||
// FIXME: not implemented yet
|
||||
memset (comp_output, 0, output_size);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
|
||||
// FIXME: not implemented yet
|
||||
memset (comp_output, 0, output_size);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
|
||||
// FIXME: not implemented yet
|
||||
memset (comp_output, 0, output_size);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
p = comp_output;
|
||||
for (z = 2; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
|
||||
t_table = (byte*)malloc(output_size);
|
||||
memcpy (t_table, p, output_size);
|
||||
|
||||
offset1 = output_size / 3;
|
||||
offset2 = offset1 * 2;
|
||||
offset3 = offset2;
|
||||
src = comp_output;
|
||||
do {
|
||||
if (offset1 == 0) break;
|
||||
offset1--;
|
||||
offset2 -= 2;
|
||||
offset3--;
|
||||
*(t_table + offset2 + 0) = *(src + offset1);
|
||||
*(t_table + offset2 + 1) = *(src + offset3);
|
||||
} while(1);
|
||||
|
||||
src = comp_output;
|
||||
length = (output_size * 8) / 12;
|
||||
k = 0;
|
||||
if (length > 0)
|
||||
{
|
||||
c = -12;
|
||||
s = 0;
|
||||
do {
|
||||
j = length + (k / 2);
|
||||
if (k & 1) {
|
||||
r = c / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j + 1);
|
||||
*(src + r + 2) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
|
||||
*(src + r + 1) = (*(src + r + 1)) | (t_tmp1 & 0xf0);
|
||||
} else {
|
||||
r = s / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 0) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
|
||||
*(src + r + 1) = ((t_tmp1 & 0xf0) >> 4);
|
||||
}
|
||||
s += 12;
|
||||
k++;
|
||||
c += 12;
|
||||
} while (k <= length);
|
||||
}
|
||||
free (t_table);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
p = comp_output;
|
||||
for (z = 2; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
|
||||
t_table = (byte*)malloc(output_size);
|
||||
memcpy (t_table, p, output_size);
|
||||
|
||||
offset1 = output_size / 3;
|
||||
offset2 = offset1 * 2;
|
||||
offset3 = offset2;
|
||||
src = comp_output;
|
||||
do {
|
||||
if (offset1 == 0) break;
|
||||
offset1--;
|
||||
offset2 -= 2;
|
||||
offset3--;
|
||||
*(t_table + offset2 + 0) = *(src + offset1);
|
||||
*(t_table + offset2 + 1) = *(src + offset3);
|
||||
} while(1);
|
||||
|
||||
src = comp_output;
|
||||
length = (output_size * 8) / 12;
|
||||
k = 1;
|
||||
c = 0;
|
||||
s = 12;
|
||||
t_tmp1 = (*(t_table + length)) >> 4;
|
||||
*(src) = t_tmp1;
|
||||
t = length + k;
|
||||
if (t > k) {
|
||||
do {
|
||||
j = length + (k / 2);
|
||||
if (k & 1) {
|
||||
r = c / 8;
|
||||
t_tmp1 = *(t_table + k - 1);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 0) = (*(src + r)) | (t_tmp1 & 0xf0);
|
||||
*(src + r + 1) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
|
||||
} else {
|
||||
r = s / 8;
|
||||
t_tmp1 = *(t_table + k - 1);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 0) = (t_tmp1 & 0xf0) >> 4;
|
||||
*(src + r - 1) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
|
||||
}
|
||||
s += 12;
|
||||
k++;
|
||||
c += 12;
|
||||
} while (k < t);
|
||||
}
|
||||
free (t_table);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
output_size = compDecode(comp_input, comp_output);
|
||||
p = comp_output;
|
||||
for (z = 2; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < output_size; z++)
|
||||
p[z] += p[z - 1];
|
||||
|
||||
t_table = (byte*)malloc(output_size);
|
||||
memcpy (t_table, p, output_size);
|
||||
|
||||
offset1 = output_size / 3;
|
||||
offset2 = offset1 * 2;
|
||||
offset3 = offset2;
|
||||
src = comp_output;
|
||||
do {
|
||||
if (offset1 == 0) break;
|
||||
offset1--;
|
||||
offset2 -= 2;
|
||||
offset3--;
|
||||
*(t_table + offset2 + 0) = *(src + offset1);
|
||||
*(t_table + offset2 + 1) = *(src + offset3);
|
||||
} while(1);
|
||||
|
||||
src = comp_output;
|
||||
length = (output_size * 8) / 12;
|
||||
k = 0;
|
||||
c = 0;
|
||||
s = -12;
|
||||
*(src) = *(output_size + t_table - 1);
|
||||
*(src + output_size - 1) = *(t_table + length - 1);
|
||||
t = length - 1;
|
||||
if (t > 0) {
|
||||
do {
|
||||
j = length + (k / 2);
|
||||
if (k & 1) {
|
||||
r = s / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 2) = (*(src + r + 2)) | (t_tmp1 & 0xf0);
|
||||
*(src + r + 3) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
|
||||
} else {
|
||||
r = c / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 2) = (t_tmp1 & 0xf0) >> 4;
|
||||
*(src + r + 1) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
|
||||
}
|
||||
s += 12;
|
||||
k++;
|
||||
c += 12;
|
||||
} while (k < t);
|
||||
}
|
||||
free (t_table);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Bundle: Unknown codec %d!\n", codec);
|
||||
output_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return output_size;
|
||||
}
|
||||
|
71
bundle.h
Normal file
71
bundle.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2002 The ScummVM project
|
||||
*
|
||||
* 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:
|
||||
*/
|
||||
|
||||
#ifndef BUNDLE_H
|
||||
#define BUNDLE_H
|
||||
|
||||
#include "scummsys.h"
|
||||
|
||||
struct CompTable {
|
||||
int32 offset;
|
||||
int32 size;
|
||||
int32 codec;
|
||||
};
|
||||
|
||||
struct BundleAudioTable {
|
||||
char filename[13];
|
||||
int32 size;
|
||||
int32 offset;
|
||||
};
|
||||
|
||||
class Scumm;
|
||||
|
||||
class Bundle {
|
||||
protected:
|
||||
|
||||
private:
|
||||
int32 compDecode(byte * src, byte * dst);
|
||||
int32 decompressCodec(int32 codec, byte * comp_input, byte * comp_output, int32 size);
|
||||
CompTable _compVoiceTable[50];
|
||||
CompTable _compMusicTable[2500];
|
||||
FILE * _voiceFile;
|
||||
FILE * _musicFile;
|
||||
BundleAudioTable * _bundleVoiceTable;
|
||||
BundleAudioTable * _bundleMusicTable;
|
||||
int32 _numVoiceFiles;
|
||||
int32 _numMusicFiles;
|
||||
Scumm * _scumm;
|
||||
|
||||
public:
|
||||
Bundle(Scumm * parent);
|
||||
~Bundle();
|
||||
|
||||
int32 openVoiceFile(char * filename);
|
||||
int32 openMusicFile(char * filename);
|
||||
int32 decompressVoiceSampleByName(char * name, byte * comp_final);
|
||||
int32 decompressVoiceSampleByIndex(int32 index, byte * comp_final);
|
||||
int32 decompressMusicSampleByName(char * name, int32 number, byte * comp_final);
|
||||
int32 decompressMusicSampleByIndex(int32 index, int32 number, byte * comp_final);
|
||||
int32 getNumberOfMusicSamplesByIndex(int32 index);
|
||||
int32 getNumberOfMusicSamplesByName(char * name);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,7 +21,7 @@ OBJS = actor.o akos.o boxes.o config-file.o costume.o gfx.o object.o resource.o
|
||||
morphos.o morphos_sound.o morphos_start.o script_v1.o script_v2.o debug.o gui.o \
|
||||
imuse.o fmopl.o mixer.o mididrv.o debugrl.o vars.o insane.o \
|
||||
gameDetector.o init.o resource_v3.o resource_v4.o util.o main.o \
|
||||
$(GUIOBJS) $(SIMONOBJS)
|
||||
bundle.o $(GUIOBJS) $(SIMONOBJS)
|
||||
|
||||
DISTFILES=$(OBJS:.o=.cpp) Makefile scumm.h scummsys.h stdafx.h stdafx.cpp \
|
||||
windows.cpp debugrl.h whatsnew.txt readme.txt copying.txt \
|
||||
|
3
scumm.h
3
scumm.h
@ -26,6 +26,7 @@
|
||||
#include "scummsys.h"
|
||||
#include "system.h"
|
||||
#include "sound/mixer.h"
|
||||
#include "bundle.h"
|
||||
|
||||
#define SCUMMVM_VERSION "0.2.2 CVS"
|
||||
#define SCUMMVM_CVS "2002-07-16"
|
||||
@ -337,6 +338,7 @@ public:
|
||||
VerbSlot *_verbs;
|
||||
ObjectData *_objs;
|
||||
ScummDebugger *_debugger;
|
||||
Bundle * _bundle;
|
||||
|
||||
struct {
|
||||
byte mode[rtNumTypes];
|
||||
@ -765,7 +767,6 @@ public:
|
||||
MP3OffsetTable *offset_table; // SO3 MP3 compressed audio
|
||||
int num_sound_effects; // SO3 MP3 compressed audio
|
||||
|
||||
BundleAudioTable *bundle_table; // DIG/CMI bundles
|
||||
void pauseSounds(bool pause);
|
||||
bool isSfxFinished();
|
||||
void playBundleSound(char *sound);
|
||||
|
@ -84,6 +84,7 @@ void Scumm::scummInit()
|
||||
setShake(0);
|
||||
setupCursor();
|
||||
|
||||
_bundle = new Bundle(this);
|
||||
/* Allocate and initilise actors */
|
||||
_actors = new Actor[MAX_ACTORS];
|
||||
for (i = 1, a = getFirstActor(); ++a, i < NUM_ACTORS; i++) {
|
||||
@ -1582,6 +1583,7 @@ void Scumm::go() {
|
||||
launch();
|
||||
setupGUIColors();
|
||||
mainRun();
|
||||
delete _bundle;
|
||||
}
|
||||
|
||||
|
||||
|
@ -297,6 +297,10 @@ SOURCE=.\boxes.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bundle.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\config-file.cpp"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -557,6 +561,10 @@ SOURCE=.\boxes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bundle.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cdmusic.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
409
sound.cpp
409
sound.cpp
@ -710,46 +710,6 @@ void *Scumm::openSfxFile()
|
||||
char buf[256];
|
||||
FILE *file = NULL;
|
||||
|
||||
if (_gameId == GID_DIG) {
|
||||
int tag, offset, num_files;
|
||||
|
||||
sprintf(buf, "%s%svoice.bun", _gameDataPath, _exe_name);
|
||||
file = fopen(buf, "rb");
|
||||
if (!file) {
|
||||
warning("Unable to open DIG voice bundle: %s", buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tag = fileReadDwordBE(file);
|
||||
offset = fileReadDwordBE(file);
|
||||
num_files = fileReadDwordBE(file);
|
||||
|
||||
bundle_table = (BundleAudioTable *) malloc(num_files * sizeof(BundleAudioTable));
|
||||
num_sound_effects = num_files;
|
||||
fileSeek(file, offset, SEEK_SET);
|
||||
|
||||
for (int i=0; i < num_files; i++) {
|
||||
char filename[13], c;
|
||||
int z = 0;
|
||||
int z2;
|
||||
|
||||
/* Construct filename */
|
||||
for (z2=0;z2<8; z2++)
|
||||
if ((c = fileReadByte(file)) != 0)
|
||||
filename[z++] = c;
|
||||
filename[z++] = '.';
|
||||
for (z2=0;z2<4;z2++)
|
||||
if ((c = fileReadByte(file)) != 0)
|
||||
filename[z++] = c;
|
||||
filename[z] = '\0';
|
||||
strcpy(bundle_table[i].filename, filename);
|
||||
bundle_table[i].offset = fileReadDwordBE(file);
|
||||
bundle_table[i].size = fileReadDwordBE(file);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Try opening the file <_exe_name>.sou first, eg tentacle.sou.
|
||||
* That way, you can keep .sou files for multiple games in the
|
||||
* same directory */
|
||||
@ -817,353 +777,62 @@ bool Scumm::isSfxFinished()
|
||||
return !_mixer->has_active_channel();
|
||||
}
|
||||
|
||||
#define NextBit bit = mask&1; mask>>=1; if (!--bitsleft) {mask = READ_LE_UINT16(srcptr); srcptr+=2; bitsleft=16;}
|
||||
int CompDecode(unsigned char *src, unsigned char *dst)
|
||||
void Scumm::playBundleSound(char *sound)
|
||||
{
|
||||
unsigned char *result, *srcptr = src, *dstptr = dst;
|
||||
int data, size, bit, bitsleft = 16, mask = READ_LE_UINT16(srcptr);
|
||||
srcptr+=2;
|
||||
char buf[256];
|
||||
byte * ptr;
|
||||
|
||||
while(1) {
|
||||
NextBit
|
||||
if (bit) {
|
||||
*dstptr++ = *srcptr++;
|
||||
} else {
|
||||
NextBit
|
||||
if (!bit) {
|
||||
NextBit size = bit<<1;
|
||||
NextBit size = (size|bit) + 3;
|
||||
data = *srcptr++ | 0xffffff00;
|
||||
} else {
|
||||
data = *srcptr++;
|
||||
size = *srcptr++;
|
||||
|
||||
data |= 0xfffff000 + ((size & 0xf0) << 4);
|
||||
size = (size & 0x0f) + 3;
|
||||
|
||||
if (size==3)
|
||||
if (((*srcptr++)+1) == 1)
|
||||
return dstptr - dst; /* End of buffer */
|
||||
}
|
||||
result = dstptr+data;
|
||||
while (size--)
|
||||
*dstptr++=*result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef NextBit
|
||||
|
||||
typedef struct {int offset, size, codec;} COMP_table;
|
||||
void Scumm::decompressBundleSound(int index) {
|
||||
int i, z;
|
||||
COMP_table table[50];
|
||||
unsigned char *CompInput, *CompOutput, *CompFinal, *Final;
|
||||
int outputSize, finalSize;
|
||||
int32 offset1, offset2, offset3, length, k, c, s, j, r, t;
|
||||
byte * src, * t_table;
|
||||
byte t_tmp1, t_tmp2;
|
||||
|
||||
fileSeek(_sfxFile, bundle_table[index].offset, SEEK_SET);
|
||||
|
||||
int tag = fileReadDwordBE(_sfxFile);
|
||||
int num = fileReadDwordBE(_sfxFile);
|
||||
fileReadDwordBE(_sfxFile); fileReadDwordBE(_sfxFile);
|
||||
|
||||
|
||||
// DO -NOT- change these MKID_BE calls to MKID! If you have
|
||||
// to do so, then your ScummSys.H file is detecting the
|
||||
// wrong endian. - Ender
|
||||
if (tag != MKID_BE('COMP')) {
|
||||
warning("Compressed sound %d invalid (%c%c%c%c)", index, tag>>24, tag>>16, tag>>8, tag);
|
||||
sprintf(buf, "%s%svoice.bun", _gameDataPath, _exe_name);
|
||||
_bundle->openVoiceFile((char*)&buf);
|
||||
ptr = (byte *)malloc(1000000);
|
||||
if (_bundle->decompressVoiceSampleByName(sound, ptr) == 0) {
|
||||
delete ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read compression table */
|
||||
for (i=0; i<num; i++) {
|
||||
table[i].offset = fileReadDwordBE(_sfxFile);
|
||||
table[i].size = fileReadDwordBE(_sfxFile);
|
||||
table[i].codec = fileReadDwordBE(_sfxFile);
|
||||
fileReadDwordBE(_sfxFile);
|
||||
int rate = 22050;
|
||||
int tag, size = -1;
|
||||
|
||||
tag = READ_BE_UINT32(ptr); ptr+=4;
|
||||
if (tag != MKID_BE('iMUS')) {
|
||||
warning("Decompression of bundle sound failed");
|
||||
free(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
CompFinal = (unsigned char *)malloc(1000000);
|
||||
|
||||
finalSize = 0;
|
||||
|
||||
/* Decompress data */
|
||||
for (i=0; i<num; i++) {
|
||||
unsigned char *p;
|
||||
fileSeek(_sfxFile, bundle_table[index].offset + table[i].offset, SEEK_SET);
|
||||
|
||||
CompInput = (unsigned char *)malloc(table[i].size);
|
||||
CompOutput = (unsigned char *)malloc(10000);
|
||||
|
||||
fileRead((FILE *)_sfxFile, CompInput, table[i].size);
|
||||
|
||||
switch(table[i].codec) {
|
||||
case 0:
|
||||
outputSize = table[i].size;
|
||||
memcpy(&CompOutput[0], &CompInput[0], outputSize);
|
||||
ptr += 12;
|
||||
while(tag != MKID_BE('DATA')) {
|
||||
tag = READ_BE_UINT32(ptr); ptr+=4;
|
||||
switch(tag) {
|
||||
case MKID_BE('FRMT'):
|
||||
size = READ_BE_UINT32(ptr); ptr+=16;
|
||||
rate = READ_BE_UINT32(ptr); ptr+=8;
|
||||
break;
|
||||
case MKID_BE('TEXT'):
|
||||
case MKID_BE('REGN'):
|
||||
case MKID_BE('STOP'):
|
||||
case MKID_BE('JUMP'):
|
||||
size = READ_BE_UINT32(ptr); ptr+=size+4;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
outputSize = CompDecode(&CompInput[0], &CompOutput[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
outputSize = CompDecode(&CompInput[0], &CompOutput[0]);
|
||||
p = CompOutput;
|
||||
for (z = 1; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
outputSize = CompDecode(&CompInput[0], &CompOutput[0]);
|
||||
p = CompOutput;
|
||||
for (z = 2; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
break;
|
||||
|
||||
case 10:
|
||||
outputSize = CompDecode(&CompInput[0], &CompOutput[0]);
|
||||
p = CompOutput;
|
||||
for (z = 2; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
|
||||
t_table = (byte*)malloc(outputSize);
|
||||
memcpy (t_table, p, outputSize);
|
||||
|
||||
offset1 = outputSize / 3;
|
||||
offset2 = offset1 * 2;
|
||||
offset3 = offset2;
|
||||
src = CompOutput;
|
||||
do {
|
||||
if (offset1 == 0) break;
|
||||
offset1--;
|
||||
offset2 -= 2;
|
||||
offset3--;
|
||||
*(t_table + offset2 + 0) = *(src + offset1);
|
||||
*(t_table + offset2 + 1) = *(src + offset3);
|
||||
} while(1);
|
||||
|
||||
src = CompOutput;
|
||||
length = (outputSize * 8) / 12;
|
||||
k = 0;
|
||||
if (length > 0)
|
||||
{
|
||||
c = -12;
|
||||
s = 0;
|
||||
do {
|
||||
j = length + (k / 2);
|
||||
if (k & 1) {
|
||||
r = c / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j + 1);
|
||||
*(src + r + 2) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
|
||||
*(src + r + 1) = (*(src + r + 1)) | (t_tmp1 & 0xf0);
|
||||
} else {
|
||||
r = s / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 0) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
|
||||
*(src + r + 1) = ((t_tmp1 & 0xf0) >> 4);
|
||||
}
|
||||
s += 12;
|
||||
k++;
|
||||
c += 12;
|
||||
} while (k <= length);
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
outputSize = CompDecode(&CompInput[0], &CompOutput[0]);
|
||||
p = CompOutput;
|
||||
for (z = 2; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
|
||||
t_table = (byte*)malloc(outputSize);
|
||||
memcpy (t_table, p, outputSize);
|
||||
|
||||
offset1 = outputSize / 3;
|
||||
offset2 = offset1 * 2;
|
||||
offset3 = offset2;
|
||||
src = CompOutput;
|
||||
do {
|
||||
if (offset1 == 0) break;
|
||||
offset1--;
|
||||
offset2 -= 2;
|
||||
offset3--;
|
||||
*(t_table + offset2 + 0) = *(src + offset1);
|
||||
*(t_table + offset2 + 1) = *(src + offset3);
|
||||
} while(1);
|
||||
|
||||
src = CompOutput;
|
||||
length = (outputSize * 8) / 12;
|
||||
k = 1;
|
||||
c = 0;
|
||||
s = 12;
|
||||
t_tmp1 = (*(t_table + length)) >> 4;
|
||||
*(src) = t_tmp1;
|
||||
t = length + k;
|
||||
if (t > k) {
|
||||
do {
|
||||
j = length + (k / 2);
|
||||
if (k & 1) {
|
||||
r = c / 8;
|
||||
t_tmp1 = *(t_table + k - 1);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 0) = (*(src + r)) | (t_tmp1 & 0xf0);
|
||||
*(src + r + 1) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
|
||||
} else {
|
||||
r = s / 8;
|
||||
t_tmp1 = *(t_table + k - 1);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 0) = (t_tmp1 & 0xf0) >> 4;
|
||||
*(src + r - 1) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
|
||||
}
|
||||
s += 12;
|
||||
k++;
|
||||
c += 12;
|
||||
} while (k < t);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 12:
|
||||
outputSize = CompDecode(&CompInput[0], &CompOutput[0]);
|
||||
p = CompOutput;
|
||||
for (z = 2; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
for (z = 1; z < outputSize; z++)
|
||||
p[z] += p[z - 1];
|
||||
|
||||
t_table = (byte*)malloc(outputSize);
|
||||
memcpy (t_table, p, outputSize);
|
||||
|
||||
offset1 = outputSize / 3;
|
||||
offset2 = offset1 * 2;
|
||||
offset3 = offset2;
|
||||
src = CompOutput;
|
||||
do {
|
||||
if (offset1 == 0) break;
|
||||
offset1--;
|
||||
offset2 -= 2;
|
||||
offset3--;
|
||||
*(t_table + offset2 + 0) = *(src + offset1);
|
||||
*(t_table + offset2 + 1) = *(src + offset3);
|
||||
} while(1);
|
||||
|
||||
src = CompOutput;
|
||||
length = (outputSize * 8) / 12;
|
||||
k = 0;
|
||||
c = 0;
|
||||
s = -12;
|
||||
*(src) = *(outputSize + t_table - 1);
|
||||
*(src + outputSize - 1) = *(t_table + length - 1);
|
||||
t = length - 1;
|
||||
if (t > 0) {
|
||||
do {
|
||||
j = length + (k / 2);
|
||||
if (k & 1) {
|
||||
r = s / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 2) = (*(src + r + 2)) | (t_tmp1 & 0xf0);
|
||||
*(src + r + 3) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
|
||||
} else {
|
||||
r = c / 8;
|
||||
t_tmp1 = *(t_table + k);
|
||||
t_tmp2 = *(t_table + j);
|
||||
*(src + r + 2) = (t_tmp1 & 0xf0) >> 4;
|
||||
*(src + r + 1) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
|
||||
}
|
||||
s += 12;
|
||||
k++;
|
||||
c += 12;
|
||||
} while (k < t);
|
||||
}
|
||||
|
||||
case MKID_BE('DATA'):
|
||||
size = READ_BE_UINT32(ptr); ptr+=4;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown codec %d!\n", table[i].codec);
|
||||
outputSize = 0;
|
||||
break;
|
||||
error("Unknown sound header %c%c%c%c", tag>>24, tag>>16, tag>>8, tag);
|
||||
}
|
||||
memcpy(&CompFinal[finalSize], &CompOutput[0], outputSize);
|
||||
finalSize+=outputSize;
|
||||
|
||||
free(CompInput); CompInput = NULL;
|
||||
free(CompOutput); CompOutput= NULL;
|
||||
}
|
||||
|
||||
{ /* Parse decompressed data */
|
||||
int rate = 22050;
|
||||
byte *ptr = CompFinal;
|
||||
int tag, size = -1;
|
||||
tag = READ_BE_UINT32(ptr); ptr+=4;
|
||||
if (tag != MKID_BE('iMUS')) {
|
||||
warning("Decompression of bundle sound failed");
|
||||
free(CompFinal);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr+=12; /* Skip header */
|
||||
while(tag != MKID_BE('DATA')) {
|
||||
tag = READ_BE_UINT32(ptr); ptr+=4;
|
||||
switch(tag) {
|
||||
case MKID_BE('FRMT'):
|
||||
size = READ_BE_UINT32(ptr); ptr+=16;
|
||||
rate = READ_BE_UINT32(ptr); ptr+=8;
|
||||
break;
|
||||
case MKID_BE('TEXT'):
|
||||
case MKID_BE('REGN'):
|
||||
case MKID_BE('STOP'):
|
||||
size = READ_BE_UINT32(ptr); ptr+=size+4;
|
||||
break;
|
||||
|
||||
case MKID_BE('DATA'):
|
||||
size = READ_BE_UINT32(ptr); ptr+=4;
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Unknown bundle header %c%c%c%c", tag>>24, tag>>16, tag>>8, tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
warning("Decompression of bundle sound failed (no size field)");
|
||||
free(CompFinal);
|
||||
return;
|
||||
}
|
||||
Final = (unsigned char *)malloc(size);
|
||||
memcpy(&Final[0], &ptr[0], size);
|
||||
_mixer->play_raw(NULL, Final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||
free(CompFinal);
|
||||
}
|
||||
}
|
||||
|
||||
void Scumm::playBundleSound(char *sound)
|
||||
{
|
||||
if (!_sfxFile) {
|
||||
warning("playBundleSound: SFX file is not open");
|
||||
if (size < 0) {
|
||||
warning("Decompression sound failed (no size field)");
|
||||
free(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; i < num_sound_effects; i++) {
|
||||
if (!scumm_stricmp(sound, bundle_table[i].filename)) {
|
||||
decompressBundleSound(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
warning("playBundleSound can't find %s", sound);
|
||||
|
||||
byte * final = (byte *)malloc(size);
|
||||
memcpy(final, ptr, size);
|
||||
_mixer->play_raw(NULL, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||
}
|
||||
|
||||
int Scumm::playSfxSound(void *sound, uint32 size, uint rate)
|
||||
|
@ -207,9 +207,4 @@ struct MP3OffsetTable { /* Compressed Sound (.SO3) */
|
||||
int compressed_size;
|
||||
};
|
||||
|
||||
struct BundleAudioTable { /* Dig/CMI .bun audio */
|
||||
char filename[13];
|
||||
int size;
|
||||
int offset;
|
||||
};
|
||||
#endif /* _mixer_h_included */
|
||||
|
Loading…
x
Reference in New Issue
Block a user