Simplify PCMAudioProvider a bit and pull it fully into the cpp file

This commit is contained in:
Thomas Goyne 2014-03-20 19:55:04 -07:00
parent df177ae869
commit 58db99cd24
5 changed files with 54 additions and 118 deletions

View File

@ -123,7 +123,6 @@
<ClInclude Include="$(SrcDir)audio_provider_ffmpegsource.h" />
<ClInclude Include="$(SrcDir)audio_provider_hd.h" />
<ClInclude Include="$(SrcDir)audio_provider_lock.h" />
<ClInclude Include="$(SrcDir)audio_provider_pcm.h" />
<ClInclude Include="$(SrcDir)audio_provider_ram.h" />
<ClInclude Include="$(SrcDir)audio_renderer.h" />
<ClInclude Include="$(SrcDir)audio_renderer_spectrum.h" />

View File

@ -195,9 +195,6 @@
<ClInclude Include="$(SrcDir)audio_provider_hd.h">
<Filter>Audio\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)audio_provider_pcm.h">
<Filter>Audio\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)audio_box.h">
<Filter>Audio\UI</Filter>
</ClInclude>

View File

@ -40,7 +40,6 @@
#include "audio_provider_ffmpegsource.h"
#include "audio_provider_hd.h"
#include "audio_provider_lock.h"
#include "audio_provider_pcm.h"
#include "audio_provider_ram.h"
#include "audio_controller.h"
@ -54,6 +53,9 @@
#include <libaegisub/log.h>
#include <libaegisub/util.h>
// Defined in audio_provider_pcm.cpp
std::unique_ptr<AudioProvider> CreatePCMAudioProvider(agi::fs::path const& filename);
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const {
GetAudio(buf, start, count);

View File

@ -34,7 +34,7 @@
#include "config.h"
#include "audio_provider_pcm.h"
#include "include/aegisub/audio_provider.h"
#include "audio_controller.h"
#include "utils.h"
@ -44,47 +44,58 @@
#include <libaegisub/log.h>
#include <libaegisub/util.h>
PCMAudioProvider::PCMAudioProvider(agi::fs::path const& filename)
: file(agi::util::make_unique<agi::read_file_mapping>(filename))
{
float_samples = false;
}
#include <vector>
PCMAudioProvider::~PCMAudioProvider() { }
class PCMAudioProvider : public AudioProvider {
void FillBuffer(void *buf, int64_t start, int64_t count) const override;
char *PCMAudioProvider::EnsureRangeAccessible(int64_t start, int64_t length) const {
try {
return file->read(start, static_cast<size_t>(length));
protected:
std::unique_ptr<agi::read_file_mapping> file;
PCMAudioProvider(agi::fs::path const& filename)
: file(agi::util::make_unique<agi::read_file_mapping>(filename))
{
float_samples = false;
}
catch (agi::fs::FileSystemError const& e) {
throw AudioDecodeError(e.GetMessage());
char *EnsureRangeAccessible(int64_t start, int64_t length) const {
try {
return file->read(start, static_cast<size_t>(length));
}
catch (agi::fs::FileSystemError const& e) {
throw AudioDecodeError(e.GetMessage());
}
}
}
struct IndexPoint {
int64_t start_byte;
int64_t num_samples;
};
std::vector<IndexPoint> index_points;
};
void PCMAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
// Read blocks from the file
size_t index = 0;
while (count > 0 && index < index_points.size()) {
// Check if this index contains the samples we're looking for
const IndexPoint &ip = index_points[index];
if (ip.start_sample <= start && ip.start_sample+ip.num_samples > start) {
auto write_buf = static_cast<char *>(buf);
auto bps = bytes_per_sample * channels;
int64_t pos = 0;
// How many samples we can maximum take from this block
int64_t samples_can_do = ip.num_samples - start + ip.start_sample;
if (samples_can_do > count) samples_can_do = count;
// Read as many samples we can
char *src = EnsureRangeAccessible(
ip.start_byte + (start - ip.start_sample) * bytes_per_sample * channels,
samples_can_do * bytes_per_sample * channels);
memcpy(buf, src, samples_can_do * bytes_per_sample * channels);
// Update data
buf = (char*)buf + samples_can_do * bytes_per_sample * channels;
start += samples_can_do;
count -= samples_can_do;
for (auto const& ip : index_points) {
if (count == 0) break;
if (pos + ip.num_samples < start) {
pos += ip.num_samples;
continue;
}
index++;
auto read_offset = start - pos;
auto read_count = std::min(count, ip.num_samples - read_offset);
auto bytes = read_count * bps;
memcpy(write_buf, file->read(ip.start_byte + read_offset * bps, bytes), bytes);
write_buf += bytes;
count -= read_count;
start += read_count;
pos += ip.num_samples;
}
}
@ -198,16 +209,9 @@ public:
if (!got_fmt_header) throw agi::AudioProviderOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.", nullptr);
int64_t samples = ch.size / bytes_per_sample;
int64_t frames = samples / channels;
IndexPoint ip;
ip.start_sample = num_samples;
ip.num_samples = frames;
ip.start_byte = filepos;
index_points.push_back(ip);
num_samples += frames;
auto samples = ch.size / bytes_per_sample / channels;
index_points.push_back(IndexPoint{filepos, samples});
num_samples += samples;
}
// Support wavl (wave list) chunks too?
@ -339,16 +343,9 @@ public:
if (!got_fmt_header)
throw agi::AudioProviderOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.", nullptr);
int64_t samples = chunk_size / bytes_per_sample;
int64_t frames = samples / channels;
IndexPoint ip;
ip.start_sample = num_samples;
ip.num_samples = frames;
ip.start_byte = filepos;
index_points.push_back(ip);
num_samples += frames;
auto samples = chunk_size / bytes_per_sample / channels;
index_points.push_back(IndexPoint{filepos, samples});
num_samples += samples;
}
// Update counters

View File

@ -1,59 +0,0 @@
// Copyright (c) 2007-2008, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
#include "include/aegisub/audio_provider.h"
#include <memory>
#include <vector>
namespace agi { class read_file_mapping; }
class PCMAudioProvider : public AudioProvider {
protected:
std::unique_ptr<agi::read_file_mapping> file;
PCMAudioProvider(agi::fs::path const& filename); // Create base object and open the file mapping
~PCMAudioProvider(); // Closes the file mapping
char *EnsureRangeAccessible(int64_t range_start, int64_t range_length) const; // Ensure that the given range of bytes are accessible in the file mapping and return a pointer to the first byte of the requested range
struct IndexPoint {
int64_t start_byte;
int64_t start_sample;
int64_t num_samples;
};
typedef std::vector<IndexPoint> IndexVector;
IndexVector index_points;
void FillBuffer(void *buf, int64_t start, int64_t count) const override;
};
// Construct the right PCM audio provider (if any) for the file
std::unique_ptr<AudioProvider> CreatePCMAudioProvider(agi::fs::path const& filename);