Commit 91bf54ac authored by Simon Morlat's avatar Simon Morlat

added audiomixer filter and channel adapter (work in progress, untested)

parent 5d984c3e
......@@ -24,7 +24,9 @@ mediastreamer2_include_HEADERS= ice.h \
dsptools.h \
msequalizer.h \
msspeexec.h \
msinterfaces.h
msinterfaces.h \
mschanadapter.h \
msaudiomixer.h
EXTRA_DIST=$(mediastreamer2_include_HEADERS)
......@@ -91,7 +91,9 @@ typedef enum MSFilterId{
MS_JPEG_ENC_ID,
MS_PULSE_READ_ID,
MS_PULSE_WRITE_ID,
MS_DRAWDIB_DISPLAY_ID
MS_DRAWDIB_DISPLAY_ID,
MS_CHANNEL_ADAPTER_ID,
MS_AUDIO_MIXER_ID
} MSFilterId;
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef mstee_h
#define mstee_h
#include "msfilter.h"
typedef struct MSAudioMixerCtl{
int pin;
float gain;
} MSAudioMixerCtl;
#define MS_AUDIO_MIXER_SET_INPUT_GAIN MS_FILTER_METHOD(MS_AUDIO_MIXER_ID,0,MSAudioMixerCtl)
#endif
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef mchanadapter_h
#define mchanadapter_h
#include "msfilter.h"
#define MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS MS_FILTER_METHOD(MS_CHANNEL_ADAPTER_ID,0,int)
#define MS_CHANNEL_ADAPTER_GET_OUTPUT_NCHANNELS MS_FILTER_METHOD(MS_CHANNEL_ADAPTER_ID,1,int)
#endif
......@@ -36,7 +36,9 @@ libmediastreamer_la_SOURCES= mscommon.c \
kiss_fft.h \
kiss_fftr.c \
kiss_fftr.h \
equalizer.c
equalizer.c \
chanadapt.c \
audiomixer.c
#dummy c++ file to force libtool to use c++ linking (because of msdscap-mingw.cc)
nodist_EXTRA_libmediastreamer_la_SOURCES = dummy.cxx
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/msaudiomixer.h"
#include "mediastreamer2/msticker.h"
#define MIXER_MAX_CHANNELS 20
#define MAX_LATENCY 0.08
typedef struct MixerState{
int nchannels;
int rate;
int purgeoffset;
int bytespertick;
MSBufferizer channels[MIXER_MAX_CHANNELS];
float gains[MIXER_MAX_CHANNELS];
int32_t *sum;
} MixerState;
static void mixer_init(MSFilter *f){
MixerState *s=ms_new0(MixerState,1);
int i;
s->nchannels=1;
s->rate=44100;
for(i=0;i<MIXER_MAX_CHANNELS;++i){
ms_bufferizer_init(&s->channels[i]);
s->gains[i]=1;
}
f->data=s;
}
static void mixer_uninit(MSFilter *f){
int i;
MixerState *s=(MixerState *)f->data;
for(i=0;i<MIXER_MAX_CHANNELS;++i){
ms_bufferizer_uninit(&s->channels[i]);
}
ms_free(s);
}
static void mixer_preprocess(MSFilter *f){
MixerState *s=(MixerState *)f->data;
s->purgeoffset=MAX_LATENCY*(float)(2*s->nchannels*s->rate);
s->bytespertick=(2*s->nchannels*s->rate*f->ticker->interval)/1000;
s->sum=ms_malloc0(s->bytespertick);
}
static void mixer_postprocess(MSFilter *f){
MixerState *s=(MixerState *)f->data;
ms_free(s->sum);
s->sum=NULL;
}
static void accumulate(int32_t *sum, int16_t* contrib, int nwords){
int i;
for(i=0;i<nwords;++i){
sum[i]+=contrib[i];
}
}
static void accumulate_mpy(int32_t *sum, int16_t* contrib, int nwords, float gain){
int i;
for(i=0;i<nwords;++i){
sum[i]+=gain*(float)contrib[i];
}
}
static inline int16_t saturate(int32_t s){
if (s>32767) return 32767;
if (s<-32767) return -32767;
return (int16_t)s;
}
static mblk_t *make_output(int32_t *sum, int nwords){
mblk_t *om=allocb(nwords*2,0);
int i;
for(i=0;i<nwords;++i,om->b_wptr+=2){
*(int16_t*)om->b_wptr=saturate(sum[i]);
}
return om;
}
static void mixer_process(MSFilter *f){
MixerState *s=(MixerState *)f->data;
int i;
int nwords=s->bytespertick/2;
uint8_t *tmpbuf=alloca(s->bytespertick);
bool_t got_something=FALSE;
memset(s->sum,0,nwords*sizeof(int32_t));
for(i=0;i<MIXER_MAX_CHANNELS;++i){
MSQueue *q=f->inputs[i];
ms_bufferizer_put_from_queue(&s->channels[i],q);
if (ms_bufferizer_get_avail(&s->channels[i])>=s->bytespertick){
ms_bufferizer_read(&s->channels[i],tmpbuf,s->bytespertick);
if (s->gains[i]==1)
accumulate(s->sum,(int16_t*)tmpbuf,nwords);
else
accumulate_mpy(s->sum,(int16_t*)tmpbuf,nwords,s->gains[i]);
got_something=TRUE;
}
if (ms_bufferizer_get_avail(&s->channels[i])>s->purgeoffset){
ms_warning("Too much data in channel %i",i);
ms_bufferizer_flush (&s->channels[i]);
}
}
if (got_something){
ms_queue_put(f->outputs[0],make_output(s->sum,nwords));
}
}
static int mixer_set_rate(MSFilter *f, void *data){
MixerState *s=(MixerState *)f->data;
s->rate=*(int*)data;
return 0;
}
static int mixer_get_rate(MSFilter *f, void *data){
MixerState *s=(MixerState *)f->data;
*(int*)data=s->rate;
return 0;
}
static int mixer_set_nchannels(MSFilter *f, void *data){
MixerState *s=(MixerState *)f->data;
s->nchannels=*(int*)data;
return 0;
}
static int mixer_get_nchannels(MSFilter *f, void *data){
MixerState *s=(MixerState *)f->data;
*(int*)data=s->nchannels;
return 0;
}
static int mixer_set_input_gain(MSFilter *f, void *data){
MixerState *s=(MixerState *)f->data;
MSAudioMixerCtl *ctl=(MSAudioMixerCtl*)data;
if (ctl->pin<0 || ctl->pin>=MIXER_MAX_CHANNELS){
ms_warning("mixer_set_input_gain: invalid pin number %i",ctl->pin);
return -1;
}
s->gains[ctl->pin]=ctl->gain;
return 0;
}
static MSFilterMethod methods[]={
{ MS_FILTER_SET_NCHANNELS , mixer_set_nchannels },
{ MS_FILTER_GET_NCHANNELS , mixer_get_nchannels },
{ MS_FILTER_SET_SAMPLE_RATE, mixer_set_rate },
{ MS_FILTER_GET_SAMPLE_RATE, mixer_get_rate },
{ MS_AUDIO_MIXER_SET_INPUT_GAIN , mixer_set_input_gain },
{0,NULL}
};
#ifdef _MSC_VER
MSFilterDesc ms_audio_mixer_desc={
MS_AUDIO_MIXER_ID,
"MSAudioMixer",
N_("A filter that mixes down 16 bit sample audio streams"),
MS_FILTER_OTHER,
NULL,
MIXER_MAX_CHANNELS,
MIXER_MAX_CHANNELS,
mixer_init,
mixer_preprocess,
mixer_process,
mixer_postprocess,
mixer_uninit,
methods
};
#else
MSFilterDesc ms_audio_mixer_desc={
.id=MS_AUDIO_MIXER_ID,
.name="MSAudioMixer",
.text=N_("A filter that mixes down 16 bit sample audio streams"),
.category=MS_FILTER_OTHER,
.ninputs=MIXER_MAX_CHANNELS,
.noutputs=1,
.init=mixer_init,
.preprocess=mixer_preprocess,
.process=mixer_process,
.postprocess=mixer_postprocess,
.uninit=mixer_uninit,
.methods=methods
};
#endif
MS_FILTER_DESC_EXPORT(ms_audio_mixer_desc)
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mschanadapter.h"
/*
This filter transforms stereo buffers to mono and vice versa.
*/
typedef struct AdapterState{
int inputchans;
int outputchans;
}AdapterState;
static void adapter_init(MSFilter *f){
AdapterState *s=ms_new(AdapterState,1);
s->inputchans=1;
s->outputchans=1;
f->data=s;
}
static void adapter_uninit(MSFilter *f){
ms_free(f->data);
}
static void adapter_process(MSFilter *f){
AdapterState *s=(AdapterState*)f->data;
mblk_t *im,*om;
int msgsize;
while((im=ms_queue_get(f->inputs[0]))!=NULL){
if (s->inputchans==s->outputchans){
ms_queue_put(f->outputs[0],im);
}else if (s->inputchans==2){
msgsize=msgdsize(im)/2;
om=allocb(msgsize,0);
for (;im->b_rptr<im->b_wptr;im->b_rptr+=4,om->b_wptr+=2){
*(int16_t*)om->b_wptr=*(int16_t*)im->b_rptr;
}
ms_queue_put(f->outputs[0],om);
freemsg(im);
}else if (s->outputchans==2){
msgsize=msgdsize(im)*2;
om=allocb(msgsize,0);
for (;im->b_rptr<im->b_wptr;im->b_rptr+=2,om->b_wptr+=4){
((int16_t*)om->b_wptr)[0]=*(int16_t*)im->b_rptr;
((int16_t*)om->b_wptr)[1]=*(int16_t*)im->b_rptr;
}
ms_queue_put(f->outputs[0],om);
freemsg(im);
}
}
}
static int adapter_set_nchannels(MSFilter *f, void *data){
AdapterState *s=(AdapterState*)f->data;
s->inputchans=*(int*)data;
return 0;
}
static int adapter_get_nchannels(MSFilter *f, void *data){
AdapterState *s=(AdapterState*)f->data;
*(int*)data=s->inputchans;
return 0;
}
static int adapter_set_out_nchannels(MSFilter *f, void *data){
AdapterState *s=(AdapterState*)f->data;
s->outputchans=*(int*)data;
return 0;
}
static int adapter_get_out_nchannels(MSFilter *f, void *data){
AdapterState *s=(AdapterState*)f->data;
*(int*)data=s->outputchans;
return 0;
}
static MSFilterMethod methods[]={
{ MS_FILTER_SET_NCHANNELS , adapter_set_nchannels },
{ MS_FILTER_GET_NCHANNELS, adapter_get_nchannels },
{ MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS, adapter_set_out_nchannels },
{ MS_CHANNEL_ADAPTER_GET_OUTPUT_NCHANNELS, adapter_get_out_nchannels },
{ 0, NULL }
};
#ifdef _MSC_VER
MSFilterDesc ms_channel_adapter_desc={
MS_CHANNEL_ADAPTER_ID,
"MSChannelAdapter",
N_("A filter that converts from mono to stereo and vice versa."),
MS_FILTER_OTHER,
NULL,
1,
1,
adapter_init,
NULL,
adapter_process,
NULL,
adapter_uninit,
methods
};
#else
MSFilterDesc ms_channel_adapter_desc={
.id=MS_CHANNEL_ADAPTER_ID,
.name="MSChannelAdapter",
.text=N_("A filter that converts from mono to stereo and vice versa."),
.category=MS_FILTER_OTHER,
.ninputs=1,
.noutputs=1,
.init=adapter_init,
.process=adapter_process,
.uninit=adapter_uninit,
.methods=methods
};
#endif
MS_FILTER_DESC_EXPORT(ms_channel_adapter_desc)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment