Initial commit : A broadcast FM Stereo modulator.

This commit is contained in:
Jean-François DEL NERO
2022-11-19 15:21:59 +01:00
commit 94f026bfaf
19 changed files with 4592 additions and 0 deletions
+525
View File
@@ -0,0 +1,525 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : broadcast_fm.c
// Contains: a broadcast FM Stereo modulator
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
//
// Disclaimer / Legal warning : Radio spectrum and the law
//
// In most countries the use of any radio transmitting device is required to be
// either licensed or specifically exempted from licensing under the local regulator.
// Other than as used in accordance with a licence (or exemption),
// the use of radio equipment is illegal.
//
// So take care to limit the emitting range and power when testing this software !
//
// --------------------------------------------------------------------------------
// Example from the FCC (United states) :
//
// Part 15 Devices
//
// Unlicensed operation on the AM and FM radio broadcast bands is permitted for
// some extremely low powered devices covered under Part 15 of the FCC's rules.
// On FM frequencies, these devices are limited to an effective service range
// of approximately 200 feet (61 meters).
// See 47 CFR (Code of Federal Regulations) Section 15.239, and the July 24,
// 1991 Public Notice (still in effect).
//
// On the AM broadcast band, these devices are limited to an effective service
// range of approximately 200 feet (61 meters). See 47 CFR Sections 15.207,
// 15.209, 15.219, and 15.221. These devices must accept any interference
// caused by any other operation, which may further limit the effective service
// range.
//
// For more information on Part 15 devices, please see OET Bulletin No. 63
// ("Understanding the FCC Regulations for Low-Power, Non-Licensed Transmitters").
// Questions not answered by this Bulletin can be directed to the FCC's Office
// of Engineering and Technology, Customer Service Branch, at the Columbia,
// Maryland office, phone (301) 362 - 3000.
//
// [...]
//
// Penalties for Operation Without A Permit or License
//
// The Commission considers unauthorized broadcast operation to be a serious matter.
// Presently, the maximum penalty for operating an unlicensed or "pirate" broadcast
// station (one which is not permitted under Part 15 or is not a Carrier Current
// Station or Campus Radio Station) is set at $10,000 for a single violation or a
// single day of operation, up to a total maximum amount of $75,000.
//
// Adjustments may be made upwards or downwards depending on the circumstances
// involved. Equipment used for an unauthorized operation may also be confiscated.
// There are also criminal penalties (fine and/or imprisonment) for
// "willfully and knowingly" operating a radio station without a license.
// DON'T DO IT!
//
// More at : https://www.fcc.gov/media/radio/low-power-radio-general-information
//
// --------------------------------------------------------------------------------
//
// Broadcast FM subcarriers
//
// ________ Stereo L - R modulation
// / \ 38KHz DSB-SC
// / \ _______ _______
// / MONO \ Pilot / \ / \ RDS
// / L + R \ | / \ / \ _ _
// / \__|__/ \/ \__/ \/ \___
//30Hz 15Khz | | | | |
// | | | | 57KHz 5%
// 19KHz 23KHz 38KHz 53KHz
// 10%
//
// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Current software design :
//
// Mod player / Left Audio -> Preemphasis (FIR) -> \ / -> Left + Right -> 15KHz low pass (FIR) -------------------------------|
// Sound \/ |
// generator /\ |
// \ Right Audio -> Preemphasis (FIR) -> / \ -> Left - Right -> 15KHz low pass (FIR) |
// | |
// Sample | Sample Rate at 200KHz V |
// Rate at | |MUL| (38KHz DSB-SC modulated)-> + ----> I+Q Modulator --> RF hardware transceiver
// 50KHz | ^ | (2MHz sample rate)
// | | |
// | 38KHz Osc |
// | (|) (These oscillators |
// | (|) must be kept in phase) |
// 19KHz Pilot Osc ------------------|
//
// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include "wave.h"
#include "modulator.h"
#include "utils.h"
#include "fir_filters/FIR_Audio_Filter_Filter.h"
#include "fir_filters/AudioPreemphasis_Filter.h"
#include "hxcmod/hxcmod.h"
#define IQ_SAMPLE_RATE 2000000
#define SUBCARRIERS_SAMPLE_RATE 200000
#define IF_FREQ 0
#define BUFFER_SAMPLES_SIZE (1024*8)
#define printf(fmt...) do { \
if(!stdoutmode) \
fprintf(stdout, fmt); \
} while (0)
int stdoutmode;
int isOption(int argc, char* argv[],char * paramtosearch,char * argtoparam)
{
int param=1;
int i,j;
char option[512];
memset(option,0,512);
while(param<=argc)
{
if(argv[param])
{
if(argv[param][0]=='-')
{
memset(option,0,512);
j=0;
i=1;
while( argv[param][i] && argv[param][i]!=':')
{
option[j]=argv[param][i];
i++;
j++;
}
if( !strcmp(option,paramtosearch) )
{
if(argtoparam)
{
if(argv[param][i]==':')
{
i++;
j=0;
while( argv[param][i] )
{
argtoparam[j]=argv[param][i];
i++;
j++;
}
argtoparam[j]=0;
return 1;
}
else
{
return -1;
}
}
else
{
return 1;
}
}
}
}
param++;
}
return 0;
}
void printhelp(char* argv[])
{
printf("Options:\n");
printf(" -stdout \t\t\t: IQ stream send to stdout\n");
printf(" -mono \t\t\t: Mono FM mode\n");
printf(" -mod_file:[MODFILE.MOD]\t: MOD music file to play\n");
printf(" -generate \t\t\t: Generate the IQ stream\n");
printf(" -help \t\t\t: This help\n\n");
printf("Example : 100.9MHz broadcasting with an hackrf\n./broadcast_fm -generate -stdout -mod_file:meo-sleeping_waste.mod | hackrf_transfer -f 100900000 -t - -x 47 -a 1 -s 2000000\n");
printf("\n");
}
int main(int argc, char* argv[])
{
unsigned int i,j,k;
FILE *f;
char filename[512];
int mod_data_size = 0;
unsigned char * mod_data;
wave_io * wave1,*wave2;
double audio_sample_l;
double audio_sample_r;
double audio_sample_final;
double audio_sample_r_car;
double pilot_sample;
double balance_sample;
double fm_mod;
double old_freq,interpolation_step;
double leftplusright_audio,leftminusright_audio;
modcontext modctx;
FIR_Audio_Filter_Filter leftplusright_audio_filter,leftminusright_audio_filter;
AudioPreemphasis_Filter preamphasis_left_filter,preamphasis_right_filter;
//FM_Baseband_Filter fmband_filter;
iq_wave_gen iqgen;
wave_gen audio_l_gen;
wave_gen audio_r_gen;
wave_gen balance_ctrl;
wave_gen audiow_stereo38KHz_gen;
wave_gen stereo_pilot_gen;
uint16_t iq_wave_buf[ BUFFER_SAMPLES_SIZE * (IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE)];
int16_t mod_wave_buf[(BUFFER_SAMPLES_SIZE*2)/4];
int16_t subcarriers_dbg_wave_buf[BUFFER_SAMPLES_SIZE];
double subcarriers_float_wave_buf[BUFFER_SAMPLES_SIZE];
int monomode;
stdoutmode = 0;
monomode = 0;
if(isOption(argc,argv,"stdout",NULL)>0)
{
stdoutmode = 1;
}
if(!stdoutmode)
{
printf("broadcast_fm v0.0.1.1\n");
printf("Copyright (C) 2022 Jean-Francois DEL NERO\n");
printf("This program comes with ABSOLUTELY NO WARRANTY\n");
printf("This is free software, and you are welcome to redistribute it\n");
printf("under certain conditions;\n\n");
}
// help option...
if(isOption(argc,argv,"help",0)>0)
{
printhelp(argv);
}
memset(filename,0,sizeof(filename));
// Input file name option
if(isOption(argc,argv,"mod_file",(char*)&filename)>0)
{
printf("Input file : %s\n",filename);
}
if(isOption(argc,argv,"mono",NULL)>0)
{
monomode = 1;
}
if(isOption(argc,argv,"generate",0)>0)
{
// Init the .mod player and load the mod file.
hxcmod_init(&modctx);
hxcmod_setcfg(&modctx, SUBCARRIERS_SAMPLE_RATE/4, 1, 0); //(50000 samples/s, 25000 Hz)
mod_data_size = 0;
mod_data = NULL;
f = fopen(filename,"r");
if(f)
{
fseek(f,0,SEEK_END);
mod_data_size = ftell(f);
fseek(f,0,SEEK_SET);
mod_data = malloc(mod_data_size);
if(fread(mod_data,mod_data_size,1,f) == 1)
{
hxcmod_load(&modctx, mod_data, mod_data_size );
}
else
{
free(mod_data);
mod_data = NULL;
mod_data_size = 0;
}
fclose(f);
}
// Init all filters
AudioPreemphasis_Filter_init(&preamphasis_left_filter);
AudioPreemphasis_Filter_init(&preamphasis_right_filter);
FIR_Audio_Filter_Filter_init(&leftplusright_audio_filter);
FIR_Audio_Filter_Filter_init(&leftminusright_audio_filter);
//FM_Baseband_Filter_init(&fmband_filter);
// Init oscillators
// Left and Right audio freq (used if no .mod music file)
audio_l_gen.phase = 0;
audio_l_gen.Frequency = 700;
audio_l_gen.Amplitude = 22.5;
audio_l_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
audio_r_gen.phase = 0;
audio_r_gen.Frequency = 1000;
audio_r_gen.Amplitude = 22.5;
audio_r_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
// Left <> Right balance LFO (used if no .mod music file)
balance_ctrl.phase = 0;
balance_ctrl.Frequency = 1.2;
balance_ctrl.Amplitude = 12.5;
balance_ctrl.sample_rate = SUBCARRIERS_SAMPLE_RATE;
// Stereo Pilot
stereo_pilot_gen.phase = 0;
stereo_pilot_gen.Frequency = 19000;
stereo_pilot_gen.Amplitude = 10.0; // 10%
stereo_pilot_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
// 38KHz +/- 15KHz stereo modulator
audiow_stereo38KHz_gen.phase = 0;
audiow_stereo38KHz_gen.Frequency = 38000;
audiow_stereo38KHz_gen.Amplitude = 1;
audiow_stereo38KHz_gen.sample_rate = SUBCARRIERS_SAMPLE_RATE;
// IQ Modulator
iqgen.phase = 0;
iqgen.Frequency = IF_FREQ;
iqgen.Amplitude = 127;
iqgen.sample_rate = IQ_SAMPLE_RATE;
audio_sample_r = 0;
audio_sample_l = 0;
if(stdoutmode)
{
// stdout / stream mode : IQ are outputed to the stdout -> use a pipe to hackrf_transfer
wave1 = create_wave(NULL,iqgen.sample_rate,WAVE_FILE_FORMAT_RAW_8BITS_IQ);
wave2 = NULL;
}
else
{
// file mode : create iq + wav files
wave1 = create_wave("broadcast_fm.iq",iqgen.sample_rate,WAVE_FILE_FORMAT_RAW_8BITS_IQ);
wave2 = create_wave("broadcast_fm.wav",SUBCARRIERS_SAMPLE_RATE,WAVE_FILE_FORMAT_WAV_16BITS_MONO);
}
if(wave1)
{
old_freq = IF_FREQ;
// Main loop...
for(i=0;(i<1024) || stdoutmode ;i++)
{
printf("%d / %d...\n",i,1024);
hxcmod_fillbuffer( &modctx, (msample*)&mod_wave_buf, BUFFER_SAMPLES_SIZE/4, NULL );
for(j=0;j<BUFFER_SAMPLES_SIZE;j++)
{
if(!mod_data_size)
{
// No music module loaded -> Play left/right tones.
// Dynamically set volumes for left and right oscillators.
balance_sample = f_get_next_sample(&balance_ctrl);
audio_l_gen.Amplitude = balance_sample;
audio_r_gen.Amplitude = -balance_sample;
if(audio_r_gen.Amplitude < 0) audio_r_gen.Amplitude = 0;
if(audio_l_gen.Amplitude < 0) audio_l_gen.Amplitude = 0;
// Get the left and right samples.
audio_sample_l = f_get_next_sample(&audio_l_gen);
audio_sample_r = f_get_next_sample(&audio_r_gen);
}
else
{
if(!(j&3))
{
audio_sample_l = ((double)((mod_wave_buf[((j/4)*2)]) / (double)32768)) * (double)22.5;
audio_sample_r = ((double)((mod_wave_buf[((j/4)*2)+1]) / (double)32768)) * (double)22.5;
// Left & Right Preamphasis filter.
AudioPreemphasis_Filter_put(&preamphasis_left_filter, audio_sample_l );
audio_sample_l = AudioPreemphasis_Filter_get(&preamphasis_left_filter);
AudioPreemphasis_Filter_put(&preamphasis_right_filter, audio_sample_r );
audio_sample_r = AudioPreemphasis_Filter_get(&preamphasis_right_filter);
}
}
// Main / Mono channel : Left + Right
leftplusright_audio = audio_sample_l + audio_sample_r;
// 0KHz<->15KHz pass band/low pass filter
FIR_Audio_Filter_Filter_put(&leftplusright_audio_filter, leftplusright_audio);
leftplusright_audio = FIR_Audio_Filter_Filter_get(&leftplusright_audio_filter);
if(!monomode)
{
// Stereo Channel : Left - Right
leftminusright_audio = audio_sample_l - audio_sample_r;
// 0KHz<->15KHz pass band/low pass filter
FIR_Audio_Filter_Filter_put(&leftminusright_audio_filter, leftminusright_audio);
leftminusright_audio = FIR_Audio_Filter_Filter_get(&leftminusright_audio_filter);
// Keep the 18KHz pilot and the 38KHz clock in phase :
audiow_stereo38KHz_gen.phase = (stereo_pilot_gen.phase * 2) + PI/2;
// 38KHz DSB-SC (Double-sideband suppressed-carrier) modulation
audio_sample_r_car = f_get_next_sample(&audiow_stereo38KHz_gen); // Get the 38KHz carrier
audio_sample_r_car = (audio_sample_r_car * leftminusright_audio ); // And multiply it with the left - right sample.
// 18KHz pilot
pilot_sample = f_get_next_sample(&stereo_pilot_gen);
}
else
{
// Mono : No pilot nor 38KHz modulation...
audio_sample_r_car = 0;
pilot_sample = 0;
}
// Mix all signals sources :
// 45% 45% 10%
audio_sample_final = ((leftplusright_audio) + audio_sample_r_car + pilot_sample);
// Main carrier frequency modulation : +/- 75KHz
fm_mod = ((audio_sample_final / (double)(100.0)) * (double)(75000));
// Low pass filter <100KHz
// Note : Not needed here since we use a 200KHz sample rate.
//FM_Baseband_Filter_put(&fmband_filter, fm_mod );
//fm_mod = FM_Baseband_Filter_get(&fmband_filter);
subcarriers_dbg_wave_buf[j] = fm_mod;
subcarriers_float_wave_buf[j] = fm_mod;
}
// Sub carriers sample rate to carrier IQ rate modulation + resampling
for(j=0;j<BUFFER_SAMPLES_SIZE;j++)
{
// linear interpolation. (TODO ?: Cubic interpolation)
interpolation_step = (subcarriers_float_wave_buf[j] - old_freq) / (double)(IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE);
for(k=0;k<(IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE);k++)
{
old_freq += interpolation_step;
iqgen.Frequency = ((double)IF_FREQ + old_freq);
iq_wave_buf[(j*(IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE))+k] = get_next_iq(&iqgen);
}
old_freq = subcarriers_float_wave_buf[j];
}
write_wave(wave1, &iq_wave_buf,BUFFER_SAMPLES_SIZE*(IQ_SAMPLE_RATE/SUBCARRIERS_SAMPLE_RATE));
write_wave(wave2, &subcarriers_dbg_wave_buf,BUFFER_SAMPLES_SIZE);
}
close_wave(wave1);
close_wave(wave2);
}
}
if( (isOption(argc,argv,"help",0)<=0) &&
(isOption(argc,argv,"generate",0)<=0)
)
{
printhelp(argv);
}
return 0;
}
@@ -0,0 +1,30 @@
#include "AudioPreemphasis_Filter.h"
static double filter_taps[AUDIOPREEMPHASIS_FILTER_TAP_NUM] = {
-2.676917973553303,
6.337642794858812,
-2.676917973553303
};
void AudioPreemphasis_Filter_init(AudioPreemphasis_Filter* f) {
int i;
for(i = 0; i < AUDIOPREEMPHASIS_FILTER_TAP_NUM; ++i)
f->history[i] = 0;
f->last_index = 0;
}
void AudioPreemphasis_Filter_put(AudioPreemphasis_Filter* f, double input) {
f->history[f->last_index++] = input;
if(f->last_index == AUDIOPREEMPHASIS_FILTER_TAP_NUM)
f->last_index = 0;
}
double AudioPreemphasis_Filter_get(AudioPreemphasis_Filter* f) {
double acc = 0;
int index = f->last_index, i;
for(i = 0; i < AUDIOPREEMPHASIS_FILTER_TAP_NUM; ++i) {
index = index != 0 ? index-1 : AUDIOPREEMPHASIS_FILTER_TAP_NUM-1;
acc += f->history[index] * filter_taps[i];
};
return acc;
}
@@ -0,0 +1,35 @@
#ifndef AUDIOPREEMPHASIS_FILTER_H_
#define AUDIOPREEMPHASIS_FILTER_H_
/*
FIR filter designed with
http://t-filter.appspot.com
sampling frequency: 50000 Hz
* 0 Hz - 2100 Hz
gain = 1
desired ripple = 5 dB
actual ripple = 1.2624293131559894 dB
* 15500 Hz - 25000 Hz
gain = 6.309573444801933
desired ripple = 5 dB
actual ripple = 2.740064802010604 dB
*/
#define AUDIOPREEMPHASIS_FILTER_TAP_NUM 3
typedef struct {
double history[AUDIOPREEMPHASIS_FILTER_TAP_NUM];
unsigned int last_index;
} AudioPreemphasis_Filter;
void AudioPreemphasis_Filter_init(AudioPreemphasis_Filter* f);
void AudioPreemphasis_Filter_put(AudioPreemphasis_Filter* f, double input);
double AudioPreemphasis_Filter_get(AudioPreemphasis_Filter* f);
#endif
@@ -0,0 +1,152 @@
#include "FIR_Audio_Filter_Filter.h"
static double filter_taps[FIR_AUDIO_FILTER_FILTER_TAP_NUM] = {
0.005517301037304242,
0.010958468006496662,
0.010240455922518009,
0.01626919575760614,
0.017121566138134488,
0.019559785776548867,
0.018573985808748823,
0.016981674306998703,
0.013027824505458897,
0.008348299295171996,
0.002827934347197235,
-0.0022439756999176066,
-0.006402028253938463,
-0.008814800382330594,
-0.009267566652943171,
-0.007703207526723216,
-0.004562291988505165,
-0.0005232995432083925,
0.003518575437801644,
0.006694025550492667,
0.008294079489543669,
0.007965160640712026,
0.005755920521670115,
0.0021526778614508585,
-0.0020452123559512488,
-0.005875787341622662,
-0.008425796705843449,
-0.009052315787298352,
-0.00752225339131066,
-0.0040990782652213,
0.00049750332784811,
0.005234144776188673,
0.008990696285244222,
0.010798308794869566,
0.010105847532439045,
0.006897132667607324,
0.0017653188321013905,
-0.00420373081909947,
-0.00964286796105942,
-0.013192556860158036,
-0.013826393925481531,
-0.011121337171052629,
-0.005396493245103629,
0.0022726920185823602,
0.010240805979570002,
0.016615084025158867,
0.019654280140049052,
0.018177759921499358,
0.011915646666813001,
0.0016581423845507999,
-0.010757223751418863,
-0.02270805003461664,
-0.03121367797048097,
-0.033501256492323245,
-0.027529898309997605,
-0.012463160702206726,
0.011056274270822274,
0.04090736333522399,
0.07374003152391906,
0.10546517736325783,
0.131881590198464,
0.1493758864385702,
0.1554926121172843,
0.1493758864385702,
0.131881590198464,
0.10546517736325783,
0.07374003152391906,
0.04090736333522399,
0.011056274270822274,
-0.012463160702206726,
-0.027529898309997605,
-0.033501256492323245,
-0.03121367797048097,
-0.02270805003461664,
-0.010757223751418863,
0.0016581423845507999,
0.011915646666813001,
0.018177759921499358,
0.019654280140049052,
0.016615084025158867,
0.010240805979570002,
0.0022726920185823602,
-0.005396493245103629,
-0.011121337171052629,
-0.013826393925481531,
-0.013192556860158036,
-0.00964286796105942,
-0.00420373081909947,
0.0017653188321013905,
0.006897132667607324,
0.010105847532439045,
0.010798308794869566,
0.008990696285244222,
0.005234144776188673,
0.00049750332784811,
-0.0040990782652213,
-0.00752225339131066,
-0.009052315787298352,
-0.008425796705843449,
-0.005875787341622662,
-0.0020452123559512488,
0.0021526778614508585,
0.005755920521670115,
0.007965160640712026,
0.008294079489543669,
0.006694025550492667,
0.003518575437801644,
-0.0005232995432083925,
-0.004562291988505165,
-0.007703207526723216,
-0.009267566652943171,
-0.008814800382330594,
-0.006402028253938463,
-0.0022439756999176066,
0.002827934347197235,
0.008348299295171996,
0.013027824505458897,
0.016981674306998703,
0.018573985808748823,
0.019559785776548867,
0.017121566138134488,
0.01626919575760614,
0.010240455922518009,
0.010958468006496662,
0.005517301037304242
};
void FIR_Audio_Filter_Filter_init(FIR_Audio_Filter_Filter* f) {
int i;
for(i = 0; i < FIR_AUDIO_FILTER_FILTER_TAP_NUM; ++i)
f->history[i] = 0;
f->last_index = 0;
}
void FIR_Audio_Filter_Filter_put(FIR_Audio_Filter_Filter* f, double input) {
f->history[f->last_index++] = input;
if(f->last_index == FIR_AUDIO_FILTER_FILTER_TAP_NUM)
f->last_index = 0;
}
double FIR_Audio_Filter_Filter_get(FIR_Audio_Filter_Filter* f) {
double acc = 0;
int index = f->last_index, i;
for(i = 0; i < FIR_AUDIO_FILTER_FILTER_TAP_NUM; ++i) {
index = index != 0 ? index-1 : FIR_AUDIO_FILTER_FILTER_TAP_NUM-1;
acc += f->history[index] * filter_taps[i];
};
return acc;
}
@@ -0,0 +1,34 @@
#ifndef FIR_AUDIO_FILTER_FILTER_H_
#define FIR_AUDIO_FILTER_FILTER_H_
/*
FIR filter designed with
http://t-filter.appspot.com
sampling frequency: 200000 Hz
* 0 Hz - 15000 Hz
gain = 1
desired ripple = 5 dB
actual ripple = 4.131020865324735 dB
* 16600 Hz - 100000 Hz
gain = 0
desired attenuation = -40 dB
actual attenuation = -40.090485410010906 dB
*/
#define FIR_AUDIO_FILTER_FILTER_TAP_NUM 125
typedef struct {
double history[FIR_AUDIO_FILTER_FILTER_TAP_NUM];
unsigned int last_index;
} FIR_Audio_Filter_Filter;
void FIR_Audio_Filter_Filter_init(FIR_Audio_Filter_Filter* f);
void FIR_Audio_Filter_Filter_put(FIR_Audio_Filter_Filter* f, double input);
double FIR_Audio_Filter_Filter_get(FIR_Audio_Filter_Filter* f);
#endif
@@ -0,0 +1,683 @@
#include "FM_Baseband_Filter.h"
static double filter_taps[FM_BASEBAND_FILTER_TAP_NUM] = {
-0.006276773743368246,
-0.002906124689895695,
-0.0034810491402275856,
-0.004053348584904465,
-0.004602917018038953,
-0.00510864933708306,
-0.005549178890478986,
-0.005903803434753803,
-0.006153352756740714,
-0.0062810419368997195,
-0.006273284055978816,
-0.0061205500978807606,
-0.005817832832522139,
-0.005365157561460779,
-0.00476798650929006,
-0.00403722847791321,
-0.003188871268023831,
-0.0022438395226593234,
-0.0012271560122908633,
-0.00016698144545659763,
0.0009061942378719186,
0.0019610873421838713,
0.0029665219630286475,
0.003892678282644405,
0.0047125166256176704,
0.005402338389433701,
0.005943231522926785,
0.006321383314346843,
0.00652916985473517,
0.006565317350605899,
0.006435200226996191,
0.006150572165634373,
0.005729115424630075,
0.0051935953163101374,
0.004570706217926675,
0.0038898729887556515,
0.003181825807588361,
0.002477679601003533,
0.001807325109970609,
0.001198808101593799,
0.000676466760403685,
0.00026038278850552165,
-0.00003519485538394603,
-0.0002024986474888905,
-0.00024019085124103728,
-0.00015331390959515178,
0.00004791480114281375,
0.00034866017633577485,
0.0007296960675978035,
0.001167933929422274,
0.001636917920572586,
0.0021085978153374337,
0.0025562644079397566,
0.0029568799307201055,
0.003291074349553435,
0.0035414284335566213,
0.0036920509207547503,
0.00373312207850841,
0.003666696471321502,
0.003502213813807159,
0.00324212650920447,
0.0028914904576434483,
0.0024934237802220847,
0.002043603816320018,
0.0015808468393586463,
0.001122598250955268,
0.0006936436970225945,
0.00031496346957593816,
0.000004837984574109052,
-0.00022232703032059695,
-0.0003566665079835044,
-0.00039339019608776595,
-0.000333110808989004,
-0.00018159497394687693,
0.00005048775593523694,
0.0003481061116814,
0.0006927997977343629,
0.0010638765819667507,
0.0014393167512730105,
0.0017971738401020903,
0.0021166520909361806,
0.0023791019266531147,
0.0025693090410960793,
0.002675931198702369,
0.0026923543124503487,
0.0026171805325111786,
0.002454031118912115,
0.0022116895646837804,
0.0019030267726684862,
0.0015446566595713781,
0.0011557133218574656,
0.0007570502661148399,
0.00037004878160910566,
0.00001556164895794005,
-0.0002873259421258282,
-0.0005225020827002275,
-0.0006778152785331262,
-0.0007458291450652108,
-0.0007237724027604178,
-0.0006139467826508875,
-0.0004230530550807403,
-0.0001628354231637733,
0.00015129060306465846,
0.0005003479818101034,
0.0008636162701018116,
0.0012200029156715312,
0.001548740624466772,
0.0018306821451188385,
0.0020487233738411786,
0.0021891204599193454,
0.002243244512808436,
0.0022077928016267247,
0.002084143087394179,
0.0018778523547873093,
0.0015991122050812935,
0.0012633901100129934,
0.0008900089027853051,
0.0004988789779988034,
0.00011015896725885363,
-0.0002535400937416474,
-0.0005702276065943115,
-0.0008248106197065263,
-0.0010037105425627479,
-0.0010922057096824714,
-0.0010918347055704724,
-0.0009972609130431105,
-0.0008171434769424912,
-0.0005602703726361708,
-0.00024184631248718984,
0.00011989306001557591,
0.0005039966417534989,
0.0008882139336450031,
0.001250150108424033,
0.0015684774729692547,
0.001824332418711941,
0.0020022457010850096,
0.0020909788043975276,
0.002084241239549793,
0.0019812511669580956,
0.001786670875323066,
0.0015105823732014887,
0.0011676956517593336,
0.0007765672753843151,
0.00035878897793891384,
-0.00006253548108123283,
-0.0004637552851828441,
-0.0008220930819068703,
-0.0011170665364279842,
-0.001331475322813246,
-0.001452868444758477,
-0.0014738073952633322,
-0.0013925554944245599,
-0.001212981144562626,
-0.000944644997827479,
-0.0006023329394979184,
-0.0002053053709292688,
0.00022392080409527296,
0.0006609144606176251,
0.0010805902221096093,
0.0014587022318349155,
0.0017727389893637477,
0.0020038657435381257,
0.0021373573333903907,
0.0021647196370404324,
0.0020828998261889996,
0.0018952302758044716,
0.0016108477670202955,
0.001244407904014974,
0.0008161029752255834,
0.00034959201045762735,
-0.00012940307877066482,
-0.0005940260022155878,
-0.0010176577556310668,
-0.0013754156241168216,
-0.0016462249002119438,
-0.0018142393477275655,
-0.0018687427312488538,
-0.0018046936739308204,
-0.0016246736311703472,
-0.001338448595903364,
-0.0009605147153735846,
-0.0005108126444730755,
-0.00001565838520828236,
0.0004975083602194651,
0.0010006023914098225,
0.001462016316333705,
0.001857288190223437,
0.0021606030300284607,
0.002354435255283183,
0.0024253663999272922,
0.0023675334058277852,
0.002182089414459102,
0.0018776951564996795,
0.0014698815939004595,
0.0009802099743280804,
0.00043530470972525385,
-0.0001346731858706825,
-0.0006976628796186629,
-0.0012215159916327684,
-0.0016757415624847984,
-0.002033429226170653,
-0.0022726649592763708,
-0.002378134377120082,
-0.002341854284500264,
-0.0021636093678711237,
-0.00185139126645343,
-0.0014208790055546586,
-0.000894944574293136,
-0.0003023080541089114,
0.00032421742432794986,
0.0009492104739322405,
0.001536916169711772,
0.0020528749242516003,
0.0024661761828563313,
0.002751173465403013,
0.0028891772783515117,
0.0028695579254982137,
0.002690486553108668,
0.002359106318284556,
0.0018913307558827979,
0.0013113627449627718,
0.0006501370380893174,
-0.00005591634751310549,
-0.0007677972770164452,
-0.001444647221437417,
-0.00204746257956741,
-0.0025398901810068483,
-0.002891736526827703,
-0.0030803898442519225,
-0.003091468726777203,
-0.0029207038921516223,
-0.0025741254950366896,
-0.002067973931355495,
-0.0014280157557714668,
-0.0006877721381443566,
0.0001126863109365815,
0.0009284005715601569,
0.0017128970482479869,
0.0024209880361363485,
0.003010137740662827,
0.0034433436111773724,
0.0036925735900344213,
0.0037392776355320164,
0.0035750549963301497,
0.003204686888263029,
0.002644455073483638,
0.0019206891969597553,
0.0010720437886563461,
0.00014236365066494383,
-0.0008162193794978551,
-0.001750205816244383,
-0.00260524888853366,
-0.003330448634355011,
-0.0038806885762527085,
-0.0042197018719619,
-0.004322310610781536,
-0.004175978670258643,
-0.003781919171806373,
-0.0031554249088873213,
-0.0023255577897850145,
-0.0013338142329436104,
-0.0002321551782802385,
0.000919847567321573,
0.002057758110308816,
0.0031159521593161162,
0.004031228465119642,
0.004746373230231019,
0.005213833074755009,
0.005398368179397916,
0.005279622770016463,
0.0048537340045996654,
0.004133945043852994,
0.003150792733934946,
0.0019506897625897466,
0.0005941555193940558,
-0.0008472848222071792,
-0.002294579340030699,
-0.0036652622277313592,
-0.004877798689965437,
-0.00585630529385358,
-0.006535021981369312,
-0.006862209393606202,
-0.006803716425690461,
-0.0063451726267535384,
-0.005494638978117847,
-0.004281728798042104,
-0.0027587324158575986,
-0.0009964288997051905,
0.0009165389378955883,
0.002878840922760619,
0.00478156331351961,
0.0065128972068082235,
0.00796484714665623,
0.009038598083889997,
0.009650143724551814,
0.009736399158760185,
0.009259146172550439,
0.008207929636538491,
0.006603125277341979,
0.004496736872907695,
0.0019706087511477417,
-0.0008653143095612088,
-0.0038758915334291878,
-0.006906924032827862,
-0.00979143836062656,
-0.012355548332571993,
-0.014427563844913744,
-0.015845425534902112,
-0.016463427343763833,
-0.016162193538925198,
-0.014851592429837827,
-0.012479356514209913,
-0.009032813295982706,
-0.00454241087129261,
0.0009187305291106804,
0.007235761344299075,
0.014255324035897835,
0.021790491494704824,
0.029627294762135707,
0.03753261929369517,
0.04526278875865766,
0.05257290583779067,
0.05922632186497995,
0.06500420017090862,
0.06971390965779961,
0.07319701890747447,
0.07533548531500543,
0.07605647784784841,
0.07533548531500543,
0.07319701890747447,
0.06971390965779961,
0.06500420017090862,
0.05922632186497995,
0.05257290583779067,
0.04526278875865766,
0.03753261929369517,
0.029627294762135707,
0.021790491494704824,
0.014255324035897835,
0.007235761344299075,
0.0009187305291106804,
-0.00454241087129261,
-0.009032813295982706,
-0.012479356514209913,
-0.014851592429837827,
-0.016162193538925198,
-0.016463427343763833,
-0.015845425534902112,
-0.014427563844913744,
-0.012355548332571993,
-0.00979143836062656,
-0.006906924032827862,
-0.0038758915334291878,
-0.0008653143095612088,
0.0019706087511477417,
0.004496736872907695,
0.006603125277341979,
0.008207929636538491,
0.009259146172550439,
0.009736399158760185,
0.009650143724551814,
0.009038598083889997,
0.00796484714665623,
0.0065128972068082235,
0.00478156331351961,
0.002878840922760619,
0.0009165389378955883,
-0.0009964288997051905,
-0.0027587324158575986,
-0.004281728798042104,
-0.005494638978117847,
-0.0063451726267535384,
-0.006803716425690461,
-0.006862209393606202,
-0.006535021981369312,
-0.00585630529385358,
-0.004877798689965437,
-0.0036652622277313592,
-0.002294579340030699,
-0.0008472848222071792,
0.0005941555193940558,
0.0019506897625897466,
0.003150792733934946,
0.004133945043852994,
0.0048537340045996654,
0.005279622770016463,
0.005398368179397916,
0.005213833074755009,
0.004746373230231019,
0.004031228465119642,
0.0031159521593161162,
0.002057758110308816,
0.000919847567321573,
-0.0002321551782802385,
-0.0013338142329436104,
-0.0023255577897850145,
-0.0031554249088873213,
-0.003781919171806373,
-0.004175978670258643,
-0.004322310610781536,
-0.0042197018719619,
-0.0038806885762527085,
-0.003330448634355011,
-0.00260524888853366,
-0.001750205816244383,
-0.0008162193794978551,
0.00014236365066494383,
0.0010720437886563461,
0.0019206891969597553,
0.002644455073483638,
0.003204686888263029,
0.0035750549963301497,
0.0037392776355320164,
0.0036925735900344213,
0.0034433436111773724,
0.003010137740662827,
0.0024209880361363485,
0.0017128970482479869,
0.0009284005715601569,
0.0001126863109365815,
-0.0006877721381443566,
-0.0014280157557714668,
-0.002067973931355495,
-0.0025741254950366896,
-0.0029207038921516223,
-0.003091468726777203,
-0.0030803898442519225,
-0.002891736526827703,
-0.0025398901810068483,
-0.00204746257956741,
-0.001444647221437417,
-0.0007677972770164452,
-0.00005591634751310549,
0.0006501370380893174,
0.0013113627449627718,
0.0018913307558827979,
0.002359106318284556,
0.002690486553108668,
0.0028695579254982137,
0.0028891772783515117,
0.002751173465403013,
0.0024661761828563313,
0.0020528749242516003,
0.001536916169711772,
0.0009492104739322405,
0.00032421742432794986,
-0.0003023080541089114,
-0.000894944574293136,
-0.0014208790055546586,
-0.00185139126645343,
-0.0021636093678711237,
-0.002341854284500264,
-0.002378134377120082,
-0.0022726649592763708,
-0.002033429226170653,
-0.0016757415624847984,
-0.0012215159916327684,
-0.0006976628796186629,
-0.0001346731858706825,
0.00043530470972525385,
0.0009802099743280804,
0.0014698815939004595,
0.0018776951564996795,
0.002182089414459102,
0.0023675334058277852,
0.0024253663999272922,
0.002354435255283183,
0.0021606030300284607,
0.001857288190223437,
0.001462016316333705,
0.0010006023914098225,
0.0004975083602194651,
-0.00001565838520828236,
-0.0005108126444730755,
-0.0009605147153735846,
-0.001338448595903364,
-0.0016246736311703472,
-0.0018046936739308204,
-0.0018687427312488538,
-0.0018142393477275655,
-0.0016462249002119438,
-0.0013754156241168216,
-0.0010176577556310668,
-0.0005940260022155878,
-0.00012940307877066482,
0.00034959201045762735,
0.0008161029752255834,
0.001244407904014974,
0.0016108477670202955,
0.0018952302758044716,
0.0020828998261889996,
0.0021647196370404324,
0.0021373573333903907,
0.0020038657435381257,
0.0017727389893637477,
0.0014587022318349155,
0.0010805902221096093,
0.0006609144606176251,
0.00022392080409527296,
-0.0002053053709292688,
-0.0006023329394979184,
-0.000944644997827479,
-0.001212981144562626,
-0.0013925554944245599,
-0.0014738073952633322,
-0.001452868444758477,
-0.001331475322813246,
-0.0011170665364279842,
-0.0008220930819068703,
-0.0004637552851828441,
-0.00006253548108123283,
0.00035878897793891384,
0.0007765672753843151,
0.0011676956517593336,
0.0015105823732014887,
0.001786670875323066,
0.0019812511669580956,
0.002084241239549793,
0.0020909788043975276,
0.0020022457010850096,
0.001824332418711941,
0.0015684774729692547,
0.001250150108424033,
0.0008882139336450031,
0.0005039966417534989,
0.00011989306001557591,
-0.00024184631248718984,
-0.0005602703726361708,
-0.0008171434769424912,
-0.0009972609130431105,
-0.0010918347055704724,
-0.0010922057096824714,
-0.0010037105425627479,
-0.0008248106197065263,
-0.0005702276065943115,
-0.0002535400937416474,
0.00011015896725885363,
0.0004988789779988034,
0.0008900089027853051,
0.0012633901100129934,
0.0015991122050812935,
0.0018778523547873093,
0.002084143087394179,
0.0022077928016267247,
0.002243244512808436,
0.0021891204599193454,
0.0020487233738411786,
0.0018306821451188385,
0.001548740624466772,
0.0012200029156715312,
0.0008636162701018116,
0.0005003479818101034,
0.00015129060306465846,
-0.0001628354231637733,
-0.0004230530550807403,
-0.0006139467826508875,
-0.0007237724027604178,
-0.0007458291450652108,
-0.0006778152785331262,
-0.0005225020827002275,
-0.0002873259421258282,
0.00001556164895794005,
0.00037004878160910566,
0.0007570502661148399,
0.0011557133218574656,
0.0015446566595713781,
0.0019030267726684862,
0.0022116895646837804,
0.002454031118912115,
0.0026171805325111786,
0.0026923543124503487,
0.002675931198702369,
0.0025693090410960793,
0.0023791019266531147,
0.0021166520909361806,
0.0017971738401020903,
0.0014393167512730105,
0.0010638765819667507,
0.0006927997977343629,
0.0003481061116814,
0.00005048775593523694,
-0.00018159497394687693,
-0.000333110808989004,
-0.00039339019608776595,
-0.0003566665079835044,
-0.00022232703032059695,
0.000004837984574109052,
0.00031496346957593816,
0.0006936436970225945,
0.001122598250955268,
0.0015808468393586463,
0.002043603816320018,
0.0024934237802220847,
0.0028914904576434483,
0.00324212650920447,
0.003502213813807159,
0.003666696471321502,
0.00373312207850841,
0.0036920509207547503,
0.0035414284335566213,
0.003291074349553435,
0.0029568799307201055,
0.0025562644079397566,
0.0021085978153374337,
0.001636917920572586,
0.001167933929422274,
0.0007296960675978035,
0.00034866017633577485,
0.00004791480114281375,
-0.00015331390959515178,
-0.00024019085124103728,
-0.0002024986474888905,
-0.00003519485538394603,
0.00026038278850552165,
0.000676466760403685,
0.001198808101593799,
0.001807325109970609,
0.002477679601003533,
0.003181825807588361,
0.0038898729887556515,
0.004570706217926675,
0.0051935953163101374,
0.005729115424630075,
0.006150572165634373,
0.006435200226996191,
0.006565317350605899,
0.00652916985473517,
0.006321383314346843,
0.005943231522926785,
0.005402338389433701,
0.0047125166256176704,
0.003892678282644405,
0.0029665219630286475,
0.0019610873421838713,
0.0009061942378719186,
-0.00016698144545659763,
-0.0012271560122908633,
-0.0022438395226593234,
-0.003188871268023831,
-0.00403722847791321,
-0.00476798650929006,
-0.005365157561460779,
-0.005817832832522139,
-0.0061205500978807606,
-0.006273284055978816,
-0.0062810419368997195,
-0.006153352756740714,
-0.005903803434753803,
-0.005549178890478986,
-0.00510864933708306,
-0.004602917018038953,
-0.004053348584904465,
-0.0034810491402275856,
-0.002906124689895695,
-0.006276773743368246
};
void FM_Baseband_Filter_init(FM_Baseband_Filter* f) {
int i;
for(i = 0; i < FM_BASEBAND_FILTER_TAP_NUM; ++i)
f->history[i] = 0;
f->last_index = 0;
}
void FM_Baseband_Filter_put(FM_Baseband_Filter* f, double input) {
f->history[f->last_index++] = input;
if(f->last_index == FM_BASEBAND_FILTER_TAP_NUM)
f->last_index = 0;
}
double FM_Baseband_Filter_get(FM_Baseband_Filter* f) {
double acc = 0;
int index = f->last_index, i;
for(i = 0; i < FM_BASEBAND_FILTER_TAP_NUM; ++i) {
index = index != 0 ? index-1 : FM_BASEBAND_FILTER_TAP_NUM-1;
acc += f->history[index] * filter_taps[i];
};
return acc;
}
@@ -0,0 +1,35 @@
#ifndef FM_BASEBAND_FILTER_H_
#define FM_BASEBAND_FILTER_H_
/*
FIR filter designed with
http://t-filter.appspot.com
sampling frequency: 2000000 Hz
* 0 Hz - 75000 Hz
gain = 1
desired ripple = 5 dB
actual ripple = 4.140342542562957 dB
* 78000 Hz - 1000000 Hz
gain = 0
desired attenuation = -40 dB
actual attenuation = -40.07162834583716 dB
*/
#define FM_BASEBAND_FILTER_TAP_NUM 655
typedef struct {
double history[FM_BASEBAND_FILTER_TAP_NUM];
unsigned int last_index;
} FM_Baseband_Filter;
void FM_Baseband_Filter_init(FM_Baseband_Filter* f);
void FM_Baseband_Filter_put(FM_Baseband_Filter* f, double input);
double FM_Baseband_Filter_get(FM_Baseband_Filter* f);
#endif
File diff suppressed because it is too large Load Diff
+309
View File
@@ -0,0 +1,309 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : hxcmod.h
// Contains: a tiny mod player
//
// Written by: Jean François DEL NERO
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#ifndef MODPLAY_DEF
#define MODPLAY_DEF
#ifdef __cplusplus
extern "C" {
#endif
#ifndef HXCMOD_SLOW_TARGET
#define HXCMOD_STATE_REPORT_SUPPORT 1
#define HXCMOD_OUTPUT_FILTER 1
#define HXCMOD_OUTPUT_STEREO_MIX 1
#define HXCMOD_CLIPPING_CHECK 1
#endif
// Warning : The following option
// required 32KB of additional RAM :
// #define HXCMOD_USE_PRECALC_VOLUME_TABLE 1
// Basic type
typedef unsigned char muchar;
typedef signed char mchar;
typedef unsigned short muint;
typedef short mint;
typedef unsigned long mulong;
#ifdef HXCMOD_16BITS_TARGET
typedef unsigned short mssize;
#else
typedef unsigned long mssize;
#endif
#ifdef HXCMOD_8BITS_OUTPUT
#ifdef HXCMOD_UNSIGNED_OUTPUT
typedef unsigned char msample;
#else
typedef signed char msample;
#endif
#else
#ifdef HXCMOD_UNSIGNED_OUTPUT
typedef unsigned short msample;
#else
typedef signed short msample;
#endif
#endif
#ifdef HXCMOD_MAXCHANNELS
#define NUMMAXCHANNELS HXCMOD_MAXCHANNELS
#else
#define NUMMAXCHANNELS 32
#endif
#define MAXNOTES 12*12
//
// MOD file structures
//
#pragma pack(1)
typedef struct {
muchar name[22];
muint length;
muchar finetune;
muchar volume;
muint reppnt;
muint replen;
} sample;
typedef struct {
muchar sampperiod;
muchar period;
muchar sampeffect;
muchar effect;
} note;
typedef struct {
muchar title[20];
sample samples[31];
muchar length;
muchar protracker;
muchar patterntable[128];
muchar signature[4];
muchar speed;
} module;
#pragma pack()
//
// HxCMod Internal structures
//
typedef struct {
mchar * sampdata;
muint length;
muint reppnt;
muint replen;
muchar sampnum;
mchar * nxt_sampdata;
muint nxt_length;
muint nxt_reppnt;
muint nxt_replen;
muchar update_nxt_repeat;
mchar * dly_sampdata;
muint dly_length;
muint dly_reppnt;
muint dly_replen;
muchar note_delay;
mchar * lst_sampdata;
muint lst_length;
muint lst_reppnt;
muint lst_replen;
muchar retrig_cnt;
muchar retrig_param;
muint funkoffset;
mint funkspeed;
mint glissando;
mulong samppos;
mulong sampinc;
muint period;
muchar volume;
#ifdef HXCMOD_USE_PRECALC_VOLUME_TABLE
mint * volume_table;
#endif
muchar effect;
muchar parameffect;
muint effect_code;
mulong last_set_offset;
mint decalperiod;
mint portaspeed;
mint portaperiod;
mint vibraperiod;
mint Arpperiods[3];
muchar ArpIndex;
muchar volumeslide;
muchar vibraparam;
muchar vibrapointeur;
muchar finetune;
muchar cut_param;
muint patternloopcnt;
muint patternloopstartpoint;
} channel;
typedef struct {
module song;
mchar * sampledata[31];
note * patterndata[128];
#ifdef HXCMOD_16BITS_TARGET
muint playrate;
#else
mulong playrate;
#endif
muint tablepos;
muint patternpos;
muint patterndelay;
muchar jump_loop_effect;
muchar bpm;
#ifdef HXCMOD_16BITS_TARGET
muint patternticks;
muint patterntickse;
muint patternticksaim;
muint patternticksem;
muint tick_cnt;
#else
mulong patternticks;
mulong patterntickse;
mulong patternticksaim;
mulong patternticksem;
mulong tick_cnt;
#endif
mulong sampleticksconst;
channel channels[NUMMAXCHANNELS];
muint number_of_channels;
muint mod_loaded;
mint last_r_sample;
mint last_l_sample;
mint stereo;
mint stereo_separation;
mint bits;
mint filter;
#ifdef EFFECTS_USAGE_STATE
int effects_event_counts[32];
#endif
#ifdef HXCMOD_USE_PRECALC_VOLUME_TABLE
mint precalc_volume_array[65*256];
mint * volume_selection_table[65];
#endif
} modcontext;
//
// Player states structures
//
typedef struct track_state_
{
unsigned char instrument_number;
unsigned short cur_period;
unsigned char cur_volume;
unsigned short cur_effect;
unsigned short cur_parameffect;
}track_state;
typedef struct tracker_state_
{
int number_of_tracks;
int bpm;
int speed;
int cur_pattern;
int cur_pattern_pos;
int cur_pattern_table_pos;
unsigned int buf_index;
track_state tracks[NUMMAXCHANNELS];
}tracker_state;
typedef struct tracker_state_instrument_
{
char name[22];
int active;
}tracker_state_instrument;
typedef struct tracker_buffer_state_
{
int nb_max_of_state;
int nb_of_state;
int cur_rd_index;
int sample_step;
char name[64];
tracker_state_instrument instruments[31];
tracker_state * track_state_buf;
}tracker_buffer_state;
///////////////////////////////////////////////////////////////////////////////////
// HxCMOD Core API:
// -------------------------------------------
// int hxcmod_init(modcontext * modctx)
//
// - Initialize the modcontext buffer. Must be called before doing anything else.
// Return 1 if success. 0 in case of error.
// -------------------------------------------
// int hxcmod_load( modcontext * modctx, void * mod_data, int mod_data_size )
//
// - "Load" a MOD from memory (from "mod_data" with size "mod_data_size").
// Return 1 if success. 0 in case of error.
// -------------------------------------------
// void hxcmod_fillbuffer( modcontext * modctx, unsigned short * outbuffer, mssize nbsample, tracker_buffer_state * trkbuf )
//
// - Generate and return the next samples chunk to outbuffer.
// nbsample specify the number of stereo 16bits samples you want.
// The output format is signed 44100Hz 16-bit Stereo PCM samples.
// The output buffer size in byte must be equal to ( nbsample * 2 * 2 ).
// The optional trkbuf parameter can be used to get detailed status of the player. Put NULL/0 is unused.
// -------------------------------------------
// void hxcmod_unload( modcontext * modctx )
//
// - "Unload" / clear the player status.
// -------------------------------------------
///////////////////////////////////////////////////////////////////////////////////
int hxcmod_init( modcontext * modctx );
int hxcmod_setcfg( modcontext * modctx, int samplerate, int stereo_separation, int filter );
int hxcmod_load( modcontext * modctx, void * mod_data, int mod_data_size );
void hxcmod_fillbuffer( modcontext * modctx, msample * outbuffer, mssize nbsample, tracker_buffer_state * trkbuf );
void hxcmod_unload( modcontext * modctx );
#ifdef __cplusplus
}
#endif
#endif /* MODPLAY_DEF */
+86
View File
@@ -0,0 +1,86 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : modulator.c
// Contains: oscillator and IQ modulator
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#include <stdint.h>
#include <math.h>
#include "modulator.h"
//
// Note about the IQ
//
// If NCO enabled and If I="cos", Q="sin" -> Output Freq = NCO Freq + IQ Freq
// If NCO enabled and If I="sin", Q="cos" -> Output Freq = NCO Freq - IQ Freq
// If NCO enabled and If I="cos", Q="cos" -> Output Freq = NCO Freq - IQ Freq AND NCO Freq + IQ Freq
// If NCO enabled and If I="const", Q="sin" -> Output Freq = NCO Freq - IQ Freq AND NCO Freq AND NCO Freq + IQ Freq
// If NCO enabled and If I="const", Q="const" -> Output Freq = NCO Freq
//
uint16_t get_next_iq(iq_wave_gen * wg)
{
int i_sample,q_sample;
char i_ub_sample,q_ub_sample;
i_sample = (int)(cos(wg->phase)*wg->Amplitude);
q_sample = (int)(sin(wg->phase)*wg->Amplitude);
wg->phase += ( (2.0 * PI * wg->Frequency) / (double)wg->sample_rate );
/* if(wg->phase > (2.0 * PI) )
wg->phase -= (2.0 * PI);
if(wg->phase < (-2.0 * PI) )
wg->phase += (2.0 * PI);
*/
i_ub_sample = (i_sample);
q_ub_sample = (q_sample);
return (unsigned short)((i_ub_sample)&0xFF) | ((((unsigned short)q_ub_sample)<<8)&0xFF00);
}
//
// 2*PI -> One cycle.
// Phase step = ( (2 * PI) / (SAMPLE_RATE / Frequency) ) -> ( (2 * PI) * Frequency ) / SAMPLE_RATE
//
double f_get_next_sample(wave_gen * wg)
{
double sample;
sample = ( cos( wg->phase ) * wg->Amplitude );
wg->phase += ( (2.0 * PI * wg->Frequency) / (double)wg->sample_rate );
if(wg->phase > (2.0 * PI) )
wg->phase -= (2.0 * PI);
if(wg->phase < (-2.0 * PI) )
wg->phase += (2.0 * PI);
return sample;
}
+65
View File
@@ -0,0 +1,65 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : modulator.h
// Contains: oscillator and IQ modulator
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#ifndef __MODULATOR_H__
#define __MODULATOR_H__
#if defined(M_PI)
#define PI M_PI
#else
#define PI 3.1415926535897932384626433832795
#endif
typedef struct iq_wave_gen_
{
double phase;
double Frequency,OldFrequency;
int sample_rate;
double Amplitude;
}iq_wave_gen;
typedef struct wave_gen_
{
double phase;
double Frequency,OldFrequency;
int sample_rate;
double Amplitude;
}wave_gen;
int find_zero_phase_index(short * buf, int size);
double find_phase(iq_wave_gen * wg, double sinoffset,short samplevalue,short * buf, int size);
int Fill_IQ_Wave_Buffer(iq_wave_gen * wg,unsigned short * wave_buf, int Size);
uint16_t get_next_iq(iq_wave_gen * wg);
int get_next_sample(wave_gen * wg);
double f_get_next_sample(wave_gen * wg);
#endif
+97
View File
@@ -0,0 +1,97 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : rand_gen.c
// Contains: random generators
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#include <stdint.h>
#include "rand_gen.h"
uint8_t rand_gen_get_next_byte(rand_gen_state *state)
{
uint8_t retbyte;
uint32_t seed;
uint32_t byte_number;
seed = state->current_seed;
byte_number = state->byte_number;
if( byte_number > 3 )
{
byte_number = 0x00;
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
seed ^= seed << 13;
seed ^= seed >> 17;
seed ^= seed << 5;
state->current_seed = seed;
}
retbyte = ( seed >> ( (3 - byte_number) << 3) ) & 0xFF;
byte_number++;
state->byte_number = byte_number;
return retbyte;
}
uint32_t rand_gen_get_next_word(rand_gen_state *state)
{
uint32_t retword;
uint32_t seed;
seed = state->current_seed;
retword = seed;
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
seed ^= seed << 13;
seed ^= seed >> 17;
seed ^= seed << 5;
state->byte_number = 0x00;
state->current_seed = seed;
return retword;
}
void rand_gen_init(rand_gen_state *state, uint32_t seed )
{
if(!state)
return;
if( seed )
{
state->current_seed = seed;
state->byte_number = 0;
}
else
{
state->current_seed = 0x12E6C816;
state->byte_number = 0;
}
}
+41
View File
@@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : rand_gen.h
// Contains: random generators
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#ifndef __RAND_GEN_H__
#define __RAND_GEN_H__
typedef struct _rand_gen_state
{
uint32_t current_seed;
int byte_number;
} rand_gen_state;
void rand_gen_init(rand_gen_state *state, uint32_t seed );
uint8_t rand_gen_get_next_byte(rand_gen_state *state);
uint32_t rand_gen_get_next_word(rand_gen_state *state);
#endif /* __RAND_GEN_H__ */
+126
View File
@@ -0,0 +1,126 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : utils.h
// Contains: misc / utils functions
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_filename(char * path,char * filename)
{
int i,done;
i=strlen(path);
done=0;
while(i && !done)
{
i--;
if(path[i]=='/')
{
done=1;
i++;
}
}
sprintf(filename,"%s",&path[i]);
i=0;
while(filename[i])
{
if(filename[i]=='.')
{
filename[i]='_';
}
i++;
}
return;
}
int is_printable_char(unsigned char c)
{
int i;
unsigned char specialchar[]={"&#{}()|_@=$!?;+*-"};
if( (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') )
{
return 1;
}
i = 0;
while(specialchar[i])
{
if(specialchar[i] == c)
{
return 1;
}
i++;
}
return 0;
}
void printbuf(void * buf,int size)
{
#define PRINTBUF_HEXPERLINE 16
#define PRINTBUF_MAXLINE_SIZE ((3*PRINTBUF_HEXPERLINE)+1+PRINTBUF_HEXPERLINE+2)
int i,j;
unsigned char *ptr = buf;
char tmp[8];
char str[PRINTBUF_MAXLINE_SIZE];
memset(str, ' ', PRINTBUF_MAXLINE_SIZE);
str[PRINTBUF_MAXLINE_SIZE-1] = 0;
j = 0;
for(i=0;i<size;i++)
{
if(!(i&(PRINTBUF_HEXPERLINE-1)) && i)
{
printf("%s\n", str);
memset(str, ' ', PRINTBUF_MAXLINE_SIZE);
str[PRINTBUF_MAXLINE_SIZE-1] = 0;
j = 0;
}
sprintf(tmp, "%02X", ptr[i]);
memcpy(&str[j*3],tmp,2);
if( is_printable_char(ptr[i]) )
str[3*PRINTBUF_HEXPERLINE + 1 + j] = ptr[i];
else
str[3*PRINTBUF_HEXPERLINE + 1 + j] = '.';
j++;
}
printf("%s\n", str);
}
+30
View File
@@ -0,0 +1,30 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : utils.h
// Contains: misc / utils functions
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
void get_filename(char * path,char * filename);
void printbuf(unsigned char * buf,int size);
int is_printable_char(unsigned char c);
+160
View File
@@ -0,0 +1,160 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : wave.c
// Contains: wave file helpers
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include "wave.h"
#include "utils.h"
wave_io * create_wave(char * path,int samplerate, int type)
{
wav_hdr wavhdr;
wave_io * w_io;
int sample_byte_size;
w_io = malloc(sizeof(wave_io));
if(w_io)
{
memset(w_io,0,sizeof(wave_io));
if(!path)
w_io->file = stdout;//fopen(stdout,"w+b");
else
w_io->file = fopen(path,"w+b");
if(w_io->file)
{
w_io->total_nb_samples = 0;
w_io->type = type;
switch(w_io->type)
{
case WAVE_FILE_FORMAT_RAW_8BITS_IQ: // Raw / IQ
w_io->sample_byte_size = 2; // I + Q
break;
case WAVE_FILE_FORMAT_WAV_8BITS_STEREO: // Wave 8 bits stereo
case WAVE_FILE_FORMAT_WAV_16BITS_STEREO: // Wave 16 bits stereo
case WAVE_FILE_FORMAT_WAV_16BITS_MONO: // Wave 16 bits mono
memset(&wavhdr,0,sizeof(wavhdr));
memcpy((char*)&wavhdr.RIFF,"RIFF",4);
memcpy((char*)&wavhdr.WAVE,"WAVE",4);
memcpy((char*)&wavhdr.fmt,"fmt ",4);
wavhdr.Subchunk1Size = 16;
wavhdr.AudioFormat = 1;
wavhdr.NumOfChan = 2; // I & Q
if(w_io->type == WAVE_FILE_FORMAT_WAV_16BITS_MONO)
wavhdr.NumOfChan = 1;
wavhdr.SamplesPerSec = samplerate;
if(w_io->type == WAVE_FILE_FORMAT_WAV_8BITS_STEREO)
wavhdr.bitsPerSample = 8;
else
wavhdr.bitsPerSample = 16;
sample_byte_size = ((wavhdr.bitsPerSample*wavhdr.NumOfChan)/8);
w_io->sample_byte_size = sample_byte_size;
wavhdr.bytesPerSec = ((samplerate*wavhdr.bitsPerSample)/8) * wavhdr.NumOfChan;
wavhdr.blockAlign = sample_byte_size;
memcpy((char*)&wavhdr.Subchunk2ID,"data",4);
wavhdr.ChunkSize = (w_io->total_nb_samples * sample_byte_size) + sizeof(wav_hdr) - 8;
wavhdr.Subchunk2Size = (w_io->total_nb_samples * sample_byte_size);
fwrite((void*)&wavhdr,sizeof(wav_hdr),1,w_io->file);
// Note about the following raw data format :
// 8-bit samples are stored as unsigned bytes, ranging from 0 to 255.
// 16-bit samples are stored as 2's-complement signed integers, ranging from -32768 to 32767.
break;
}
}
}
return w_io;
}
void write_wave(wave_io * w_io, void * buffer, int nbsamples)
{
if(w_io)
{
if(!w_io->file)
return;
fwrite(buffer,nbsamples * w_io->sample_byte_size,1, w_io->file);
w_io->total_nb_samples += nbsamples;
}
}
void close_wave(wave_io * w_io)
{
wav_hdr wavhdr;
if(w_io)
{
if(!w_io->file)
return;
switch(w_io->type)
{
case WAVE_FILE_FORMAT_RAW_8BITS_IQ: // Raw / IQ
fclose(w_io->file);
break;
case WAVE_FILE_FORMAT_WAV_8BITS_STEREO: // Wave 8 bits stereo
case WAVE_FILE_FORMAT_WAV_16BITS_STEREO: // Wave 16 bits stereo
case WAVE_FILE_FORMAT_WAV_16BITS_MONO: // Wave 16 bits mono
fseek(w_io->file,0,SEEK_SET);
if(fread(&wavhdr,sizeof(wav_hdr),1,w_io->file) == 1)
{
wavhdr.ChunkSize += ( w_io->total_nb_samples * w_io->sample_byte_size );
wavhdr.Subchunk2Size += ( w_io->total_nb_samples * w_io->sample_byte_size );
fseek(w_io->file,0,SEEK_SET);
fwrite(&wavhdr,sizeof(wav_hdr),1,w_io->file);
}
fclose(w_io->file);
break;
}
free(w_io);
}
}
+68
View File
@@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : wave.h
// Contains: wave file helpers
//
// This file is part of rf-tools.
//
// Written by: Jean-François DEL NERO
//
// Copyright (C) 2022 Jean-François DEL NERO
//
// You are free to do what you want with this code.
// A credit is always appreciated if you use it into your product :)
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#ifndef __WAVE_H__
#define __WAVE_H__
#pragma pack(1)
typedef struct wav_hdr_ //
{
char RIFF[4]; // RIFF Header
int ChunkSize; // RIFF Chunk Size
char WAVE[4]; // WAVE Header
char fmt[4]; // FMT header
int Subchunk1Size; // Size of the fmt chunk
short int AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
short int NumOfChan; // Number of channels 1=Mono 2=Stereo
int SamplesPerSec; // Sampling Frequency in Hz
int bytesPerSec; // bytes per second */
short int blockAlign; // 2=16-bit mono, 4=16-bit stereo
short int bitsPerSample; // Number of bits per sample
char Subchunk2ID[4]; // "data" string
int Subchunk2Size; // Sampled data length
}wav_hdr;
#pragma pack()
typedef struct wave_io_
{
FILE * file;
int type;
int total_nb_samples;
int sample_byte_size;
}wave_io;
#define WAVE_FILE_FORMAT_RAW_8BITS_IQ 0
#define WAVE_FILE_FORMAT_WAV_8BITS_STEREO 1
#define WAVE_FILE_FORMAT_WAV_16BITS_STEREO 2
#define WAVE_FILE_FORMAT_WAV_16BITS_MONO 3
wave_io * create_wave(char * path,int samplerate,int type);
void write_wave(wave_io * w_io, void * buffer, int nbsamples);
void close_wave(wave_io * w_io);
#endif