mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
231 lines
8.2 KiB
C++
231 lines
8.2 KiB
C++
/* Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
|
|
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
|
|
*
|
|
* Inspired by tonegenerator of
|
|
* Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004)
|
|
* Inspired by ringbuffer of Audacity 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 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Additional permission under GNU GPL version 3 section 7:
|
|
*
|
|
* If you modify this program, or any covered work, by linking or
|
|
* combining it with the OpenSSL project's OpenSSL library (or a
|
|
* modified version of that library), containing parts covered by the
|
|
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
|
|
* grants you additional permission to convey the resulting work.
|
|
* Corresponding Source for a non-source form of such a combination
|
|
* shall include the source code for the parts of OpenSSL used as well
|
|
* as that of the covered work.
|
|
*/
|
|
#include <fstream>
|
|
#include <cmath>
|
|
#include <samplerate.h>
|
|
#include <cstring>
|
|
#include <vector>
|
|
#include <climits>
|
|
|
|
#include "audiofile.h"
|
|
#include "audio/codecs/audiocodec.h"
|
|
#include "audio/samplerateconverter.h"
|
|
#include "logger.h"
|
|
|
|
RawFile::RawFile(const std::string& name, sfl::AudioCodec *codec, unsigned int sampleRate)
|
|
: AudioFile(name, sampleRate), audioCodec_(codec)
|
|
{
|
|
if (filepath_.empty())
|
|
throw AudioFileException("Unable to open audio file: filename is empty");
|
|
|
|
std::fstream file;
|
|
file.open(filepath_.c_str(), std::fstream::in);
|
|
|
|
if (!file.is_open())
|
|
throw AudioFileException("Unable to open audio file");
|
|
|
|
file.seekg(0, std::ios::end);
|
|
size_t length = file.tellg();
|
|
file.seekg(0, std::ios::beg);
|
|
|
|
std::vector<char> fileBuffer(length);
|
|
file.read(&fileBuffer[0], length);
|
|
file.close();
|
|
|
|
const unsigned int frameSize = audioCodec_->getFrameSize();
|
|
const unsigned int bitrate = audioCodec_->getBitRate() * 1000 / 8;
|
|
const unsigned int audioRate = audioCodec_->getClockRate();
|
|
const unsigned int encFrameSize = frameSize * bitrate / audioRate;
|
|
const unsigned int decodedSize = length * (frameSize / encFrameSize);
|
|
|
|
/*SFLAudioSample *monoBuffer = new SFLAudioSample[decodedSize];
|
|
SFLAudioSample *bufpos = monoBuffer;*/
|
|
AudioBuffer * buffer = new AudioBuffer(decodedSize);
|
|
unsigned bufpos = 0;
|
|
unsigned char *filepos = reinterpret_cast<unsigned char *>(&fileBuffer[0]);
|
|
//size_ = decodedSize;
|
|
|
|
while (length >= encFrameSize) {
|
|
//bufpos += audioCodec_->decode(bufpos, filepos, encFrameSize);
|
|
bufpos += audioCodec_->decode(buffer->getData(), filepos, encFrameSize, bufpos);
|
|
filepos += encFrameSize;
|
|
length -= encFrameSize;
|
|
}
|
|
|
|
if (sampleRate == audioRate)
|
|
buffer_ = buffer;
|
|
else {
|
|
double factord = (double) sampleRate / audioRate;
|
|
|
|
const size_t channels = buffer->getChannelNum();
|
|
|
|
if (channels > 2)
|
|
throw AudioFileException("WaveFile: unsupported number of channels");
|
|
|
|
size_t samples = buffer->samples();
|
|
size_t size = channels * samples;
|
|
float* floatBufferIn = new float[size];
|
|
buffer->interleaveFloat(floatBufferIn);
|
|
|
|
int samplesOut = ceil(factord * samples);
|
|
int sizeOut = samplesOut*channels;
|
|
|
|
//src_short_to_float_array(monoBuffer, floatBufferIn, size_);
|
|
//delete [] monoBuffer;
|
|
//delete [] buffer_;
|
|
//delete buffer;
|
|
delete buffer_;
|
|
//buffer_ = new SFLAudioSample[sizeOut];
|
|
|
|
SRC_DATA src_data;
|
|
src_data.data_in = floatBufferIn;
|
|
src_data.input_frames = samples;
|
|
src_data.output_frames = samplesOut;
|
|
src_data.src_ratio = factord;
|
|
|
|
float* floatBufferOut = new float[sizeOut];
|
|
src_data.data_out = floatBufferOut;
|
|
|
|
src_simple(&src_data, SRC_SINC_BEST_QUALITY, channels);
|
|
samplesOut = src_data.output_frames_gen;
|
|
sizeOut = samplesOut*channels;
|
|
|
|
SFLAudioSample *scratch = new SFLAudioSample[sizeOut];
|
|
src_float_to_short_array(floatBufferOut, scratch, src_data.output_frames_gen);
|
|
buffer->fromInterleaved(scratch, samplesOut, channels);
|
|
buffer_ = buffer;
|
|
|
|
delete [] floatBufferOut;
|
|
delete [] floatBufferIn;
|
|
delete [] scratch;
|
|
}
|
|
}
|
|
|
|
|
|
WaveFile::WaveFile(const std::string &fileName, unsigned int sampleRate) : AudioFile(fileName, sampleRate)
|
|
{
|
|
const std::fstream fs(fileName.c_str(), std::ios_base::in);
|
|
|
|
if (!fs)
|
|
throw AudioFileException("File " + fileName + " doesn't exist");
|
|
|
|
std::fstream fileStream;
|
|
fileStream.open(fileName.c_str(), std::ios::in | std::ios::binary);
|
|
|
|
char riff[4] = { 0, 0, 0, 0 };
|
|
fileStream.read(riff, sizeof riff / sizeof *riff);
|
|
|
|
if (strncmp("RIFF", riff, sizeof riff / sizeof *riff) != 0)
|
|
throw AudioFileException("File is not of RIFF format");
|
|
|
|
char fmt[4] = { 0, 0, 0, 0 };
|
|
int maxIteration = 10;
|
|
|
|
while (maxIteration-- and strncmp("fmt ", fmt, sizeof fmt / sizeof *fmt))
|
|
fileStream.read(fmt, sizeof fmt / sizeof *fmt);
|
|
|
|
if (maxIteration == 0)
|
|
throw AudioFileException("Could not find \"fmt \" chunk");
|
|
|
|
SINT32 chunkSize; // fmt chunk size
|
|
fileStream.read(reinterpret_cast<char *>(&chunkSize), sizeof chunkSize); // Read fmt chunk size.
|
|
unsigned short formatTag; // data compression tag
|
|
fileStream.read(reinterpret_cast<char *>(&formatTag), sizeof formatTag);
|
|
|
|
if (formatTag != 1) // PCM = 1, FLOAT = 3
|
|
throw AudioFileException("File contains an unsupported data format type");
|
|
|
|
// Get number of channels from the header.
|
|
SINT16 chan;
|
|
fileStream.read(reinterpret_cast<char *>(&chan), sizeof chan);
|
|
|
|
if (chan > 2)
|
|
throw AudioFileException("WaveFile: unsupported number of channels");
|
|
|
|
// Get file sample rate from the header.
|
|
SINT32 fileRate;
|
|
fileStream.read(reinterpret_cast<char *>(&fileRate), sizeof fileRate);
|
|
|
|
SINT32 avgb;
|
|
fileStream.read(reinterpret_cast<char *>(&avgb), sizeof avgb);
|
|
|
|
SINT16 blockal;
|
|
fileStream.read(reinterpret_cast<char *>(&blockal), sizeof blockal);
|
|
|
|
// Determine the data type
|
|
SINT16 dt;
|
|
fileStream.read(reinterpret_cast<char *>(&dt), sizeof dt);
|
|
|
|
if (dt != 8 && dt != 16 && dt != 32)
|
|
throw AudioFileException("File's bits per sample with is not supported");
|
|
|
|
// Find the "data" chunk
|
|
char data[4] = { 0, 0, 0, 0 };
|
|
maxIteration = 10;
|
|
|
|
while (maxIteration-- && strncmp("data", data, sizeof data / sizeof *data))
|
|
fileStream.read(data, sizeof data / sizeof *data);
|
|
|
|
// Samplerate converter initialized with 88200 sample long
|
|
const int rate = static_cast<SINT32>(sampleRate);
|
|
SamplerateConverter converter(std::max(fileRate, rate), chan);
|
|
|
|
// Get length of data from the header.
|
|
SINT32 bytes;
|
|
fileStream.read(reinterpret_cast<char *>(&bytes), sizeof bytes);
|
|
|
|
// sample frames, should not be longer than a minute
|
|
int nbSamples = std::min(60 * fileRate, 8 * bytes / dt / chan);
|
|
|
|
DEBUG("Frame size %ld, data size %d align %d rate %d avgbyte %d "
|
|
"chunk size %d dt %d", nbSamples, bytes, blockal, fileRate, avgb,
|
|
chunkSize, dt);
|
|
|
|
//size_ = nbSamples;
|
|
SFLAudioSample * tempBuffer = new SFLAudioSample[nbSamples*chan];
|
|
|
|
fileStream.read(reinterpret_cast<char *>(tempBuffer),
|
|
nbSamples*chan * sizeof(SFLAudioSample));
|
|
|
|
AudioBuffer * buffer = new AudioBuffer(nbSamples, chan, fileRate);
|
|
buffer->fromInterleaved(tempBuffer, nbSamples, chan);
|
|
|
|
if (fileRate != rate) {
|
|
AudioBuffer * resampled = new AudioBuffer(nbSamples, chan, rate);
|
|
converter.resample(*buffer, *resampled);
|
|
delete [] buffer;
|
|
buffer_ = resampled;
|
|
} else
|
|
buffer_ = buffer;
|
|
}
|