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)
...
@@ -78,7 +78,7 @@ filter_plugin_config(const char *filter_template_name, GError **error_r)
* @return the number of filters which were successfully added
* @return the number of filters which were successfully added
*/
*/
unsigned
int
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
// Split on comma
...
@@ -89,26 +89,27 @@ filter_chain_parse(struct filter *chain, const char *spec, GError **error_r)
...
@@ -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
// Add each name to the filter chain by instantiating an actual filter
char
**
template_names
=
tokens
;
char
**
template_names
=
tokens
;
while
(
*
template_names
!=
NULL
)
{
while
(
*
template_names
!=
NULL
)
{
struct
filter
*
f
;
const
struct
config_param
*
cfg
;
// Squeeze whitespace
// Squeeze whitespace
g_strstrip
(
*
template_names
);
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
)
{
if
(
cfg
==
NULL
)
{
// The error has already been set, just stop.
// The error has already been set, just stop.
break
;
break
;
}
}
// Instantiate one of those filter plugins with the template name as a hint
// 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
)
{
if
(
f
==
NULL
)
{
// The error has already been set, just stop.
// The error has already been set, just stop.
break
;
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
;
++
added_filters
;
++
template_names
;
++
template_names
;
...
...
src/FilterConfig.hxx
View file @
a9ce0218
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
#include "gerror.h"
#include "gerror.h"
struct
f
ilter
;
class
F
ilter
;
/**
/**
* Builds a filter chain from a configuration string on the form
* Builds a filter chain from a configuration string on the form
...
@@ -39,6 +39,6 @@ struct filter;
...
@@ -39,6 +39,6 @@ struct filter;
* @return the number of filters which were successfully added
* @return the number of filters which were successfully added
*/
*/
unsigned
int
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
#endif
src/FilterInternal.hxx
View file @
a9ce0218
...
@@ -25,14 +25,47 @@
...
@@ -25,14 +25,47 @@
#ifndef MPD_FILTER_INTERNAL_HXX
#ifndef MPD_FILTER_INTERNAL_HXX
#define MPD_FILTER_INTERNAL_HXX
#define MPD_FILTER_INTERNAL_HXX
struct
filter
{
struct
audio_format
;
const
struct
filter_plugin
*
plugin
;
};
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
)
* Closes the filter. After that, you may call Open() again.
{
*/
filter
->
plugin
=
plugin
;
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
#endif
src/FilterPlugin.cxx
View file @
a9ce0218
...
@@ -24,13 +24,9 @@
...
@@ -24,13 +24,9 @@
#include "conf.h"
#include "conf.h"
#include "ConfigQuark.hxx"
#include "ConfigQuark.hxx"
#ifndef NDEBUG
#include "audio_format.h"
#endif
#include <assert.h>
#include <assert.h>
struct
f
ilter
*
F
ilter
*
filter_new
(
const
struct
filter_plugin
*
plugin
,
filter_new
(
const
struct
filter_plugin
*
plugin
,
const
struct
config_param
*
param
,
GError
**
error_r
)
const
struct
config_param
*
param
,
GError
**
error_r
)
{
{
...
@@ -40,7 +36,7 @@ filter_new(const struct filter_plugin *plugin,
...
@@ -40,7 +36,7 @@ filter_new(const struct filter_plugin *plugin,
return
plugin
->
init
(
param
,
error_r
);
return
plugin
->
init
(
param
,
error_r
);
}
}
struct
f
ilter
*
F
ilter
*
filter_configured_new
(
const
struct
config_param
*
param
,
GError
**
error_r
)
filter_configured_new
(
const
struct
config_param
*
param
,
GError
**
error_r
)
{
{
const
char
*
plugin_name
;
const
char
*
plugin_name
;
...
@@ -65,53 +61,3 @@ filter_configured_new(const struct config_param *param, GError **error_r)
...
@@ -65,53 +61,3 @@ filter_configured_new(const struct config_param *param, GError **error_r)
return
filter_new
(
plugin
,
param
,
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 @@
...
@@ -31,7 +31,7 @@
#include <stddef.h>
#include <stddef.h>
struct
config_param
;
struct
config_param
;
struct
f
ilter
;
class
F
ilter
;
struct
filter_plugin
{
struct
filter_plugin
{
const
char
*
name
;
const
char
*
name
;
...
@@ -39,38 +39,7 @@ struct filter_plugin {
...
@@ -39,38 +39,7 @@ struct filter_plugin {
/**
/**
* Allocates and configures a filter.
* Allocates and configures a filter.
*/
*/
struct
filter
*
(
*
init
)(
const
struct
config_param
*
param
,
Filter
*
(
*
init
)(
const
struct
config_param
*
param
,
GError
**
error_r
);
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
);
};
};
/**
/**
...
@@ -82,7 +51,7 @@ struct filter_plugin {
...
@@ -82,7 +51,7 @@ struct filter_plugin {
* ignore errors.
* ignore errors.
* @return a new filter object, or NULL on error
* @return a new filter object, or NULL on error
*/
*/
struct
f
ilter
*
F
ilter
*
filter_new
(
const
struct
filter_plugin
*
plugin
,
filter_new
(
const
struct
filter_plugin
*
plugin
,
const
struct
config_param
*
param
,
GError
**
error_r
);
const
struct
config_param
*
param
,
GError
**
error_r
);
...
@@ -95,55 +64,7 @@ filter_new(const struct filter_plugin *plugin,
...
@@ -95,55 +64,7 @@ filter_new(const struct filter_plugin *plugin,
* ignore errors.
* ignore errors.
* @return a new filter object, or NULL on error
* @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
);
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
#endif
src/OutputFinish.cxx
View file @
a9ce0218
...
@@ -25,7 +25,7 @@ extern "C" {
...
@@ -25,7 +25,7 @@ extern "C" {
#include "mixer_control.h"
#include "mixer_control.h"
}
}
#include "Filter
Plugin
.hxx"
#include "Filter
Internal
.hxx"
#include <assert.h>
#include <assert.h>
...
@@ -42,13 +42,9 @@ ao_base_finish(struct audio_output *ao)
...
@@ -42,13 +42,9 @@ ao_base_finish(struct audio_output *ao)
g_cond_free
(
ao
->
cond
);
g_cond_free
(
ao
->
cond
);
g_mutex_free
(
ao
->
mutex
);
g_mutex_free
(
ao
->
mutex
);
if
(
ao
->
replay_gain_filter
!=
NULL
)
delete
ao
->
replay_gain_filter
;
filter_free
(
ao
->
replay_gain_filter
);
delete
ao
->
other_replay_gain_filter
;
delete
ao
->
filter
;
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_free
(
ao
->
other_replay_gain_filter
);
filter_free
(
ao
->
filter
);
pcm_buffer_deinit
(
&
ao
->
cross_fade_buffer
);
pcm_buffer_deinit
(
&
ao
->
cross_fade_buffer
);
}
}
...
...
src/OutputInit.cxx
View file @
a9ce0218
...
@@ -100,7 +100,7 @@ static struct mixer *
...
@@ -100,7 +100,7 @@ static struct mixer *
audio_output_load_mixer
(
struct
audio_output
*
ao
,
audio_output_load_mixer
(
struct
audio_output
*
ao
,
const
struct
config_param
*
param
,
const
struct
config_param
*
param
,
const
struct
mixer_plugin
*
plugin
,
const
struct
mixer_plugin
*
plugin
,
struct
filter
*
filter_chain
,
Filter
&
filter_chain
,
GError
**
error_r
)
GError
**
error_r
)
{
{
struct
mixer
*
mixer
;
struct
mixer
*
mixer
;
...
@@ -120,7 +120,7 @@ audio_output_load_mixer(struct audio_output *ao,
...
@@ -120,7 +120,7 @@ audio_output_load_mixer(struct audio_output *ao,
mixer
=
mixer_new
(
&
software_mixer_plugin
,
NULL
,
NULL
,
NULL
);
mixer
=
mixer_new
(
&
software_mixer_plugin
,
NULL
,
NULL
,
NULL
);
assert
(
mixer
!=
NULL
);
assert
(
mixer
!=
NULL
);
filter_chain_append
(
filter_chain
,
filter_chain_append
(
filter_chain
,
"software_mixer"
,
software_mixer_get_filter
(
mixer
));
software_mixer_get_filter
(
mixer
));
return
mixer
;
return
mixer
;
}
}
...
@@ -190,15 +190,15 @@ ao_base_init(struct audio_output *ao,
...
@@ -190,15 +190,15 @@ ao_base_init(struct audio_output *ao,
/* create the normalization filter (if configured) */
/* create the normalization filter (if configured) */
if
(
config_get_bool
(
CONF_VOLUME_NORMALIZATION
,
false
))
{
if
(
config_get_bool
(
CONF_VOLUME_NORMALIZATION
,
false
))
{
struct
f
ilter
*
normalize_filter
=
F
ilter
*
normalize_filter
=
filter_new
(
&
normalize_filter_plugin
,
NULL
,
NULL
);
filter_new
(
&
normalize_filter_plugin
,
NULL
,
NULL
);
assert
(
normalize_filter
!=
NULL
);
assert
(
normalize_filter
!=
NULL
);
filter_chain_append
(
ao
->
filter
,
filter_chain_append
(
*
ao
->
filter
,
"normalize"
,
autoconvert_filter_new
(
normalize_filter
));
autoconvert_filter_new
(
normalize_filter
));
}
}
filter_chain_parse
(
ao
->
filter
,
filter_chain_parse
(
*
ao
->
filter
,
config_get_block_string
(
param
,
AUDIO_FILTERS
,
""
),
config_get_block_string
(
param
,
AUDIO_FILTERS
,
""
),
&
error
&
error
);
);
...
@@ -258,7 +258,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
...
@@ -258,7 +258,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
GError
*
error
=
NULL
;
GError
*
error
=
NULL
;
ao
->
mixer
=
audio_output_load_mixer
(
ao
,
param
,
ao
->
mixer
=
audio_output_load_mixer
(
ao
,
param
,
ao
->
plugin
->
mixer_plugin
,
ao
->
plugin
->
mixer_plugin
,
ao
->
filter
,
&
error
);
*
ao
->
filter
,
&
error
);
if
(
ao
->
mixer
==
NULL
&&
error
!=
NULL
)
{
if
(
ao
->
mixer
==
NULL
&&
error
!=
NULL
)
{
g_warning
(
"Failed to initialize hardware mixer for '%s': %s"
,
g_warning
(
"Failed to initialize hardware mixer for '%s': %s"
,
ao
->
name
,
error
->
message
);
ao
->
name
,
error
->
message
);
...
@@ -285,7 +285,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
...
@@ -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
);
ao
->
convert_filter
=
filter_new
(
&
convert_filter_plugin
,
NULL
,
NULL
);
assert
(
ao
->
convert_filter
!=
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
;
return
true
;
}
}
...
...
src/OutputThread.cxx
View file @
a9ce0218
...
@@ -27,7 +27,7 @@ extern "C" {
...
@@ -27,7 +27,7 @@ extern "C" {
}
}
#include "notify.hxx"
#include "notify.hxx"
#include "Filter
Plugin
.hxx"
#include "Filter
Internal
.hxx"
#include "filter/ConvertFilterPlugin.hxx"
#include "filter/ConvertFilterPlugin.hxx"
#include "filter/ReplayGainFilterPlugin.hxx"
#include "filter/ReplayGainFilterPlugin.hxx"
#include "PlayerControl.hxx"
#include "PlayerControl.hxx"
...
@@ -98,26 +98,24 @@ ao_disable(struct audio_output *ao)
...
@@ -98,26 +98,24 @@ ao_disable(struct audio_output *ao)
}
}
static
const
struct
audio_format
*
static
const
struct
audio_format
*
ao_filter_open
(
struct
audio_output
*
ao
,
ao_filter_open
(
struct
audio_output
*
ao
,
audio_format
&
format
,
struct
audio_format
*
audio_format
,
GError
**
error_r
)
GError
**
error_r
)
{
{
assert
(
audio_format_valid
(
audio_
format
));
assert
(
audio_format_valid
(
&
format
));
/* the replay_gain filter cannot fail here */
/* the replay_gain filter cannot fail here */
if
(
ao
->
replay_gain_filter
!=
NULL
)
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
)
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_open
(
ao
->
other_replay_gain_filter
,
audio_format
,
ao
->
other_replay_gain_filter
->
Open
(
format
,
error_r
);
error_r
);
const
struct
audio_format
*
af
const
struct
audio_format
*
af
=
filter_open
(
ao
->
filter
,
audio_
format
,
error_r
);
=
ao
->
filter
->
Open
(
format
,
error_r
);
if
(
af
==
NULL
)
{
if
(
af
==
NULL
)
{
if
(
ao
->
replay_gain_filter
!=
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
)
if
(
ao
->
other_replay_gain_filter
!=
NULL
)
filter_close
(
ao
->
other_replay_gain_filter
);
ao
->
other_replay_gain_filter
->
Close
(
);
}
}
return
af
;
return
af
;
...
@@ -127,11 +125,11 @@ static void
...
@@ -127,11 +125,11 @@ static void
ao_filter_close
(
struct
audio_output
*
ao
)
ao_filter_close
(
struct
audio_output
*
ao
)
{
{
if
(
ao
->
replay_gain_filter
!=
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
)
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
static
void
...
@@ -139,7 +137,6 @@ ao_open(struct audio_output *ao)
...
@@ -139,7 +137,6 @@ ao_open(struct audio_output *ao)
{
{
bool
success
;
bool
success
;
GError
*
error
=
NULL
;
GError
*
error
=
NULL
;
const
struct
audio_format
*
filter_audio_format
;
struct
audio_format_string
af_string
;
struct
audio_format_string
af_string
;
assert
(
!
ao
->
open
);
assert
(
!
ao
->
open
);
...
@@ -164,7 +161,8 @@ ao_open(struct audio_output *ao)
...
@@ -164,7 +161,8 @@ ao_open(struct audio_output *ao)
/* open the filter */
/* 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
)
{
if
(
filter_audio_format
==
NULL
)
{
g_warning
(
"Failed to open filter for
\"
%s
\"
[%s]: %s"
,
g_warning
(
"Failed to open filter for
\"
%s
\"
[%s]: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
@@ -196,7 +194,7 @@ ao_open(struct audio_output *ao)
...
@@ -196,7 +194,7 @@ ao_open(struct audio_output *ao)
return
;
return
;
}
}
convert_filter_set
(
ao
->
convert_filter
,
&
ao
->
out_audio_format
);
convert_filter_set
(
ao
->
convert_filter
,
ao
->
out_audio_format
);
ao
->
open
=
true
;
ao
->
open
=
true
;
...
@@ -244,7 +242,7 @@ ao_reopen_filter(struct audio_output *ao)
...
@@ -244,7 +242,7 @@ ao_reopen_filter(struct audio_output *ao)
GError
*
error
=
NULL
;
GError
*
error
=
NULL
;
ao_filter_close
(
ao
);
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
)
{
if
(
filter_audio_format
==
NULL
)
{
g_warning
(
"Failed to open filter for
\"
%s
\"
[%s]: %s"
,
g_warning
(
"Failed to open filter for
\"
%s
\"
[%s]: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
@@ -267,7 +265,7 @@ ao_reopen_filter(struct audio_output *ao)
...
@@ -267,7 +265,7 @@ ao_reopen_filter(struct audio_output *ao)
return
;
return
;
}
}
convert_filter_set
(
ao
->
convert_filter
,
&
ao
->
out_audio_format
);
convert_filter_set
(
ao
->
convert_filter
,
ao
->
out_audio_format
);
}
}
static
void
static
void
...
@@ -322,7 +320,7 @@ ao_wait(struct audio_output *ao)
...
@@ -322,7 +320,7 @@ ao_wait(struct audio_output *ao)
static
const
void
*
static
const
void
*
ao_chunk_data
(
struct
audio_output
*
ao
,
const
struct
music_chunk
*
chunk
,
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
,
unsigned
*
replay_gain_serial_p
,
size_t
*
length_r
)
size_t
*
length_r
)
{
{
...
@@ -347,8 +345,8 @@ ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
...
@@ -347,8 +345,8 @@ ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
}
}
GError
*
error
=
NULL
;
GError
*
error
=
NULL
;
data
=
filter_filter
(
replay_gain_filter
,
data
,
length
,
data
=
replay_gain_filter
->
FilterPCM
(
data
,
length
,
&
length
,
&
error
);
&
length
,
&
error
);
if
(
data
==
NULL
)
{
if
(
data
==
NULL
)
{
g_warning
(
"
\"
%s
\"
[%s] failed to filter: %s"
,
g_warning
(
"
\"
%s
\"
[%s] failed to filter: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
@@ -421,7 +419,7 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
...
@@ -421,7 +419,7 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
/* apply filter chain */
/* apply filter chain */
data
=
filter_filter
(
ao
->
filter
,
data
,
length
,
&
length
,
&
error
);
data
=
ao
->
filter
->
FilterPCM
(
data
,
length
,
&
length
,
&
error
);
if
(
data
==
NULL
)
{
if
(
data
==
NULL
)
{
g_warning
(
"
\"
%s
\"
[%s] failed to filter: %s"
,
g_warning
(
"
\"
%s
\"
[%s] failed to filter: %s"
,
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
ao
->
name
,
ao
->
plugin
->
name
,
error
->
message
);
...
...
src/filter/AutoConvertFilterPlugin.cxx
View file @
a9ce0218
...
@@ -27,143 +27,106 @@
...
@@ -27,143 +27,106 @@
#include <assert.h>
#include <assert.h>
struct
AutoConvertFilter
{
class
AutoConvertFilter
final
:
public
Filter
{
struct
filter
base
;
/**
/**
* The audio format being fed to the underlying filter. This
* The audio format being fed to the underlying filter. This
* plugin actually doesn't need this variable, we have it here
* plugin actually doesn't need this variable, we have it here
* just so our open() method doesn't return a stack pointer.
* 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.
* The underlying filter.
*/
*/
struct
f
ilter
*
filter
;
F
ilter
*
filter
;
/**
/**
* A convert_filter, just in case conversion is needed. nullptr
* A convert_filter, just in case conversion is needed. nullptr
* if unused.
* if unused.
*/
*/
struct
filter
*
convert
;
Filter
*
convert
;
AutoConvertFilter
(
const
filter_plugin
&
plugin
,
struct
filter
*
_filter
)
:
filter
(
_filter
)
{
filter_init
(
&
base
,
&
plugin
);
}
public
:
AutoConvertFilter
(
Filter
*
_filter
)
:
filter
(
_filter
)
{}
~
AutoConvertFilter
()
{
~
AutoConvertFilter
()
{
filter_free
(
filter
)
;
delete
filter
;
}
}
};
static
void
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
GError
**
error_r
);
autoconvert_filter_finish
(
struct
filter
*
_filter
)
virtual
void
Close
();
{
virtual
const
void
*
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
size_t
*
dest_size_r
,
GError
**
error_r
);
};
delete
filter
;
}
static
const
struct
audio_format
*
const
struct
audio_format
*
autoconvert_filter_open
(
struct
filter
*
_filter
,
AutoConvertFilter
::
Open
(
audio_format
&
in_audio_format
,
GError
**
error_r
)
struct
audio_format
*
in_audio_format
,
GError
**
error_r
)
{
{
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
assert
(
audio_format_valid
(
&
in_audio_format
));
const
struct
audio_format
*
out_audio_format
;
assert
(
audio_format_valid
(
in_audio_format
));
/* open the "real" filter */
/* open the "real" filter */
filter
->
in_audio_format
=
*
in_audio_format
;
child_audio_format
=
in_audio_format
;
const
audio_format
*
out_audio_format
=
out_audio_format
=
filter_open
(
filter
->
filter
,
filter
->
Open
(
child_audio_format
,
error_r
);
&
filter
->
in_audio_format
,
error_r
);
if
(
out_audio_format
==
nullptr
)
if
(
out_audio_format
==
nullptr
)
return
nullptr
;
return
nullptr
;
/* need to convert? */
/* 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 */
/* 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
,
convert
=
filter_new
(
&
convert_filter_plugin
,
nullptr
,
error_r
);
error_r
);
if
(
convert
==
nullptr
)
{
if
(
filter
->
convert
==
nullptr
)
{
filter
->
Close
();
filter_close
(
filter
->
filter
);
return
nullptr
;
return
nullptr
;
}
}
audio_format3
=
filter_open
(
filter
->
convert
,
&
audio_format2
,
audio_format
audio_format2
=
in_audio_format
;
error_r
);
const
audio_format
*
audio_format3
=
convert
->
Open
(
audio_format2
,
error_r
);
if
(
audio_format3
==
nullptr
)
{
if
(
audio_format3
==
nullptr
)
{
filter_free
(
filter
->
convert
)
;
delete
convert
;
filter
_close
(
filter
->
filter
);
filter
->
Close
(
);
return
nullptr
;
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
}
else
/* no */
/* no */
filter
->
convert
=
nullptr
;
convert
=
nullptr
;
return
out_audio_format
;
return
out_audio_format
;
}
}
static
void
void
autoconvert_filter_close
(
struct
filter
*
_filter
)
AutoConvertFilter
::
Close
(
)
{
{
AutoConvertFilter
*
filter
=
if
(
convert
!=
nullptr
)
{
(
AutoConvertFilter
*
)
_filter
;
convert
->
Close
();
delete
convert
;
if
(
filter
->
convert
!=
nullptr
)
{
filter_close
(
filter
->
convert
);
filter_free
(
filter
->
convert
);
}
}
filter
_close
(
filter
->
filter
);
filter
->
Close
(
);
}
}
static
const
void
*
const
void
*
autoconvert_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
AutoConvertFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
src_size
,
size_t
*
dest_size_r
,
size_t
*
dest_size_r
,
GError
**
error_r
)
GError
**
error_r
)
{
{
AutoConvertFilter
*
filter
=
(
AutoConvertFilter
*
)
_filter
;
if
(
convert
!=
nullptr
)
{
src
=
convert
->
FilterPCM
(
src
,
src_size
,
&
src_size
,
error_r
);
if
(
filter
->
convert
!=
nullptr
)
{
src
=
filter_filter
(
filter
->
convert
,
src
,
src_size
,
&
src_size
,
error_r
);
if
(
src
==
nullptr
)
if
(
src
==
nullptr
)
return
nullptr
;
return
nullptr
;
}
}
return
filter_filter
(
filter
->
filter
,
src
,
src_size
,
dest_size_r
,
return
filter
->
FilterPCM
(
src
,
src_size
,
dest_size_r
,
error_r
);
error_r
);
}
}
static
const
struct
filter_plugin
autoconvert_filter_plugin
=
{
Filter
*
"convert"
,
autoconvert_filter_new
(
Filter
*
filter
)
nullptr
,
autoconvert_filter_finish
,
autoconvert_filter_open
,
autoconvert_filter_close
,
autoconvert_filter_filter
,
};
struct
filter
*
autoconvert_filter_new
(
struct
filter
*
_filter
)
{
{
AutoConvertFilter
*
filter
=
return
new
AutoConvertFilter
(
filter
);
new
AutoConvertFilter
(
autoconvert_filter_plugin
,
_filter
);
return
&
filter
->
base
;
}
}
src/filter/AutoConvertFilterPlugin.hxx
View file @
a9ce0218
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX
#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX
#define 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
* Creates a new "autoconvert" filter. When opened, it ensures that
...
@@ -28,7 +28,7 @@ struct filter;
...
@@ -28,7 +28,7 @@ struct filter;
* requests a different format, it automatically creates a
* requests a different format, it automatically creates a
* convert_filter.
* convert_filter.
*/
*/
struct
f
ilter
*
F
ilter
*
autoconvert_filter_new
(
struct
f
ilter
*
filter
);
autoconvert_filter_new
(
F
ilter
*
filter
);
#endif
#endif
src/filter/ChainFilterPlugin.cxx
View file @
a9ce0218
...
@@ -31,20 +31,39 @@
...
@@ -31,20 +31,39 @@
#include <assert.h>
#include <assert.h>
struct
ChainFilter
{
class
ChainFilter
final
:
public
Filter
{
/** the base class */
struct
Child
{
struct
filter
base
;
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
()
{
std
::
list
<
Child
>
children
;
filter_init
(
&
base
,
&
chain_filter_plugin
);
}
~
ChainFilter
()
{
public
:
for
(
auto
i
:
children
)
void
Append
(
const
char
*
name
,
Filter
*
filter
)
{
filter_free
(
i
);
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
static
inline
GQuark
...
@@ -53,37 +72,23 @@ filter_quark(void)
...
@@ -53,37 +72,23 @@ filter_quark(void)
return
g_quark_from_static_string
(
"filter"
);
return
g_quark_from_static_string
(
"filter"
);
}
}
static
struct
f
ilter
*
static
F
ilter
*
chain_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
chain_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
ChainFilter
*
chain
=
new
ChainFilter
();
return
new
ChainFilter
();
return
&
chain
->
base
;
}
static
void
chain_filter_finish
(
struct
filter
*
_filter
)
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
delete
chain
;
}
}
/**
void
* Close all filters in the chain until #until is reached. #until
ChainFilter
::
CloseUntil
(
const
Filter
*
until
)
* itself is not closed.
*/
static
void
chain_close_until
(
ChainFilter
*
chain
,
const
struct
filter
*
until
)
{
{
for
(
auto
filter
:
chain
->
children
)
{
for
(
auto
&
child
:
children
)
{
if
(
filter
==
until
)
if
(
child
.
filter
==
until
)
/* don't close this filter */
/* don't close this filter */
return
;
return
;
/* close this filter */
/* close this filter */
filter_close
(
filter
);
child
.
filter
->
Close
(
);
}
}
/* this assertion fails if #until does not exist (anymore) */
/* this assertion fails if #until does not exist (anymore) */
...
@@ -91,43 +96,41 @@ chain_close_until(ChainFilter *chain, const struct filter *until)
...
@@ -91,43 +96,41 @@ chain_close_until(ChainFilter *chain, const struct filter *until)
}
}
static
const
struct
audio_format
*
static
const
struct
audio_format
*
chain_open_child
(
struct
f
ilter
*
filter
,
chain_open_child
(
const
char
*
name
,
F
ilter
*
filter
,
const
struct
audio_format
*
prev_audio_format
,
const
audio_format
&
prev_audio_format
,
GError
**
error_r
)
GError
**
error_r
)
{
{
struct
audio_format
conv_audio_format
=
*
prev_audio_format
;
audio_format
conv_audio_format
=
prev_audio_format
;
const
struct
audio_format
*
next_audio_format
;
const
audio_format
*
next_audio_format
=
filter
->
Open
(
conv_audio_format
,
error_r
);
next_audio_format
=
filter_open
(
filter
,
&
conv_audio_format
,
error_r
);
if
(
next_audio_format
==
NULL
)
if
(
next_audio_format
==
NULL
)
return
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
;
struct
audio_format_string
s
;
filter
_close
(
filter
);
filter
->
Close
(
);
g_set_error
(
error_r
,
filter_quark
(),
0
,
g_set_error
(
error_r
,
filter_quark
(),
0
,
"Audio format not supported by filter '%s': %s"
,
"Audio format not supported by filter '%s': %s"
,
filter
->
plugin
->
name
,
name
,
audio_format_to_string
(
prev_audio_format
,
&
s
));
audio_format_to_string
(
&
prev_audio_format
,
&
s
));
return
NULL
;
return
NULL
;
}
}
return
next_audio_format
;
return
next_audio_format
;
}
}
static
const
struct
audio_format
*
const
audio_format
*
chain_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
in_audio_format
,
ChainFilter
::
Open
(
audio_format
&
in_audio_format
,
GError
**
error_r
)
GError
**
error_r
)
{
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
const
audio_format
*
audio_format
=
&
in_audio_format
;
const
struct
audio_format
*
audio_format
=
in_audio_format
;
for
(
auto
filter
:
chain
->
children
)
{
for
(
auto
&
child
:
children
)
{
audio_format
=
chain_open_child
(
filter
,
audio_format
,
error_r
);
audio_format
=
chain_open_child
(
child
.
name
,
child
.
filter
,
*
audio_format
,
error_r
);
if
(
audio_format
==
NULL
)
{
if
(
audio_format
==
NULL
)
{
/* rollback, close all children */
/* rollback, close all children */
chain_close_until
(
chain
,
filter
);
CloseUntil
(
child
.
filter
);
return
NULL
;
return
NULL
;
}
}
}
}
...
@@ -136,26 +139,22 @@ chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format,
...
@@ -136,26 +139,22 @@ chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format,
return
audio_format
;
return
audio_format
;
}
}
static
void
void
chain_filter_close
(
struct
filter
*
_filter
)
ChainFilter
::
Close
(
)
{
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
for
(
auto
&
child
:
children
)
child
.
filter
->
Close
();
for
(
auto
filter
:
chain
->
children
)
filter_close
(
filter
);
}
}
static
const
void
*
const
void
*
chain_filter_filter
(
struct
filter
*
_filter
,
ChainFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
size_t
*
dest_size_r
,
GError
**
error_r
)
{
{
ChainFilter
*
chain
=
(
ChainFilter
*
)
_filter
;
for
(
auto
&
child
:
children
)
{
for
(
auto
filter
:
chain
->
children
)
{
/* feed the output of the previous filter as input
/* feed the output of the previous filter as input
into the current one */
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
)
if
(
src
==
NULL
)
return
NULL
;
return
NULL
;
}
}
...
@@ -168,26 +167,18 @@ chain_filter_filter(struct filter *_filter,
...
@@ -168,26 +167,18 @@ chain_filter_filter(struct filter *_filter,
const
struct
filter_plugin
chain_filter_plugin
=
{
const
struct
filter_plugin
chain_filter_plugin
=
{
"chain"
,
"chain"
,
chain_filter_init
,
chain_filter_init
,
chain_filter_finish
,
chain_filter_open
,
chain_filter_close
,
chain_filter_filter
,
};
};
struct
f
ilter
*
F
ilter
*
filter_chain_new
(
void
)
filter_chain_new
(
void
)
{
{
struct
filter
*
filter
=
filter_new
(
&
chain_filter_plugin
,
NULL
,
NULL
);
return
new
ChainFilter
();
/* chain_filter_init() never fails */
assert
(
filter
!=
NULL
);
return
filter
;
}
}
void
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 @@
...
@@ -27,12 +27,12 @@
#ifndef MPD_FILTER_CHAIN_HXX
#ifndef MPD_FILTER_CHAIN_HXX
#define MPD_FILTER_CHAIN_HXX
#define MPD_FILTER_CHAIN_HXX
struct
f
ilter
;
class
F
ilter
;
/**
/**
* Creates a new filter chain.
* Creates a new filter chain.
*/
*/
struct
f
ilter
*
F
ilter
*
filter_chain_new
(
void
);
filter_chain_new
(
void
);
/**
/**
...
@@ -43,6 +43,6 @@ filter_chain_new(void);
...
@@ -43,6 +43,6 @@ filter_chain_new(void);
* @param filter the filter to be appended to #chain
* @param filter the filter to be appended to #chain
*/
*/
void
void
filter_chain_append
(
struct
filter
*
chain
,
struct
f
ilter
*
filter
);
filter_chain_append
(
Filter
&
chain
,
const
char
*
name
,
F
ilter
*
filter
);
#endif
#endif
src/filter/ConvertFilterPlugin.cxx
View file @
a9ce0218
...
@@ -31,114 +31,89 @@
...
@@ -31,114 +31,89 @@
#include <assert.h>
#include <assert.h>
#include <string.h>
#include <string.h>
struct
ConvertFilter
{
class
ConvertFilter
final
:
public
Filter
{
struct
filter
base
;
/**
/**
* The input audio format; PCM data is passed to the filter()
* The input audio format; PCM data is passed to the filter()
* method in this format.
* method in this format.
*/
*/
struct
audio_format
in_audio_format
;
audio_format
in_audio_format
;
/**
/**
* The output audio format; the consumer of this plugin
* The output audio format; the consumer of this plugin
* expects PCM data in this format. This defaults to
* expects PCM data in this format. This defaults to
* #in_audio_format, and can be set with convert_filter_set().
* #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
;
Manual
<
PcmConvert
>
state
;
ConvertFilter
()
{
public
:
filter_init
(
&
base
,
&
convert_filter_plugin
);
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
,
convert_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
ConvertFilter
*
filter
=
new
ConvertFilter
();
return
new
ConvertFilter
();
return
&
filter
->
base
;
}
static
void
convert_filter_finish
(
struct
filter
*
filter
)
{
delete
filter
;
}
}
static
const
struct
audio_format
*
const
struct
audio_format
*
convert_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
ConvertFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_r
)
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
;
return
&
in_audio_format
;
filter
->
state
.
Construct
();
return
&
filter
->
in_audio_format
;
}
}
static
void
void
convert_filter_close
(
struct
filter
*
_filter
)
ConvertFilter
::
Close
(
)
{
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
state
.
Destruct
();
filter
->
state
.
Destruct
();
poison_undefined
(
&
filter
->
in_audio_format
,
poison_undefined
(
&
in_audio_format
,
sizeof
(
in_audio_format
));
sizeof
(
filter
->
in_audio_format
));
poison_undefined
(
&
out_audio_format
,
sizeof
(
out_audio_format
));
poison_undefined
(
&
filter
->
out_audio_format
,
sizeof
(
filter
->
out_audio_format
));
}
}
static
const
void
*
const
void
*
convert_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
ConvertFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
size_t
*
dest_size_r
,
GError
**
error_r
)
{
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
if
(
audio_format_equals
(
&
in_audio_format
,
&
out_audio_format
))
{
const
void
*
dest
;
if
(
audio_format_equals
(
&
filter
->
in_audio_format
,
&
filter
->
out_audio_format
))
{
/* optimized special case: no-op */
/* optimized special case: no-op */
*
dest_size_r
=
src_size
;
*
dest_size_r
=
src_size
;
return
src
;
return
src
;
}
}
dest
=
filter
->
state
->
Convert
(
&
filter
->
in_audio_format
,
return
state
->
Convert
(
&
in_audio_format
,
src
,
src_size
,
src
,
src_size
,
&
filter
->
out_audio_format
,
dest_size_r
,
&
out_audio_format
,
dest_size_r
,
error_r
);
error_r
);
if
(
dest
==
NULL
)
return
NULL
;
return
dest
;
}
}
const
struct
filter_plugin
convert_filter_plugin
=
{
const
struct
filter_plugin
convert_filter_plugin
=
{
"convert"
,
"convert"
,
convert_filter_init
,
convert_filter_init
,
convert_filter_finish
,
convert_filter_open
,
convert_filter_close
,
convert_filter_filter
,
};
};
void
void
convert_filter_set
(
struct
filter
*
_filter
,
convert_filter_set
(
Filter
*
_filter
,
const
audio_format
&
out_audio_format
)
const
struct
audio_format
*
out_audio_format
)
{
{
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
ConvertFilter
*
filter
=
(
ConvertFilter
*
)
_filter
;
assert
(
filter
!=
NULL
);
filter
->
Set
(
out_audio_format
);
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
;
}
}
src/filter/ConvertFilterPlugin.hxx
View file @
a9ce0218
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
#ifndef MPD_CONVERT_FILTER_PLUGIN_HXX
#ifndef MPD_CONVERT_FILTER_PLUGIN_HXX
#define MPD_CONVERT_FILTER_PLUGIN_HXX
#define MPD_CONVERT_FILTER_PLUGIN_HXX
struct
f
ilter
;
class
F
ilter
;
struct
audio_format
;
struct
audio_format
;
/**
/**
...
@@ -30,7 +30,6 @@ struct audio_format;
...
@@ -30,7 +30,6 @@ struct audio_format;
* the last in a chain.
* the last in a chain.
*/
*/
void
void
convert_filter_set
(
struct
filter
*
filter
,
convert_filter_set
(
Filter
*
filter
,
const
audio_format
&
out_audio_format
);
const
audio_format
*
out_audio_format
);
#endif
#endif
src/filter/NormalizeFilterPlugin.cxx
View file @
a9ce0218
...
@@ -28,68 +28,51 @@
...
@@ -28,68 +28,51 @@
#include <assert.h>
#include <assert.h>
#include <string.h>
#include <string.h>
struct
normalize_filter
{
class
NormalizeFilter
final
:
public
Filter
{
struct
filter
filter
;
struct
Compressor
*
compressor
;
struct
Compressor
*
compressor
;
struct
pcm_buffer
buffer
;
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
,
normalize_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
struct
normalize_filter
*
filter
=
g_new
(
struct
normalize_filter
,
1
);
return
new
NormalizeFilter
();
filter_init
(
&
filter
->
filter
,
&
normalize_filter_plugin
);
return
&
filter
->
filter
;
}
}
static
void
const
struct
audio_format
*
normalize_filter_finish
(
struct
filter
*
filte
r
)
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
*
compressor
=
Compressor_new
(
0
);
normalize_filter_open
(
struct
filter
*
_filter
,
pcm_buffer_init
(
&
buffer
);
struct
audio_format
*
audio_format
,
gcc_unused
GError
**
error_r
)
{
struct
normalize_filter
*
filter
=
(
struct
normalize_filter
*
)
_filter
;
audio_format
->
format
=
SAMPLE_FORMAT_S16
;
return
&
audio_format
;
filter
->
compressor
=
Compressor_new
(
0
);
pcm_buffer_init
(
&
filter
->
buffer
);
return
audio_format
;
}
}
static
void
void
normalize_filter_close
(
struct
filter
*
_filter
)
NormalizeFilter
::
Close
(
)
{
{
struct
normalize_filter
*
filter
=
(
struct
normalize_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
buffer
);
Compressor_delete
(
compressor
);
pcm_buffer_deinit
(
&
filter
->
buffer
);
Compressor_delete
(
filter
->
compressor
);
}
}
static
const
void
*
const
void
*
normalize_filter_filter
(
struct
filter
*
_filter
,
NormalizeFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
struct
normalize_filter
*
filter
=
(
struct
normalize_filter
*
)
_filter
;
int16_t
*
dest
=
(
int16_t
*
)
pcm_buffer_get
(
&
buffer
,
src_size
);
int16_t
*
dest
=
(
int16_t
*
)
pcm_buffer_get
(
&
filter
->
buffer
,
src_size
);
memcpy
(
dest
,
src
,
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
;
*
dest_size_r
=
src_size
;
return
dest
;
return
dest
;
...
@@ -98,8 +81,4 @@ normalize_filter_filter(struct filter *_filter,
...
@@ -98,8 +81,4 @@ normalize_filter_filter(struct filter *_filter,
const
struct
filter_plugin
normalize_filter_plugin
=
{
const
struct
filter_plugin
normalize_filter_plugin
=
{
"normalize"
,
"normalize"
,
normalize_filter_init
,
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 @@
...
@@ -30,65 +30,31 @@
#include "FilterRegistry.hxx"
#include "FilterRegistry.hxx"
#include "gcc.h"
#include "gcc.h"
#include <glib.h>
class
NullFilter
final
:
public
Filter
{
public
:
struct
null_filter
{
virtual
const
audio_format
*
Open
(
audio_format
&
af
,
struct
filter
filter
;
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
,
null_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
struct
null_filter
*
filter
=
g_new
(
struct
null_filter
,
1
);
return
new
NullFilter
();
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
;
}
}
const
struct
filter_plugin
null_filter_plugin
=
{
const
struct
filter_plugin
null_filter_plugin
=
{
"null"
,
"null"
,
null_filter_init
,
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" {
...
@@ -38,9 +38,7 @@ extern "C" {
#undef G_LOG_DOMAIN
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "replay_gain"
#define G_LOG_DOMAIN "replay_gain"
struct
replay_gain_filter
{
class
ReplayGainFilter
final
:
public
Filter
{
struct
filter
filter
;
/**
/**
* If set, then this hardware mixer is used for applying
* If set, then this hardware mixer is used for applying
* replay gain, instead of the software volume library.
* replay gain, instead of the software volume library.
...
@@ -71,9 +69,56 @@ struct replay_gain_filter {
...
@@ -71,9 +69,56 @@ struct replay_gain_filter {
*/
*/
unsigned
volume
;
unsigned
volume
;
struct
audio_format
audio_
format
;
struct
audio_format
format
;
struct
pcm_buffer
buffer
;
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
static
inline
GQuark
...
@@ -82,30 +127,27 @@ replay_gain_quark(void)
...
@@ -82,30 +127,27 @@ replay_gain_quark(void)
return
g_quark_from_static_string
(
"replay_gain"
);
return
g_quark_from_static_string
(
"replay_gain"
);
}
}
/**
void
* Recalculates the new volume after a property was changed.
ReplayGainFilter
::
Update
()
*/
static
void
replay_gain_filter_update
(
struct
replay_gain_filter
*
filter
)
{
{
if
(
filter
->
mode
!=
REPLAY_GAIN_OFF
)
{
if
(
mode
!=
REPLAY_GAIN_OFF
)
{
float
scale
=
replay_gain_tuple_scale
(
&
filter
->
info
.
tuples
[
filter
->
mode
],
float
scale
=
replay_gain_tuple_scale
(
&
info
.
tuples
[
mode
],
replay_gain_preamp
,
replay_gain_missing_preamp
,
replay_gain_limit
);
replay_gain_preamp
,
replay_gain_missing_preamp
,
replay_gain_limit
);
g_debug
(
"scale=%f
\n
"
,
(
double
)
scale
);
g_debug
(
"scale=%f
\n
"
,
(
double
)
scale
);
filter
->
volume
=
pcm_float_to_volume
(
scale
);
volume
=
pcm_float_to_volume
(
scale
);
}
else
}
else
filter
->
volume
=
PCM_VOLUME_1
;
volume
=
PCM_VOLUME_1
;
if
(
filter
->
mixer
!=
NULL
)
{
if
(
mixer
!=
NULL
)
{
/* update the hardware mixer volume */
/* update the hardware mixer volume */
unsigned
volume
=
(
filter
->
volume
*
filter
->
base
)
/
PCM_VOLUME_1
;
unsigned
_volume
=
(
volume
*
base
)
/
PCM_VOLUME_1
;
if
(
volume
>
100
)
if
(
_
volume
>
100
)
volume
=
100
;
_
volume
=
100
;
GError
*
error
=
NULL
;
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"
,
g_warning
(
"Failed to update hardware mixer: %s"
,
error
->
message
);
error
->
message
);
g_error_free
(
error
);
g_error_free
(
error
);
...
@@ -113,70 +155,41 @@ replay_gain_filter_update(struct replay_gain_filter *filter)
...
@@ -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
,
replay_gain_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
struct
replay_gain_filter
*
filter
=
g_new
(
struct
replay_gain_filter
,
1
);
return
new
ReplayGainFilter
();
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
;
}
}
static
void
const
audio_format
*
replay_gain_filter_finish
(
struct
filter
*
filte
r
)
ReplayGainFilter
::
Open
(
audio_format
&
af
,
gcc_unused
GError
**
error_
r
)
{
{
g_free
(
filter
);
format
=
af
;
}
pcm_buffer_init
(
&
buffer
);
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
);
return
&
f
ilter
->
audio_f
ormat
;
return
&
format
;
}
}
static
void
void
replay_gain_filter_close
(
struct
filter
*
_filter
)
ReplayGainFilter
::
Close
(
)
{
{
struct
replay_gain_filter
*
filter
=
pcm_buffer_deinit
(
&
buffer
);
(
struct
replay_gain_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
filter
->
buffer
);
}
}
static
const
void
*
const
void
*
replay_gain_filter_filter
(
struct
filter
*
_filter
,
ReplayGainFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
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
;
*
dest_size_r
=
src_size
;
if
(
filter
->
volume
==
PCM_VOLUME_1
)
if
(
volume
==
PCM_VOLUME_1
)
/* optimized special case: 100% volume = no-op */
/* optimized special case: 100% volume = no-op */
return
src
;
return
src
;
dest
=
pcm_buffer_get
(
&
filter
->
buffer
,
src_size
);
void
*
dest
=
pcm_buffer_get
(
&
buffer
,
src_size
);
if
(
volume
<=
0
)
{
if
(
filter
->
volume
<=
0
)
{
/* optimized special case: 0% volume = memset(0) */
/* optimized special case: 0% volume = memset(0) */
/* XXX is this valid for all sample formats? What
/* XXX is this valid for all sample formats? What
about floating point? */
about floating point? */
...
@@ -186,9 +199,9 @@ replay_gain_filter_filter(struct filter *_filter,
...
@@ -186,9 +199,9 @@ replay_gain_filter_filter(struct filter *_filter,
memcpy
(
dest
,
src
,
src_size
);
memcpy
(
dest
,
src
,
src_size
);
success
=
pcm_volume
(
dest
,
src_size
,
bool
success
=
pcm_volume
(
dest
,
src_size
,
sample_format
(
filter
->
audio_
format
.
format
),
sample_format
(
format
.
format
),
filter
->
volume
);
volume
);
if
(
!
success
)
{
if
(
!
success
)
{
g_set_error
(
error_r
,
replay_gain_quark
(),
0
,
g_set_error
(
error_r
,
replay_gain_quark
(),
0
,
"pcm_volume() has failed"
);
"pcm_volume() has failed"
);
...
@@ -201,55 +214,29 @@ replay_gain_filter_filter(struct filter *_filter,
...
@@ -201,55 +214,29 @@ replay_gain_filter_filter(struct filter *_filter,
const
struct
filter_plugin
replay_gain_filter_plugin
=
{
const
struct
filter_plugin
replay_gain_filter_plugin
=
{
"replay_gain"
,
"replay_gain"
,
replay_gain_filter_init
,
replay_gain_filter_init
,
replay_gain_filter_finish
,
replay_gain_filter_open
,
replay_gain_filter_close
,
replay_gain_filter_filter
,
};
};
void
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
)
unsigned
base
)
{
{
struct
replay_gain_filter
*
filter
=
ReplayGainFilter
*
filter
=
(
ReplayGainFilter
*
)
_filter
;
(
struct
replay_gain_filter
*
)
_filter
;
assert
(
mixer
==
NULL
||
(
base
>
0
&&
base
<=
100
));
filter
->
mixer
=
mixer
;
filter
->
base
=
base
;
replay_gain_filter_update
(
filter
);
filter
->
SetMixer
(
mixer
,
base
);
}
}
void
void
replay_gain_filter_set_info
(
struct
filter
*
_filter
,
replay_gain_filter_set_info
(
Filter
*
_filter
,
const
replay_gain_info
*
info
)
const
struct
replay_gain_info
*
info
)
{
{
struct
replay_gain_filter
*
filter
=
ReplayGainFilter
*
filter
=
(
ReplayGainFilter
*
)
_filter
;
(
struct
replay_gain_filter
*
)
_filter
;
if
(
info
!=
NULL
)
{
filter
->
SetInfo
(
info
);
filter
->
info
=
*
info
;
replay_gain_info_complete
(
&
filter
->
info
);
}
else
replay_gain_info_init
(
&
filter
->
info
);
replay_gain_filter_update
(
filter
);
}
}
void
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
=
ReplayGainFilter
*
filter
=
(
ReplayGainFilter
*
)
_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
);
filter
->
mode
=
mode
;
filter
->
SetMode
(
mode
);
replay_gain_filter_update
(
filter
);
}
}
src/filter/ReplayGainFilterPlugin.hxx
View file @
a9ce0218
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
#include "replay_gain_info.h"
#include "replay_gain_info.h"
struct
f
ilter
;
class
F
ilter
;
struct
mixer
;
struct
mixer
;
/**
/**
...
@@ -34,7 +34,7 @@ struct mixer;
...
@@ -34,7 +34,7 @@ struct mixer;
* (including).
* (including).
*/
*/
void
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
);
unsigned
base
);
/**
/**
...
@@ -44,10 +44,9 @@ replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer,
...
@@ -44,10 +44,9 @@ replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer,
* gain data is available for the current song
* gain data is available for the current song
*/
*/
void
void
replay_gain_filter_set_info
(
struct
filter
*
filter
,
replay_gain_filter_set_info
(
Filter
*
filter
,
const
replay_gain_info
*
info
);
const
struct
replay_gain_info
*
info
);
void
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
#endif
src/filter/RouteFilterPlugin.cxx
View file @
a9ce0218
...
@@ -53,14 +53,7 @@
...
@@ -53,14 +53,7 @@
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
class
RouteFilter
final
:
public
Filter
{
struct
route_filter
{
/**
* Inherit (and support cast to/from) filter
*/
struct
filter
base
;
/**
/**
* The minimum number of channels we need for output
* The minimum number of channels we need for output
* to be able to perform all the copies the user has specified
* to be able to perform all the copies the user has specified
...
@@ -110,21 +103,31 @@ struct route_filter {
...
@@ -110,21 +103,31 @@ struct route_filter {
*/
*/
struct
pcm_buffer
output_buffer
;
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
);
};
};
/**
bool
* Parse the "routes" section, a string on the form
RouteFilter
::
Configure
(
const
config_param
*
param
,
GError
**
error_r
)
{
* 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
)
{
/* TODO:
/* TODO:
* With a more clever way of marking "don't copy to output N",
* 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,
...
@@ -139,8 +142,8 @@ route_filter_parse(const struct config_param *param,
const
char
*
routes
=
const
char
*
routes
=
config_get_block_string
(
param
,
"routes"
,
"0>0, 1>1"
);
config_get_block_string
(
param
,
"routes"
,
"0>0, 1>1"
);
filter
->
min_input_channels
=
0
;
min_input_channels
=
0
;
filter
->
min_output_channels
=
0
;
min_output_channels
=
0
;
tokens
=
g_strsplit
(
routes
,
","
,
255
);
tokens
=
g_strsplit
(
routes
,
","
,
255
);
number_of_copies
=
g_strv_length
(
tokens
);
number_of_copies
=
g_strv_length
(
tokens
);
...
@@ -171,28 +174,28 @@ route_filter_parse(const struct config_param *param,
...
@@ -171,28 +174,28 @@ route_filter_parse(const struct config_param *param,
// Keep track of the highest channel numbers seen
// Keep track of the highest channel numbers seen
// as either in- or outputs
// as either in- or outputs
if
(
source
>=
filter
->
min_input_channels
)
if
(
source
>=
min_input_channels
)
filter
->
min_input_channels
=
source
+
1
;
min_input_channels
=
source
+
1
;
if
(
dest
>=
filter
->
min_output_channels
)
if
(
dest
>=
min_output_channels
)
filter
->
min_output_channels
=
dest
+
1
;
min_output_channels
=
dest
+
1
;
g_strfreev
(
sd
);
g_strfreev
(
sd
);
}
}
if
(
!
audio_valid_channel_count
(
filter
->
min_output_channels
))
{
if
(
!
audio_valid_channel_count
(
min_output_channels
))
{
g_strfreev
(
tokens
);
g_strfreev
(
tokens
);
g_set_error
(
error_r
,
audio_format_quark
(),
0
,
g_set_error
(
error_r
,
audio_format_quark
(),
0
,
"Invalid number of output channels requested: %d"
,
"Invalid number of output channels requested: %d"
,
filter
->
min_output_channels
);
min_output_channels
);
return
false
;
return
false
;
}
}
// Allocate a map of "copy nothing to me"
// Allocate a map of "copy nothing to me"
filter
->
sources
=
(
signed
char
*
)
sources
=
(
signed
char
*
)
g_malloc
(
filter
->
min_output_channels
*
sizeof
(
signed
char
));
g_malloc
(
min_output_channels
*
sizeof
(
signed
char
));
for
(
int
i
=
0
;
i
<
filter
->
min_output_channels
;
++
i
)
for
(
int
i
=
0
;
i
<
min_output_channels
;
++
i
)
filter
->
sources
[
i
]
=
-
1
;
sources
[
i
]
=
-
1
;
// Run through the spec again, and save the
// Run through the spec again, and save the
// actual mapping output <- input
// actual mapping output <- input
...
@@ -216,7 +219,7 @@ route_filter_parse(const struct config_param *param,
...
@@ -216,7 +219,7 @@ route_filter_parse(const struct config_param *param,
source
=
strtol
(
sd
[
0
],
NULL
,
10
);
source
=
strtol
(
sd
[
0
],
NULL
,
10
);
dest
=
strtol
(
sd
[
1
],
NULL
,
10
);
dest
=
strtol
(
sd
[
1
],
NULL
,
10
);
filter
->
sources
[
dest
]
=
source
;
sources
[
dest
]
=
source
;
g_strfreev
(
sd
);
g_strfreev
(
sd
);
}
}
...
@@ -226,73 +229,53 @@ route_filter_parse(const struct config_param *param,
...
@@ -226,73 +229,53 @@ route_filter_parse(const struct config_param *param,
return
true
;
return
true
;
}
}
static
struct
filter
*
static
Filter
*
route_filter_init
(
const
struct
config_param
*
param
,
route_filter_init
(
const
config_param
*
param
,
GError
**
error_r
)
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
)
{
{
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
);
return
filter
;
g_free
(
filter
);
}
}
static
const
struct
audio_format
*
const
struct
audio_format
*
route_filter_open
(
struct
filter
*
_filter
,
struct
audio_format
*
audio_format
,
RouteFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
struct
route_filter
*
filter
=
(
struct
route_filter
*
)
_filter
;
// Copy the input format for later reference
// Copy the input format for later reference
filter
->
input_format
=
*
audio_format
;
input_format
=
audio_format
;
filter
->
input_frame_size
=
input_frame_size
=
audio_format_frame_size
(
&
input_format
);
audio_format_frame_size
(
&
filter
->
input_format
);
// Decide on an output format which has enough channels,
// Decide on an output format which has enough channels,
// and is otherwise identical
// and is otherwise identical
filter
->
output_format
=
*
audio_format
;
output_format
=
audio_format
;
filter
->
output_format
.
channels
=
filter
->
min_output_channels
;
output_format
.
channels
=
min_output_channels
;
// Precalculate this simple value, to speed up allocation later
// Precalculate this simple value, to speed up allocation later
filter
->
output_frame_size
=
output_frame_size
=
audio_format_frame_size
(
&
output_format
);
audio_format_frame_size
(
&
filter
->
output_format
);
// This buffer grows as needed
// 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
void
route_filter_close
(
struct
filter
*
_filter
)
RouteFilter
::
Close
(
)
{
{
struct
route_filter
*
filter
=
(
struct
route_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
output_buffer
);
pcm_buffer_deinit
(
&
filter
->
output_buffer
);
}
}
static
const
void
*
const
void
*
route_filter_filter
(
struct
filter
*
_filter
,
RouteFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
gcc_unused
GError
**
error_r
)
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
/
input_frame_size
;
size_t
number_of_frames
=
src_size
/
filter
->
input_frame_size
;
size_t
bytes_per_frame_per_channel
=
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
// 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
;
const
uint8_t
*
base_source
=
(
const
uint8_t
*
)
src
;
...
@@ -301,18 +284,18 @@ route_filter_filter(struct filter *_filter,
...
@@ -301,18 +284,18 @@ route_filter_filter(struct filter *_filter,
uint8_t
*
chan_destination
;
uint8_t
*
chan_destination
;
// Grow our reusable buffer, if needed, and set the moving pointer
// 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
*
)
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
// Perform our copy operations, with N input channels and M output channels
for
(
unsigned
int
s
=
0
;
s
<
number_of_frames
;
++
s
)
{
for
(
unsigned
int
s
=
0
;
s
<
number_of_frames
;
++
s
)
{
// Need to perform one copy per output channel
// Need to perform one copy per output channel
for
(
unsigned
int
c
=
0
;
c
<
filter
->
min_output_channels
;
++
c
)
{
for
(
unsigned
int
c
=
0
;
c
<
min_output_channels
;
++
c
)
{
if
(
filter
->
sources
[
c
]
==
-
1
||
if
(
sources
[
c
]
==
-
1
||
(
unsigned
)
filter
->
sources
[
c
]
>=
filter
->
input_format
.
channels
)
{
(
unsigned
)
sources
[
c
]
>=
input_format
.
channels
)
{
// No source for this destination output,
// No source for this destination output,
// give it zeroes as input
// give it zeroes as input
memset
(
chan_destination
,
memset
(
chan_destination
,
...
@@ -322,7 +305,7 @@ route_filter_filter(struct filter *_filter,
...
@@ -322,7 +305,7 @@ route_filter_filter(struct filter *_filter,
// Get the data from channel sources[c]
// Get the data from channel sources[c]
// and copy it to the output
// and copy it to the output
const
uint8_t
*
data
=
base_source
+
const
uint8_t
*
data
=
base_source
+
(
filter
->
sources
[
c
]
*
bytes_per_frame_per_channel
);
(
sources
[
c
]
*
bytes_per_frame_per_channel
);
memcpy
(
chan_destination
,
memcpy
(
chan_destination
,
data
,
data
,
bytes_per_frame_per_channel
);
bytes_per_frame_per_channel
);
...
@@ -333,18 +316,14 @@ route_filter_filter(struct filter *_filter,
...
@@ -333,18 +316,14 @@ route_filter_filter(struct filter *_filter,
// Go on to the next N input samples
// 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!
// 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
=
{
const
struct
filter_plugin
route_filter_plugin
=
{
"route"
,
"route"
,
route_filter_init
,
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 @@
...
@@ -30,17 +30,36 @@
#include <assert.h>
#include <assert.h>
#include <string.h>
#include <string.h>
struct
volume_filter
{
class
VolumeFilter
final
:
public
Filter
{
struct
filter
filter
;
/**
/**
* The current volume, from 0 to #PCM_VOLUME_1.
* The current volume, from 0 to #PCM_VOLUME_1.
*/
*/
unsigned
volume
;
unsigned
volume
;
struct
audio_format
audio_
format
;
struct
audio_format
format
;
struct
pcm_buffer
buffer
;
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
static
inline
GQuark
...
@@ -49,61 +68,41 @@ volume_quark(void)
...
@@ -49,61 +68,41 @@ volume_quark(void)
return
g_quark_from_static_string
(
"pcm_volume"
);
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
,
volume_filter_init
(
gcc_unused
const
struct
config_param
*
param
,
gcc_unused
GError
**
error_r
)
gcc_unused
GError
**
error_r
)
{
{
struct
volume_filter
*
filter
=
g_new
(
struct
volume_filter
,
1
);
return
new
VolumeFilter
();
filter_init
(
&
filter
->
filter
,
&
volume_filter_plugin
);
filter
->
volume
=
PCM_VOLUME_1
;
return
&
filter
->
filter
;
}
}
static
void
const
struct
audio_format
*
volume_filter_finish
(
struct
filter
*
filte
r
)
VolumeFilter
::
Open
(
audio_format
&
audio_format
,
gcc_unused
GError
**
error_
r
)
{
{
g_free
(
filter
);
format
=
audio_format
;
}
pcm_buffer_init
(
&
buffer
);
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
);
return
&
f
ilter
->
audio_f
ormat
;
return
&
format
;
}
}
static
void
void
volume_filter_close
(
struct
filter
*
_filter
)
VolumeFilter
::
Close
(
)
{
{
struct
volume_filter
*
filter
=
(
struct
volume_filter
*
)
_filter
;
pcm_buffer_deinit
(
&
buffer
);
pcm_buffer_deinit
(
&
filter
->
buffer
);
}
}
static
const
void
*
const
void
*
volume_filter_filter
(
struct
filter
*
_filter
,
const
void
*
src
,
size_t
src_size
,
VolumeFilter
::
FilterPCM
(
const
void
*
src
,
size_t
src_size
,
size_t
*
dest_size_r
,
GError
**
error_r
)
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
;
*
dest_size_r
=
src_size
;
if
(
filter
->
volume
>=
PCM_VOLUME_1
)
if
(
volume
>=
PCM_VOLUME_1
)
/* optimized special case: 100% volume = no-op */
/* optimized special case: 100% volume = no-op */
return
src
;
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) */
/* optimized special case: 0% volume = memset(0) */
/* XXX is this valid for all sample formats? What
/* XXX is this valid for all sample formats? What
about floating point? */
about floating point? */
...
@@ -113,9 +112,9 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
...
@@ -113,9 +112,9 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
memcpy
(
dest
,
src
,
src_size
);
memcpy
(
dest
,
src
,
src_size
);
success
=
pcm_volume
(
dest
,
src_size
,
bool
success
=
pcm_volume
(
dest
,
src_size
,
sample_format
(
filter
->
audio_
format
.
format
),
sample_format
(
format
.
format
),
filter
->
volume
);
volume
);
if
(
!
success
)
{
if
(
!
success
)
{
g_set_error
(
error_r
,
volume_quark
(),
0
,
g_set_error
(
error_r
,
volume_quark
(),
0
,
"pcm_volume() has failed"
);
"pcm_volume() has failed"
);
...
@@ -128,32 +127,22 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
...
@@ -128,32 +127,22 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
const
struct
filter_plugin
volume_filter_plugin
=
{
const
struct
filter_plugin
volume_filter_plugin
=
{
"volume"
,
"volume"
,
volume_filter_init
,
volume_filter_init
,
volume_filter_finish
,
volume_filter_open
,
volume_filter_close
,
volume_filter_filter
,
};
};
unsigned
unsigned
volume_filter_get
(
const
struct
f
ilter
*
_filter
)
volume_filter_get
(
const
F
ilter
*
_filter
)
{
{
const
struct
volume_f
ilter
*
filter
=
const
VolumeF
ilter
*
filter
=
(
const
struct
volume_f
ilter
*
)
_filter
;
(
const
VolumeF
ilter
*
)
_filter
;
assert
(
filter
->
filter
.
plugin
==
&
volume_filter_plugin
);
return
filter
->
GetVolume
();
assert
(
filter
->
volume
<=
PCM_VOLUME_1
);
return
filter
->
volume
;
}
}
void
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
;
VolumeFilter
*
filter
=
(
VolumeFilter
*
)
_filter
;
assert
(
filter
->
filter
.
plugin
==
&
volume_filter_plugin
);
assert
(
volume
<=
PCM_VOLUME_1
);
filter
->
volume
=
volume
;
filter
->
SetVolume
(
volume
)
;
}
}
src/filter/VolumeFilterPlugin.hxx
View file @
a9ce0218
...
@@ -20,12 +20,12 @@
...
@@ -20,12 +20,12 @@
#ifndef MPD_VOLUME_FILTER_PLUGIN_HXX
#ifndef MPD_VOLUME_FILTER_PLUGIN_HXX
#define MPD_VOLUME_FILTER_PLUGIN_HXX
#define MPD_VOLUME_FILTER_PLUGIN_HXX
struct
f
ilter
;
class
F
ilter
;
unsigned
unsigned
volume_filter_get
(
const
struct
f
ilter
*
filter
);
volume_filter_get
(
const
F
ilter
*
filter
);
void
void
volume_filter_set
(
struct
f
ilter
*
filter
,
unsigned
volume
);
volume_filter_set
(
F
ilter
*
filter
,
unsigned
volume
);
#endif
#endif
src/mixer/SoftwareMixerPlugin.cxx
View file @
a9ce0218
...
@@ -32,7 +32,7 @@ struct software_mixer {
...
@@ -32,7 +32,7 @@ struct software_mixer {
/** the base mixer class */
/** the base mixer class */
struct
mixer
base
;
struct
mixer
base
;
struct
f
ilter
*
filter
;
F
ilter
*
filter
;
unsigned
volume
;
unsigned
volume
;
};
};
...
@@ -100,7 +100,7 @@ const struct mixer_plugin software_mixer_plugin = {
...
@@ -100,7 +100,7 @@ const struct mixer_plugin software_mixer_plugin = {
true
,
true
,
};
};
struct
f
ilter
*
F
ilter
*
software_mixer_get_filter
(
struct
mixer
*
mixer
)
software_mixer_get_filter
(
struct
mixer
*
mixer
)
{
{
struct
software_mixer
*
sm
=
(
struct
software_mixer
*
)
mixer
;
struct
software_mixer
*
sm
=
(
struct
software_mixer
*
)
mixer
;
...
...
src/mixer/SoftwareMixerPlugin.hxx
View file @
a9ce0218
...
@@ -21,13 +21,13 @@
...
@@ -21,13 +21,13 @@
#define MPD_SOFTWARE_MIXER_PLUGIN_HXX
#define MPD_SOFTWARE_MIXER_PLUGIN_HXX
struct
mixer
;
struct
mixer
;
struct
f
ilter
;
class
F
ilter
;
/**
/**
* Returns the (volume) filter associated with this mixer. All users
* Returns the (volume) filter associated with this mixer. All users
* of this mixer plugin should install this filter.
* of this mixer plugin should install this filter.
*/
*/
struct
f
ilter
*
F
ilter
*
software_mixer_get_filter
(
struct
mixer
*
mixer
);
software_mixer_get_filter
(
struct
mixer
*
mixer
);
#endif
#endif
src/output_internal.h
View file @
a9ce0218
...
@@ -27,6 +27,12 @@
...
@@ -27,6 +27,12 @@
#include <time.h>
#include <time.h>
#ifdef __cplusplus
class
Filter
;
#else
typedef
void
*
Filter
;
#endif
struct
config_param
;
struct
config_param
;
enum
audio_output_command
{
enum
audio_output_command
{
...
@@ -156,13 +162,13 @@ struct audio_output {
...
@@ -156,13 +162,13 @@ struct audio_output {
* The filter object of this audio output. This is an
* The filter object of this audio output. This is an
* instance of chain_filter_plugin.
* instance of chain_filter_plugin.
*/
*/
struct
f
ilter
*
filter
;
F
ilter
*
filter
;
/**
/**
* The replay_gain_filter_plugin instance of this audio
* The replay_gain_filter_plugin instance of this audio
* output.
* output.
*/
*/
struct
f
ilter
*
replay_gain_filter
;
F
ilter
*
replay_gain_filter
;
/**
/**
* The serial number of the last replay gain info. 0 means no
* The serial number of the last replay gain info. 0 means no
...
@@ -175,7 +181,7 @@ struct audio_output {
...
@@ -175,7 +181,7 @@ struct audio_output {
* output, to be applied to the second chunk during
* output, to be applied to the second chunk during
* cross-fading.
* 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
* The serial number of the last replay gain info by the
...
@@ -189,7 +195,7 @@ struct audio_output {
...
@@ -189,7 +195,7 @@ struct audio_output {
* for converting the input data into the appropriate format
* for converting the input data into the appropriate format
* for this audio output.
* for this audio output.
*/
*/
struct
f
ilter
*
convert_filter
;
F
ilter
*
convert_filter
;
/**
/**
* The thread handle, or NULL if the output thread isn't
* The thread handle, or NULL if the output thread isn't
...
...
test/run_filter.cxx
View file @
a9ce0218
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "AudioParser.hxx"
#include "AudioParser.hxx"
#include "audio_format.h"
#include "audio_format.h"
#include "FilterPlugin.hxx"
#include "FilterPlugin.hxx"
#include "FilterInternal.hxx"
#include "PcmVolume.hxx"
#include "PcmVolume.hxx"
#include "mixer_control.h"
#include "mixer_control.h"
#include "stdbin.h"
#include "stdbin.h"
...
@@ -66,11 +67,10 @@ find_named_config_block(ConfigOption option, const char *name)
...
@@ -66,11 +67,10 @@ find_named_config_block(ConfigOption option, const char *name)
return
NULL
;
return
NULL
;
}
}
static
struct
f
ilter
*
static
F
ilter
*
load_filter
(
const
char
*
name
)
load_filter
(
const
char
*
name
)
{
{
const
struct
config_param
*
param
;
const
struct
config_param
*
param
;
struct
filter
*
filter
;
GError
*
error
=
NULL
;
GError
*
error
=
NULL
;
param
=
find_named_config_block
(
CONF_AUDIO_FILTER
,
name
);
param
=
find_named_config_block
(
CONF_AUDIO_FILTER
,
name
);
...
@@ -79,7 +79,7 @@ load_filter(const char *name)
...
@@ -79,7 +79,7 @@ load_filter(const char *name)
return
nullptr
;
return
nullptr
;
}
}
filter
=
filter_configured_new
(
param
,
&
error
);
Filter
*
filter
=
filter_configured_new
(
param
,
&
error
);
if
(
filter
==
NULL
)
{
if
(
filter
==
NULL
)
{
g_printerr
(
"Failed to load filter: %s
\n
"
,
error
->
message
);
g_printerr
(
"Failed to load filter: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
g_error_free
(
error
);
...
@@ -95,7 +95,6 @@ int main(int argc, char **argv)
...
@@ -95,7 +95,6 @@ int main(int argc, char **argv)
struct
audio_format_string
af_string
;
struct
audio_format_string
af_string
;
bool
success
;
bool
success
;
GError
*
error
=
NULL
;
GError
*
error
=
NULL
;
struct
filter
*
filter
;
const
struct
audio_format
*
out_audio_format
;
const
struct
audio_format
*
out_audio_format
;
char
buffer
[
4096
];
char
buffer
[
4096
];
...
@@ -137,17 +136,17 @@ int main(int argc, char **argv)
...
@@ -137,17 +136,17 @@ int main(int argc, char **argv)
/* initialize the filter */
/* initialize the filter */
filter
=
load_filter
(
argv
[
2
]);
Filter
*
filter
=
load_filter
(
argv
[
2
]);
if
(
filter
==
NULL
)
if
(
filter
==
NULL
)
return
1
;
return
1
;
/* open the filter */
/* 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
)
{
if
(
out_audio_format
==
NULL
)
{
g_printerr
(
"Failed to open filter: %s
\n
"
,
error
->
message
);
g_printerr
(
"Failed to open filter: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
g_error_free
(
error
);
filter_free
(
filter
)
;
delete
filter
;
return
1
;
return
1
;
}
}
...
@@ -165,28 +164,28 @@ int main(int argc, char **argv)
...
@@ -165,28 +164,28 @@ int main(int argc, char **argv)
if
(
nbytes
<=
0
)
if
(
nbytes
<=
0
)
break
;
break
;
dest
=
filter
_filter
(
filter
,
buffer
,
(
size_t
)
nbytes
,
dest
=
filter
->
FilterPCM
(
buffer
,
(
size_t
)
nbytes
,
&
length
,
&
error
);
&
length
,
&
error
);
if
(
dest
==
NULL
)
{
if
(
dest
==
NULL
)
{
g_printerr
(
"Filter failed: %s
\n
"
,
error
->
message
);
g_printerr
(
"Filter failed: %s
\n
"
,
error
->
message
);
filter
_close
(
filter
);
filter
->
Close
(
);
filter_free
(
filter
)
;
delete
filter
;
return
1
;
return
1
;
}
}
nbytes
=
write
(
1
,
dest
,
length
);
nbytes
=
write
(
1
,
dest
,
length
);
if
(
nbytes
<
0
)
{
if
(
nbytes
<
0
)
{
g_printerr
(
"Failed to write: %s
\n
"
,
g_strerror
(
errno
));
g_printerr
(
"Failed to write: %s
\n
"
,
g_strerror
(
errno
));
filter
_close
(
filter
);
filter
->
Close
(
);
filter_free
(
filter
)
;
delete
filter
;
return
1
;
return
1
;
}
}
}
}
/* cleanup and exit */
/* cleanup and exit */
filter
_close
(
filter
);
filter
->
Close
(
);
filter_free
(
filter
)
;
delete
filter
;
config_global_finish
();
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