Add IMA4 support
This commit is contained in:
parent
469097ed5b
commit
976c85ff57
@ -47,7 +47,7 @@ int main( int argc, char *argv[] ) {
|
|||||||
printf("playing sample2\n");
|
printf("playing sample2\n");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
SGSoundSample *sample3 = new SGSoundSample("jet.wav", srcDir);
|
SGSoundSample *sample3 = new SGSoundSample("jet_ima4.wav", srcDir);
|
||||||
sample3->set_volume(0.5);
|
sample3->set_volume(0.5);
|
||||||
sample3->set_pitch(0.8);
|
sample3->set_pitch(0.8);
|
||||||
sample3->play_looped();
|
sample3->play_looped();
|
||||||
|
@ -38,6 +38,7 @@ namespace
|
|||||||
public:
|
public:
|
||||||
ALvoid* data;
|
ALvoid* data;
|
||||||
unsigned int format;
|
unsigned int format;
|
||||||
|
unsigned int block_align;
|
||||||
ALsizei length;
|
ALsizei length;
|
||||||
ALfloat frequency;
|
ALfloat frequency;
|
||||||
SGPath path;
|
SGPath path;
|
||||||
@ -96,10 +97,10 @@ namespace
|
|||||||
mantissa = mulawbyte & 0x0F;
|
mantissa = mulawbyte & 0x0F;
|
||||||
sample = exp_lut[exponent] + (mantissa << (exponent + 3));
|
sample = exp_lut[exponent] + (mantissa << (exponent + 3));
|
||||||
return sign ? -sample : sample;
|
return sign ? -sample : sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
void codecULaw (Buffer* b)
|
void codecULaw (Buffer* b)
|
||||||
{
|
{
|
||||||
uint8_t *d = (uint8_t *) b->data;
|
uint8_t *d = (uint8_t *) b->data;
|
||||||
size_t newLength = b->length * 2;
|
size_t newLength = b->length * 2;
|
||||||
int16_t *buf = (int16_t *) malloc(newLength);
|
int16_t *buf = (int16_t *) malloc(newLength);
|
||||||
@ -115,6 +116,98 @@ namespace
|
|||||||
b->length = newLength;
|
b->length = newLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16_t ima2linear (uint8_t nibble, int16_t *val, uint8_t *idx)
|
||||||
|
{
|
||||||
|
const int16_t _ima4_index_table[16] =
|
||||||
|
{
|
||||||
|
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||||
|
-1, -1, -1, -1, 2, 4, 6, 8
|
||||||
|
};
|
||||||
|
const int16_t _ima4_step_table[89] =
|
||||||
|
{
|
||||||
|
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||||
|
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||||
|
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||||
|
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||||
|
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||||
|
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||||
|
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||||
|
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||||
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||||
|
};
|
||||||
|
int32_t predictor;
|
||||||
|
int16_t diff, step;
|
||||||
|
int8_t delta, sign;
|
||||||
|
int8_t index;
|
||||||
|
|
||||||
|
index = *idx;
|
||||||
|
if (index > 88) index = 88;
|
||||||
|
else if (index < 0) index = 0;
|
||||||
|
|
||||||
|
predictor = *val;
|
||||||
|
step = _ima4_step_table[index];
|
||||||
|
|
||||||
|
sign = nibble & 0x8;
|
||||||
|
delta = nibble & 0x7;
|
||||||
|
|
||||||
|
diff = 0;
|
||||||
|
if (delta & 4) diff += step;
|
||||||
|
if (delta & 2) diff += (step >> 1);
|
||||||
|
if (delta & 1) diff += (step >> 2);
|
||||||
|
diff += (step >> 3);
|
||||||
|
|
||||||
|
if (sign) predictor -= diff;
|
||||||
|
else predictor += diff;
|
||||||
|
|
||||||
|
index += _ima4_index_table[nibble];
|
||||||
|
if (index > 88) index = 88;
|
||||||
|
else if (index < 0) index = 0;
|
||||||
|
*idx = index;
|
||||||
|
|
||||||
|
if (predictor < -32768) predictor = -32768;
|
||||||
|
else if (predictor > 32767) predictor = 32767;
|
||||||
|
*val = predictor;
|
||||||
|
|
||||||
|
return *val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void codecIMA4 (Buffer* b)
|
||||||
|
{
|
||||||
|
uint8_t *d = (uint8_t *) b->data;
|
||||||
|
unsigned int block_align = b->block_align;
|
||||||
|
size_t blocks = b->length/block_align;
|
||||||
|
size_t newLength = block_align * blocks * 4;
|
||||||
|
int16_t *buf = (int16_t *) malloc ( newLength );
|
||||||
|
if (buf == NULL)
|
||||||
|
throw sg_exception("malloc failed decoing IMA4 WAV file");
|
||||||
|
|
||||||
|
int16_t *ptr = buf;
|
||||||
|
for (size_t i = 0; i < blocks; i++)
|
||||||
|
{
|
||||||
|
int16_t predictor;
|
||||||
|
uint8_t index;
|
||||||
|
|
||||||
|
predictor = *d++;
|
||||||
|
predictor |= *d++ << 8;
|
||||||
|
index = *d++;
|
||||||
|
d++;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < block_align; j += 4)
|
||||||
|
{
|
||||||
|
for (unsigned int q=0; q<4; q++)
|
||||||
|
{
|
||||||
|
uint8_t nibble = *d++;
|
||||||
|
*ptr++ = ima2linear(nibble & 0xF, &predictor, &index);
|
||||||
|
*ptr++ = ima2linear(nibble >> 4, &predictor, &index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(b->data);
|
||||||
|
b->data = buf;
|
||||||
|
b->length = newLength;
|
||||||
|
}
|
||||||
|
|
||||||
bool gzSkip(gzFile fd, int skipCount)
|
bool gzSkip(gzFile fd, int skipCount)
|
||||||
{
|
{
|
||||||
int r = gzseek(fd, skipCount, SEEK_CUR);
|
int r = gzseek(fd, skipCount, SEEK_CUR);
|
||||||
@ -219,10 +312,23 @@ namespace
|
|||||||
codec = codecULaw;
|
codec = codecULaw;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 17: /* IMA4 ADPCM */
|
||||||
|
if (alIsExtensionPresent((ALchar *)"AL_EXT_ima4") &&
|
||||||
|
(alIsExtensionPresent((ALchar *)"AL_SOFT_block_alignment")
|
||||||
|
|| blockAlign == 65)) {
|
||||||
|
compressed = true;
|
||||||
|
codec = codecLinear;
|
||||||
|
} else {
|
||||||
|
bitsPerSample *= 4; /* uLaw is 16-bit packed into 8 bits */
|
||||||
|
codec = codecIMA4;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw sg_io_exception("unsupported WAV encoding", b->path);
|
throw sg_io_exception("unsupported WAV encoding", b->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b->block_align = blockAlign;
|
||||||
b->frequency = samplesPerSecond;
|
b->frequency = samplesPerSecond;
|
||||||
b->format = formatConstruct(numChannels, bitsPerSample, compressed);
|
b->format = formatConstruct(numChannels, bitsPerSample, compressed);
|
||||||
} else if (magic == WAV_DATA_4CC) {
|
} else if (magic == WAV_DATA_4CC) {
|
||||||
@ -256,7 +362,7 @@ namespace
|
|||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|
||||||
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf)
|
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf, unsigned int& block_align)
|
||||||
{
|
{
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
throw sg_io_exception("loadWAVFromFile: file not found", path);
|
throw sg_io_exception("loadWAVFromFile: file not found", path);
|
||||||
@ -275,6 +381,7 @@ ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size,
|
|||||||
ALvoid* data = b.data;
|
ALvoid* data = b.data;
|
||||||
b.data = NULL; // don't free when Buffer does out of scope
|
b.data = NULL; // don't free when Buffer does out of scope
|
||||||
format = b.format;
|
format = b.format;
|
||||||
|
block_align = b.block_align;
|
||||||
size = b.length;
|
size = b.length;
|
||||||
freqf = b.frequency;
|
freqf = b.frequency;
|
||||||
|
|
||||||
@ -287,9 +394,10 @@ ALuint createBufferFromFile(const SGPath& path)
|
|||||||
ALuint buffer = -1;
|
ALuint buffer = -1;
|
||||||
#ifdef ENABLE_SOUND
|
#ifdef ENABLE_SOUND
|
||||||
unsigned int format;
|
unsigned int format;
|
||||||
|
unsigned int block_align;
|
||||||
ALsizei size;
|
ALsizei size;
|
||||||
ALfloat sampleFrequency;
|
ALfloat sampleFrequency;
|
||||||
ALvoid* data = loadWAVFromFile(path, format, size, sampleFrequency);
|
ALvoid* data = loadWAVFromFile(path, format, size, sampleFrequency, block_alight);
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
alGenBuffers(1, &buffer);
|
alGenBuffers(1, &buffer);
|
||||||
@ -299,6 +407,7 @@ ALuint createBufferFromFile(const SGPath& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
alBufferData (buffer, format, data, size, (ALsizei) sampleFrequency);
|
alBufferData (buffer, format, data, size, (ALsizei) sampleFrequency);
|
||||||
|
alBufferi (buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, block_align);
|
||||||
if (alGetError() != AL_NO_ERROR) {
|
if (alGetError() != AL_NO_ERROR) {
|
||||||
alDeleteBuffers(1, &buffer);
|
alDeleteBuffers(1, &buffer);
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -16,7 +16,7 @@ class SGPath;
|
|||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf);
|
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf, unsigned int& block_align);
|
||||||
|
|
||||||
ALuint createBufferFromFile(const SGPath& path);
|
ALuint createBufferFromFile(const SGPath& path);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,17 @@ public:
|
|||||||
* Returns the format of this audio sample.
|
* Returns the format of this audio sample.
|
||||||
* @return SimGear format-id
|
* @return SimGear format-id
|
||||||
*/
|
*/
|
||||||
inline unsigned int get_format() { return (_tracks | _bits | _compressed*256); }
|
inline unsigned int get_format() {
|
||||||
|
return (_tracks | _bits | _compressed*256);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the block alignment of this audio sample.
|
||||||
|
* @return block alignment in bytes
|
||||||
|
*/
|
||||||
|
inline unsigned int get_block_align() {
|
||||||
|
return _block_align;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the reference name of this audio sample.
|
* Get the reference name of this audio sample.
|
||||||
@ -170,6 +180,7 @@ protected:
|
|||||||
unsigned int _tracks;
|
unsigned int _tracks;
|
||||||
unsigned int _samples;
|
unsigned int _samples;
|
||||||
unsigned int _frequency;
|
unsigned int _frequency;
|
||||||
|
unsigned int _block_align;
|
||||||
bool _compressed;
|
bool _compressed;
|
||||||
bool _loop;
|
bool _loop;
|
||||||
|
|
||||||
@ -432,6 +443,14 @@ public:
|
|||||||
_tracks = fmt & 0x3; _bits = fmt & 0x1C; _compressed = fmt & 0x100;
|
_tracks = fmt & 0x3; _bits = fmt & 0x1C; _compressed = fmt & 0x100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the block alignament for compressed audio.
|
||||||
|
* @param block the block alignment in bytes
|
||||||
|
*/
|
||||||
|
inline void set_block_align( int block ) {
|
||||||
|
_block_align = block;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the frequency (in Herz) of this audio sample.
|
* Set the frequency (in Herz) of this audio sample.
|
||||||
* @param freq Frequency
|
* @param freq Frequency
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -60,6 +61,9 @@ using std::vector;
|
|||||||
#ifndef AL_FORMAT_MONO_IMA4
|
#ifndef AL_FORMAT_MONO_IMA4
|
||||||
# define AL_FORMAT_MONO_IMA4 0x1300
|
# define AL_FORMAT_MONO_IMA4 0x1300
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef AL_UNPACK_BLOCK_ALIGNMENT_SOFT
|
||||||
|
# define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C
|
||||||
|
#endif
|
||||||
|
|
||||||
class SGSoundMgr::SoundManagerPrivate
|
class SGSoundMgr::SoundManagerPrivate
|
||||||
{
|
{
|
||||||
@ -141,6 +145,8 @@ SGSoundMgr::SGSoundMgr() :
|
|||||||
{
|
{
|
||||||
d.reset(new SoundManagerPrivate);
|
d.reset(new SoundManagerPrivate);
|
||||||
d->_base_pos = SGVec3d::fromGeod(_geod_pos);
|
d->_base_pos = SGVec3d::fromGeod(_geod_pos);
|
||||||
|
|
||||||
|
_block_support = alIsExtensionPresent((ALchar *)"AL_SOFT_block_alignment");
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
@ -542,11 +548,11 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
|||||||
|
|
||||||
// sample name was not found in the buffer cache.
|
// sample name was not found in the buffer cache.
|
||||||
if ( sample->is_file() ) {
|
if ( sample->is_file() ) {
|
||||||
int freq, format;
|
int freq, format, block;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bool res = load(sample_name, &sample_data, &format, &size, &freq);
|
bool res = load(sample_name, &sample_data, &format, &size, &freq, &block);
|
||||||
if (res == false) return NO_BUFFER;
|
if (res == false) return NO_BUFFER;
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
SG_LOG(SG_SOUND, SG_ALERT,
|
SG_LOG(SG_SOUND, SG_ALERT,
|
||||||
@ -555,6 +561,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
|||||||
return FAILED_BUFFER;
|
return FAILED_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sample->set_block_align( block );
|
||||||
sample->set_frequency( freq );
|
sample->set_frequency( freq );
|
||||||
sample->set_format( format );
|
sample->set_format( format );
|
||||||
sample->set_size( size );
|
sample->set_size( size );
|
||||||
@ -573,11 +580,17 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
|||||||
if (fmt == SG_SAMPLE_MONO16) format = AL_FORMAT_MONO16;
|
if (fmt == SG_SAMPLE_MONO16) format = AL_FORMAT_MONO16;
|
||||||
else if (fmt == SG_SAMPLE_MONO8) format = AL_FORMAT_MONO8;
|
else if (fmt == SG_SAMPLE_MONO8) format = AL_FORMAT_MONO8;
|
||||||
else if (fmt == SG_SAMPLE_MULAW) format = AL_FORMAT_MONO_MULAW_EXT;
|
else if (fmt == SG_SAMPLE_MULAW) format = AL_FORMAT_MONO_MULAW_EXT;
|
||||||
|
else if (fmt == SG_SAMPLE_ADPCM) format = AL_FORMAT_MONO_IMA4;
|
||||||
|
|
||||||
ALsizei size = sample->get_size();
|
ALsizei size = sample->get_size();
|
||||||
ALsizei freq = sample->get_frequency();
|
ALsizei freq = sample->get_frequency();
|
||||||
alBufferData( buffer, format, sample_data, size, freq );
|
alBufferData( buffer, format, sample_data, size, freq );
|
||||||
|
|
||||||
|
if (_block_support) {
|
||||||
|
ALsizei block_align = sample->get_block_align();
|
||||||
|
alBufferi (buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, block_align);
|
||||||
|
}
|
||||||
|
|
||||||
if ( !testForError("buffer add data") ) {
|
if ( !testForError("buffer add data") ) {
|
||||||
sample->set_buffer(buffer);
|
sample->set_buffer(buffer);
|
||||||
d->_buffers[sample_name] = refUint(buffer);
|
d->_buffers[sample_name] = refUint(buffer);
|
||||||
@ -763,19 +776,21 @@ bool SGSoundMgr::load( const std::string &samplepath,
|
|||||||
void **dbuf,
|
void **dbuf,
|
||||||
int *fmt,
|
int *fmt,
|
||||||
size_t *sz,
|
size_t *sz,
|
||||||
int *frq )
|
int *frq,
|
||||||
|
int *block )
|
||||||
{
|
{
|
||||||
if ( !is_working() )
|
if ( !is_working() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned int format;
|
unsigned int format;
|
||||||
|
unsigned int block_align;
|
||||||
ALsizei size;
|
ALsizei size;
|
||||||
ALsizei freq;
|
ALsizei freq;
|
||||||
ALvoid *data;
|
ALvoid *data;
|
||||||
|
|
||||||
ALfloat freqf;
|
ALfloat freqf;
|
||||||
|
|
||||||
data = simgear::loadWAVFromFile(samplepath, format, size, freqf );
|
data = simgear::loadWAVFromFile(samplepath, format, size, freqf, block_align );
|
||||||
freq = (ALsizei)freqf;
|
freq = (ALsizei)freqf;
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
throw sg_io_exception("Failed to load wav file", sg_location(samplepath));
|
throw sg_io_exception("Failed to load wav file", sg_location(samplepath));
|
||||||
@ -788,6 +803,7 @@ bool SGSoundMgr::load( const std::string &samplepath,
|
|||||||
|
|
||||||
*dbuf = (void *)data;
|
*dbuf = (void *)data;
|
||||||
*fmt = (int)format;
|
*fmt = (int)format;
|
||||||
|
*block = (int)block_align;
|
||||||
*sz = (size_t)size;
|
*sz = (size_t)size;
|
||||||
*frq = (int)freq;
|
*frq = (int)freq;
|
||||||
|
|
||||||
|
@ -312,7 +312,8 @@ public:
|
|||||||
void **data,
|
void **data,
|
||||||
int *format,
|
int *format,
|
||||||
size_t *size,
|
size_t *size,
|
||||||
int *freq );
|
int *freq,
|
||||||
|
int *block );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of available playback devices.
|
* Get a list of available playback devices.
|
||||||
@ -333,6 +334,7 @@ private:
|
|||||||
/// private implementation object
|
/// private implementation object
|
||||||
std::auto_ptr<SoundManagerPrivate> d;
|
std::auto_ptr<SoundManagerPrivate> d;
|
||||||
|
|
||||||
|
bool _block_support;
|
||||||
bool _active;
|
bool _active;
|
||||||
bool _changed;
|
bool _changed;
|
||||||
float _volume;
|
float _volume;
|
||||||
|
Loading…
Reference in New Issue
Block a user