Use a proper auto-deleting temp file for the HD audio cache
This commit is contained in:
parent
a63db6b519
commit
b1f132ec6f
7 changed files with 164 additions and 183 deletions
|
@ -31,62 +31,14 @@
|
||||||
|
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
|
|
||||||
namespace agi {
|
namespace {
|
||||||
file_mapping::file_mapping(agi::fs::path const& filename, boost::interprocess::mode_t mode)
|
char *map(int64_t s_offset, uint64_t length, boost::interprocess::mode_t mode,
|
||||||
#ifdef _WIN32
|
uint64_t file_size, agi::file_mapping const& file,
|
||||||
: handle(CreateFileW(filename.wstring().c_str(), (unsigned int)mode, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0))
|
std::unique_ptr<mapped_region>& region, uint64_t& mapping_start)
|
||||||
{
|
{
|
||||||
if (handle == ipcdetail::invalid_file()) {
|
|
||||||
switch (GetLastError()) {
|
|
||||||
case ERROR_FILE_NOT_FOUND:
|
|
||||||
case ERROR_PATH_NOT_FOUND:
|
|
||||||
throw fs::FileNotFound(filename);
|
|
||||||
case ERROR_ACCESS_DENIED:
|
|
||||||
throw fs::ReadDenied(filename);
|
|
||||||
default:
|
|
||||||
throw fs::FileSystemUnknownError(util::ErrorString(GetLastError()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
: handle(ipcdetail::open_existing_file(filename.string().c_str(), mode))
|
|
||||||
{
|
|
||||||
if (handle == ipcdetail::invalid_file()) {
|
|
||||||
switch (errno) {
|
|
||||||
case ENOENT:
|
|
||||||
throw fs::FileNotFound(filename);
|
|
||||||
case EACCES:
|
|
||||||
throw fs::ReadDenied(filename);
|
|
||||||
case EIO:
|
|
||||||
throw fs::FileSystemUnknownError("Fatal I/O opening path: " + filename.string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
file_mapping::~file_mapping() {
|
|
||||||
if (handle != ipcdetail::invalid_file()) {
|
|
||||||
ipcdetail::close_file(handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
read_file_mapping::read_file_mapping(fs::path const& filename)
|
|
||||||
: file(filename, read_only)
|
|
||||||
{
|
|
||||||
offset_t size;
|
|
||||||
ipcdetail::get_file_size(file.get_mapping_handle().handle, size);
|
|
||||||
file_size = static_cast<uint64_t>(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
read_file_mapping::~read_file_mapping() { }
|
|
||||||
|
|
||||||
const char *read_file_mapping::read() {
|
|
||||||
return read(0, size());
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *read_file_mapping::read(int64_t s_offset, uint64_t length) {
|
|
||||||
auto offset = static_cast<uint64_t>(s_offset);
|
auto offset = static_cast<uint64_t>(s_offset);
|
||||||
if (offset + length > file_size)
|
if (offset + length > file_size)
|
||||||
throw InternalError("Attempted to map beyond end of file", nullptr);
|
throw agi::InternalError("Attempted to map beyond end of file", nullptr);
|
||||||
|
|
||||||
// Check if we can just use the current mapping
|
// Check if we can just use the current mapping
|
||||||
if (region && offset >= mapping_start && offset + length <= mapping_start + region->get_size())
|
if (region && offset >= mapping_start && offset + length <= mapping_start + region->get_size())
|
||||||
|
@ -108,12 +60,103 @@ const char *read_file_mapping::read(int64_t s_offset, uint64_t length) {
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
region = agi::util::make_unique<mapped_region>(file, read_only, mapping_start, static_cast<size_t>(length));
|
region = agi::util::make_unique<mapped_region>(file, mode, mapping_start, static_cast<size_t>(length));
|
||||||
}
|
}
|
||||||
catch (interprocess_exception const&) {
|
catch (interprocess_exception const&) {
|
||||||
throw fs::FileSystemUnknownError("Failed mapping a view of the file");
|
throw agi::fs::FileSystemUnknownError("Failed mapping a view of the file");
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<char *>(region->get_address()) + offset - mapping_start;
|
return static_cast<char *>(region->get_address()) + offset - mapping_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace agi {
|
||||||
|
file_mapping::file_mapping(fs::path const& filename, bool temporary)
|
||||||
|
#ifdef _WIN32
|
||||||
|
: handle(CreateFileW(filename.wstring().c_str(),
|
||||||
|
temporary ? read_write : read_only,
|
||||||
|
temporary ? FILE_SHARE_READ | FILE_SHARE_WRITE : FILE_SHARE_READ,
|
||||||
|
nullptr,
|
||||||
|
temporary ? OPEN_ALWAYS : OPEN_EXISTING,
|
||||||
|
0, 0))
|
||||||
|
{
|
||||||
|
if (handle == ipcdetail::invalid_file()) {
|
||||||
|
switch (GetLastError()) {
|
||||||
|
case ERROR_FILE_NOT_FOUND:
|
||||||
|
case ERROR_PATH_NOT_FOUND:
|
||||||
|
throw fs::FileNotFound(filename);
|
||||||
|
case ERROR_ACCESS_DENIED:
|
||||||
|
throw fs::ReadDenied(filename);
|
||||||
|
default:
|
||||||
|
throw fs::FileSystemUnknownError(util::ErrorString(GetLastError()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
: handle(temporary
|
||||||
|
? ipcdetail::create_or_open_file(filename.string().c_str(), read_write)
|
||||||
|
: ipcdetail::open_existing_file(filename.string().c_str(), read_only))
|
||||||
|
{
|
||||||
|
if (handle == ipcdetail::invalid_file()) {
|
||||||
|
switch (errno) {
|
||||||
|
case ENOENT:
|
||||||
|
throw fs::FileNotFound(filename);
|
||||||
|
case EACCES:
|
||||||
|
throw fs::ReadDenied(filename);
|
||||||
|
case EIO:
|
||||||
|
throw fs::FileSystemUnknownError("Fatal I/O opening path: " + filename.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
file_mapping::~file_mapping() {
|
||||||
|
if (handle != ipcdetail::invalid_file()) {
|
||||||
|
ipcdetail::close_file(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_file_mapping::read_file_mapping(fs::path const& filename)
|
||||||
|
: file(filename, false)
|
||||||
|
{
|
||||||
|
offset_t size;
|
||||||
|
ipcdetail::get_file_size(file.get_mapping_handle().handle, size);
|
||||||
|
file_size = static_cast<uint64_t>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
read_file_mapping::~read_file_mapping() { }
|
||||||
|
|
||||||
|
const char *read_file_mapping::read() {
|
||||||
|
return read(0, size());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *read_file_mapping::read(int64_t offset, uint64_t length) {
|
||||||
|
return map(offset, length, read_only, file_size, file, region, mapping_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_file_mapping::temp_file_mapping(fs::path const& filename, uint64_t size)
|
||||||
|
: file(filename, true)
|
||||||
|
, file_size(size)
|
||||||
|
{
|
||||||
|
auto handle = file.get_mapping_handle().handle;
|
||||||
|
#ifdef _WIN32
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = size;
|
||||||
|
SetFilePointerEx(handle, li, nullptr, FILE_BEGIN);
|
||||||
|
SetEndOfFile(handle);
|
||||||
|
#else
|
||||||
|
ftruncate(handle, size);
|
||||||
|
unlink(filename.string().c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_file_mapping::~temp_file_mapping() { }
|
||||||
|
|
||||||
|
const char *temp_file_mapping::read(int64_t offset, uint64_t length) {
|
||||||
|
return write(offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *temp_file_mapping::write(int64_t offset, uint64_t length) {
|
||||||
|
return map(offset, length, read_write, file_size, file, region, mapping_start);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace agi {
|
||||||
boost::interprocess::file_handle_t handle;
|
boost::interprocess::file_handle_t handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
file_mapping(fs::path const& filename, boost::interprocess::mode_t mode);
|
file_mapping(fs::path const& filename, bool temporary);
|
||||||
~file_mapping();
|
~file_mapping();
|
||||||
boost::interprocess::mapping_handle_t get_mapping_handle() const {
|
boost::interprocess::mapping_handle_t get_mapping_handle() const {
|
||||||
return boost::interprocess::ipcdetail::mapping_handle_from_file_handle(handle);
|
return boost::interprocess::ipcdetail::mapping_handle_from_file_handle(handle);
|
||||||
|
@ -46,4 +46,18 @@ namespace agi {
|
||||||
const char *read(int64_t offset, uint64_t length);
|
const char *read(int64_t offset, uint64_t length);
|
||||||
const char *read(); // Map the entire file
|
const char *read(); // Map the entire file
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class temp_file_mapping {
|
||||||
|
file_mapping file;
|
||||||
|
std::unique_ptr<boost::interprocess::mapped_region> region;
|
||||||
|
uint64_t mapping_start = 0;
|
||||||
|
uint64_t file_size = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
temp_file_mapping(fs::path const& filename, uint64_t size);
|
||||||
|
~temp_file_mapping();
|
||||||
|
|
||||||
|
const char *read(int64_t offset, uint64_t length);
|
||||||
|
char *write(int64_t offset, uint64_t length);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,19 @@
|
||||||
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
|
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
/// @file audio_provider_hd.cpp
|
|
||||||
/// @brief Caching audio provider using a file for backing
|
|
||||||
/// @ingroup audio_input
|
|
||||||
///
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "audio_provider_hd.h"
|
#include "audio_provider_hd.h"
|
||||||
|
@ -39,82 +21,55 @@
|
||||||
#include "audio_controller.h"
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#include <libaegisub/access.h>
|
|
||||||
#include <libaegisub/background_runner.h>
|
#include <libaegisub/background_runner.h>
|
||||||
#include <libaegisub/file_mapping.h>
|
#include <libaegisub/file_mapping.h>
|
||||||
#include <libaegisub/fs.h>
|
#include <libaegisub/fs.h>
|
||||||
#include <libaegisub/io.h>
|
|
||||||
#include <libaegisub/path.h>
|
#include <libaegisub/path.h>
|
||||||
#include <libaegisub/util.h>
|
#include <libaegisub/util.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
namespace {
|
#include <boost/interprocess/detail/os_thread_functions.hpp>
|
||||||
agi::fs::path cache_dir() {
|
|
||||||
std::string path = OPT_GET("Audio/Cache/HD/Location")->GetString();
|
|
||||||
if (path == "default")
|
|
||||||
path = "?temp";
|
|
||||||
|
|
||||||
return config::path->MakeAbsolute(config::path->Decode(path), "?temp");
|
|
||||||
}
|
|
||||||
|
|
||||||
agi::fs::path cache_path() {
|
|
||||||
std::string pattern = OPT_GET("Audio/Cache/HD/Name")->GetString();
|
|
||||||
if (!boost::contains(pattern, "%02i")) pattern = "audio%02i.tmp";
|
|
||||||
boost::replace_all(pattern, "%02i", "%%%%-%%%%-%%%%-%%%%");
|
|
||||||
return unique_path(cache_dir()/pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br)
|
HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br)
|
||||||
: AudioProviderWrapper(std::move(src))
|
: AudioProviderWrapper(std::move(src))
|
||||||
, cache_filename(cache_path())
|
|
||||||
{
|
{
|
||||||
|
auto path = OPT_GET("Audio/Cache/HD/Location")->GetString();
|
||||||
|
if (path == "default")
|
||||||
|
path = "?temp";
|
||||||
|
auto cache_dir = config::path->MakeAbsolute(config::path->Decode(path), "?temp");
|
||||||
|
|
||||||
|
auto bps = bytes_per_sample * channels;
|
||||||
|
|
||||||
// Check free space
|
// Check free space
|
||||||
if ((uint64_t)num_samples * channels * bytes_per_sample > agi::fs::FreeSpace(cache_dir()))
|
if ((uint64_t)num_samples * bps > agi::fs::FreeSpace(cache_dir))
|
||||||
throw agi::AudioCacheOpenError("Not enough free disk space in " + cache_dir().string() + " to cache the audio", nullptr);
|
throw agi::AudioCacheOpenError("Not enough free disk space in " + cache_dir.string() + " to cache the audio", nullptr);
|
||||||
|
|
||||||
try {
|
auto filename = str(boost::format("audio-%lld-%lld")
|
||||||
{
|
% (long long)time(nullptr)
|
||||||
agi::io::Save out(cache_filename, true);
|
% (long long)boost::interprocess::ipcdetail::get_current_process_id());
|
||||||
br->Run(bind(&HDAudioProvider::FillCache, this, source.get(), &out.Get(), std::placeholders::_1));
|
|
||||||
|
file = agi::util::make_unique<agi::temp_file_mapping>(cache_dir / filename, num_samples * bps);
|
||||||
|
br->Run([&] (agi::ProgressSink *ps) {
|
||||||
|
ps->SetMessage(from_wx(_("Reading to Hard Disk cache")));
|
||||||
|
|
||||||
|
int64_t block = 65536;
|
||||||
|
for (int64_t i = 0; i < num_samples; i += block) {
|
||||||
|
block = std::min(block, num_samples - i);
|
||||||
|
source->GetAudio(file->write(i * bps, block * bps), i, block);
|
||||||
|
ps->SetProgress(i, num_samples);
|
||||||
|
if (ps->IsCancelled()) return;
|
||||||
}
|
}
|
||||||
file = agi::util::make_unique<agi::read_file_mapping>(cache_filename);
|
});
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
agi::fs::Remove(cache_filename);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HDAudioProvider::~HDAudioProvider() {
|
HDAudioProvider::~HDAudioProvider() { }
|
||||||
file.reset(); // explicitly close the file so we can delete it
|
|
||||||
agi::fs::Remove(cache_filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HDAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
|
void HDAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
|
||||||
start *= channels * bytes_per_sample;
|
start *= channels * bytes_per_sample;
|
||||||
count *= channels * bytes_per_sample;
|
count *= channels * bytes_per_sample;
|
||||||
memcpy(buf, file->read(start, count), count);
|
memcpy(buf, file->read(start, count), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HDAudioProvider::FillCache(AudioProvider *src, std::ostream *out, agi::ProgressSink *ps) {
|
|
||||||
ps->SetMessage(from_wx(_("Reading to Hard Disk cache")));
|
|
||||||
|
|
||||||
int64_t block = 65536;
|
|
||||||
std::vector<char> read_buf;
|
|
||||||
read_buf.resize(block * channels * bytes_per_sample);
|
|
||||||
|
|
||||||
for (int64_t i = 0; i < num_samples; i += block) {
|
|
||||||
block = std::min(block, num_samples - i);
|
|
||||||
src->GetAudio(&read_buf[0], i, block);
|
|
||||||
out->write(&read_buf[0], block * channels * bytes_per_sample);
|
|
||||||
ps->SetProgress(i, num_samples);
|
|
||||||
|
|
||||||
if (ps->IsCancelled()) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,55 +1,28 @@
|
||||||
// Copyright (c) 2006, Rodrigo Braz Monteiro
|
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
/// @file audio_provider_hd.h
|
|
||||||
/// @see audio_provider_hd.cpp
|
|
||||||
/// @ingroup audio_input
|
|
||||||
///
|
|
||||||
|
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
class BackgroundRunner;
|
class BackgroundRunner;
|
||||||
class ProgressSink;
|
class temp_file_mapping;
|
||||||
class read_file_mapping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class HDAudioProvider final : public AudioProviderWrapper {
|
class HDAudioProvider final : public AudioProviderWrapper {
|
||||||
/// Name of the file which the decoded audio is written to
|
std::unique_ptr<agi::temp_file_mapping> file;
|
||||||
agi::fs::path cache_filename;
|
|
||||||
std::unique_ptr<agi::read_file_mapping> file;
|
|
||||||
|
|
||||||
/// Fill the cache with all of the data from the source audio provider
|
|
||||||
/// @param src Audio data to cache
|
|
||||||
/// @param file File to write to
|
|
||||||
/// @param ps Sink for progress reporting
|
|
||||||
void FillCache(AudioProvider *src, std::ostream *file, agi::ProgressSink *ps);
|
|
||||||
|
|
||||||
void FillBuffer(void *buf, int64_t start, int64_t count) const override;
|
void FillBuffer(void *buf, int64_t start, int64_t count) const override;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
"Cache" : {
|
"Cache" : {
|
||||||
"HD" : {
|
"HD" : {
|
||||||
"Location" : "default",
|
"Location" : "default",
|
||||||
"Name" : "audio%02i.tmp"
|
|
||||||
},
|
},
|
||||||
"Type" : 1
|
"Type" : 1
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
"Cache" : {
|
"Cache" : {
|
||||||
"HD" : {
|
"HD" : {
|
||||||
"Location" : "default",
|
"Location" : "default",
|
||||||
"Name" : "audio%02i.tmp"
|
|
||||||
},
|
},
|
||||||
"Type" : 1
|
"Type" : 1
|
||||||
},
|
},
|
||||||
|
|
|
@ -507,9 +507,7 @@ Advanced_Audio::Advanced_Audio(wxTreebook *book, Preferences *parent): OptionPag
|
||||||
const wxString ct_arr[3] = { _("None (NOT RECOMMENDED)"), _("RAM"), _("Hard Disk") };
|
const wxString ct_arr[3] = { _("None (NOT RECOMMENDED)"), _("RAM"), _("Hard Disk") };
|
||||||
wxArrayString ct_choice(3, ct_arr);
|
wxArrayString ct_choice(3, ct_arr);
|
||||||
OptionChoice(cache, _("Cache type"), ct_choice, "Audio/Cache/Type");
|
OptionChoice(cache, _("Cache type"), ct_choice, "Audio/Cache/Type");
|
||||||
|
|
||||||
OptionBrowse(cache, _("Path"), "Audio/Cache/HD/Location");
|
OptionBrowse(cache, _("Path"), "Audio/Cache/HD/Location");
|
||||||
OptionAdd(cache, _("File name"), "Audio/Cache/HD/Name");
|
|
||||||
|
|
||||||
wxFlexGridSizer *spectrum = PageSizer(_("Spectrum"));
|
wxFlexGridSizer *spectrum = PageSizer(_("Spectrum"));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue