mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-04 02:00:04 -04:00
Split libacm files to third_party/libacm and AudioEncode
Logically adecode/aencode belongs to AudioEncode.
This commit is contained in:
148
AudioEncode/adecode.cpp
Normal file
148
AudioEncode/adecode.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adecode.h"
|
||||
#include "libacm.h"
|
||||
|
||||
using namespace AudioDecoder;
|
||||
|
||||
namespace {
|
||||
|
||||
class InternalAudioDecoder : public IAudioDecoder {
|
||||
public:
|
||||
InternalAudioDecoder(ReadDataFunction readerFunction, void *pReaderData);
|
||||
~InternalAudioDecoder();
|
||||
|
||||
// Initialize the decoder
|
||||
bool Initialize();
|
||||
|
||||
// Read data from the audio decoder.
|
||||
// pBuffer: The buffer to receive the data into
|
||||
// amount: How much data to read
|
||||
// Returns the number of bytes read - zero when we're at the end of the file
|
||||
uint32_t Read(void *pBuffer, uint32_t amount);
|
||||
|
||||
ACMStream *m_acm = nullptr;
|
||||
ReadDataFunction m_readerFunction;
|
||||
void *m_pReaderData;
|
||||
};
|
||||
|
||||
/**************************************************************/
|
||||
/* Construction */
|
||||
/**************************************************************/
|
||||
|
||||
int AcmReadFunc(void *ptr, int size, int n, void *datasrc) {
|
||||
InternalAudioDecoder *iad = reinterpret_cast<InternalAudioDecoder *>(datasrc);
|
||||
int ret = iad->m_readerFunction(iad->m_pReaderData, ptr, (uint32_t)size * n);
|
||||
// ret < 0: error, ret == 0: EOF, ret > 0: read ret bytes of data
|
||||
// apparently acm_io_callbacks::read() expects pretty much the same behavior,
|
||||
// except that for > 0 it's not number of bytes but number of items (like in
|
||||
// fread())
|
||||
if (ret > 0) {
|
||||
ret /= size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
InternalAudioDecoder::InternalAudioDecoder(ReadDataFunction readerFunction, void *pReaderData)
|
||||
: m_readerFunction(readerFunction), m_pReaderData(pReaderData) {}
|
||||
|
||||
// Initialize the decoder
|
||||
bool InternalAudioDecoder::Initialize() {
|
||||
|
||||
// set the read function, the others are optional
|
||||
acm_io_callbacks io = {AcmReadFunc};
|
||||
|
||||
// force_channels 0 means libacm will use number of chans from ACM file header
|
||||
const int force_channels = 0;
|
||||
int ret = acm_open_decoder(&m_acm, this, io, force_channels);
|
||||
return ret == ACM_OK;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* Destruction */
|
||||
/**************************************************************/
|
||||
|
||||
InternalAudioDecoder::~InternalAudioDecoder() {
|
||||
if (m_acm != nullptr)
|
||||
acm_close(m_acm);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* Reading */
|
||||
/**************************************************************/
|
||||
|
||||
// Read data from the audio decoder.
|
||||
// pBuffer: The buffer to receive the data into
|
||||
// amount: How much data to read
|
||||
// Returns the number of bytes read - zero when we're at the end of the file
|
||||
uint32_t InternalAudioDecoder::Read(void *pBuffer, uint32_t amount) {
|
||||
const int bigendianp = 0; // we want little endian samples - TODO: or only on little endian platforms?
|
||||
const int wordlen = 2; // the only supported value
|
||||
const int sgned = 1; // we want signed samples
|
||||
uint32_t totalBytesRead = 0;
|
||||
uint8_t *pBuf = reinterpret_cast<uint8_t *>(pBuffer);
|
||||
|
||||
while (totalBytesRead < amount) {
|
||||
int numRead = acm_read(m_acm, pBuf, amount - totalBytesRead, bigendianp, wordlen, sgned);
|
||||
// numRead < 0: error, numRead == 0: EOF, numRead > 0: amount of bytes read
|
||||
if (numRead <= 0)
|
||||
break;
|
||||
totalBytesRead += numRead;
|
||||
pBuf += numRead;
|
||||
}
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/**************************************************************/
|
||||
/* Interface Functions */
|
||||
/**************************************************************/
|
||||
|
||||
// Create an audio decoder
|
||||
// You supply a function for reading bytes from the compressed data via a
|
||||
// void* pData handle, and the handle itself (typically a FILE *).
|
||||
// Create_AudioDecoder returns a new AudioDecoder which can be used to
|
||||
// read uncompressed decoded data from the compressed stream,
|
||||
// and also returns the number of channels (1 or 2), the sample rate
|
||||
// (e.g. 22050), and the number of samples contained in the compressed file
|
||||
// (in case you want to pre-allocate a buffer to load them all into memory).
|
||||
IAudioDecoder *AudioDecoder::CreateDecoder(ReadDataFunction readerFunction, void *pReaderData, uint32_t &numChannels,
|
||||
uint32_t &sampleRate, uint32_t &sampleCount) {
|
||||
// allocate our decoder
|
||||
InternalAudioDecoder *pDecoder = new InternalAudioDecoder(readerFunction, pReaderData);
|
||||
if (pDecoder == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// initialize
|
||||
if (!pDecoder->Initialize()) {
|
||||
// Failed
|
||||
delete pDecoder;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// extract the header information for the caller
|
||||
numChannels = pDecoder->m_acm->info.channels;
|
||||
sampleRate = pDecoder->m_acm->info.rate;
|
||||
sampleCount = pDecoder->m_acm->total_values;
|
||||
|
||||
// return the decoder back to the user
|
||||
return pDecoder;
|
||||
}
|
||||
Reference in New Issue
Block a user