Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
57e0cc5442 | ||
![]() |
73f45d87d5 | ||
![]() |
ae88ba986e | ||
![]() |
d6247902ec | ||
![]() |
a566c28a49 | ||
![]() |
2eddb63a83 | ||
![]() |
fc7d5b055d | ||
![]() |
87c8953e8e | ||
![]() |
45d27a52f1 | ||
![]() |
d22acc59c9 | ||
![]() |
c064e8d62f | ||
![]() |
099a2cb586 | ||
![]() |
042fe2a9d0 | ||
![]() |
ff1c1107f3 | ||
![]() |
41a3fd0fd0 | ||
![]() |
b9169a5670 | ||
![]() |
2ecd5fa28d | ||
![]() |
e719b6cc41 | ||
![]() |
67b8124a1d | ||
![]() |
51ec499c89 | ||
![]() |
3a4df25db2 | ||
![]() |
37cf78ef45 | ||
![]() |
727c622659 | ||
![]() |
74a778e65f | ||
![]() |
1fc0c9fe8a | ||
![]() |
740d8ec5ab | ||
![]() |
0bcc477d46 | ||
![]() |
35297f8d4f | ||
![]() |
6f4202408c | ||
![]() |
0b6548a282 | ||
![]() |
faf5821816 | ||
![]() |
188673b746 | ||
![]() |
287c70e361 | ||
![]() |
f6b44af998 | ||
![]() |
84c3d9674f | ||
![]() |
47d3758820 | ||
![]() |
573ff3a24f | ||
![]() |
32fcc22cb3 |
NEWSconfigure.ac
doc
src
DatabaseGlue.cxxDatabasePlugin.hxxDatabaseSimple.hxxDecoderAPI.cxxDecoderThread.cxxDespotifyUtils.cxxMapper.cxxMapper.hxxSongSave.cxxStats.cxxStats.hxx
archive
db
decoder
encoder
filter
input
output
pcm
system
util
test
22
NEWS
22
NEWS
@@ -1,3 +1,25 @@
|
||||
ver 0.18.5 (2013/11/23)
|
||||
* configuration
|
||||
- fix crash when db_file is configured without music_directory
|
||||
- fix crash on "stats" without db_file/music_directory
|
||||
* database
|
||||
- proxy: auto-reload statistics
|
||||
- proxy: provide "db_update" in "stats" response
|
||||
* input
|
||||
- curl: work around stream resume bug (fixed in libcurl 7.32.0)
|
||||
* decoder
|
||||
- fluidsynth: auto-detect by default
|
||||
* clip 24 bit data from libsamplerate
|
||||
* fix ia64, mipsel and other little-endian architectures
|
||||
* fix build failures due to missing includes
|
||||
* fix build failure with static libmpdclient
|
||||
|
||||
ver 0.18.4 (2013/11/13)
|
||||
* decoder
|
||||
- dsdiff: fix byte order bug
|
||||
* fix build failures due to missing includes
|
||||
* libc++ compatibility
|
||||
|
||||
ver 0.18.3 (2013/11/08)
|
||||
* fix stuck MPD after song change (0.18.2 regression)
|
||||
|
||||
|
10
configure.ac
10
configure.ac
@@ -1,6 +1,6 @@
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT(mpd, 0.18.3, musicpd-dev-team@lists.sourceforge.net)
|
||||
AC_INIT(mpd, 0.18.5, musicpd-dev-team@lists.sourceforge.net)
|
||||
|
||||
VERSION_MAJOR=0
|
||||
VERSION_MINOR=18
|
||||
@@ -874,10 +874,12 @@ AM_CONDITIONAL(HAVE_FLAC, test x$enable_flac = xyes)
|
||||
enable_flac_encoder=$enable_flac
|
||||
|
||||
dnl -------------------------------- FluidSynth -------------------------------
|
||||
|
||||
MPD_AUTO_PKG(fluidsynth, FLUIDSYNTH, [fluidsynth >= 1.1],
|
||||
[fluidsynth decoder], [fluidsynth not found])
|
||||
|
||||
if test x$enable_fluidsynth = xyes; then
|
||||
PKG_CHECK_MODULES(FLUIDSYNTH, [fluidsynth >= 1.1],
|
||||
AC_DEFINE(ENABLE_FLUIDSYNTH, 1, [Define for fluidsynth support]),
|
||||
enable_fluidsynth=no)
|
||||
AC_DEFINE(ENABLE_FLUIDSYNTH, 1, [Define for fluidsynth support])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(ENABLE_FLUIDSYNTH, test x$enable_fluidsynth = xyes)
|
||||
|
@@ -210,7 +210,6 @@ input {
|
||||
# type "alsa"
|
||||
# name "My ALSA Device"
|
||||
## device "hw:0,0" # optional
|
||||
## format "44100:16:2" # optional
|
||||
## mixer_type "hardware" # optional
|
||||
## mixer_device "default" # optional
|
||||
## mixer_control "PCM" # optional
|
||||
@@ -223,7 +222,6 @@ input {
|
||||
# type "oss"
|
||||
# name "My OSS Device"
|
||||
## device "/dev/dsp" # optional
|
||||
## format "44100:16:2" # optional
|
||||
## mixer_type "hardware" # optional
|
||||
## mixer_device "/dev/mixer" # optional
|
||||
## mixer_control "PCM" # optional
|
||||
@@ -327,12 +325,6 @@ input {
|
||||
# mixer_type "none" # optional
|
||||
#}
|
||||
#
|
||||
# This setting will change all decoded audio to be converted to the specified
|
||||
# format before being passed to the audio outputs. By default, this setting is
|
||||
# disabled.
|
||||
#
|
||||
#audio_output_format "44100:16:2"
|
||||
#
|
||||
# If MPD has been compiled with libsamplerate support, this setting specifies
|
||||
# the sample rate converter to use. Possible values can be found in the
|
||||
# mpd.conf man page or the libsamplerate documentation. By default, this is
|
||||
|
@@ -148,12 +148,12 @@ DatabaseGlobalOpen(Error &error)
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t
|
||||
db_get_mtime(void)
|
||||
bool
|
||||
db_exists()
|
||||
{
|
||||
assert(db != nullptr);
|
||||
assert(db_is_open);
|
||||
assert(db_is_simple());
|
||||
|
||||
return ((SimpleDatabase *)db)->GetLastModified();
|
||||
return ((SimpleDatabase *)db)->GetUpdateStamp() > 0;
|
||||
}
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include "tag/TagType.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct config_param;
|
||||
struct DatabaseSelection;
|
||||
struct db_visitor;
|
||||
@@ -132,6 +134,13 @@ public:
|
||||
virtual bool GetStats(const DatabaseSelection &selection,
|
||||
DatabaseStats &stats,
|
||||
Error &error) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the time stamp of the last database update.
|
||||
* Returns 0 if that is not not known/available.
|
||||
*/
|
||||
gcc_pure
|
||||
virtual time_t GetUpdateStamp() const = 0;
|
||||
};
|
||||
|
||||
struct DatabasePlugin {
|
||||
|
@@ -62,25 +62,13 @@ db_get_directory(const char *name);
|
||||
bool
|
||||
db_save(Error &error);
|
||||
|
||||
/**
|
||||
* May only be used if db_is_simple() returns true.
|
||||
*/
|
||||
gcc_pure
|
||||
time_t
|
||||
db_get_mtime(void);
|
||||
|
||||
/**
|
||||
* Returns true if there is a valid database file on the disk.
|
||||
*
|
||||
* May only be used if db_is_simple() returns true.
|
||||
*/
|
||||
gcc_pure
|
||||
static inline bool
|
||||
db_exists(void)
|
||||
{
|
||||
/* mtime is set only if the database file was loaded or saved
|
||||
successfully */
|
||||
return db_get_mtime() > 0;
|
||||
}
|
||||
bool
|
||||
db_exists();
|
||||
|
||||
#endif
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
void
|
||||
decoder_initialized(Decoder &decoder,
|
||||
|
@@ -38,6 +38,8 @@
|
||||
#include "tag/ApeReplayGain.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <functional>
|
||||
|
||||
static constexpr Domain decoder_thread_domain("decoder_thread");
|
||||
|
||||
/**
|
||||
|
@@ -28,6 +28,8 @@ extern "C" {
|
||||
#include <despotify.h>
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
const Domain despotify_domain("despotify");
|
||||
|
||||
static struct despotify_session *g_session;
|
||||
|
@@ -133,7 +133,9 @@ void mapper_finish(void)
|
||||
const char *
|
||||
mapper_get_music_directory_utf8(void)
|
||||
{
|
||||
return music_dir_utf8.c_str();
|
||||
return music_dir_utf8.empty()
|
||||
? nullptr
|
||||
: music_dir_utf8.c_str();
|
||||
}
|
||||
|
||||
const AllocatedPath &
|
||||
|
@@ -41,7 +41,8 @@ mapper_init(AllocatedPath &&music_dir, AllocatedPath &&playlist_dir);
|
||||
void mapper_finish(void);
|
||||
|
||||
/**
|
||||
* Return the absolute path of the music directory encoded in UTF-8.
|
||||
* Return the absolute path of the music directory encoded in UTF-8 or
|
||||
* nullptr if no music directory was configured.
|
||||
*/
|
||||
gcc_const
|
||||
const char *
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SONG_MTIME "mtime"
|
||||
#define SONG_END "song_end"
|
||||
|
@@ -30,59 +30,75 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
struct stats stats;
|
||||
static GTimer *uptime;
|
||||
static DatabaseStats stats;
|
||||
|
||||
void stats_global_init(void)
|
||||
{
|
||||
stats.timer = g_timer_new();
|
||||
uptime = g_timer_new();
|
||||
}
|
||||
|
||||
void stats_global_finish(void)
|
||||
{
|
||||
g_timer_destroy(stats.timer);
|
||||
g_timer_destroy(uptime);
|
||||
}
|
||||
|
||||
void stats_update(void)
|
||||
{
|
||||
assert(GetDatabase() != nullptr);
|
||||
|
||||
Error error;
|
||||
|
||||
DatabaseStats stats2;
|
||||
|
||||
const DatabaseSelection selection("", true);
|
||||
if (GetDatabase()->GetStats(selection, stats2, error)) {
|
||||
stats.song_count = stats2.song_count;
|
||||
stats.song_duration = stats2.total_duration;
|
||||
stats.artist_count = stats2.artist_count;
|
||||
stats.album_count = stats2.album_count;
|
||||
stats = stats2;
|
||||
} else {
|
||||
LogError(error);
|
||||
|
||||
stats.song_count = 0;
|
||||
stats.song_duration = 0;
|
||||
stats.artist_count = 0;
|
||||
stats.album_count = 0;
|
||||
stats.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
db_stats_print(Client &client)
|
||||
{
|
||||
assert(GetDatabase() != nullptr);
|
||||
|
||||
if (!db_is_simple())
|
||||
/* reload statistics if we're using the "proxy"
|
||||
database plugin */
|
||||
/* TODO: move this into the "proxy" database plugin as
|
||||
an "idle" handler */
|
||||
stats_update();
|
||||
|
||||
client_printf(client,
|
||||
"artists: %u\n"
|
||||
"albums: %u\n"
|
||||
"songs: %u\n"
|
||||
"db_playtime: %lu\n",
|
||||
stats.artist_count,
|
||||
stats.album_count,
|
||||
stats.song_count,
|
||||
stats.total_duration);
|
||||
|
||||
const time_t update_stamp = GetDatabase()->GetUpdateStamp();
|
||||
if (update_stamp > 0)
|
||||
client_printf(client,
|
||||
"db_update: %lu\n",
|
||||
(unsigned long)update_stamp);
|
||||
}
|
||||
|
||||
void
|
||||
stats_print(Client &client)
|
||||
{
|
||||
client_printf(client,
|
||||
"artists: %u\n"
|
||||
"albums: %u\n"
|
||||
"songs: %i\n"
|
||||
"uptime: %li\n"
|
||||
"playtime: %li\n"
|
||||
"db_playtime: %li\n",
|
||||
stats.artist_count,
|
||||
stats.album_count,
|
||||
stats.song_count,
|
||||
(long)g_timer_elapsed(stats.timer, NULL),
|
||||
(long)(client.player_control.GetTotalPlayTime() + 0.5),
|
||||
stats.song_duration);
|
||||
"uptime: %lu\n"
|
||||
"playtime: %lu\n",
|
||||
(unsigned long)g_timer_elapsed(uptime, NULL),
|
||||
(unsigned long)(client.player_control.GetTotalPlayTime() + 0.5));
|
||||
|
||||
if (db_is_simple())
|
||||
client_printf(client,
|
||||
"db_update: %li\n",
|
||||
(long)db_get_mtime());
|
||||
if (GetDatabase() != nullptr)
|
||||
db_stats_print(client);
|
||||
}
|
||||
|
@@ -21,26 +21,6 @@
|
||||
#define MPD_STATS_HXX
|
||||
|
||||
class Client;
|
||||
typedef struct _GTimer GTimer;
|
||||
|
||||
struct stats {
|
||||
GTimer *timer;
|
||||
|
||||
/** number of song files in the music directory */
|
||||
unsigned song_count;
|
||||
|
||||
/** sum of all song durations in the music directory (in
|
||||
seconds) */
|
||||
unsigned long song_duration;
|
||||
|
||||
/** number of distinct artist names in the music directory */
|
||||
unsigned artist_count;
|
||||
|
||||
/** number of distinct album names in the music directory */
|
||||
unsigned album_count;
|
||||
};
|
||||
|
||||
extern struct stats stats;
|
||||
|
||||
void stats_global_init(void);
|
||||
|
||||
|
@@ -190,18 +190,16 @@ iso9660_input_read(InputStream *is, void *ptr, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
Iso9660InputStream *iis = (Iso9660InputStream *)is;
|
||||
int toread, readed = 0;
|
||||
int readed = 0;
|
||||
int no_blocks, cur_block;
|
||||
size_t left_bytes = iis->statbuf->size - is->offset;
|
||||
|
||||
size = (size * ISO_BLOCKSIZE) / ISO_BLOCKSIZE;
|
||||
|
||||
if (left_bytes < size) {
|
||||
toread = left_bytes;
|
||||
no_blocks = CEILING(left_bytes,ISO_BLOCKSIZE);
|
||||
} else {
|
||||
toread = size;
|
||||
no_blocks = toread / ISO_BLOCKSIZE;
|
||||
no_blocks = size / ISO_BLOCKSIZE;
|
||||
}
|
||||
if (no_blocks > 0) {
|
||||
|
||||
|
@@ -46,6 +46,9 @@ class ProxyDatabase : public Database {
|
||||
struct mpd_connection *connection;
|
||||
Directory *root;
|
||||
|
||||
/* this is mutable because GetStats() must be "const" */
|
||||
mutable time_t update_stamp;
|
||||
|
||||
public:
|
||||
static Database *Create(const config_param ¶m,
|
||||
Error &error);
|
||||
@@ -71,6 +74,10 @@ public:
|
||||
DatabaseStats &stats,
|
||||
Error &error) const override;
|
||||
|
||||
virtual time_t GetUpdateStamp() const override {
|
||||
return update_stamp;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
@@ -237,6 +244,7 @@ ProxyDatabase::Open(Error &error)
|
||||
return false;
|
||||
|
||||
root = Directory::NewRoot();
|
||||
update_stamp = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -631,6 +639,8 @@ ProxyDatabase::GetStats(const DatabaseSelection &selection,
|
||||
if (stats2 == nullptr)
|
||||
return CheckError(connection, error);
|
||||
|
||||
update_stamp = (time_t)mpd_stats_get_db_update_time(stats2);
|
||||
|
||||
stats.song_count = mpd_stats_get_number_of_songs(stats2);
|
||||
stats.total_duration = mpd_stats_get_db_play_time(stats2);
|
||||
stats.artist_count = mpd_stats_get_number_of_artists(stats2);
|
||||
|
@@ -26,8 +26,6 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct Directory;
|
||||
|
||||
class SimpleDatabase : public Database {
|
||||
@@ -55,11 +53,6 @@ public:
|
||||
|
||||
bool Save(Error &error);
|
||||
|
||||
gcc_pure
|
||||
time_t GetLastModified() const {
|
||||
return mtime;
|
||||
}
|
||||
|
||||
static Database *Create(const config_param ¶m,
|
||||
Error &error);
|
||||
|
||||
@@ -85,6 +78,10 @@ public:
|
||||
DatabaseStats &stats,
|
||||
Error &error) const override;
|
||||
|
||||
virtual time_t GetUpdateStamp() const override {
|
||||
return mtime;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
|
@@ -47,6 +47,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DffDsdUint64 {
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
|
||||
public:
|
||||
constexpr uint64_t Read() const {
|
||||
return (uint64_t(FromBE32(hi)) << 32) |
|
||||
uint64_t(FromBE32(lo));
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
dsdlib_read(Decoder *decoder, InputStream &is,
|
||||
void *data, size_t length);
|
||||
|
@@ -43,13 +43,13 @@
|
||||
|
||||
struct DsdiffHeader {
|
||||
DsdId id;
|
||||
DsdUint64 size;
|
||||
DffDsdUint64 size;
|
||||
DsdId format;
|
||||
};
|
||||
|
||||
struct DsdiffChunkHeader {
|
||||
DsdId id;
|
||||
DsdUint64 size;
|
||||
DffDsdUint64 size;
|
||||
|
||||
/**
|
||||
* Read the "size" attribute from the specified header, converting it
|
||||
@@ -294,7 +294,6 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
|
||||
if (!dsdiff_read_chunk_header(decoder, is, chunk_header))
|
||||
return false;
|
||||
}
|
||||
chunk_size = 0;
|
||||
}
|
||||
/* done processing chunk headers, process tags if any */
|
||||
|
||||
@@ -385,10 +384,10 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is,
|
||||
while (chunk_size > 0) {
|
||||
/* see how much aligned data from the remaining chunk
|
||||
fits into the local buffer */
|
||||
unsigned now_frames = buffer_frames;
|
||||
size_t now_size = buffer_size;
|
||||
if (chunk_size < (uint64_t)now_size) {
|
||||
now_frames = (unsigned)chunk_size / frame_size;
|
||||
unsigned now_frames =
|
||||
(unsigned)chunk_size / frame_size;
|
||||
now_size = now_frames * frame_size;
|
||||
}
|
||||
|
||||
|
@@ -240,10 +240,10 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
|
||||
while (chunk_size > 0) {
|
||||
/* see how much aligned data from the remaining chunk
|
||||
fits into the local buffer */
|
||||
unsigned now_frames = buffer_frames;
|
||||
size_t now_size = buffer_size;
|
||||
if (chunk_size < (uint64_t)now_size) {
|
||||
now_frames = (unsigned)chunk_size / frame_size;
|
||||
unsigned now_frames =
|
||||
(unsigned)chunk_size / frame_size;
|
||||
now_size = now_frames * frame_size;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include "OggSyncState.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
bool
|
||||
OggFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet)
|
||||
{
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct opus_encoder {
|
||||
/** the base class */
|
||||
|
@@ -56,6 +56,7 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
class RouteFilter final : public Filter {
|
||||
/**
|
||||
|
@@ -273,12 +273,27 @@ public:
|
||||
SocketAction(CURL_SOCKET_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a kludge to allow pausing/resuming a stream with
|
||||
* libcurl < 7.32.0. Read the curl_easy_pause manpage for
|
||||
* more information.
|
||||
*/
|
||||
void ResumeSockets() {
|
||||
int running_handles;
|
||||
curl_multi_socket_all(multi, &running_handles);
|
||||
}
|
||||
|
||||
private:
|
||||
static int TimerFunction(CURLM *multi, long timeout_ms, void *userp);
|
||||
|
||||
virtual void OnTimeout() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* libcurl version number encoded in a 24 bit integer.
|
||||
*/
|
||||
static unsigned curl_version_num;
|
||||
|
||||
/** libcurl should accept "ICY 200 OK" */
|
||||
static struct curl_slist *http_200_aliases;
|
||||
|
||||
@@ -330,6 +345,13 @@ input_curl_resume(struct input_curl *c)
|
||||
if (c->paused) {
|
||||
c->paused = false;
|
||||
curl_easy_pause(c->easy, CURLPAUSE_CONT);
|
||||
|
||||
if (curl_version_num < 0x072000)
|
||||
/* libcurl older than 7.32.0 does not update
|
||||
its sockets after curl_easy_pause(); force
|
||||
libcurl to do it now */
|
||||
curl_multi->ResumeSockets();
|
||||
|
||||
curl_multi->InvalidateSockets();
|
||||
}
|
||||
}
|
||||
@@ -586,6 +608,16 @@ input_curl_init(const config_param ¶m, Error &error)
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto version_info = curl_version_info(CURLVERSION_FIRST);
|
||||
if (version_info != nullptr) {
|
||||
FormatDebug(curl_domain, "version %s", version_info->version);
|
||||
if (version_info->features & CURL_VERSION_SSL)
|
||||
FormatDebug(curl_domain, "with %s",
|
||||
version_info->ssl_version);
|
||||
|
||||
curl_version_num = version_info->version_num;
|
||||
}
|
||||
|
||||
http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK");
|
||||
|
||||
proxy = param.GetBlockValue("proxy");
|
||||
|
@@ -30,6 +30,11 @@
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "event/ServerSocket.hxx"
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
/* can't use incomplete template arguments with libc++ */
|
||||
#include "HttpdClient.hxx"
|
||||
#endif
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
struct config_param;
|
||||
|
@@ -148,3 +148,26 @@ PcmResampler::Resample32(unsigned channels, unsigned src_rate,
|
||||
src_rate, src_buffer, src_size,
|
||||
dest_rate, dest_size_r);
|
||||
}
|
||||
|
||||
const int32_t *
|
||||
PcmResampler::Resample24(unsigned channels, unsigned src_rate,
|
||||
const int32_t *src_buffer, size_t src_size,
|
||||
unsigned dest_rate, size_t *dest_size_r,
|
||||
Error &error_r)
|
||||
{
|
||||
#ifdef HAVE_LIBSAMPLERATE
|
||||
if (pcm_resample_lsr_enabled())
|
||||
return pcm_resample_lsr_24(this, channels,
|
||||
src_rate, src_buffer, src_size,
|
||||
dest_rate, dest_size_r,
|
||||
error_r);
|
||||
#else
|
||||
(void)error_r;
|
||||
#endif
|
||||
|
||||
/* reuse the 32 bit code - the resampler code doesn't care if
|
||||
the upper 8 bits are actually used */
|
||||
return pcm_resample_fallback_32(this, channels,
|
||||
src_rate, src_buffer, src_size,
|
||||
dest_rate, dest_size_r);
|
||||
}
|
||||
|
@@ -124,13 +124,7 @@ struct PcmResampler {
|
||||
const int32_t *Resample24(unsigned channels, unsigned src_rate,
|
||||
const int32_t *src_buffer, size_t src_size,
|
||||
unsigned dest_rate, size_t *dest_size_r,
|
||||
Error &error_r)
|
||||
{
|
||||
/* reuse the 32 bit code - the resampler code doesn't care if
|
||||
the upper 8 bits are actually used */
|
||||
return Resample32(channels, src_rate, src_buffer, src_size,
|
||||
dest_rate, dest_size_r, error_r);
|
||||
}
|
||||
Error &error_r);
|
||||
};
|
||||
|
||||
bool
|
||||
|
@@ -69,6 +69,15 @@ pcm_resample_lsr_32(PcmResampler *state,
|
||||
unsigned dest_rate, size_t *dest_size_r,
|
||||
Error &error);
|
||||
|
||||
const int32_t *
|
||||
pcm_resample_lsr_24(PcmResampler *state,
|
||||
unsigned channels,
|
||||
unsigned src_rate,
|
||||
const int32_t *src_buffer,
|
||||
size_t src_size,
|
||||
unsigned dest_rate, size_t *dest_size_r,
|
||||
Error &error);
|
||||
|
||||
#endif
|
||||
|
||||
const int16_t *
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "PcmResampleInternal.hxx"
|
||||
#include "PcmUtils.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
@@ -283,3 +284,27 @@ pcm_resample_lsr_32(PcmResampler *state,
|
||||
|
||||
return dest_buffer;
|
||||
}
|
||||
|
||||
const int32_t *
|
||||
pcm_resample_lsr_24(PcmResampler *state,
|
||||
unsigned channels,
|
||||
unsigned src_rate,
|
||||
const int32_t *src_buffer, size_t src_size,
|
||||
unsigned dest_rate, size_t *dest_size_r,
|
||||
Error &error)
|
||||
{
|
||||
const auto result = pcm_resample_lsr_32(state, channels,
|
||||
src_rate, src_buffer, src_size,
|
||||
dest_rate, dest_size_r,
|
||||
error);
|
||||
if (result != nullptr)
|
||||
/* src_float_to_int_array() clamps for 32 bit
|
||||
integers; now make sure everything's fine for 24
|
||||
bit */
|
||||
/* TODO: eliminate the 32 bit clamp to reduce overhead */
|
||||
PcmClampN<int32_t, int32_t, 24>(const_cast<int32_t *>(result),
|
||||
result,
|
||||
*dest_size_r / sizeof(*result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -63,4 +63,16 @@ PcmClamp(U x)
|
||||
return T(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the values in this buffer are within the range of the
|
||||
* provided bit size, and clamps them whenever necessary.
|
||||
*/
|
||||
template<typename T, typename U, unsigned bits>
|
||||
static inline void
|
||||
PcmClampN(T *dest, const U *src, unsigned n)
|
||||
{
|
||||
while (n-- > 0)
|
||||
*dest++ = PcmClamp<T, U, bits>(*src++);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -33,11 +33,23 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__ARMEL__)
|
||||
#define IS_LITTLE_ENDIAN true
|
||||
#define IS_BIG_ENDIAN false
|
||||
/* well-known little-endian */
|
||||
# define IS_LITTLE_ENDIAN true
|
||||
# define IS_BIG_ENDIAN false
|
||||
#elif defined(__MIPSEB__)
|
||||
/* well-known big-endian */
|
||||
# define IS_LITTLE_ENDIAN false
|
||||
# define IS_BIG_ENDIAN true
|
||||
#else
|
||||
#define IS_LITTLE_ENDIAN false
|
||||
#define IS_BIG_ENDIAN true
|
||||
/* generic compile-time check */
|
||||
# include <endian.h>
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define IS_LITTLE_ENDIAN true
|
||||
# define IS_BIG_ENDIAN false
|
||||
# else
|
||||
# define IS_LITTLE_ENDIAN false
|
||||
# define IS_BIG_ENDIAN true
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static inline constexpr bool
|
||||
|
@@ -104,6 +104,11 @@ socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBMPDCLIENT
|
||||
/* Avoid symbol conflict with statically linked libmpdclient */
|
||||
#define socket_cloexec_nonblock socket_cloexec_nonblock_noconflict
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag
|
||||
* (atomically if supported by the OS).
|
||||
|
@@ -49,12 +49,12 @@ public:
|
||||
*/
|
||||
void AutoCreate();
|
||||
|
||||
result_type min() const {
|
||||
return engine->min();
|
||||
static constexpr result_type min() {
|
||||
return std::mt19937::min();
|
||||
}
|
||||
|
||||
result_type max() const {
|
||||
return engine->max();
|
||||
static constexpr result_type max() {
|
||||
return std::mt19937::max();
|
||||
}
|
||||
|
||||
result_type operator()() {
|
||||
|
@@ -42,7 +42,12 @@ class RefCount {
|
||||
std::atomic_uint n;
|
||||
|
||||
public:
|
||||
constexpr RefCount():n(1) {}
|
||||
#ifndef _LIBCPP_VERSION
|
||||
/* the "constexpr" is missing in libc++'s "atomic"
|
||||
implementation */
|
||||
constexpr
|
||||
#endif
|
||||
RefCount():n(1) {}
|
||||
|
||||
void Increment() {
|
||||
++n;
|
||||
|
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void
|
||||
|
Reference in New Issue
Block a user