mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
commit liboil porting changes
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/liboil-test@344 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
0c9873e5b3
commit
e1f008f2a3
23 changed files with 917 additions and 232 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
140
polyp/channelmap.c
Normal file
140
polyp/channelmap.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
75
polyp/channelmap.h
Normal file
75
polyp/channelmap.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
85
polyp/sink.c
85
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->ref = 1;
|
||||
s->core = core;
|
||||
|
||||
s->state = PA_SINK_RUNNING;
|
||||
s->name = pa_xstrdup(name);
|
||||
s->description = NULL;
|
||||
s->typeid = typeid;
|
||||
|
||||
s->ref = 1;
|
||||
s->state = PA_SINK_RUNNING;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
42
polyp/sink.h
42
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
161
polyp/volume.c
Normal file
161
polyp/volume.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
98
polyp/volume.h
Normal file
98
polyp/volume.h
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue