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

68
build/Makefile Normal file
View File

@ -0,0 +1,68 @@
CC=gcc
UNAME := $(shell uname)
DEBUG ?= 0
ifeq ($(DEBUG), 1)
CFLAGS=-O0 $(INCLUDES) -Wall -g -DDEBUG -I ../src/common/
LDFLAGS= -lc -lm -ldl -lpthread -lasan
else
CFLAGS=-O3 $(INCLUDES) -Wall -I ../src/common/
LDFLAGS= -lc -lm -ldl -s
endif
ifeq ($(UNAME), Darwin)
CFLAGS += -arch x86_64 -mmacosx-version-min=10.9
LDFLAGS += -arch x86_64 -mmacosx-version-min=10.9
endif
ifeq ($(UNAME), Linux)
LDFLAGS += -Wl,-rpath=.
endif
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
endif
EXEC=broadcast_fm
all: $(EXEC)
broadcast_fm: broadcast_fm.o wave.o modulator.o FIR_Audio_Filter_Filter.o FM_Baseband_Filter.o AudioPreemphasis_Filter.o hxcmod.o rand_gen.o
$(CC) -o $@ $^ $(LDFLAGS)
broadcast_fm.o: ../src/broadcast_fm/broadcast_fm.c
$(CC) -o $@ -c $< $(CFLAGS)
utils.o: ../src/common/utils.c
$(CC) -o $@ -c $< $(CFLAGS)
wave.o: ../src/common/wave.c
$(CC) -o $@ -c $< $(CFLAGS)
modulator.o: ../src/common/modulator.c
$(CC) -o $@ -c $< $(CFLAGS)
FIR_Audio_Filter_Filter.o: ../src/broadcast_fm/fir_filters/FIR_Audio_Filter_Filter.c
$(CC) -o $@ -c $< $(CFLAGS)
FM_Baseband_Filter.o: ../src/broadcast_fm/fir_filters/FM_Baseband_Filter.c
$(CC) -o $@ -c $< $(CFLAGS)
AudioPreemphasis_Filter.o: ../src/broadcast_fm/fir_filters/AudioPreemphasis_Filter.c
$(CC) -o $@ -c $< $(CFLAGS)
hxcmod.o: ../src/common/hxcmod/hxcmod.c
$(CC) -o $@ -c $< $(CFLAGS)
rand_gen.o: ../src/common/rand_gen.c
$(CC) -o $@ -c $< $(CFLAGS)
clean:
rm -rf *.o
rm -rf *.so
mrproper: clean
rm -rf $(EXEC)
.PHONY: clean mrproper

11
readme Normal file
View File

@ -0,0 +1,11 @@
rf-tools : Radio frequency tools and modulators
Disclaimer / Legal warning : Radio spectrum and the law
In most / all 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 these softwares !

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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

2037
src/common/hxcmod/hxcmod.c Normal file

File diff suppressed because it is too large Load Diff

309
src/common/hxcmod/hxcmod.h Normal file
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
src/common/modulator.c Normal file
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
src/common/modulator.h Normal file
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
src/common/rand_gen.c Normal file
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
src/common/rand_gen.h Normal file
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
src/common/utils.c Normal file
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
src/common/utils.h Normal file
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
src/common/wave.c Normal file
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
src/common/wave.h Normal file
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