Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
a9ce0218
Commit
a9ce0218
authored
Feb 01, 2013
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
FilterInternal: convert struct filter to a OO interface
parent
7bb5a960
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
529 additions
and
802 deletions
+529
-802
FilterConfig.cxx
src/FilterConfig.cxx
+8
-7
FilterConfig.hxx
src/FilterConfig.hxx
+2
-2
FilterInternal.hxx
src/FilterInternal.hxx
+41
-8
FilterPlugin.cxx
src/FilterPlugin.cxx
+2
-56
FilterPlugin.hxx
src/FilterPlugin.hxx
+4
-83
OutputFinish.cxx
src/OutputFinish.cxx
+4
-8
OutputInit.cxx
src/OutputInit.cxx
+7
-7
OutputThread.cxx
src/OutputThread.cxx
+20
-22
AutoConvertFilterPlugin.cxx
src/filter/AutoConvertFilterPlugin.cxx
+45
-82
AutoConvertFilterPlugin.hxx
src/filter/AutoConvertFilterPlugin.hxx
+3
-3
ChainFilterPlugin.cxx
src/filter/ChainFilterPlugin.cxx
+67
-76
ChainFilterPlugin.hxx
src/filter/ChainFilterPlugin.hxx
+3
-3
ConvertFilterPlugin.cxx
src/filter/ConvertFilterPlugin.cxx
+38
-63
ConvertFilterPlugin.hxx
src/filter/ConvertFilterPlugin.hxx
+2
-3
NormalizeFilterPlugin.cxx
src/filter/NormalizeFilterPlugin.cxx
+24
-45
NullFilterPlugin.cxx
src/filter/NullFilterPlugin.cxx
+17
-51
ReplayGainFilterPlugin.cxx
src/filter/ReplayGainFilterPlugin.cxx
+88
-101
ReplayGainFilterPlugin.hxx
src/filter/ReplayGainFilterPlugin.hxx
+4
-5
RouteFilterPlugin.cxx
src/filter/RouteFilterPlugin.cxx
+70
-91
VolumeFilterPlugin.cxx
src/filter/VolumeFilterPlugin.cxx
+49
-60
VolumeFilterPlugin.hxx
src/filter/VolumeFilterPlugin.hxx
+3
-3
SoftwareMixerPlugin.cxx
src/mixer/SoftwareMixerPlugin.cxx
+2
-2
SoftwareMixerPlugin.hxx
src/mixer/SoftwareMixerPlugin.hxx
+2
-2
output_internal.h
src/output_internal.h
+10
-4
run_filter.cxx
test/run_filter.cxx
+14
-15
No files found.
src/FilterConfig.cxx
View file @
a9ce0218
...
...
@@ -78,7 +78,7 @@ filter_plugin_config(const char *filter_template_name, GError **error_r)
* @return the number of filters which were successfully added
*/
unsigned
int
filter_chain_parse
(
struct
filter
*
chain
,
const
char
*
spec
,
GError
**
error_r
)
filter_chain_parse
(
Filter
&
chain
,
const
char
*
spec
,
GError
**
error_r
)
{
// Split on comma
...
...
@@ -89,26 +89,27 @@ filter_chain_parse(struct filter *chain, const char *spec, GError **error_r)
// Add each name to the filter chain by instantiating an actual filter
char
**
template_names
=
tokens
;
while
(
*
template_names
!=
NULL
)
{
struct
filter
*
f
;
const
struct
config_param
*
cfg
;
// Squeeze whitespace
g_strstrip
(
*
template_names
);
cfg
=
filter_plugin_config
(
*
template_names
,
error_r
);
const
struct
config_param
*
cfg
=
filter_plugin_config
(
*
template_names
,
error_r
);
if
(
cfg
==
NULL
)
{
// The error has already been set, just stop.
break
;
}
// Instantiate one of those filter plugins with the template name as a hint
f
=
filter_configured_new
(
cfg
,
error_r
);
Filter
*
f
=
filter_configured_new
(
cfg
,
error_r
);
if
(
f
==
NULL
)
{
// The error has already been set, just stop.
break
;
}
filter_chain_append
(
chain
,
f
);
const
char
*
plugin_name
=
config_get_block_string
(
cfg
,
"plugin"
,
"unknown"
);
filter_chain_append
(
chain
,
plugin_name
,
f
);
++
added_filters
;
++
template_names
;
...
...
src/FilterConfig.hxx
View file @
a9ce0218
...
...
@@ -27,7 +27,7 @@
#include "gerror.h"
struct
f
ilter
;
class
F
ilter
;
/**
* Builds a filter chain from a configuration string on the form
...
...
@@ -39,6 +39,6 @@ struct filter;
* @return the number of filters which were successfully added
*/
unsigned
int
filter_chain_parse
(
struct
filter
*
chain
,
const
char
*
spec
,
GError
**
error_r
);
filter_chain_parse
(
Filter
&
chain
,
const
char
*
spec
,
GError
**
error_r
);
#endif
src/FilterInternal.hxx
View file @
a9ce0218
...
...
@@ -25,14 +25,47 @@
#ifndef MPD_FILTER_INTERNAL_HXX
#define MPD_FILTER_INTERNAL_HXX
struct
filter
{
const
struct
filter_plugin
*
plugin
;
};
struct
audio_format
;
class
Filter
{
public
:
virtual
~
Filter
()
{}
/**
* Opens the filter, preparing it for FilterPCM().
*
* @param filter the filter object
* @param audio_format the audio format of incoming data; the
* plugin may modify the object to enforce another input
* format
* @param error location to store the error occurring, or NULL
* to ignore errors.
* @return the format of outgoing data
*/
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
)
=
0
;
static
inline
void
filter_init
(
struct
filter
*
filter
,
const
struct
filter_plugin
*
plugin
)
{
filter
->
plugin
=
plugin
;
}
/**
* Closes the filter. After that, you may call Open() again.
*/
virtual
void
Close
()
=
0
;
/**
* Filters a block of PCM data.
*
* @param filter the filter object
* @param src the input buffer
* @param src_size the size of #src_buffer in bytes
* @param dest_size_r the size of the returned buffer
* @param error location to store the error occurring, or NULL
* to ignore errors.
* @return the destination buffer on success (will be
* invalidated by filter_close() or filter_filter()), NULL on
* error
*/
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
=
0
;
};
#endif
src/FilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -24,13 +24,9 @@
#include "conf.h"
#include "ConfigQuark.hxx"
#ifndef NDEBUG
#include "audio_format.h"
#endif
#include <assert.h>
struct
f
ilter
*
F
ilter
*
filter_new
(
const
struct
filter_plugin
*
plugin
,
const
struct
config_param
*
param
,
GError
**
error_r
)
{
...
...
@@ -40,7 +36,7 @@ filter_new(const struct filter_plugin *plugin,
return
plugin
->
init
(
param
,
error_r
);
}
struct
f
ilter
*
F
ilter
*
filter_configured_new
(
const
struct
config_param
*
param
,
GError
**
error_r
)
{
const
char
*
plugin_name
;
...
...
@@ -65,53 +61,3 @@ filter_configured_new(const struct config_param *param, GError **error_r)
return
filter_new
(
plugin
,
param
,
error_r
);
}
void
filter_free
(
struct
filter
*
filter
)
{
assert
(
filter
!=
NULL
);
filter
->
plugin
->
finish
(
filter
);
}
const
struct
audio_format
*
filter_open
(
struct
filter
*
filter
,
struct
audio_format
*
audio_format
,
GError
**
error_r
)
{
const
struct
audio_format
*
out_audio_format
;
assert
(
filter
!=
NULL
);
assert
(
audio_format
!=
NULL
);
assert
(
audio_format_valid
(
audio_format
));
assert
(
error_r
==
NULL
||
*
error_r
==
NULL
);
out_audio_format
=
filter
->
plugin
->
open
(
filter
,
audio_format
,
error_r
);
assert
(
out_audio_format
==
NULL
||
audio_format_valid
(
audio_format
));
assert
(
out_audio_format
==
NULL
||
audio_format_valid
(
out_audio_format
));
return
out_audio_format
;
}
void
filter_close
(
struct
filter
*
filter
)
{
assert
(
filter
!=
NULL
);
filter
->
plugin
->
close
(
filter
);
}
const
void
*
filter_filter
(
struct
filter
*
filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
{
assert
(
filter
!=
NULL
);
assert
(
src
!=
NULL
);
assert
(
src_size
>
0
);
assert
(
dest_size_r
!=
NULL
);
assert
(
error_r
==
NULL
||
*
error_r
==
NULL
);
return
filter
->
plugin
->
filter
(
filter
,
src
,
src_size
,
dest_size_r
,
error_r
);
}
src/FilterPlugin.hxx
View file @
a9ce0218
...
...
@@ -31,7 +31,7 @@
#include <stddef.h>
struct
config_param
;
struct
f
ilter
;
class
F
ilter
;
struct
filter_plugin
{
const
char
*
name
;
...
...
@@ -39,38 +39,7 @@ struct filter_plugin {
/**
* Allocates and configures a filter.
*/
struct
filter
*
(
*
init
)(
const
struct
config_param
*
param
,
GError
**
error_r
);
/**
* Free instance data.
*/
void
(
*
finish
)(
struct
filter
*
filter
);
/**
* Opens a filter.
*
* @param audio_format the audio format of incoming data; the
* plugin may modify the object to enforce another input
* format
*/
const
struct
audio_format
*
(
*
open
)(
struct
filter
*
filter
,
struct
audio_format
*
audio_format
,
GError
**
error_r
);
/**
* Closes a filter.
*/
void
(
*
close
)(
struct
filter
*
filter
);
/**
* Filters a block of PCM data.
*/
const
void
*
(
*
filter
)(
struct
filter
*
filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_buffer_r
,
GError
**
error_r
);
Filter
*
(
*
init
)(
const
struct
config_param
*
param
,
GError
**
error_r
);
};
/**
...
...
@@ -82,7 +51,7 @@ struct filter_plugin {
* ignore errors.
* @return a new filter object, or NULL on error
*/
struct
f
ilter
*
F
ilter
*
filter_new
(
const
struct
filter_plugin
*
plugin
,
const
struct
config_param
*
param
,
GError
**
error_r
);
...
...
@@ -95,55 +64,7 @@ filter_new(const struct filter_plugin *plugin,
* ignore errors.
* @return a new filter object, or NULL on error
*/
struct
f
ilter
*
F
ilter
*
filter_configured_new
(
const
struct
config_param
*
param
,
GError
**
error_r
);
/**
* Deletes a filter. It must be closed prior to calling this
* function, see filter_close().
*
* @param filter the filter object
*/
void
filter_free
(
struct
filter
*
filter
);
/**
* Opens the filter, preparing it for filter_filter().
*
* @param filter the filter object
* @param audio_format the audio format of incoming data; the plugin
* may modify the object to enforce another input format
* @param error location to store the error occurring, or NULL to
* ignore errors.
* @return the format of outgoing data
*/
const
struct
audio_format
*
filter_open
(
struct
filter
*
filter
,
struct
audio_format
*
audio_format
,
GError
**
error_r
);
/**
* Closes the filter. After that, you may call filter_open() again.
*
* @param filter the filter object
*/
void
filter_close
(
struct
filter
*
filter
);
/**
* Filters a block of PCM data.
*
* @param filter the filter object
* @param src the input buffer
* @param src_size the size of #src_buffer in bytes
* @param dest_size_r the size of the returned buffer
* @param error location to store the error occurring, or NULL to
* ignore errors.
* @return the destination buffer on success (will be invalidated by
* filter_close() or filter_filter()), NULL on error
*/
const
void
*
filter_filter
(
struct
filter
*
filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
#endif
src/OutputFinish.cxx
View file @
a9ce0218
...
...
@@ -25,7 +25,7 @@ extern "C" {
#include "mixer_control.h"
}
#include "Filter
Plugin
.hxx"
#include "Filter
Internal
.hxx"
#include <assert.h>
...
...
@@ -42,13 +42,9 @@ ao_base_finish(struct audio_output *ao)
g_cond_free
(
ao
->
cond
);
g_mutex_free
(
ao
->
mutex
);
if
(
ao
->
replay_gain_filter
!=
NULL
)
filter_free
(
ao
->
replay_gain_filter
);
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_free
(
ao
->
other_replay_gain_filter
);
filter_free
(
ao
->
filter
);
delete
ao
->
replay_gain_filter
;
delete
ao
->
other_replay_gain_filter
;
delete
ao
->
filter
;
pcm_buffer_deinit
(
&
ao
->
cross_fade_buffer
);
}
...
...
src/OutputInit.cxx
View file @
a9ce0218
...
...
@@ -100,7 +100,7 @@ static struct mixer *
audio_output_load_mixer
(
struct
audio_output
*
ao
,
const
struct
config_param
*
param
,
const
struct
mixer_plugin
*
plugin
,
struct
filter
*
filter_chain
,
Filter
&
filter_chain
,
GError
**
error_r
)
{
struct
mixer
*
mixer
;
...
...
@@ -120,7 +120,7 @@ audio_output_load_mixer(struct audio_output *ao,
mixer
=
mixer_new
(
&
software_mixer_plugin
,
NULL
,
NULL
,
NULL
);
assert
(
mixer
!=
NULL
);
filter_chain_append
(
filter_chain
,
filter_chain_append
(
filter_chain
,
"software_mixer"
,
software_mixer_get_filter
(
mixer
));
return
mixer
;
}
...
...
@@ -190,15 +190,15 @@ ao_base_init(struct audio_output *ao,
/* create the normalization filter (if configured) */
if
(
config_get_bool
(
CONF_VOLUME_NORMALIZATION
,
false
))
{
struct
f
ilter
*
normalize_filter
=
F
ilter
*
normalize_filter
=
filter_new
(
&
normalize_filter_plugin
,
NULL
,
NULL
);
assert
(
normalize_filter
!=
NULL
);
filter_chain_append
(
ao
->
filter
,
filter_chain_append
(
*
ao
->
filter
,
"normalize"
,
autoconvert_filter_new
(
normalize_filter
));
}
filter_chain_parse
(
ao
->
filter
,
filter_chain_parse
(
*
ao
->
filter
,
config_get_block_string
(
param
,
AUDIO_FILTERS
,
""
),
&
error
);
...
...
@@ -258,7 +258,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
GError
*
error
=
NULL
;
ao
->
mixer
=
audio_output_load_mixer
(
ao
,
param
,
ao
->
plugin
->
mixer_plugin
,
ao
->
filter
,
&
error
);
*
ao
->
filter
,
&
error
);
if
(
ao
->
mixer
==
NULL
&&
error
!=
NULL
)
{
g_warning
(
"Failed to initialize hardware mixer for '%s': %s"
,
ao
->
name
,
error
->
message
);
...
...
@@ -285,7 +285,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
ao
->
convert_filter
=
filter_new
(
&
convert_filter_plugin
,
NULL
,
NULL
);
assert
(
ao
->
convert_filter
!=
NULL
);
filter_chain_append
(
ao
->
filter
,
ao
->
convert_filter
);
filter_chain_append
(
*
ao
->
filter
,
"convert"
,
ao
->
convert_filter
);
return
true
;
}
...
...
src/OutputThread.cxx
View file @
a9ce0218
...
...
@@ -27,7 +27,7 @@ extern "C" {
}
#include "notify.hxx"
#include "Filter
Plugin
.hxx"
#include "Filter
Internal
.hxx"
#include "filter/ConvertFilterPlugin.hxx"
#include "filter/ReplayGainFilterPlugin.hxx"
#include "PlayerControl.hxx"
...
...
@@ -98,26 +98,24 @@ ao_disable(struct audio_output *ao)
}
static
const
struct
audio_format
*
ao_filter_open
(
struct
audio_output
*
ao
,
struct
audio_format
*
audio_format
,
ao_filter_open
(
struct
audio_output
*
ao
,
audio_format
&
format
,
GError
**
error_r
)
{
assert
(
audio_format_valid
(
audio_
format
));
assert
(
audio_format_valid
(
&
format
));
/* the replay_gain filter cannot fail here */
if
(
ao
->
replay_gain_filter
!=
NULL
)
filter_open
(
ao
->
replay_gain_filter
,
audio_
format
,
error_r
);
ao
->
replay_gain_filter
->
Open
(
format
,
error_r
);
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_open
(
ao
->
other_replay_gain_filter
,
audio_format
,
error_r
);
ao
->
other_replay_gain_filter
->
Open
(
format
,
error_r
);
const
struct
audio_format
*
af
=
filter_open
(
ao
->
filter
,
audio_
format
,
error_r
);
=
ao
->
filter
->
Open
(
format
,
error_r
);
if
(
af
==
NULL
)
{
if
(
ao
->
replay_gain_filter
!=
NULL
)
filter_close
(
ao
->
replay_gain_filter
);
ao
->
replay_gain_filter
->
Close
(
);
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_close
(
ao
->
other_replay_gain_filter
);
ao
->
other_replay_gain_filter
->
Close
(
);
}
return
af
;
...
...
@@ -127,11 +125,11 @@ static void
ao_filter_close
(
struct
audio_output
*
ao
)
{
if
(
ao
->
replay_gain_filter
!=
NULL
)
filter_close
(
ao
->
replay_gain_filter
);
ao
->
replay_gain_filter
->
Close
(
);
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_close
(
ao
->
other_replay_gain_filter
);
ao
->
other_replay_gain_filter
->
Close
(
);
filter_close
(
ao
->
filter
);
ao
->
filter
->
Close
(
);
}
static
void
...
...
@@ -139,7 +137,6 @@ ao_open(struct audio_output *ao)
{
bool
success
;
GError
*
error
=
NULL
;
const
struct
audio_format
*
filter_audio_format
;
struct
audio_format_string
af_string
;
assert
(
!
ao
->
open
);
...
...
@@ -164,7 +161,8 @@ ao_open(struct audio_output *ao)
/* open the filter */
filter_audio_format
=
ao_filter_open
(
ao
,
&
ao
->
in_audio_format
,
&
error
);
const
audio_format
*
filter_audio_format
=
ao_filter_open
(
ao
,
ao
->
in_audio_format
,
&
error
);
if
(
filter_audio_format
==
NULL
)
{
g_warning
(
"Failed to open filter for
\"
%s
\"
[%s]: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
...
@@ -196,7 +194,7 @@ ao_open(struct audio_output *ao)
return
;
}
convert_filter_set
(
ao
->
convert_filter
,
&
ao
->
out_audio_format
);
convert_filter_set
(
ao
->
convert_filter
,
ao
->
out_audio_format
);
ao
->
open
=
true
;
...
...
@@ -244,7 +242,7 @@ ao_reopen_filter(struct audio_output *ao)
GError
*
error
=
NULL
;
ao_filter_close
(
ao
);
filter_audio_format
=
ao_filter_open
(
ao
,
&
ao
->
in_audio_format
,
&
error
);
filter_audio_format
=
ao_filter_open
(
ao
,
ao
->
in_audio_format
,
&
error
);
if
(
filter_audio_format
==
NULL
)
{
g_warning
(
"Failed to open filter for
\"
%s
\"
[%s]: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
...
@@ -267,7 +265,7 @@ ao_reopen_filter(struct audio_output *ao)
return
;
}
convert_filter_set
(
ao
->
convert_filter
,
&
ao
->
out_audio_format
);
convert_filter_set
(
ao
->
convert_filter
,
ao
->
out_audio_format
);
}
static
void
...
...
@@ -322,7 +320,7 @@ ao_wait(struct audio_output *ao)
static
const
void
*
ao_chunk_data
(
struct
audio_output
*
ao
,
const
struct
music_chunk
*
chunk
,
struct
f
ilter
*
replay_gain_filter
,
F
ilter
*
replay_gain_filter
,
unsigned
*
replay_gain_serial_p
,
size_t
*
length_r
)
{
...
...
@@ -347,8 +345,8 @@ ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
}
GError
*
error
=
NULL
;
data
=
filter_filter
(
replay_gain_filter
,
data
,
length
,
&
length
,
&
error
);
data
=
replay_gain_filter
->
FilterPCM
(
data
,
length
,
&
length
,
&
error
);
if
(
data
==
NULL
)
{
g_warning
(
"
\"
%s
\"
[%s] failed to filter: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
...
@@ -421,7 +419,7 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
/* apply filter chain */
data
=
filter_filter
(
ao
->
filter
,
data
,
length
,
&
length
,
&
error
);
data
=
ao
->
filter
->
FilterPCM
(
data
,
length
,
&
length
,
&
error
);
if
(
data
==
NULL
)
{
g_warning
(
"
\"
%s
\"
[%s] failed to filter: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
...
src/filter/AutoConvertFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -27,143 +27,106 @@
#include <assert.h>
struct
AutoConvertFilter
{
struct
filter
base
;
class
AutoConvertFilter
final
:
public
Filter
{
/**
* The audio format being fed to the underlying filter. This
* plugin actually doesn't need this variable, we have it here
* just so our open() method doesn't return a stack pointer.
*/
struct
audio_format
in
_audio_format
;
audio_format
child
_audio_format
;
/**
* The underlying filter.
*/
struct
f
ilter
*
filter
;
F
ilter
*
filter
;
/**
* A convert_filter, just in case conversion is needed. nullptr
* if unused.
*/
struct
filter
*
convert
;
AutoConvertFilter
(
const
filter_plugin
&
plugin
,
struct
filter
*
_filter
)
:
filter
(
_filter
)
{
filter_init
(
&
base
,
&
plugin
);
}
Filter
*
convert
;
public
:
AutoConvertFilter
(
Filter
*
_filter
)
:
filter
(
_filter
)
{}
~
AutoConvertFilter
()
{
filter_free
(
filter
)
;
delete
filter
;
}
};
static
void
autoconvert_filter_finish
(
struct
filter
*
_filter
)
{
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
delete
filter
;
}
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
};
static
const
struct
audio_format
*
autoconvert_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
in_audio_format
,
GError
**
error_r
)
const
struct
audio_format
*
AutoConvertFilter
::
Open
(
audio_format
&
in_audio_format
,
GError
**
error_r
)
{
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
const
struct
audio_format
*
out_audio_format
;
assert
(
audio_format_valid
(
in_audio_format
));
assert
(
audio_format_valid
(
&
in_audio_format
));
/* open the "real" filter */
filter
->
in_audio_format
=
*
in_audio_format
;
out_audio_format
=
filter_open
(
filter
->
filter
,
&
filter
->
in_audio_format
,
error_r
);
child_audio_format
=
in_audio_format
;
const
audio_format
*
out_audio_format
=
filter
->
Open
(
child_audio_format
,
error_r
);
if
(
out_audio_format
==
nullptr
)
return
nullptr
;
/* need to convert? */
if
(
!
audio_format_equals
(
&
filter
->
in_audio_format
,
in_audio_format
))
{
if
(
!
audio_format_equals
(
&
child_audio_format
,
&
in_audio_format
))
{
/* yes - create a convert_filter */
struct
audio_format
audio_format2
=
*
in_audio_format
;
const
struct
audio_format
*
audio_format3
;
filter
->
convert
=
filter_new
(
&
convert_filter_plugin
,
nullptr
,
error_r
);
if
(
filter
->
convert
==
nullptr
)
{
filter_close
(
filter
->
filter
);
convert
=
filter_new
(
&
convert_filter_plugin
,
nullptr
,
error_r
);
if
(
convert
==
nullptr
)
{
filter
->
Close
();
return
nullptr
;
}
audio_format3
=
filter_open
(
filter
->
convert
,
&
audio_format2
,
error_r
);
audio_format
audio_format2
=
in_audio_format
;
const
audio_format
*
audio_format3
=
convert
->
Open
(
audio_format2
,
error_r
);
if
(
audio_format3
==
nullptr
)
{
filter_free
(
filter
->
convert
)
;
filter
_close
(
filter
->
filter
);
delete
convert
;
filter
->
Close
(
);
return
nullptr
;
}
assert
(
audio_format_equals
(
&
audio_format2
,
in_audio_format
));
assert
(
audio_format_equals
(
&
audio_format2
,
&
in_audio_format
));
convert_filter_set
(
filter
->
convert
,
&
filter
->
in
_audio_format
);
convert_filter_set
(
convert
,
child
_audio_format
);
}
else
/* no */
filter
->
convert
=
nullptr
;
convert
=
nullptr
;
return
out_audio_format
;
}
static
void
autoconvert_filter_close
(
struct
filter
*
_filter
)
void
AutoConvertFilter
::
Close
(
)
{
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
if
(
filter
->
convert
!=
nullptr
)
{
filter_close
(
filter
->
convert
);
filter_free
(
filter
->
convert
);
if
(
convert
!=
nullptr
)
{
convert
->
Close
();
delete
convert
;
}
filter
_close
(
filter
->
filter
);
filter
->
Close
(
);
}
static
const
void
*
autoconvert_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
const
void
*
AutoConvertFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
{
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
if
(
filter
->
convert
!=
nullptr
)
{
src
=
filter_filter
(
filter
->
convert
,
src
,
src_size
,
&
src_size
,
error_r
);
if
(
convert
!=
nullptr
)
{
src
=
convert
->
FilterPCM
(
src
,
src_size
,
&
src_size
,
error_r
);
if
(
src
==
nullptr
)
return
nullptr
;
}
return
filter_filter
(
filter
->
filter
,
src
,
src_size
,
dest_size_r
,
error_r
);
return
filter
->
FilterPCM
(
src
,
src_size
,
dest_size_r
,
error_r
);
}
static
const
struct
filter_plugin
autoconvert_filter_plugin
=
{
"convert"
,
nullptr
,
autoconvert_filter_finish
,
autoconvert_filter_open
,
autoconvert_filter_close
,
autoconvert_filter_filter
,
};
struct
filter
*
autoconvert_filter_new
(
struct
filter
*
_filter
)
Filter
*
autoconvert_filter_new
(
Filter
*
filter
)
{
AutoConvertFilter
*
filter
=
new
AutoConvertFilter
(
autoconvert_filter_plugin
,
_filter
);
return
&
filter
->
base
;
return
new
AutoConvertFilter
(
filter
);
}
src/filter/AutoConvertFilterPlugin.hxx
View file @
a9ce0218
...
...
@@ -20,7 +20,7 @@
#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX
#define MPD_AUTOCONVERT_FILTER_PLUGIN_HXX
struct
f
ilter
;
class
F
ilter
;
/**
* Creates a new "autoconvert" filter. When opened, it ensures that
...
...
@@ -28,7 +28,7 @@ struct filter;
* requests a different format, it automatically creates a
* convert_filter.
*/
struct
f
ilter
*
autoconvert_filter_new
(
struct
f
ilter
*
filter
);
F
ilter
*
autoconvert_filter_new
(
F
ilter
*
filter
);
#endif
src/filter/ChainFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -31,20 +31,39 @@
#include <assert.h>
struct
ChainFilter
{
/** the base class */
struct
filter
base
;
class
ChainFilter
final
:
public
Filter
{
struct
Child
{
const
char
*
name
;
Filter
*
filter
;
Child
(
const
char
*
_name
,
Filter
*
_filter
)
:
name
(
_name
),
filter
(
_filter
)
{}
~
Child
()
{
delete
filter
;
}
std
::
list
<
struct
filter
*>
children
;
Child
(
const
Child
&
)
=
delete
;
Child
&
operator
=
(
const
Child
&
)
=
delete
;
};
ChainFilter
()
{
filter_init
(
&
base
,
&
chain_filter_plugin
);
}
std
::
list
<
Child
>
children
;
~
ChainFilter
()
{
for
(
auto
i
:
children
)
filter_free
(
i
);
public
:
void
Append
(
const
char
*
name
,
Filter
*
filter
)
{
children
.
emplace_back
(
name
,
filter
);
}
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
private
:
/**
* Close all filters in the chain until #until is reached.
* #until itself is not closed.
*/
void
CloseUntil
(
const
Filter
*
until
);
};
static
inline
GQuark
...
...
@@ -53,37 +72,23 @@ filter_quark(void)
return
g_quark_from_static_string
(
"filter"
);
}
static
struct
f
ilter
*
static
F
ilter
*
chain_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
ChainFilter
*
chain
=
new
ChainFilter
();
return
&
chain
->
base
;
}
static
void
chain_filter_finish
(
struct
filter
*
_filter
)
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
delete
chain
;
return
new
ChainFilter
();
}
/**
* Close all filters in the chain until #until is reached. #until
* itself is not closed.
*/
static
void
chain_close_until
(
ChainFilter
*
chain
,
const
struct
filter
*
until
)
void
ChainFilter
::
CloseUntil
(
const
Filter
*
until
)
{
for
(
auto
filter
:
chain
->
children
)
{
if
(
filter
==
until
)
for
(
auto
&
child
:
children
)
{
if
(
child
.
filter
==
until
)
/* don't close this filter */
return
;
/* close this filter */
filter_close
(
filter
);
child
.
filter
->
Close
(
);
}
/* this assertion fails if #until does not exist (anymore) */
...
...
@@ -91,43 +96,41 @@ chain_close_until(ChainFilter *chain, const struct filter *until)
}
static
const
struct
audio_format
*
chain_open_child
(
struct
f
ilter
*
filter
,
const
struct
audio_format
*
prev_audio_format
,
chain_open_child
(
const
char
*
name
,
F
ilter
*
filter
,
const
audio_format
&
prev_audio_format
,
GError
**
error_r
)
{
struct
audio_format
conv_audio_format
=
*
prev_audio_format
;
const
struct
audio_format
*
next_audio_format
;
next_audio_format
=
filter_open
(
filter
,
&
conv_audio_format
,
error_r
);
audio_format
conv_audio_format
=
prev_audio_format
;
const
audio_format
*
next_audio_format
=
filter
->
Open
(
conv_audio_format
,
error_r
);
if
(
next_audio_format
==
NULL
)
return
NULL
;
if
(
!
audio_format_equals
(
&
conv_audio_format
,
prev_audio_format
))
{
if
(
!
audio_format_equals
(
&
conv_audio_format
,
&
prev_audio_format
))
{
struct
audio_format_string
s
;
filter
_close
(
filter
);
filter
->
Close
(
);
g_set_error
(
error_r
,
filter_quark
(),
0
,
"Audio format not supported by filter '%s': %s"
,
filter
->
plugin
->
name
,
audio_format_to_string
(
prev_audio_format
,
&
s
));
name
,
audio_format_to_string
(
&
prev_audio_format
,
&
s
));
return
NULL
;
}
return
next_audio_format
;
}
static
const
struct
audio_format
*
chain_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
in_audio_format
,
GError
**
error_r
)
const
audio_format
*
ChainFilter
::
Open
(
audio_format
&
in_audio_format
,
GError
**
error_r
)
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
const
struct
audio_format
*
audio_format
=
in_audio_format
;
const
audio_format
*
audio_format
=
&
in_audio_format
;
for
(
auto
filter
:
chain
->
children
)
{
audio_format
=
chain_open_child
(
filter
,
audio_format
,
error_r
);
for
(
auto
&
child
:
children
)
{
audio_format
=
chain_open_child
(
child
.
name
,
child
.
filter
,
*
audio_format
,
error_r
);
if
(
audio_format
==
NULL
)
{
/* rollback, close all children */
chain_close_until
(
chain
,
filter
);
CloseUntil
(
child
.
filter
);
return
NULL
;
}
}
...
...
@@ -136,26 +139,22 @@ chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format,
return
audio_format
;
}
static
void
chain_filter_close
(
struct
filter
*
_filter
)
void
ChainFilter
::
Close
(
)
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
for
(
auto
filter
:
chain
->
children
)
filter_close
(
filter
);
for
(
auto
&
child
:
children
)
child
.
filter
->
Close
();
}
static
const
void
*
chain_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
const
void
*
ChainFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
for
(
auto
filter
:
chain
->
children
)
{
for
(
auto
&
child
:
children
)
{
/* feed the output of the previous filter as input
into the current one */
src
=
filter_filter
(
filter
,
src
,
src_size
,
&
src_size
,
error_r
);
src
=
child
.
filter
->
FilterPCM
(
src
,
src_size
,
&
src_size
,
error_r
);
if
(
src
==
NULL
)
return
NULL
;
}
...
...
@@ -168,26 +167,18 @@ chain_filter_filter(struct filter *_filter,
const
struct
filter_plugin
chain_filter_plugin
=
{
"chain"
,
chain_filter_init
,
chain_filter_finish
,
chain_filter_open
,
chain_filter_close
,
chain_filter_filter
,
};
struct
f
ilter
*
F
ilter
*
filter_chain_new
(
void
)
{
struct
filter
*
filter
=
filter_new
(
&
chain_filter_plugin
,
NULL
,
NULL
);
/* chain_filter_init() never fails */
assert
(
filter
!=
NULL
);
return
filter
;
return
new
ChainFilter
();
}
void
filter_chain_append
(
struct
filter
*
_chain
,
struct
f
ilter
*
filter
)
filter_chain_append
(
Filter
&
_chain
,
const
char
*
name
,
F
ilter
*
filter
)
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_chain
;
ChainFilter
&
chain
=
(
ChainFilter
&
)
_chain
;
chain
->
children
.
push_back
(
filter
);
chain
.
Append
(
name
,
filter
);
}
src/filter/ChainFilterPlugin.hxx
View file @
a9ce0218
...
...
@@ -27,12 +27,12 @@
#ifndef MPD_FILTER_CHAIN_HXX
#define MPD_FILTER_CHAIN_HXX
struct
f
ilter
;
class
F
ilter
;
/**
* Creates a new filter chain.
*/
struct
f
ilter
*
F
ilter
*
filter_chain_new
(
void
);
/**
...
...
@@ -43,6 +43,6 @@ filter_chain_new(void);
* @param filter the filter to be appended to #chain
*/
void
filter_chain_append
(
struct
filter
*
chain
,
struct
f
ilter
*
filter
);
filter_chain_append
(
Filter
&
chain
,
const
char
*
name
,
F
ilter
*
filter
);
#endif
src/filter/ConvertFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -31,114 +31,89 @@
#include <assert.h>
#include <string.h>
struct
ConvertFilter
{
struct
filter
base
;
class
ConvertFilter
final
:
public
Filter
{
/**
* The input audio format; PCM data is passed to the filter()
* method in this format.
*/
struct
audio_format
in_audio_format
;
audio_format
in_audio_format
;
/**
* The output audio format; the consumer of this plugin
* expects PCM data in this format. This defaults to
* #in_audio_format, and can be set with convert_filter_set().
*/
struct
audio_format
out_audio_format
;
audio_format
out_audio_format
;
Manual
<
PcmConvert
>
state
;
ConvertFilter
()
{
filter_init
(
&
base
,
&
convert_filter_plugin
);
public
:
void
Set
(
const
audio_format
&
_out_audio_format
)
{
assert
(
audio_format_valid
(
&
in_audio_format
));
assert
(
audio_format_valid
(
&
out_audio_format
));
assert
(
audio_format_valid
(
&
_out_audio_format
));
out_audio_format
=
_out_audio_format
;
}
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
};
static
struct
f
ilter
*
static
F
ilter
*
convert_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
ConvertFilter
*
filter
=
new
ConvertFilter
();
return
&
filter
->
base
;
}
static
void
convert_filter_finish
(
struct
filter
*
filter
)
{
delete
filter
;
return
new
ConvertFilter
();
}
static
const
struct
audio_format
*
convert_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
const
struct
audio_format
*
ConvertFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_r
)
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
assert
(
audio_format_valid
(
&
audio_format
))
;
assert
(
audio_format_valid
(
audio_format
));
in_audio_format
=
out_audio_format
=
audio_format
;
state
.
Construct
();
filter
->
in_audio_format
=
filter
->
out_audio_format
=
*
audio_format
;
filter
->
state
.
Construct
();
return
&
filter
->
in_audio_format
;
return
&
in_audio_format
;
}
static
void
convert_filter_close
(
struct
filter
*
_filter
)
void
ConvertFilter
::
Close
(
)
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
filter
->
state
.
Destruct
();
state
.
Destruct
();
poison_undefined
(
&
filter
->
in_audio_format
,
sizeof
(
filter
->
in_audio_format
));
poison_undefined
(
&
filter
->
out_audio_format
,
sizeof
(
filter
->
out_audio_format
));
poison_undefined
(
&
in_audio_format
,
sizeof
(
in_audio_format
));
poison_undefined
(
&
out_audio_format
,
sizeof
(
out_audio_format
));
}
static
const
void
*
convert_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
const
void
*
ConvertFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
const
void
*
dest
;
if
(
audio_format_equals
(
&
filter
->
in_audio_format
,
&
filter
->
out_audio_format
))
{
if
(
audio_format_equals
(
&
in_audio_format
,
&
out_audio_format
))
{
/* optimized special case: no-op */
*
dest_size_r
=
src_size
;
return
src
;
}
dest
=
filter
->
state
->
Convert
(
&
filter
->
in_audio_format
,
src
,
src_size
,
&
filter
->
out_audio_format
,
dest_size_r
,
error_r
);
if
(
dest
==
NULL
)
return
NULL
;
return
dest
;
return
state
->
Convert
(
&
in_audio_format
,
src
,
src_size
,
&
out_audio_format
,
dest_size_r
,
error_r
);
}
const
struct
filter_plugin
convert_filter_plugin
=
{
"convert"
,
convert_filter_init
,
convert_filter_finish
,
convert_filter_open
,
convert_filter_close
,
convert_filter_filter
,
};
void
convert_filter_set
(
struct
filter
*
_filter
,
const
struct
audio_format
*
out_audio_format
)
convert_filter_set
(
Filter
*
_filter
,
const
audio_format
&
out_audio_format
)
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
assert
(
filter
!=
NULL
);
assert
(
audio_format_valid
(
&
filter
->
in_audio_format
));
assert
(
audio_format_valid
(
&
filter
->
out_audio_format
));
assert
(
out_audio_format
!=
NULL
);
assert
(
audio_format_valid
(
out_audio_format
));
filter
->
out_audio_format
=
*
out_audio_format
;
filter
->
Set
(
out_audio_format
);
}
src/filter/ConvertFilterPlugin.hxx
View file @
a9ce0218
...
...
@@ -20,7 +20,7 @@
#ifndef MPD_CONVERT_FILTER_PLUGIN_HXX
#define MPD_CONVERT_FILTER_PLUGIN_HXX
struct
f
ilter
;
class
F
ilter
;
struct
audio_format
;
/**
...
...
@@ -30,7 +30,6 @@ struct audio_format;
* the last in a chain.
*/
void
convert_filter_set
(
struct
filter
*
filter
,
const
audio_format
*
out_audio_format
);
convert_filter_set
(
Filter
*
filter
,
const
audio_format
&
out_audio_format
);
#endif
src/filter/NormalizeFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -28,68 +28,51 @@
#include <assert.h>
#include <string.h>
struct
normalize_filter
{
struct
filter
filter
;
class
NormalizeFilter
final
:
public
Filter
{
struct
Compressor
*
compressor
;
struct
pcm_buffer
buffer
;
public
:
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
};
static
struct
f
ilter
*
static
F
ilter
*
normalize_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
struct
normalize_filter
*
filter
=
g_new
(
struct
normalize_filter
,
1
);
filter_init
(
&
filter
->
filter
,
&
normalize_filter_plugin
);
return
&
filter
->
filter
;
return
new
NormalizeFilter
();
}
static
void
normalize_filter_finish
(
struct
filter
*
filte
r
)
const
struct
audio_format
*
NormalizeFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_
r
)
{
g_free
(
filter
);
}
audio_format
.
format
=
SAMPLE_FORMAT_S16
;
static
const
struct
audio_format
*
normalize_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
{
struct
normalize_filter
*
filter
=
(
struct
normalize_filter
*
)
_filter
;
compressor
=
Compressor_new
(
0
);
pcm_buffer_init
(
&
buffer
);
audio_format
->
format
=
SAMPLE_FORMAT_S16
;
filter
->
compressor
=
Compressor_new
(
0
);
pcm_buffer_init
(
&
filter
->
buffer
);
return
audio_format
;
return
&
audio_format
;
}
static
void
normalize_filter_close
(
struct
filter
*
_filter
)
void
NormalizeFilter
::
Close
(
)
{
struct
normalize_filter
*
filter
=
(
struct
normalize_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
filter
->
buffer
);
Compressor_delete
(
filter
->
compressor
);
pcm_buffer_deinit
(
&
buffer
);
Compressor_delete
(
compressor
);
}
static
const
void
*
normalize_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
const
void
*
NormalizeFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
{
struct
normalize_filter
*
filter
=
(
struct
normalize_filter
*
)
_filter
;
int16_t
*
dest
=
(
int16_t
*
)
pcm_buffer_get
(
&
filter
->
buffer
,
src_size
);
int16_t
*
dest
=
(
int16_t
*
)
pcm_buffer_get
(
&
buffer
,
src_size
);
memcpy
(
dest
,
src
,
src_size
);
Compressor_Process_int16
(
filter
->
compressor
,
dest
,
src_size
/
2
);
Compressor_Process_int16
(
compressor
,
dest
,
src_size
/
2
);
*
dest_size_r
=
src_size
;
return
dest
;
...
...
@@ -98,8 +81,4 @@ normalize_filter_filter(struct filter *_filter,
const
struct
filter_plugin
normalize_filter_plugin
=
{
"normalize"
,
normalize_filter_init
,
normalize_filter_finish
,
normalize_filter_open
,
normalize_filter_close
,
normalize_filter_filter
,
};
src/filter/NullFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -30,65 +30,31 @@
#include "FilterRegistry.hxx"
#include "gcc.h"
#include <glib.h>
struct
null_filter
{
struct
filter
filter
;
class
NullFilter
final
:
public
Filter
{
public
:
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
gcc_unused
GError
**
error_r
)
{
return
&
af
;
}
virtual
void
Close
()
{}
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
{
*
dest_size_r
=
src_size
;
return
src
;
}
};
static
struct
f
ilter
*
static
F
ilter
*
null_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
struct
null_filter
*
filter
=
g_new
(
struct
null_filter
,
1
);
filter_init
(
&
filter
->
filter
,
&
null_filter_plugin
);
return
&
filter
->
filter
;
}
static
void
null_filter_finish
(
struct
filter
*
_filter
)
{
struct
null_filter
*
filter
=
(
struct
null_filter
*
)
_filter
;
g_free
(
filter
);
}
static
const
struct
audio_format
*
null_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
{
struct
null_filter
*
filter
=
(
struct
null_filter
*
)
_filter
;
(
void
)
filter
;
return
audio_format
;
}
static
void
null_filter_close
(
struct
filter
*
_filter
)
{
struct
null_filter
*
filter
=
(
struct
null_filter
*
)
_filter
;
(
void
)
filter
;
}
static
const
void
*
null_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
{
struct
null_filter
*
filter
=
(
struct
null_filter
*
)
_filter
;
(
void
)
filter
;
/* return the unmodified source buffer */
*
dest_size_r
=
src_size
;
return
src
;
return
new
NullFilter
();
}
const
struct
filter_plugin
null_filter_plugin
=
{
"null"
,
null_filter_init
,
null_filter_finish
,
null_filter_open
,
null_filter_close
,
null_filter_filter
,
};
src/filter/ReplayGainFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -38,9 +38,7 @@ extern "C" {
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "replay_gain"
struct
replay_gain_filter
{
struct
filter
filter
;
class
ReplayGainFilter
final
:
public
Filter
{
/**
* If set, then this hardware mixer is used for applying
* replay gain, instead of the software volume library.
...
...
@@ -71,9 +69,56 @@ struct replay_gain_filter {
*/
unsigned
volume
;
struct
audio_format
audio_
format
;
struct
audio_format
format
;
struct
pcm_buffer
buffer
;
public
:
ReplayGainFilter
()
:
mixer
(
nullptr
),
mode
(
REPLAY_GAIN_OFF
),
volume
(
PCM_VOLUME_1
)
{
replay_gain_info_init
(
&
info
);
}
void
SetMixer
(
struct
mixer
*
_mixer
,
unsigned
_base
)
{
assert
(
_mixer
==
NULL
||
(
_base
>
0
&&
_base
<=
100
));
mixer
=
_mixer
;
base
=
_base
;
Update
();
}
void
SetInfo
(
const
struct
replay_gain_info
*
_info
)
{
if
(
_info
!=
NULL
)
{
info
=
*
_info
;
replay_gain_info_complete
(
&
info
);
}
else
replay_gain_info_init
(
&
info
);
Update
();
}
void
SetMode
(
enum
replay_gain_mode
_mode
)
{
if
(
_mode
==
mode
)
/* no change */
return
;
g_debug
(
"replay gain mode has changed %d->%d
\n
"
,
mode
,
_mode
);
mode
=
_mode
;
Update
();
}
/**
* Recalculates the new volume after a property was changed.
*/
void
Update
();
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
};
static
inline
GQuark
...
...
@@ -82,30 +127,27 @@ replay_gain_quark(void)
return
g_quark_from_static_string
(
"replay_gain"
);
}
/**
* Recalculates the new volume after a property was changed.
*/
static
void
replay_gain_filter_update
(
struct
replay_gain_filter
*
filter
)
void
ReplayGainFilter
::
Update
()
{
if
(
filter
->
mode
!=
REPLAY_GAIN_OFF
)
{
float
scale
=
replay_gain_tuple_scale
(
&
filter
->
info
.
tuples
[
filter
->
mode
],
if
(
mode
!=
REPLAY_GAIN_OFF
)
{
float
scale
=
replay_gain_tuple_scale
(
&
info
.
tuples
[
mode
],
replay_gain_preamp
,
replay_gain_missing_preamp
,
replay_gain_limit
);
g_debug
(
"scale=%f
\n
"
,
(
double
)
scale
);
filter
->
volume
=
pcm_float_to_volume
(
scale
);
volume
=
pcm_float_to_volume
(
scale
);
}
else
filter
->
volume
=
PCM_VOLUME_1
;
volume
=
PCM_VOLUME_1
;
if
(
filter
->
mixer
!=
NULL
)
{
if
(
mixer
!=
NULL
)
{
/* update the hardware mixer volume */
unsigned
volume
=
(
filter
->
volume
*
filter
->
base
)
/
PCM_VOLUME_1
;
if
(
volume
>
100
)
volume
=
100
;
unsigned
_volume
=
(
volume
*
base
)
/
PCM_VOLUME_1
;
if
(
_
volume
>
100
)
_
volume
=
100
;
GError
*
error
=
NULL
;
if
(
!
mixer_set_volume
(
filter
->
mixer
,
volume
,
&
error
))
{
if
(
!
mixer_set_volume
(
mixer
,
_
volume
,
&
error
))
{
g_warning
(
"Failed to update hardware mixer: %s"
,
error
->
message
);
g_error_free
(
error
);
...
...
@@ -113,70 +155,41 @@ replay_gain_filter_update(struct replay_gain_filter *filter)
}
}
static
struct
f
ilter
*
static
F
ilter
*
replay_gain_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
struct
replay_gain_filter
*
filter
=
g_new
(
struct
replay_gain_filter
,
1
);
filter_init
(
&
filter
->
filter
,
&
replay_gain_filter_plugin
);
filter
->
mixer
=
NULL
;
filter
->
mode
=
REPLAY_GAIN_OFF
;
replay_gain_info_init
(
&
filter
->
info
);
filter
->
volume
=
PCM_VOLUME_1
;
return
&
filter
->
filter
;
return
new
ReplayGainFilter
();
}
static
void
replay_gain_filter_finish
(
struct
filter
*
filte
r
)
const
audio_format
*
ReplayGainFilter
::
Open
(
audio_format
&
af
,
gcc_unused
GError
**
error_
r
)
{
g_free
(
filter
);
}
static
const
struct
audio_format
*
replay_gain_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
{
struct
replay_gain_filter
*
filter
=
(
struct
replay_gain_filter
*
)
_filter
;
filter
->
audio_format
=
*
audio_format
;
pcm_buffer_init
(
&
filter
->
buffer
);
format
=
af
;
pcm_buffer_init
(
&
buffer
);
return
&
f
ilter
->
audio_f
ormat
;
return
&
format
;
}
static
void
replay_gain_filter_close
(
struct
filter
*
_filter
)
void
ReplayGainFilter
::
Close
(
)
{
struct
replay_gain_filter
*
filter
=
(
struct
replay_gain_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
filter
->
buffer
);
pcm_buffer_deinit
(
&
buffer
);
}
static
const
void
*
replay_gain_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
const
void
*
ReplayGainFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
{
struct
replay_gain_filter
*
filter
=
(
struct
replay_gain_filter
*
)
_filter
;
bool
success
;
void
*
dest
;
*
dest_size_r
=
src_size
;
if
(
filter
->
volume
==
PCM_VOLUME_1
)
if
(
volume
==
PCM_VOLUME_1
)
/* optimized special case: 100% volume = no-op */
return
src
;
dest
=
pcm_buffer_get
(
&
filter
->
buffer
,
src_size
);
if
(
filter
->
volume
<=
0
)
{
void
*
dest
=
pcm_buffer_get
(
&
buffer
,
src_size
);
if
(
volume
<=
0
)
{
/* optimized special case: 0% volume = memset(0) */
/* XXX is this valid for all sample formats? What
about floating point? */
...
...
@@ -186,9 +199,9 @@ replay_gain_filter_filter(struct filter *_filter,
memcpy
(
dest
,
src
,
src_size
);
success
=
pcm_volume
(
dest
,
src_size
,
sample_format
(
filter
->
audio_
format
.
format
),
filter
->
volume
);
bool
success
=
pcm_volume
(
dest
,
src_size
,
sample_format
(
format
.
format
),
volume
);
if
(
!
success
)
{
g_set_error
(
error_r
,
replay_gain_quark
(),
0
,
"pcm_volume() has failed"
);
...
...
@@ -201,55 +214,29 @@ replay_gain_filter_filter(struct filter *_filter,
const
struct
filter_plugin
replay_gain_filter_plugin
=
{
"replay_gain"
,
replay_gain_filter_init
,
replay_gain_filter_finish
,
replay_gain_filter_open
,
replay_gain_filter_close
,
replay_gain_filter_filter
,
};
void
replay_gain_filter_set_mixer
(
struct
f
ilter
*
_filter
,
struct
mixer
*
mixer
,
replay_gain_filter_set_mixer
(
F
ilter
*
_filter
,
struct
mixer
*
mixer
,
unsigned
base
)
{
struct
replay_gain_filter
*
filter
=
(
struct
replay_gain_filter
*
)
_filter
;
assert
(
mixer
==
NULL
||
(
base
>
0
&&
base
<=
100
));
filter
->
mixer
=
mixer
;
filter
->
base
=
base
;
ReplayGainFilter
*
filter
=
(
ReplayGainFilter
*
)
_filter
;
replay_gain_filter_update
(
filter
);
filter
->
SetMixer
(
mixer
,
base
);
}
void
replay_gain_filter_set_info
(
struct
filter
*
_filter
,
const
struct
replay_gain_info
*
info
)
replay_gain_filter_set_info
(
Filter
*
_filter
,
const
replay_gain_info
*
info
)
{
struct
replay_gain_filter
*
filter
=
(
struct
replay_gain_filter
*
)
_filter
;
ReplayGainFilter
*
filter
=
(
ReplayGainFilter
*
)
_filter
;
if
(
info
!=
NULL
)
{
filter
->
info
=
*
info
;
replay_gain_info_complete
(
&
filter
->
info
);
}
else
replay_gain_info_init
(
&
filter
->
info
);
replay_gain_filter_update
(
filter
);
filter
->
SetInfo
(
info
);
}
void
replay_gain_filter_set_mode
(
struct
f
ilter
*
_filter
,
enum
replay_gain_mode
mode
)
replay_gain_filter_set_mode
(
F
ilter
*
_filter
,
enum
replay_gain_mode
mode
)
{
struct
replay_gain_filter
*
filter
=
(
struct
replay_gain_filter
*
)
_filter
;
if
(
mode
==
filter
->
mode
)
/* no change */
return
;
g_debug
(
"replay gain mode has changed %d->%d
\n
"
,
filter
->
mode
,
mode
);
ReplayGainFilter
*
filter
=
(
ReplayGainFilter
*
)
_filter
;
filter
->
mode
=
mode
;
replay_gain_filter_update
(
filter
);
filter
->
SetMode
(
mode
);
}
src/filter/ReplayGainFilterPlugin.hxx
View file @
a9ce0218
...
...
@@ -22,7 +22,7 @@
#include "replay_gain_info.h"
struct
f
ilter
;
class
F
ilter
;
struct
mixer
;
/**
...
...
@@ -34,7 +34,7 @@ struct mixer;
* (including).
*/
void
replay_gain_filter_set_mixer
(
struct
f
ilter
*
_filter
,
struct
mixer
*
mixer
,
replay_gain_filter_set_mixer
(
F
ilter
*
_filter
,
struct
mixer
*
mixer
,
unsigned
base
);
/**
...
...
@@ -44,10 +44,9 @@ replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer,
* gain data is available for the current song
*/
void
replay_gain_filter_set_info
(
struct
filter
*
filter
,
const
struct
replay_gain_info
*
info
);
replay_gain_filter_set_info
(
Filter
*
filter
,
const
replay_gain_info
*
info
);
void
replay_gain_filter_set_mode
(
struct
f
ilter
*
filter
,
enum
replay_gain_mode
mode
);
replay_gain_filter_set_mode
(
F
ilter
*
filter
,
enum
replay_gain_mode
mode
);
#endif
src/filter/RouteFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -53,14 +53,7 @@
#include <string.h>
#include <stdlib.h>
struct
route_filter
{
/**
* Inherit (and support cast to/from) filter
*/
struct
filter
base
;
class
RouteFilter
final
:
public
Filter
{
/**
* The minimum number of channels we need for output
* to be able to perform all the copies the user has specified
...
...
@@ -110,21 +103,31 @@ struct route_filter {
*/
struct
pcm_buffer
output_buffer
;
public
:
RouteFilter
()
:
sources
(
nullptr
)
{}
~
RouteFilter
()
{
g_free
(
sources
);
}
/**
* Parse the "routes" section, a string on the form
* a>b, c>d, e>f, ...
* where a... are non-unique, non-negative integers
* and input channel a gets copied to output channel b, etc.
* @param param the configuration block to read
* @param filter a route_filter whose min_channels and sources[] to set
* @return true on success, false on error
*/
bool
Configure
(
const
config_param
*
param
,
GError
**
error_r
);
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
};
/**
* Parse the "routes" section, a string on the form
* a>b, c>d, e>f, ...
* where a... are non-unique, non-negative integers
* and input channel a gets copied to output channel b, etc.
* @param param the configuration block to read
* @param filter a route_filter whose min_channels and sources[] to set
* @return true on success, false on error
*/
static
bool
route_filter_parse
(
const
struct
config_param
*
param
,
struct
route_filter
*
filter
,
GError
**
error_r
)
{
bool
RouteFilter
::
Configure
(
const
config_param
*
param
,
GError
**
error_r
)
{
/* TODO:
* With a more clever way of marking "don't copy to output N",
...
...
@@ -139,8 +142,8 @@ route_filter_parse(const struct config_param *param,
const
char
*
routes
=
config_get_block_string
(
param
,
"routes"
,
"0>0, 1>1"
);
filter
->
min_input_channels
=
0
;
filter
->
min_output_channels
=
0
;
min_input_channels
=
0
;
min_output_channels
=
0
;
tokens
=
g_strsplit
(
routes
,
","
,
255
);
number_of_copies
=
g_strv_length
(
tokens
);
...
...
@@ -171,28 +174,28 @@ route_filter_parse(const struct config_param *param,
// Keep track of the highest channel numbers seen
// as either in- or outputs
if
(
source
>=
filter
->
min_input_channels
)
filter
->
min_input_channels
=
source
+
1
;
if
(
dest
>=
filter
->
min_output_channels
)
filter
->
min_output_channels
=
dest
+
1
;
if
(
source
>=
min_input_channels
)
min_input_channels
=
source
+
1
;
if
(
dest
>=
min_output_channels
)
min_output_channels
=
dest
+
1
;
g_strfreev
(
sd
);
}
if
(
!
audio_valid_channel_count
(
filter
->
min_output_channels
))
{
if
(
!
audio_valid_channel_count
(
min_output_channels
))
{
g_strfreev
(
tokens
);
g_set_error
(
error_r
,
audio_format_quark
(),
0
,
"Invalid number of output channels requested: %d"
,
filter
->
min_output_channels
);
min_output_channels
);
return
false
;
}
// Allocate a map of "copy nothing to me"
filter
->
sources
=
(
signed
char
*
)
g_malloc
(
filter
->
min_output_channels
*
sizeof
(
signed
char
));
sources
=
(
signed
char
*
)
g_malloc
(
min_output_channels
*
sizeof
(
signed
char
));
for
(
int
i
=
0
;
i
<
filter
->
min_output_channels
;
++
i
)
filter
->
sources
[
i
]
=
-
1
;
for
(
int
i
=
0
;
i
<
min_output_channels
;
++
i
)
sources
[
i
]
=
-
1
;
// Run through the spec again, and save the
// actual mapping output <- input
...
...
@@ -216,7 +219,7 @@ route_filter_parse(const struct config_param *param,
source
=
strtol
(
sd
[
0
],
NULL
,
10
);
dest
=
strtol
(
sd
[
1
],
NULL
,
10
);
filter
->
sources
[
dest
]
=
source
;
sources
[
dest
]
=
source
;
g_strfreev
(
sd
);
}
...
...
@@ -226,73 +229,53 @@ route_filter_parse(const struct config_param *param,
return
true
;
}
static
struct
filter
*
route_filter_init
(
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
struct
route_filter
*
filter
=
g_new
(
struct
route_filter
,
1
);
filter_init
(
&
filter
->
base
,
&
route_filter_plugin
);
// Allocate and set the filter->sources[] array
route_filter_parse
(
param
,
filter
,
error_r
);
return
&
filter
->
base
;
}
static
void
route_filter_finish
(
struct
filter
*
_filter
)
static
Filter
*
route_filter_init
(
const
config_param
*
param
,
GError
**
error_r
)
{
struct
route_filter
*
filter
=
(
struct
route_filter
*
)
_filter
;
RouteFilter
*
filter
=
new
RouteFilter
();
if
(
!
filter
->
Configure
(
param
,
error_r
))
{
delete
filter
;
return
nullptr
;
}
g_free
(
filter
->
sources
);
g_free
(
filter
);
return
filter
;
}
static
const
struct
audio_format
*
route_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
const
struct
audio_format
*
RouteFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_r
)
{
struct
route_filter
*
filter
=
(
struct
route_filter
*
)
_filter
;
// Copy the input format for later reference
filter
->
input_format
=
*
audio_format
;
filter
->
input_frame_size
=
audio_format_frame_size
(
&
filter
->
input_format
);
input_format
=
audio_format
;
input_frame_size
=
audio_format_frame_size
(
&
input_format
);
// Decide on an output format which has enough channels,
// and is otherwise identical
filter
->
output_format
=
*
audio_format
;
filter
->
output_format
.
channels
=
filter
->
min_output_channels
;
output_format
=
audio_format
;
output_format
.
channels
=
min_output_channels
;
// Precalculate this simple value, to speed up allocation later
filter
->
output_frame_size
=
audio_format_frame_size
(
&
filter
->
output_format
);
output_frame_size
=
audio_format_frame_size
(
&
output_format
);
// This buffer grows as needed
pcm_buffer_init
(
&
filter
->
output_buffer
);
pcm_buffer_init
(
&
output_buffer
);
return
&
filter
->
output_format
;
return
&
output_format
;
}
static
void
route_filter_close
(
struct
filter
*
_filter
)
void
RouteFilter
::
Close
(
)
{
struct
route_filter
*
filter
=
(
struct
route_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
filter
->
output_buffer
);
pcm_buffer_deinit
(
&
output_buffer
);
}
static
const
void
*
route_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
const
void
*
RouteFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
{
struct
route_filter
*
filter
=
(
struct
route_filter
*
)
_filter
;
size_t
number_of_frames
=
src_size
/
filter
->
input_frame_size
;
size_t
number_of_frames
=
src_size
/
input_frame_size
;
size_t
bytes_per_frame_per_channel
=
audio_format_sample_size
(
&
filter
->
input_format
);
audio_format_sample_size
(
&
input_format
);
// A moving pointer that always refers to channel 0 in the input, at the currently handled frame
const
uint8_t
*
base_source
=
(
const
uint8_t
*
)
src
;
...
...
@@ -301,18 +284,18 @@ route_filter_filter(struct filter *_filter,
uint8_t
*
chan_destination
;
// Grow our reusable buffer, if needed, and set the moving pointer
*
dest_size_r
=
number_of_frames
*
filter
->
output_frame_size
;
*
dest_size_r
=
number_of_frames
*
output_frame_size
;
chan_destination
=
(
uint8_t
*
)
pcm_buffer_get
(
&
filter
->
output_buffer
,
*
dest_size_r
);
pcm_buffer_get
(
&
output_buffer
,
*
dest_size_r
);
// Perform our copy operations, with N input channels and M output channels
for
(
unsigned
int
s
=
0
;
s
<
number_of_frames
;
++
s
)
{
// Need to perform one copy per output channel
for
(
unsigned
int
c
=
0
;
c
<
filter
->
min_output_channels
;
++
c
)
{
if
(
filter
->
sources
[
c
]
==
-
1
||
(
unsigned
)
filter
->
sources
[
c
]
>=
filter
->
input_format
.
channels
)
{
for
(
unsigned
int
c
=
0
;
c
<
min_output_channels
;
++
c
)
{
if
(
sources
[
c
]
==
-
1
||
(
unsigned
)
sources
[
c
]
>=
input_format
.
channels
)
{
// No source for this destination output,
// give it zeroes as input
memset
(
chan_destination
,
...
...
@@ -322,7 +305,7 @@ route_filter_filter(struct filter *_filter,
// Get the data from channel sources[c]
// and copy it to the output
const
uint8_t
*
data
=
base_source
+
(
filter
->
sources
[
c
]
*
bytes_per_frame_per_channel
);
(
sources
[
c
]
*
bytes_per_frame_per_channel
);
memcpy
(
chan_destination
,
data
,
bytes_per_frame_per_channel
);
...
...
@@ -333,18 +316,14 @@ route_filter_filter(struct filter *_filter,
// Go on to the next N input samples
base_source
+=
filter
->
input_frame_size
;
base_source
+=
input_frame_size
;
}
// Here it is, ladies and gentlemen! Rerouted data!
return
(
void
*
)
filter
->
output_buffer
.
buffer
;
return
(
void
*
)
output_buffer
.
buffer
;
}
const
struct
filter_plugin
route_filter_plugin
=
{
"route"
,
route_filter_init
,
route_filter_finish
,
route_filter_open
,
route_filter_close
,
route_filter_filter
,
};
src/filter/VolumeFilterPlugin.cxx
View file @
a9ce0218
...
...
@@ -30,17 +30,36 @@
#include <assert.h>
#include <string.h>
struct
volume_filter
{
struct
filter
filter
;
class
VolumeFilter
final
:
public
Filter
{
/**
* The current volume, from 0 to #PCM_VOLUME_1.
*/
unsigned
volume
;
struct
audio_format
audio_
format
;
struct
audio_format
format
;
struct
pcm_buffer
buffer
;
public
:
VolumeFilter
()
:
volume
(
PCM_VOLUME_1
)
{}
unsigned
GetVolume
()
const
{
assert
(
volume
<=
PCM_VOLUME_1
);
return
volume
;
}
void
SetVolume
(
unsigned
_volume
)
{
assert
(
_volume
<=
PCM_VOLUME_1
);
volume
=
_volume
;
}
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
virtual
void
Close
();
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
);
};
static
inline
GQuark
...
...
@@ -49,61 +68,41 @@ volume_quark(void)
return
g_quark_from_static_string
(
"pcm_volume"
);
}
static
struct
f
ilter
*
static
F
ilter
*
volume_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
{
struct
volume_filter
*
filter
=
g_new
(
struct
volume_filter
,
1
);
filter_init
(
&
filter
->
filter
,
&
volume_filter_plugin
);
filter
->
volume
=
PCM_VOLUME_1
;
return
&
filter
->
filter
;
return
new
VolumeFilter
();
}
static
void
volume_filter_finish
(
struct
filter
*
filte
r
)
const
struct
audio_format
*
VolumeFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_
r
)
{
g_free
(
filter
);
}
static
const
struct
audio_format
*
volume_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
{
struct
volume_filter
*
filter
=
(
struct
volume_filter
*
)
_filter
;
filter
->
audio_format
=
*
audio_format
;
pcm_buffer_init
(
&
filter
->
buffer
);
format
=
audio_format
;
pcm_buffer_init
(
&
buffer
);
return
&
f
ilter
->
audio_f
ormat
;
return
&
format
;
}
static
void
volume_filter_close
(
struct
filter
*
_filter
)
void
VolumeFilter
::
Close
(
)
{
struct
volume_filter
*
filter
=
(
struct
volume_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
filter
->
buffer
);
pcm_buffer_deinit
(
&
buffer
);
}
static
const
void
*
volume_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
const
void
*
VolumeFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
{
struct
volume_filter
*
filter
=
(
struct
volume_filter
*
)
_filter
;
bool
success
;
void
*
dest
;
*
dest_size_r
=
src_size
;
if
(
filter
->
volume
>=
PCM_VOLUME_1
)
if
(
volume
>=
PCM_VOLUME_1
)
/* optimized special case: 100% volume = no-op */
return
src
;
dest
=
pcm_buffer_get
(
&
filter
->
buffer
,
src_size
);
void
*
dest
=
pcm_buffer_get
(
&
buffer
,
src_size
);
if
(
filter
->
volume
<=
0
)
{
if
(
volume
<=
0
)
{
/* optimized special case: 0% volume = memset(0) */
/* XXX is this valid for all sample formats? What
about floating point? */
...
...
@@ -113,9 +112,9 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
memcpy
(
dest
,
src
,
src_size
);
success
=
pcm_volume
(
dest
,
src_size
,
sample_format
(
filter
->
audio_
format
.
format
),
filter
->
volume
);
bool
success
=
pcm_volume
(
dest
,
src_size
,
sample_format
(
format
.
format
),
volume
);
if
(
!
success
)
{
g_set_error
(
error_r
,
volume_quark
(),
0
,
"pcm_volume() has failed"
);
...
...
@@ -128,32 +127,22 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
const
struct
filter_plugin
volume_filter_plugin
=
{
"volume"
,
volume_filter_init
,
volume_filter_finish
,
volume_filter_open
,
volume_filter_close
,
volume_filter_filter
,
};
unsigned
volume_filter_get
(
const
struct
f
ilter
*
_filter
)
volume_filter_get
(
const
F
ilter
*
_filter
)
{
const
struct
volume_f
ilter
*
filter
=
(
const
struct
volume_f
ilter
*
)
_filter
;
const
VolumeF
ilter
*
filter
=
(
const
VolumeF
ilter
*
)
_filter
;
assert
(
filter
->
filter
.
plugin
==
&
volume_filter_plugin
);
assert
(
filter
->
volume
<=
PCM_VOLUME_1
);
return
filter
->
volume
;
return
filter
->
GetVolume
();
}
void
volume_filter_set
(
struct
f
ilter
*
_filter
,
unsigned
volume
)
volume_filter_set
(
F
ilter
*
_filter
,
unsigned
volume
)
{
struct
volume_filter
*
filter
=
(
struct
volume_filter
*
)
_filter
;
assert
(
filter
->
filter
.
plugin
==
&
volume_filter_plugin
);
assert
(
volume
<=
PCM_VOLUME_1
);
VolumeFilter
*
filter
=
(
VolumeFilter
*
)
_filter
;
filter
->
volume
=
volume
;
filter
->
SetVolume
(
volume
)
;
}
src/filter/VolumeFilterPlugin.hxx
View file @
a9ce0218
...
...
@@ -20,12 +20,12 @@
#ifndef MPD_VOLUME_FILTER_PLUGIN_HXX
#define MPD_VOLUME_FILTER_PLUGIN_HXX
struct
f
ilter
;
class
F
ilter
;
unsigned
volume_filter_get
(
const
struct
f
ilter
*
filter
);
volume_filter_get
(
const
F
ilter
*
filter
);
void
volume_filter_set
(
struct
f
ilter
*
filter
,
unsigned
volume
);
volume_filter_set
(
F
ilter
*
filter
,
unsigned
volume
);
#endif
src/mixer/SoftwareMixerPlugin.cxx
View file @
a9ce0218
...
...
@@ -32,7 +32,7 @@ struct software_mixer {
/** the base mixer class */
struct
mixer
base
;
struct
f
ilter
*
filter
;
F
ilter
*
filter
;
unsigned
volume
;
};
...
...
@@ -100,7 +100,7 @@ const struct mixer_plugin software_mixer_plugin = {
true
,
};
struct
f
ilter
*
F
ilter
*
software_mixer_get_filter
(
struct
mixer
*
mixer
)
{
struct
software_mixer
*
sm
=
(
struct
software_mixer
*
)
mixer
;
...
...
src/mixer/SoftwareMixerPlugin.hxx
View file @
a9ce0218
...
...
@@ -21,13 +21,13 @@
#define MPD_SOFTWARE_MIXER_PLUGIN_HXX
struct
mixer
;
struct
f
ilter
;
class
F
ilter
;
/**
* Returns the (volume) filter associated with this mixer. All users
* of this mixer plugin should install this filter.
*/
struct
f
ilter
*
F
ilter
*
software_mixer_get_filter
(
struct
mixer
*
mixer
);
#endif
src/output_internal.h
View file @
a9ce0218
...
...
@@ -27,6 +27,12 @@
#include <time.h>
#ifdef __cplusplus
class
Filter
;
#else
typedef
void
*
Filter
;
#endif
struct
config_param
;
enum
audio_output_command
{
...
...
@@ -156,13 +162,13 @@ struct audio_output {
* The filter object of this audio output. This is an
* instance of chain_filter_plugin.
*/
struct
f
ilter
*
filter
;
F
ilter
*
filter
;
/**
* The replay_gain_filter_plugin instance of this audio
* output.
*/
struct
f
ilter
*
replay_gain_filter
;
F
ilter
*
replay_gain_filter
;
/**
* The serial number of the last replay gain info. 0 means no
...
...
@@ -175,7 +181,7 @@ struct audio_output {
* output, to be applied to the second chunk during
* cross-fading.
*/
struct
f
ilter
*
other_replay_gain_filter
;
F
ilter
*
other_replay_gain_filter
;
/**
* The serial number of the last replay gain info by the
...
...
@@ -189,7 +195,7 @@ struct audio_output {
* for converting the input data into the appropriate format
* for this audio output.
*/
struct
f
ilter
*
convert_filter
;
F
ilter
*
convert_filter
;
/**
* The thread handle, or NULL if the output thread isn't
...
...
test/run_filter.cxx
View file @
a9ce0218
...
...
@@ -23,6 +23,7 @@
#include "AudioParser.hxx"
#include "audio_format.h"
#include "FilterPlugin.hxx"
#include "FilterInternal.hxx"
#include "PcmVolume.hxx"
#include "mixer_control.h"
#include "stdbin.h"
...
...
@@ -66,11 +67,10 @@ find_named_config_block(ConfigOption option, const char *name)
return
NULL
;
}
static
struct
f
ilter
*
static
F
ilter
*
load_filter
(
const
char
*
name
)
{
const
struct
config_param
*
param
;
struct
filter
*
filter
;
GError
*
error
=
NULL
;
param
=
find_named_config_block
(
CONF_AUDIO_FILTER
,
name
);
...
...
@@ -79,7 +79,7 @@ load_filter(const char *name)
return
nullptr
;
}
filter
=
filter_configured_new
(
param
,
&
error
);
Filter
*
filter
=
filter_configured_new
(
param
,
&
error
);
if
(
filter
==
NULL
)
{
g_printerr
(
"Failed to load filter: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
...
...
@@ -95,7 +95,6 @@ int main(int argc, char **argv)
struct
audio_format_string
af_string
;
bool
success
;
GError
*
error
=
NULL
;
struct
filter
*
filter
;
const
struct
audio_format
*
out_audio_format
;
char
buffer
[
4096
];
...
...
@@ -137,17 +136,17 @@ int main(int argc, char **argv)
/* initialize the filter */
filter
=
load_filter
(
argv
[
2
]);
Filter
*
filter
=
load_filter
(
argv
[
2
]);
if
(
filter
==
NULL
)
return
1
;
/* open the filter */
out_audio_format
=
filter
_open
(
filter
,
&
audio_format
,
&
error
);
out_audio_format
=
filter
->
Open
(
audio_format
,
&
error
);
if
(
out_audio_format
==
NULL
)
{
g_printerr
(
"Failed to open filter: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
filter_free
(
filter
)
;
delete
filter
;
return
1
;
}
...
...
@@ -165,28 +164,28 @@ int main(int argc, char **argv)
if
(
nbytes
<=
0
)
break
;
dest
=
filter
_filter
(
filter
,
buffer
,
(
size_t
)
nbytes
,
&
length
,
&
error
);
dest
=
filter
->
FilterPCM
(
buffer
,
(
size_t
)
nbytes
,
&
length
,
&
error
);
if
(
dest
==
NULL
)
{
g_printerr
(
"Filter failed: %s
\n
"
,
error
->
message
);
filter
_close
(
filter
);
filter_free
(
filter
)
;
filter
->
Close
(
);
delete
filter
;
return
1
;
}
nbytes
=
write
(
1
,
dest
,
length
);
if
(
nbytes
<
0
)
{
g_printerr
(
"Failed to write: %s
\n
"
,
g_strerror
(
errno
));
filter
_close
(
filter
);
filter_free
(
filter
)
;
filter
->
Close
(
);
delete
filter
;
return
1
;
}
}
/* cleanup and exit */
filter
_close
(
filter
);
filter_free
(
filter
)
;
filter
->
Close
(
);
delete
filter
;
config_global_finish
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment