summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2005-09-15 23:42:56 +0000
committerLennart Poettering <lennart@poettering.net>2005-09-15 23:42:56 +0000
commite1f008f2a395422b0f1e0c931ea1550df853e6e4 (patch)
tree6b130f01398ec72d2166c9bd484cf53cc2632ee7
parent0c9873e5b3212adc273400ff133e040080ee4b65 (diff)
commit liboil porting changes
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/liboil-test@344 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--polyp/Makefile.am2
-rw-r--r--polyp/channelmap.c140
-rw-r--r--polyp/channelmap.h75
-rw-r--r--polyp/client.c6
-rw-r--r--polyp/client.h5
-rw-r--r--polyp/resampler.c136
-rw-r--r--polyp/resampler.h19
-rw-r--r--polyp/sample-util.c76
-rw-r--r--polyp/sample-util.h13
-rw-r--r--polyp/sample.c60
-rw-r--r--polyp/sample.h48
-rw-r--r--polyp/sink-input.c40
-rw-r--r--polyp/sink-input.h29
-rw-r--r--polyp/sink.c85
-rw-r--r--polyp/sink.h42
-rw-r--r--polyp/source-output.c20
-rw-r--r--polyp/source-output.h23
-rw-r--r--polyp/source.c23
-rw-r--r--polyp/source.h27
-rw-r--r--polyp/tagstruct.h4
-rw-r--r--polyp/voltest.c17
-rw-r--r--polyp/volume.c161
-rw-r--r--polyp/volume.h98
23 files changed, 917 insertions, 232 deletions
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 009707c2..18e1a2ab 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -542,7 +542,7 @@ mainloop_test_SOURCES = mainloop-test.c
mainloop_test_CFLAGS = $(AM_CFLAGS)
mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la
-voltest_SOURCES = voltest.c sample.c
+voltest_SOURCES = voltest.c volume.c
voltest_CFLAGS = $(AM_CFLAGS)
voltest_LDADD = $(AM_LDADD)
diff --git a/polyp/channelmap.c b/polyp/channelmap.c
new file mode 100644
index 00000000..97876528
--- /dev/null
+++ b/polyp/channelmap.c
@@ -0,0 +1,140 @@
+/* $Id$ */
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "channelmap.h"
+
+
+struct pa_channel_map* pa_channel_map_init(struct pa_channel_map *m) {
+ unsigned c;
+ assert(m);
+
+ for (c = 0; c < PA_CHANNELS_MAX; c++)
+ m->map[c] = PA_CHANNEL_POSITION_INVALID;
+
+ return m;
+}
+
+struct pa_channel_map* pa_channel_map_init_mono(struct pa_channel_map *m) {
+ assert(m);
+
+ pa_channel_map_init(m);
+ m->map[0] = PA_CHANNEL_POSITION_MONO;
+ return m;
+}
+
+struct pa_channel_map* pa_channel_map_init_stereo(struct pa_channel_map *m) {
+ assert(m);
+
+ pa_channel_map_init(m);
+ m->map[0] = PA_CHANNEL_POSITION_LEFT;
+ m->map[1] = PA_CHANNEL_POSITION_RIGHT;
+ return m;
+}
+
+struct pa_channel_map* pa_channel_map_init_auto(struct pa_channel_map *m, int channels) {
+ assert(m);
+ assert(channels > 0);
+
+ pa_channel_map_init(m);
+
+ switch (channels) {
+ case 1:
+ m->map[0] = PA_CHANNEL_POSITION_MONO;
+ return m;
+
+ case 8:
+ m->mpa[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
+ m->mpa[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
+ /* Fall through */
+
+ case 6:
+ m->mpa[5] = PA_CHANNEL_POSITION_LFE;
+ /* Fall through */
+
+ case 5:
+ m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
+ /* Fall through */
+
+ case 4:
+ m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+ m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ /* Fall through */
+
+ case 2:
+ m->map[0] = PA_CHANNEL_MAP_FRONT_LEFT;
+ m->map[1] = PA_CHANNEL_MAP_FRONT_RIGHT;
+ return m;
+
+ default:
+ return NULL;
+ }
+}
+
+
+const char* pa_channel_position_to_string(pa_channel_position_t pos) {
+ const char *const table[] = {
+ [PA_CHANNEL_POSITION_MONO] = "mono",
+
+ [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center",
+ [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left",
+ [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right",
+
+ [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center",
+ [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left",
+ [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right",
+
+ [PA_CHANNEL_POSITION_LFE] = "lfe",
+
+ [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center",
+ [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center",
+
+ [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left",
+ [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right"
+ };
+
+ if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
+ return NULL;
+
+ return table[pos];
+}
+
+int pa_channel_map_equal(struct pa_channel_map *a, struct pa_channel_map *b, int channels) {
+ char c;
+
+ assert(a);
+ assert(b);
+ assert(channels > 0);
+
+ if (channels > PA_CHANNELS_MAX)
+ channels = PA_CHANNELS_MAX;
+
+ for (c = 0; c < channels; c++)
+ if (a->map[c] != b->map[c])
+ return 1;
+
+ return 0;
+}
diff --git a/polyp/channelmap.h b/polyp/channelmap.h
new file mode 100644
index 00000000..946247a1
--- /dev/null
+++ b/polyp/channelmap.h
@@ -0,0 +1,75 @@
+#ifndef foochannelmaphfoo
+#define foochannelmaphfoo
+
+/* $Id$ */
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <polyp/sample.h>
+#include <polyp/cdecl.h>
+
+/** \file
+ * Constants and routines for channel mapping handling */
+
+PA_C_DECL_BEGIN
+
+typedef enum {
+ PA_CHANNEL_POSITION_INVALID = -1,
+ PA_CHANNEL_POSITION_MONO = 0,
+
+ PA_CHANNEL_POSITION_LEFT,
+ PA_CHANNEL_POSITION_RIGHT,
+
+ PA_CHANNEL_POSITION_FRONT_CENTER,
+ PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT,
+ PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT,
+
+ PA_CHANNEL_POSITION_REAR_CENTER,
+ PA_CHANNEL_POSITION_REAR_LEFT,
+ PA_CHANNEL_POSITION_REAR_RIGHT,
+
+ PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_LFE,
+
+ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+
+ PA_CHANNEL_POSITION_SIDE_LEFT,
+ PA_CHANNEL_POSITION_SIDE_RIGHT,
+
+ PA_CHANNEL_POSITION_MAX
+} pa_channel_position_t;
+
+struct {
+ pa_channel_position_t map[PA_CHANNELS_MAX];
+} pa_channel_map;
+
+struct pa_channel_map* pa_channel_map_init(struct pa_channel_map *m);
+struct pa_channel_map* pa_channel_map_init_mono(struct pa_channel_map *m);
+struct pa_channel_map* pa_channel_map_init_stereo(struct pa_channel_map *m);
+struct pa_channel_map* pa_channel_map_init_auto(struct pa_channel_map *m, int channels);
+
+const char* pa_channel_position_to_string(pa_channel_position_t pos);
+
+int pa_channel_map_equal(struct pa_channel_map *a, struct pa_channel_map *b, int channels)
+
+PA_C_DECL_END
+
+#endif
diff --git a/polyp/client.c b/polyp/client.c
index 8c7f4800..dca7b526 100644
--- a/polyp/client.c
+++ b/polyp/client.c
@@ -33,16 +33,16 @@
#include "subscribe.h"
#include "log.h"
-struct pa_client *pa_client_new(struct pa_core *core, pa_typeid_t typeid, const char *name) {
+struct pa_client *pa_client_new(struct pa_core *core, const char *name, const char *driver) {
struct pa_client *c;
int r;
assert(core);
c = pa_xmalloc(sizeof(struct pa_client));
c->name = pa_xstrdup(name);
+ c->driver = pa_xstrdup(driver);
c->owner = NULL;
c->core = core;
- c->typeid = typeid;
c->kill = NULL;
c->userdata = NULL;
@@ -68,8 +68,8 @@ void pa_client_free(struct pa_client *c) {
pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name);
pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
pa_xfree(c->name);
+ pa_xfree(c->driver);
pa_xfree(c);
-
}
void pa_client_kill(struct pa_client *c) {
diff --git a/polyp/client.h b/polyp/client.h
index 2a3a09e0..082dc29f 100644
--- a/polyp/client.h
+++ b/polyp/client.h
@@ -32,17 +32,16 @@
struct pa_client {
uint32_t index;
- pa_typeid_t typeid;
struct pa_module *owner;
- char *name;
+ char *name, *driver;
struct pa_core *core;
void (*kill)(struct pa_client *c);
void *userdata;
};
-struct pa_client *pa_client_new(struct pa_core *c, pa_typeid_t typeid, const char *name);
+struct pa_client *pa_client_new(struct pa_core *c, const char *name, const char *driver);
/* This function should be called only by the code that created the client */
void pa_client_free(struct pa_client *c);
diff --git a/polyp/resampler.c b/polyp/resampler.c
index 28e49209..d3165c95 100644
--- a/polyp/resampler.c
+++ b/polyp/resampler.c
@@ -35,11 +35,12 @@
struct pa_resampler {
struct pa_sample_spec i_ss, o_ss;
+ struct pa_channel_map i_cm, o_cm;
size_t i_fz, o_fz;
struct pa_memblock_stat *memblock_stat;
void *impl_data;
int channels;
- enum pa_resample_method resample_method;
+ pa_resample_method_t resample_method;
void (*impl_free)(struct pa_resampler *r);
void (*impl_set_input_rate)(struct pa_resampler *r, uint32_t rate);
@@ -62,7 +63,14 @@ struct impl_trivial {
static int libsamplerate_init(struct pa_resampler*r);
static int trivial_init(struct pa_resampler*r);
-struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, enum pa_resample_method resample_method) {
+struct pa_resampler* pa_resampler_new(
+ const struct pa_sample_spec *a,
+ const struct pa_channel_map *am,
+ const struct pa_sample_spec *b,
+ const struct pa_channel_map *bm,
+ struct pa_memblock_stat *s,
+ pa_resample_method_t resample_method) {
+
struct pa_resampler *r = NULL;
assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b) && resample_method != PA_RESAMPLER_INVALID);
@@ -82,6 +90,17 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru
r->i_ss = *a;
r->o_ss = *b;
+ if (am)
+ r->i_cm = *am;
+ else
+ pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels);
+
+ if (bm)
+ r->o_cm = *bm;
+ else
+ pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels);
+
+
r->i_fz = pa_frame_size(a);
r->o_fz = pa_frame_size(b);
@@ -90,7 +109,7 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru
r->channels = b->channels;
/* Choose implementation */
- if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL) {
+ if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL || !pa_channel_map_equal(&r->i_cm, &r->o_cm)) {
/* Use the libsamplerate based resampler for the complicated cases */
if (resample_method == PA_RESAMPLER_TRIVIAL)
r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
@@ -141,31 +160,11 @@ size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) {
return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
}
-enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r) {
+pa_resample_method_t pa_resampler_get_method(struct pa_resampler *r) {
assert(r);
return r->resample_method;
}
-/* Parse a libsamplrate compatible resampling implementation */
-enum pa_resample_method pa_parse_resample_method(const char *string) {
- assert(string);
-
- if (!strcmp(string, "src-sinc-best-quality"))
- return PA_RESAMPLER_SRC_SINC_BEST_QUALITY;
- else if (!strcmp(string, "src-sinc-medium-quality"))
- return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY;
- else if (!strcmp(string, "src-sinc-fastest"))
- return PA_RESAMPLER_SRC_SINC_FASTEST;
- else if (!strcmp(string, "src-zero-order-hold"))
- return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
- else if (!strcmp(string, "src-linear"))
- return PA_RESAMPLER_SRC_LINEAR;
- else if (!strcmp(string, "trivial"))
- return PA_RESAMPLER_TRIVIAL;
- else
- return PA_RESAMPLER_INVALID;
-}
-
/*** libsamplerate based implementation ***/
static void libsamplerate_free(struct pa_resampler *r) {
@@ -181,6 +180,70 @@ static void libsamplerate_free(struct pa_resampler *r) {
pa_xfree(i);
}
+static void calc_map_table(struct pa_resampler *r) {
+ struct impl_libsamplerate *u;
+ unsigned oc;
+ assert(r);
+ assert(r->impl_data);
+
+ u = r->impl_data;
+
+ if ((u->map_required = (!pa_channel_map_equal(&r->i_cm, r->o_cm) || r->i_ss.channels != r->o_ss.channels))) {
+
+ memset(u->map_table, -1, sizeof(u->map_table));
+
+ for (oc = 0; oc < r->o_iss.channels; oc++) {
+ unsigned i = 0, ic;
+
+ for (ic = 0; ic < r->i_ss.channels; ic++) {
+ pa_channel_position_t a, b;
+
+ a = r->i_cm.map[ic];
+ b = r->o_cm.map[oc];
+
+ if (a == b ||
+ (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) ||
+ (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) ||
+ (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) ||
+ (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO))
+
+ u->map_table[oc][i++] = ic;
+ }
+ }
+ }
+}
+
+
+static float *remap_to_float(struct pa_resampler *r, const struct pa_memchunk *in) {
+ unsigned nsamples;
+ struct impl_libsamplerate *u;
+ assert(r);
+ assert(r->impl_data);
+
+ u = r->impl_data;
+
+ nsamples = in->length / u->i_fz;
+
+ if () {
+
+ if (u->i_buf_samples < nsamples)
+ u->i_buf = pa_xrealloc(i->i_buf, sizeof(float) * (i->i_buf_samples = nsamples));
+
+ i->to_float32ne_func(ff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, i->i_buf);
+
+ }
+
+
+}
+
+
+static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) {
+
+
+
+}
+
+
static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) {
unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons;
float *cbuf;
@@ -191,7 +254,8 @@ static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *
/* How many input samples? */
ins = in->length/r->i_fz;
-/* pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */
+
+ /* pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */
/* How much space for output samples? */
if (i->src_state)
@@ -395,7 +459,7 @@ static int trivial_init(struct pa_resampler*r) {
return 0;
}
-const char *pa_resample_method_to_string(enum pa_resample_method m) {
+const char *pa_resample_method_to_string(pa_resample_method_t m) {
static const char * const resample_methods[] = {
"src-sinc-best-quality",
"src-sinc-medium-quality",
@@ -410,3 +474,23 @@ const char *pa_resample_method_to_string(enum pa_resample_method m) {
return resample_methods[m];
}
+
+pa_resample_method_t pa_parse_resample_method(const char *string) {
+ assert(string);
+
+ if (!strcmp(string, "src-sinc-best-quality"))
+ return PA_RESAMPLER_SRC_SINC_BEST_QUALITY;
+ else if (!strcmp(string, "src-sinc-medium-quality"))
+ return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY;
+ else if (!strcmp(string, "src-sinc-fastest"))
+ return PA_RESAMPLER_SRC_SINC_FASTEST;
+ else if (!strcmp(string, "src-zero-order-hold"))
+ return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
+ else if (!strcmp(string, "src-linear"))
+ return PA_RESAMPLER_SRC_LINEAR;
+ else if (!strcmp(string, "trivial"))
+ return PA_RESAMPLER_TRIVIAL;
+ else
+ return PA_RESAMPLER_INVALID;
+}
+
diff --git a/polyp/resampler.h b/polyp/resampler.h
index 0109e790..ec6a8080 100644
--- a/polyp/resampler.h
+++ b/polyp/resampler.h
@@ -30,7 +30,7 @@
struct pa_resampler;
-enum pa_resample_method {
+typedef enum {
PA_RESAMPLER_INVALID = -1,
PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY,
PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY,
@@ -39,9 +39,16 @@ enum pa_resample_method {
PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR,
PA_RESAMPLER_TRIVIAL,
PA_RESAMPLER_MAX
-};
+} pa_resample_method_t;
+
+struct pa_resampler* pa_resampler_new(
+ const struct pa_sample_spec *a,
+ const struct pa_channel_map *am,
+ const struct pa_sample_spec *b,
+ const struct pa_channel_map *bm,
+ struct pa_memblock_stat *s,
+ pa_resample_method_t resample_method);
-struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method);
void pa_resampler_free(struct pa_resampler *r);
/* Returns the size of an input memory block which is required to return the specified amount of output data */
@@ -54,12 +61,12 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru
void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate);
/* Return the resampling method of the resampler object */
-enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r);
+pa_resample_method_t pa_resampler_get_method(struct pa_resampler *r);
/* Try to parse the resampler method */
-enum pa_resample_method pa_parse_resample_method(const char *string);
+pa_resample_method_t pa_parse_resample_method(const char *string);
/* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */
-const char *pa_resample_method_to_string(enum pa_resample_method m);
+const char *pa_resample_method_to_string(pa_resample_method_t m);
#endif
diff --git a/polyp/sample-util.c b/polyp/sample-util.c
index d521afe4..44cacfc6 100644
--- a/polyp/sample-util.c
+++ b/polyp/sample-util.c
@@ -65,30 +65,37 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec
memset(p, c, length);
}
-size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume) {
- assert(channels && data && length && spec);
+size_t pa_mix(struct pa_mix_info streams[],
+ unsigned nstreams,
+ void *data,
+ size_t length,
+ const struct pa_sample_spec *spec,
+ const struct pa_cvolume *volume) {
+
+ assert(streams && data && length && spec);
if (spec->format == PA_SAMPLE_S16NE) {
size_t d;
+ unsigned channel = 0;
for (d = 0;; d += sizeof(int16_t)) {
- unsigned c;
+ unsigned i;
int32_t sum = 0;
if (d >= length)
return d;
- for (c = 0; c < nchannels; c++) {
+ for (i = 0; i < nstreams; i++) {
int32_t v;
- pa_volume_t cvolume = channels[c].volume;
+ pa_volume_t cvolume = streams[i].volume.values[channel];
- if (d >= channels[c].chunk.length)
+ if (d >= streams[i].chunk.length)
return d;
if (cvolume == PA_VOLUME_MUTED)
v = 0;
else {
- v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d));
+ v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
if (cvolume != PA_VOLUME_NORM) {
v *= cvolume;
@@ -111,28 +118,32 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
*((int16_t*) data) = sum;
data = (uint8_t*) data + sizeof(int16_t);
+
+ if (++channel >= spec->channels)
+ channel = 0;
}
} else if (spec->format == PA_SAMPLE_U8) {
size_t d;
+ unsigned channel = 0;
for (d = 0;; d ++) {
int32_t sum = 0;
- unsigned c;
+ unsigned i;
if (d >= length)
return d;
- for (c = 0; c < nchannels; c++) {
+ for (i = 0; i < nstreams; i++) {
int32_t v;
- pa_volume_t cvolume = channels[c].volume;
+ pa_volume_t cvolume = streams[i].volume.values[channel];
- if (d >= channels[c].chunk.length)
+ if (d >= streams[i].chunk.length)
return d;
if (cvolume == PA_VOLUME_MUTED)
v = 0;
else {
- v = (int32_t) *((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d) - 0x80;
+ v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80;
if (cvolume != PA_VOLUME_NORM) {
v *= cvolume;
@@ -155,29 +166,33 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
*((uint8_t*) data) = (uint8_t) (sum + 0x80);
data = (uint8_t*) data + 1;
+
+ if (++channel >= spec->channels)
+ channel = 0;
}
} else if (spec->format == PA_SAMPLE_FLOAT32NE) {
size_t d;
+ unsigned channel = 0;
for (d = 0;; d += sizeof(float)) {
float_t sum = 0;
- unsigned c;
+ unsigned i;
if (d >= length)
return d;
- for (c = 0; c < nchannels; c++) {
+ for (i = 0; i < nstreams; i++) {
float v;
- pa_volume_t cvolume = channels[c].volume;
+ pa_volume_t cvolume = streams[i].volume.values[channel];
- if (d >= channels[c].chunk.length)
+ if (d >= streams[i].chunk.length)
return d;
if (cvolume == PA_VOLUME_MUTED)
v = 0;
else {
- v = *((float*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d));
+ v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
if (cvolume != PA_VOLUME_NORM)
v = v*cvolume/PA_VOLUME_NORM;
@@ -196,6 +211,9 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
*((float*) data) = sum;
data = (uint8_t*) data + sizeof(float);
+
+ if (++channel >= spec->channels)
+ channel = 0;
}
} else {
abort();
@@ -203,13 +221,14 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
}
-void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume) {
+void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, const struct pa_cvolume *volume) {
assert(c && spec && (c->length % pa_frame_size(spec) == 0));
+ assert(volume);
- if (volume == PA_VOLUME_NORM)
+ if (pa_cvolume_channels_equal_to(volume, spec->channels, PA_VOLUME_NORM))
return;
- if (volume == PA_VOLUME_MUTED) {
+ if (pa_cvolume_channels_equal_to(volume, spec->channels, PA_VOLUME_MUTED)) {
pa_silence_memchunk(c, spec);
return;
}
@@ -217,26 +236,31 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec,
if (spec->format == PA_SAMPLE_S16NE) {
int16_t *d;
size_t n;
+ unsigned c = 0;
for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
int32_t t = (int32_t)(*d);
- t *= volume;
+ t *= volume->values[c];
t /= PA_VOLUME_NORM;
if (t < -0x8000) t = -0x8000;
if (t > 0x7FFF) t = 0x7FFF;
*d = (int16_t) t;
+
+ if (++c >= spec->channels)
+ c = 0;
}
} else if (spec->format == PA_SAMPLE_U8) {
uint8_t *d;
size_t n;
+ unsigned c = 0;
for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) {
int32_t t = (int32_t) *d - 0x80;
- t *= volume;
+ t *= volume->values[c];
t /= PA_VOLUME_NORM;
if (t < -0x80) t = -0x80;
@@ -244,21 +268,27 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec,
*d = (uint8_t) (t + 0x80);
+ if (++c >= spec->channels)
+ c = 0;
}
} else if (spec->format == PA_SAMPLE_FLOAT32NE) {
float *d;
size_t n;
+ unsigned c = 0;
for (d = (float*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(float); n > 0; d++, n--) {
float t = *d;
- t *= volume;
+ t *= volume->values[c];
t /= PA_VOLUME_NORM;
if (t < -1) t = -1;
if (t > 1) t = 1;
*d = t;
+
+ if (++c >= spec->channels)
+ c = 0;
}
} else {
diff --git a/polyp/sample-util.h b/polyp/sample-util.h
index aafdda63..f0c71b8c 100644
--- a/polyp/sample-util.h
+++ b/polyp/sample-util.h
@@ -33,12 +33,19 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec
struct pa_mix_info {
struct pa_memchunk chunk;
- pa_volume_t volume;
+ struct pa_cvolume cvolume;
void *userdata;
};
-size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume);
+size_t pa_mix(const struct pa_mix_info channels[],
+ unsigned nchannels,
+ void *data,
+ size_t length,
+ const struct pa_sample_spec *spec,
+ const struct pa_cvolume *volume);
-void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume);
+void pa_volume_memchunk(struct pa_memchunk*c,
+ const struct pa_sample_spec *spec,
+ const struct pa_cvolume *volume);
#endif
diff --git a/polyp/sample.c b/polyp/sample.c
index f9d0c458..d38cc1b0 100644
--- a/polyp/sample.c
+++ b/polyp/sample.c
@@ -69,10 +69,11 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec) {
int pa_sample_spec_valid(const struct pa_sample_spec *spec) {
assert(spec);
- if (spec->rate <= 0 || spec->channels <= 0)
- return 0;
-
- if (spec->format >= PA_SAMPLE_MAX || spec->format < 0)
+ if (spec->rate <= 0 ||
+ spec->channels <= 0 ||
+ spec->channels >= PA_CHANNELS_MAX ||
+ spec->format >= PA_SAMPLE_MAX ||
+ spec->format < 0)
return 0;
return 1;
@@ -86,13 +87,13 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s
const char *pa_sample_format_to_string(enum pa_sample_format f) {
static const char* const table[]= {
- [PA_SAMPLE_U8] = "U8",
- [PA_SAMPLE_ALAW] = "ALAW",
- [PA_SAMPLE_ULAW] = "ULAW",
- [PA_SAMPLE_S16LE] = "S16LE",
- [PA_SAMPLE_S16BE] = "S16BE",
- [PA_SAMPLE_FLOAT32LE] = "FLOAT32LE",
- [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE",
+ [PA_SAMPLE_U8] = "u8",
+ [PA_SAMPLE_ALAW] = "aLaw",
+ [PA_SAMPLE_ULAW] = "uLaw",
+ [PA_SAMPLE_S16LE] = "s16le",
+ [PA_SAMPLE_S16BE] = "s16be",
+ [PA_SAMPLE_FLOAT32LE] = "float32le",
+ [PA_SAMPLE_FLOAT32BE] = "float32be",
};
if (f >= PA_SAMPLE_MAX)
@@ -112,43 +113,6 @@ char *pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spe
return s;
}
-pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) {
- uint64_t p = a;
- p *= b;
- p /= PA_VOLUME_NORM;
-
- return (pa_volume_t) p;
-}
-
-pa_volume_t pa_volume_from_dB(double f) {
- if (f <= PA_DECIBEL_MININFTY)
- return PA_VOLUME_MUTED;
-
- return (pa_volume_t) (pow(10, f/20)*PA_VOLUME_NORM);
-}
-
-double pa_volume_to_dB(pa_volume_t v) {
- if (v == PA_VOLUME_MUTED)
- return PA_DECIBEL_MININFTY;
-
- return 20*log10((double) v/PA_VOLUME_NORM);
-}
-
-#define USER_DECIBEL_RANGE 30
-
-double pa_volume_to_user(pa_volume_t v) {
- double dB = pa_volume_to_dB(v);
-
- return dB < -USER_DECIBEL_RANGE ? 0 : dB/USER_DECIBEL_RANGE+1;
-}
-
-pa_volume_t pa_volume_from_user(double v) {
-
- if (v <= 0)
- return PA_VOLUME_MUTED;
-
- return pa_volume_from_dB((v-1)*USER_DECIBEL_RANGE);
-}
void pa_bytes_snprint(char *s, size_t l, unsigned v) {
if (v >= ((unsigned) 1024)*1024*1024)
diff --git a/polyp/sample.h b/polyp/sample.h
index 0494c7de..c4ccd3da 100644
--- a/polyp/sample.h
+++ b/polyp/sample.h
@@ -33,8 +33,11 @@
PA_C_DECL_BEGIN
+/* Maximum allowed channels */
+#define PA_CHANNELS_MAX 16
+
/** Sample format */
-enum pa_sample_format {
+typedef enum {
PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */
PA_SAMPLE_ALAW, /**< 8 Bit a-Law */
PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */
@@ -44,7 +47,7 @@ enum pa_sample_format {
PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */
PA_SAMPLE_MAX, /**< Upper limit of valid sample types */
PA_SAMPLE_INVALID = -1 /**< An invalid value */
-};
+} pa_sample_format_t;
#ifdef WORDS_BIGENDIAN
/** Signed 16 Bit PCM, native endian */
@@ -63,7 +66,7 @@ enum pa_sample_format {
/** A sample format and attribute specification */
struct pa_sample_spec {
- enum pa_sample_format format; /**< The sample format */
+ pa_sample_format_t format; /**< The sample format */
uint32_t rate; /**< The sample rate. (e.g. 44100) */
uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */
};
@@ -87,7 +90,10 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec);
int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b);
/* Return a descriptive string for the specified sample format. \since 0.8 */
-const char *pa_sample_format_to_string(enum pa_sample_format f);
+const char *pa_sample_format_to_string(pa_sample_format_t f);
+
+/** Parse a sample format text. Inverse of pa_sample_format_to_string() */
+pa_sample_format_t pa_parse_sample_format(const char *format);
/** Maximum required string length for pa_sample_spec_snprint() */
#define PA_SAMPLE_SPEC_SNPRINT_MAX 32
@@ -95,43 +101,9 @@ const char *pa_sample_format_to_string(enum pa_sample_format f);
/** Pretty print a sample type specification to a string */
char* pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec);
-/** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */
-typedef uint32_t pa_volume_t;
-
-/** Normal volume (100%) */
-#define PA_VOLUME_NORM (0x100)
-
-/** Muted volume (0%) */
-#define PA_VOLUME_MUTED (0)
-
-/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */
-pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b);
-
-/** Convert volume from decibel to linear level. \since 0.4 */
-pa_volume_t pa_volume_from_dB(double f);
-
-/** Convert volume from linear level to decibel. \since 0.4 */
-double pa_volume_to_dB(pa_volume_t v);
-
-/** Convert volume to scaled value understandable by the user (between 0 and 1). \since 0.6 */
-double pa_volume_to_user(pa_volume_t v);
-
-/** Convert user volume to polypaudio volume. \since 0.6 */
-pa_volume_t pa_volume_from_user(double v);
-
-#ifdef INFINITY
-#define PA_DECIBEL_MININFTY (-INFINITY)
-#else
-/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */
-#define PA_DECIBEL_MININFTY (-200)
-#endif
-
/** Pretty print a byte size value. (i.e. "2.5 MB") */
void pa_bytes_snprint(char *s, size_t l, unsigned v);
-/** Parse a sample format text. Inverse of pa_sample_format_to_string() */
-enum pa_sample_format pa_parse_sample_format(const char *format);
-
PA_C_DECL_END
#endif
diff --git a/polyp/sink-input.c b/polyp/sink-input.c
index 3e7fdf7b..40ee7052 100644
--- a/polyp/sink-input.c
+++ b/polyp/sink-input.c
@@ -36,12 +36,23 @@
#define CONVERT_BUFFER_LENGTH 4096
-struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) {
+struct pa_sink_input* pa_sink_input_new(
+ struct pa_sink *s,
+ const char *name,
+ const char *driver,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map,
+ int variable_rate,
+ int resample_method) {
+
struct pa_sink_input *i;
struct pa_resampler *resampler = NULL;
int r;
char st[256];
- assert(s && spec && s->state == PA_SINK_RUNNING);
+
+ assert(s);
+ assert(spec);
+ assert(s->state == PA_SINK_RUNNING);
if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) {
pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n");
@@ -52,18 +63,23 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, c
resample_method = s->core->resample_method;
if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec))
- if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method)))
+ if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method)))
return NULL;
i = pa_xmalloc(sizeof(struct pa_sink_input));
i->ref = 1;
i->state = PA_SINK_INPUT_RUNNING;
i->name = pa_xstrdup(name);
- i->typeid = typeid;
+ i->driver = pa_xstrdup(driver);
i->client = NULL;
i->owner = NULL;
i->sink = s;
+
i->sample_spec = *spec;
+ if (map)
+ i->channel_map = *map;
+ else
+ pa_channel_map_init_auto(&i->channel_map, spec->channels);
i->peek = NULL;
i->drop = NULL;
@@ -72,7 +88,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, c
i->userdata = NULL;
i->underrun = NULL;
- i->volume = PA_VOLUME_NORM;
+ pa_cvolume_reset(&i->volume);
i->playing = 0;
i->resampled_chunk.memblock = NULL;
@@ -124,6 +140,7 @@ static void sink_input_free(struct pa_sink_input* i) {
pa_resampler_free(i->resampler);
pa_xfree(i->name);
+ pa_xfree(i->driver);
pa_xfree(i);
}
@@ -234,15 +251,22 @@ void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk
}
}
-void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) {
+void pa_sink_input_set_volume(struct pa_sink_input *i, const struct pa_cvolume *volume) {
assert(i && i->sink && i->sink->core && i->ref >= 1);
- if (i->volume != volume) {
- i->volume = volume;
+ if (!pa_cvolume_equal(&i->volume, volume)) {
+ i->volume = *volume;
pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
}
+const struct pa_cvolume * pa_sink_input_get_volume(struct pa_sink_input *i) {
+ assert(i);
+ assert(i->ref >= 1);
+
+ return &i->volume;
+}
+
void pa_sink_input_cork(struct pa_sink_input *i, int b) {
int n;
assert(i && i->ref >= 1);
diff --git a/polyp/sink-input.h b/polyp/sink-input.h
index 83abe537..90723c0d 100644
--- a/polyp/sink-input.h
+++ b/polyp/sink-input.h
@@ -31,25 +31,25 @@
#include "module.h"
#include "client.h"
-enum pa_sink_input_state {
+typedef enum {
PA_SINK_INPUT_RUNNING,
PA_SINK_INPUT_CORKED,
PA_SINK_INPUT_DISCONNECTED
-};
+} pa_sink_input_state_t;
struct pa_sink_input {
int ref;
- enum pa_sink_input_state state;
-
uint32_t index;
- pa_typeid_t typeid;
-
- char *name;
+ pa_sink_input_state_t state;
+
+ char *name, *driver;
struct pa_module *owner;
struct pa_client *client;
struct pa_sink *sink;
+
struct pa_sample_spec sample_spec;
- uint32_t volume;
+ struct pa_channel_map channel_map;
+ struct pa_cvolume volume;
int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk);
void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
@@ -65,7 +65,15 @@ struct pa_sink_input {
struct pa_resampler *resampler;
};
-struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method);
+struct pa_sink_input* pa_sink_input_new(
+ struct pa_sink *s,
+ const char *name,
+ const char *driver,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map,
+ int variable_rate,
+ int resample_method);
+
void pa_sink_input_unref(struct pa_sink_input* i);
struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i);
@@ -80,7 +88,8 @@ pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i);
int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk);
void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
-void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume);
+void pa_sink_input_set_volume(struct pa_sink_input *i, const struct pa_cvolume *volume);
+const struct pa_cvolume *volume pa_sink_input_get_volume(struct pa_sink_input *i);
void pa_sink_input_cork(struct pa_sink_input *i, int b);
diff --git a/polyp/sink.c b/polyp/sink.c
index 481e5cf7..3b074721 100644
--- a/polyp/sink.c
+++ b/polyp/sink.c
@@ -39,12 +39,23 @@
#define MAX_MIX_CHANNELS 32
-struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) {
+struct pa_sink* pa_sink_new(
+ struct pa_core *core,
+ const char *name,
+ const char *driver,
+ int fail,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map) {
+
struct pa_sink *s;
char *n = NULL;
char st[256];
int r;
- assert(core && name && *name && spec);
+
+ assert(core);
+ assert(name);
+ assert(*name);
+ assert(spec);
s = pa_xmalloc(sizeof(struct pa_sink));
@@ -53,31 +64,41 @@ struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char
return NULL;
}
- s->name = pa_xstrdup(name);
- s->description = NULL;
- s->typeid = typeid;
-
s->ref = 1;
+ s->core = core;
+
s->state = PA_SINK_RUNNING;
-
+ s->name = pa_xstrdup(name);
+ s->description = NULL;
+ s->driver = pa_xstrdup(driver);
s->owner = NULL;
- s->core = core;
+
s->sample_spec = *spec;
+ if (map)
+ s->channel_map = *map;
+ else
+ pa_channel_map_init_auto(&s->channel_map, spec->channels);
+
s->inputs = pa_idxset_new(NULL, NULL);
n = pa_sprintf_malloc("%s_monitor", name);
- s->monitor_source = pa_source_new(core, typeid, n, 0, spec);
+ s->monitor_source = pa_source_new(core, n, driver, 0, spec, map);
assert(s->monitor_source);
pa_xfree(n);
s->monitor_source->monitor_of = s;
s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name);
-
- s->volume = PA_VOLUME_NORM;
+
+ pa_cvolume_reset(&s->sw_volume);
+ pa_cvolume_reset(&s->hw_volume);
s->notify = NULL;
s->get_latency = NULL;
+ s->set_volume = NULL;
+ s->get_volume = NULL;
s->userdata = NULL;
+ s->flags = 0;
+
r = pa_idxset_put(core->sinks, s, &s->index);
assert(s->index != PA_IDXSET_INVALID && r >= 0);
@@ -127,6 +148,7 @@ static void sink_free(struct pa_sink *s) {
pa_xfree(s->name);
pa_xfree(s->description);
+ pa_xfree(s->driver);
pa_xfree(s);
}
@@ -360,11 +382,38 @@ void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) {
pa_source_set_owner(s->monitor_source, m);
}
-void pa_sink_set_volume(struct pa_sink *s, pa_volume_t volume) {
- assert(s && s->ref >= 1);
-
- if (s->volume != volume) {
- s->volume = volume;
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
- }
+void pa_sink_set_volume(struct pa_sink *s, pa_mixer_t m, const struct pa_cvolume *volume) {
+ struct pa_cvolume *v;
+ assert(s);
+ assert(s->ref >= 1);
+ assert(volume);
+
+ if ((m == PA_MIXER_HARDWARE || m == PA_MIXER_AUTO) && s->set_volume)
+ v = &s->hw_volume;
+ else
+ v = &s->sw_volume;
+
+ if (pa_cvolume_equal(v, volume))
+ return;
+
+ *v = volume;
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+
+ if (v == &s->hw_volume)
+ s->set_volume(s);
+}
+
+const struct pa_cvolume *pa_sink_get_volume(struct pa_sink *sink, pa_mixer_t m) {
+ struct pa_cvolume *v;
+ assert(s);
+ assert(s->ref >= 1);
+
+ if ((m == PA_MIXER_HARDWARE || m == PA_MIXER_AUTO) && s->set_volume) {
+
+ if (s->get_volume)
+ s->get_volume(s);
+
+ return &s->hw_volume;
+ } else
+ return &s->sw_volume;
}
diff --git a/polyp/sink.h b/polyp/sink.h
index 844af964..a6d7efa1 100644
--- a/polyp/sink.h
+++ b/polyp/sink.h
@@ -30,38 +30,51 @@ struct pa_sink;
#include "sample.h"
#include "idxset.h"
#include "source.h"
-#include "typeid.h"
+#include "channelmap.h"
#define PA_MAX_INPUTS_PER_SINK 6
-enum pa_sink_state {
+typedef enum {
PA_SINK_RUNNING,
PA_SINK_DISCONNECTED
-};
+} pa_sink_state_t;
+
+typedef enum {
+ PA_MIXER_AUTO,
+ PA_MIXER_SOFTWARE,
+ PA_MIXER_HARDWARE
+} pa_mixer_t;
struct pa_sink {
int ref;
- enum pa_sink_state state;
-
uint32_t index;
- pa_typeid_t typeid;
-
- char *name, *description;
- struct pa_module *owner;
struct pa_core *core;
+ pa_sink_state_t state;
+
+ char *name, *description, *driver;
struct pa_sample_spec sample_spec;
+ struct pa_channel_map channel_map;
struct pa_idxset *inputs;
-
+ struct pa_module *owner;
struct pa_source *monitor_source;
-
- pa_volume_t volume;
+ struct pa_cvolume hw_volume, sw_volume;
void (*notify)(struct pa_sink*sink);
pa_usec_t (*get_latency)(struct pa_sink *s);
+ void (*set_volume)(struct pa_sink *s);
+ void (*get_volume)(struct pa_sink *s);
+
void *userdata;
};
-struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec);
+struct pa_sink* pa_sink_new(
+ struct pa_core *core,
+ const char *name,
+ const char *driver,
+ int fail,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map);
+
void pa_sink_disconnect(struct pa_sink* s);
void pa_sink_unref(struct pa_sink*s);
struct pa_sink* pa_sink_ref(struct pa_sink *s);
@@ -77,6 +90,7 @@ void pa_sink_notify(struct pa_sink*s);
void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m);
-void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume);
+void pa_sink_set_volume(struct pa_sink *sink, pa_mixer_t m, const struct pa_cvolume *volume);
+const struct pa_cvolume *pa_sink_get_volume(struct pa_sink *sink, pa_mixer_t m);
#endif
diff --git a/polyp/source-output.c b/polyp/source-output.c
index f954c23f..fa9f252f 100644
--- a/polyp/source-output.c
+++ b/polyp/source-output.c
@@ -33,7 +33,14 @@
#include "subscribe.h"
#include "log.h"
-struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method) {
+struct pa_source_output* pa_source_output_new(
+ struct pa_source *s,
+ const char *name,
+ const char *driver,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map,
+ int resample_method) {
+
struct pa_source_output *o;
struct pa_resampler *resampler = NULL;
int r;
@@ -49,19 +56,24 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t t
resample_method = s->core->resample_method;
if (!pa_sample_spec_equal(&s->sample_spec, spec))
- if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method)))
+ if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method)))
return NULL;
o = pa_xmalloc(sizeof(struct pa_source_output));
o->ref = 1;
o->state = PA_SOURCE_OUTPUT_RUNNING;
o->name = pa_xstrdup(name);
- o->typeid = typeid;
+ o->driver = pa_xstrdup(driver);
o->client = NULL;
o->owner = NULL;
o->source = s;
+
o->sample_spec = *spec;
+ if (map)
+ c->channel_map = *map;
+ else
+ pa_channel_map_init_auto(&c->channel_map, spec->channels);
o->push = NULL;
o->kill = NULL;
@@ -96,7 +108,6 @@ void pa_source_output_disconnect(struct pa_source_output*o) {
o->push = NULL;
o->kill = NULL;
-
o->state = PA_SOURCE_OUTPUT_DISCONNECTED;
}
@@ -112,6 +123,7 @@ static void source_output_free(struct pa_source_output* o) {
pa_resampler_free(o->resampler);
pa_xfree(o->name);
+ pa_xfree(o->driver);
pa_xfree(o);
}
diff --git a/polyp/source-output.h b/polyp/source-output.h
index f3187aa9..f561e050 100644
--- a/polyp/source-output.h
+++ b/polyp/source-output.h
@@ -31,24 +31,24 @@
#include "module.h"
#include "client.h"
-enum pa_source_output_state {
+typedef enum {
PA_SOURCE_OUTPUT_RUNNING,
PA_SOURCE_OUTPUT_CORKED,
PA_SOURCE_OUTPUT_DISCONNECTED
-};
+} pa_source_output_state_t;
struct pa_source_output {
int ref;
- enum pa_source_output_state state;
-
uint32_t index;
- pa_typeid_t typeid;
-
- char *name;
+ pa_source_output_state_t state;
+
+ char *name, *driver;
struct pa_module *owner;
struct pa_client *client;
struct pa_source *source;
+
struct pa_sample_spec sample_spec;
+ struct pa_channel_map channel_map;
void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk);
void (*kill)(struct pa_source_output* o);
@@ -59,7 +59,14 @@ struct pa_source_output {
void *userdata;
};
-struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method);
+struct pa_source_output* pa_source_output_new(
+ struct pa_source *s,
+ const char *name,
+ const char *driver,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map;
+ int resample_method);
+
void pa_source_output_unref(struct pa_source_output* o);
struct pa_source_output* pa_source_output_ref(struct pa_source_output *o);
diff --git a/polyp/source.c b/polyp/source.c
index fc73272c..a80c6af7 100644
--- a/polyp/source.c
+++ b/polyp/source.c
@@ -35,11 +35,22 @@
#include "subscribe.h"
#include "log.h"
-struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) {
+struct pa_source* pa_source_new(
+ struct pa_core *core,
+ const char *name,
+ const char *driver,
+ int fail,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map) {
+
struct pa_source *s;
char st[256];
int r;
- assert(core && spec && name && *name);
+
+ assert(core);
+ assert(name);
+ assert(*name);
+ assert(spec);
s = pa_xmalloc(sizeof(struct pa_source));
@@ -53,11 +64,16 @@ struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const
s->name = pa_xstrdup(name);
s->description = NULL;
- s->typeid = typeid;
+ s->driver = pa_xstrdup(driver);
s->owner = NULL;
s->core = core;
s->sample_spec = *spec;
+ if (map)
+ s->channel_map = *map;
+ else
+ pa_channel_map_init_auto(&s->channel_map, spec->channels);
+
s->outputs = pa_idxset_new(NULL, NULL);
s->monitor_of = NULL;
@@ -108,6 +124,7 @@ static void source_free(struct pa_source *s) {
pa_xfree(s->name);
pa_xfree(s->description);
+ pa_xfree(s->driver);
pa_xfree(s);
}
diff --git a/polyp/source.h b/polyp/source.h
index 0fac2b34..21ebda53 100644
--- a/polyp/source.h
+++ b/polyp/source.h
@@ -31,35 +31,42 @@ struct pa_source;
#include "memblock.h"
#include "memchunk.h"
#include "sink.h"
-#include "typeid.h"
+#include "channelmap.h"
#define PA_MAX_OUTPUTS_PER_SOURCE 16
-enum pa_source_state {
+typedef enum {
PA_SOURCE_RUNNING,
PA_SOURCE_DISCONNECTED
-};
+} pa_source_state_t;
struct pa_source {
int ref;
- enum pa_source_state state;
-
uint32_t index;
- pa_typeid_t typeid;
-
- char *name, *description;
- struct pa_module *owner;
struct pa_core *core;
+ pa_source_state_t state;
+
+ char *name, *description, *driver;
struct pa_sample_spec sample_spec;
+ struct pa_channel_map channel_map;
struct pa_idxset *outputs;
struct pa_sink *monitor_of;
+ struct pa_module *owner;
void (*notify)(struct pa_source*source);
pa_usec_t (*get_latency)(struct pa_source *s);
+
void *userdata;
};
-struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec);
+struct pa_source* pa_source_new(
+ struct pa_core *core,
+ const char *name,
+ const char *driver,
+ int fail,
+ const struct pa_sample_spec *spec,
+ const struct pa_channel_map *map);
+
void pa_source_disconnect(struct pa_source *s);
void pa_source_unref(struct pa_source *s);
struct pa_source* pa_source_ref(struct pa_source *c);
diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h
index 135825e6..f867cfb4 100644
--- a/polyp/tagstruct.h
+++ b/polyp/tagstruct.h
@@ -44,6 +44,8 @@ void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t len
void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b);
void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv);
void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u);
+void pa_tagstruct_put_channel_map(struct pa_tagstruct *t, const struct pa_channel_map *map);
+void pa_tagstruct_put_cvolume(struct pa_tagstruct *t, const struct pa_cvolume *cvolume);
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s);
int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c);
@@ -54,6 +56,8 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le
int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b);
int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv);
int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u);
+int pa_tagstruct_get_channel_map(struct pa_tagstruct *t, struct pa_channel_map *map);
+int pa_tagstruct_get_cvolume(struct pa_tagstruct *t, struct pa_cvolume *v);
int pa_tagstruct_eof(struct pa_tagstruct*t);
const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l);
diff --git a/polyp/voltest.c b/polyp/voltest.c
index d8d5c569..0c4e2326 100644
--- a/polyp/voltest.c
+++ b/polyp/voltest.c
@@ -2,13 +2,18 @@
#include <stdio.h>
-#include <polyp/sample.h>
+#include <polyp/volume.h>
int main() {
- int p;
- for (p = 0; p <= 200; p++) {
- pa_volume_t v = pa_volume_from_user((double) p/100);
- double dB = pa_volume_to_dB(v);
- printf("%3i%% = %u = %0.2f dB = %u = %3i%%\n", p, v, dB, pa_volume_from_dB(dB), (int) (pa_volume_to_user(v)*100));
+ pa_volume_t v;
+
+ for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) {
+
+ double dB = pa_sw_volume_to_dB(v);
+ double f = pa_sw_volume_to_linear(v);
+
+ printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n",
+ v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f));
+
}
}
diff --git a/polyp/volume.c b/polyp/volume.c
new file mode 100644
index 00000000..bb9d30db
--- /dev/null
+++ b/polyp/volume.c
@@ -0,0 +1,161 @@
+/* $Id$ */
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "volume.h"
+
+int pa_cvolume_equal(const struct pa_cvolume *a, const struct pa_cvolume *b) {
+ int i;
+ assert(a);
+ assert(b);
+
+ if (a->channels != b->channels)
+ return 0;
+
+ for (i = 0; i < a->channels; i++)
+ if (a->values[i] != b->values[i])
+ return 0;
+
+ return 1;
+}
+
+void pa_cvolume_set(struct pa_cvolume *a, pa_volume_t v) {
+ int i;
+ assert(a);
+
+ a->channels = PA_CHANNELS_MAX;
+
+ for (i = 0; i < a->channels; i++)
+ a->values[i] = v;
+}
+
+void pa_cvolume_reset(struct pa_cvolume *a) {
+ assert(a);
+ pa_cvolume_set(a, PA_VOLUME_NORM);
+}
+
+void pa_cvolume_mute(struct pa_cvolume *a) {
+ assert(a);
+ pa_cvolume_set(a, PA_VOLUME_MUTED);
+}
+
+pa_volume_t pa_cvolume_avg(const struct pa_cvolume *a) {
+ uint64_t sum = 0;
+ int i;
+ assert(a);
+
+ for (i = 0; i < a->channels; i++)
+ sum += a->values[i];
+
+ sum /= a->channels;
+
+ return (pa_volume_t) sum;
+}
+
+pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
+ uint64_t p = a;
+ p *= b;
+ p /= PA_VOLUME_NORM;
+
+ return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b));
+}
+
+#define USER_DECIBEL_RANGE 30
+
+pa_volume_t pa_sw_volume_from_dB(double dB) {
+ if (dB <= -USER_DECIBEL_RANGE)
+ return PA_VOLUME_MUTED;
+
+ return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM);
+}
+
+double pa_sw_volume_to_dB(pa_volume_t v) {
+ if (v == PA_VOLUME_MUTED)
+ return PA_DECIBEL_MININFTY;
+
+ return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE;
+}
+
+pa_volume_t pa_sw_volume_from_linear(double v) {
+
+ if (v <= 0)
+ return PA_VOLUME_MUTED;
+
+ if (v == 1)
+ return PA_VOLUME_NORM;
+
+ return pa_sw_volume_from_dB(20*log10(v));
+}
+
+double pa_sw_volume_to_linear(pa_volume_t v) {
+
+ if (v == PA_VOLUME_MUTED)
+ return 0;
+
+ return pow(10, pa_sw_volume_to_dB(v)/20);
+
+}
+
+char *pa_cvolume_snprintf(char *s, size_t l, const struct pa_cvolume *c, unsigned channels) {
+ unsigned c;
+ int first = 1;
+
+ assert(s);
+ assert(l > 0);
+ assert(c);
+
+ if (channels > PA_CHANNELS_MAX || channels <= 0)
+ channels = PA_CHANNELS_MAX;
+
+ *s = 0;
+
+ for (c = 0; c < channels && l > 1; c++) {
+ l -= snprintf(s, l, "%s%u: %3u%%",
+ first ? "" : " ",
+ c,
+ (c->channels[c]*100)/PA_VOLUME_NORM);
+
+ s = strchr(s, 0);
+ }
+
+ return s;
+}
+
+
+/** Return non-zero if the volume of all channels is equal to the specified value */
+int pa_cvolume_channels_equal_to(const struct pa_cvolume *a, uint8_t channels, pa_volume_t v) {
+ unsigned c;
+ assert(a);
+
+ if (channels > PA_CHANNELS_MAX)
+ channels = PA_CHANNELS_MAX;
+
+ for (c = 0; c < channels; c++)
+ if (a->map[c] != v)
+ return 0;
+
+ return 1;
+}
diff --git a/polyp/volume.h b/polyp/volume.h
new file mode 100644
index 00000000..c013ddde
--- /dev/null
+++ b/polyp/volume.h
@@ -0,0 +1,98 @@
+#ifndef foovolumehfoo
+#define foovolumehfoo
+
+/* $Id$ */
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <inttypes.h>
+#include <polyp/cdecl.h>
+#include <polyp/sample.h>
+
+/** \file
+ * Constants and routines for volume handling */
+
+PA_C_DECL_BEGIN
+
+/** Volume specification:
+ * PA_VOLUME_MUTED: silence;
+ * < PA_VOLUME_NORM: decreased volume;
+ * PA_VOLUME_NORM: normal volume;
+ * > PA_VOLUME_NORM: increased volume */
+typedef uint32_t pa_volume_t;
+
+/** Normal volume (100%) */
+#define PA_VOLUME_NORM (0x10000)
+
+/** Muted volume (0%) */
+#define PA_VOLUME_MUTED (0)
+
+/** A structure encapsulating a per-channel volume */
+struct pa_cvolume {
+ uint8_t channels;
+ pa_volume_t values[PA_CHANNELS_MAX];
+};
+
+/** Return non-zero when *a == *b */
+int pa_cvolume_equal(const struct pa_cvolume *a, const struct pa_cvolume *b);
+
+/** Set the volume of all channels to PA_VOLUME_NORM */
+void pa_cvolume_reset(struct pa_cvolume *a);
+
+/** Set the volume of all channels to PA_VOLUME_MUTED */
+void pa_cvolume_mute(struct pa_cvolume *a);
+
+/** Set the volume of all channels to the specified parameter */
+void pa_cvolume_set(struct pa_cvolume *a, pa_volume_t v);
+
+/** Pretty print a volume structure */
+char *pa_cvolume_snprintf(char *s, size_t l, const struct pa_cvolume *c, unsigned channels);
+
+/** Return the average volume of all channels */
+pa_volume_t pa_cvolume_avg(const struct pa_cvolume *a);
+
+/** Return non-zero if the volume of all channels is equal to the specified value */
+int pa_cvolume_channels_equal_to(const struct pa_cvolume *a, uint8_t channels, pa_volume_t v);
+
+/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */
+pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b);
+
+/** Convert a decibel value to a volume. \since 0.4 */
+pa_volume_t pa_sw_volume_from_dB(double f);
+
+/** Convert a volume to a decibel value. \since 0.4 */
+double pa_sw_volume_to_dB(pa_volume_t v);
+
+/** Convert a linear factor to a volume. \since 0.8 */
+pa_volume_t pa_sw_volume_from_linear(double v);
+
+/** Convert a volume to a linear factor. \since 0.8 */
+double pa_sw_volume_to_linear(pa_volume_t v);
+
+#ifdef INFINITY
+#define PA_DECIBEL_MININFTY (-INFINITY)
+#else
+/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */
+#define PA_DECIBEL_MININFTY (-200)
+#endif
+
+PA_C_DECL_END
+
+#endif