Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/g191.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ This edition introduces changes to Annex A, which describes the ITU-T Software T

* SHQ2/SHQ3 half-band and HP50 high-pass FIR filters

* P.863/P.863.2 resampling FIR filters for rate-change factors 2, 3, 4 and 6 (as published in ETSI TR 103 138)

* Cross-platform portability fixes with expanded CTest regression coverage

Recommendation ITU-T G.191 includes an electronic attachment containing STL2026 and manual.
Expand Down
8 changes: 8 additions & 0 deletions doc/g191_Annex_A.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ The functions included are as follows:
| `shq_down_3_to_1_init` | initialize 3:1 SHQ down-sampling filter. |
| `hp50_32khz_init` | initialize 50-Hz high-pass filter (32-kHz sampling). |
| `hp50_48khz_init` | initialize 50-Hz high-pass filter (48-kHz sampling). |
| `p863_up_1_to_2_init` | initialize P.863/P.863.2 resampling 1:2 up-sampling filter (256 taps). |
| `p863_down_2_to_1_init` | initialize P.863/P.863.2 resampling 2:1 down-sampling filter (256 taps). |
| `p863_up_1_to_3_init` | initialize P.863/P.863.2 resampling 1:3 up-sampling filter (384 taps). |
| `p863_down_3_to_1_init` | initialize P.863/P.863.2 resampling 3:1 down-sampling filter (384 taps). |
| `p863_up_1_to_4_init` | initialize P.863/P.863.2 resampling 1:4 up-sampling filter (512 taps). |
| `p863_down_4_to_1_init` | initialize P.863/P.863.2 resampling 4:1 down-sampling filter (512 taps). |
| `p863_up_1_to_6_init` | initialize P.863/P.863.2 resampling 1:6 up-sampling filter (768 taps). |
| `p863_down_6_to_1_init` | initialize P.863/P.863.2 resampling 6:1 down-sampling filter (768 taps). |
| `hq_kernel` | FIR filtering function. |
| `hq_reset` | clear state variables. |
| `hq_free` | deallocate FIR-filter memory. |
Expand Down
50 changes: 50 additions & 0 deletions doc/manual/rate.tex
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,8 @@ \subsection{FIR module}

High-pass filters with 50 Hz cutoff frequency (3\,dB point) for the 32 and 48 kHz sampling rates (HP50\_32K with 1119 coefficients and HP50\_48K with 1679 coefficients) are also provided. Their frequency response is given in figure \ref{hp50}.

Resampling filters as used in ITU-T Rec.\ P.863 (POLQA) and ITU-T Rec.\ P.863.2 (PAMD), also published in ETSI TR~103~138, are provided for rate-change factors 2, 3, 4 and~6 (with 256, 384, 512 and 768 taps, respectively). These filters use a normalized cutoff frequency of~0.475 and are intended for standardized resampling of speech signals between sampling rates of 8, 16 and~48~kHz.

Since the digital filters have memory, state variables are needed. In
this version of the STL, a type {\tt SCD\_FIR} is defined, containing the past
sample memory, as well as filter coefficients and other control
Expand Down Expand Up @@ -1245,6 +1247,14 @@ \subsection{FIR module}
SCD\_FIR *LP12\_48kHz\_init (void);\\
SCD\_FIR *LP14\_48kHz\_init (void);\\
SCD\_FIR *L20\_48kHz\_init (void);\\
SCD\_FIR *p863\_up\_1\_to\_2\_init (void);\\
SCD\_FIR *p863\_down\_2\_to\_1\_init (void);\\
SCD\_FIR *p863\_up\_1\_to\_3\_init (void);\\
SCD\_FIR *p863\_down\_3\_to\_1\_init (void);\\
SCD\_FIR *p863\_up\_1\_to\_4\_init (void);\\
SCD\_FIR *p863\_down\_4\_to\_1\_init (void);\\
SCD\_FIR *p863\_up\_1\_to\_6\_init (void);\\
SCD\_FIR *p863\_down\_6\_to\_1\_init (void);\\
}


Expand Down Expand Up @@ -1463,6 +1473,46 @@ \subsection{FIR module}
point for this filter is located at approximately 20000 Hz. Code is
in file {\tt fir-LP.c}.

{\tt p863\_up\_1\_to\_2\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR up-sampling filter by a factor of~2
(256~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_down\_2\_to\_1\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR down-sampling filter by a factor of~2
(256~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_up\_1\_to\_3\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR up-sampling filter by a factor of~3
(384~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_down\_3\_to\_1\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR down-sampling filter by a factor of~3
(384~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_up\_1\_to\_4\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR up-sampling filter by a factor of~4
(512~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_down\_4\_to\_1\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR down-sampling filter by a factor of~4
(512~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_up\_1\_to\_6\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR up-sampling filter by a factor of~6
(768~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.

{\tt p863\_down\_6\_to\_1\_init} is the initialization routine for the
P.863/P.863.2 resampling FIR down-sampling filter by a factor of~6
(768~taps, normalized cutoff frequency 0.475). Code is in file {\tt
fir-resamp.c}.


\rulex{1mm}

Expand Down
63 changes: 60 additions & 3 deletions src/fir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ include_directories(../iir)
include_directories(../utl)


add_executable(filter filter.c fir-dsm.c fir-flat.c fir-irs.c fir-lib.c fir-pso.c fir-tia.c fir-hirs.c fir-wb.c fir-msin.c fir-LP.c ../iir/iir-lib.c ../iir/iir-g712.c ../iir/iir-dir.c ../iir/iir-flat.c ../utl/ugst-utl.c ../utl/wav_io.c)
add_executable(filter filter.c fir-dsm.c fir-flat.c fir-irs.c fir-lib.c fir-pso.c fir-tia.c fir-hirs.c fir-wb.c fir-msin.c fir-LP.c fir-resamp.c ../iir/iir-lib.c ../iir/iir-g712.c ../iir/iir-dir.c ../iir/iir-flat.c ../utl/ugst-utl.c ../utl/wav_io.c)
target_link_libraries(filter ${M_LIBRARY})

add_executable(flt fltresp.c fir-dsm.c fir-flat.c fir-irs.c fir-lib.c fir-pso.c fir-tia.c fir-hirs.c fir-wb.c fir-msin.c fir-LP.c ../iir/iir-lib.c ../iir/iir-g712.c ../iir/iir-dir.c ../iir/iir-flat.c)
add_executable(flt fltresp.c fir-dsm.c fir-flat.c fir-irs.c fir-lib.c fir-pso.c fir-tia.c fir-hirs.c fir-wb.c fir-msin.c fir-LP.c fir-resamp.c ../iir/iir-lib.c ../iir/iir-g712.c ../iir/iir-dir.c ../iir/iir-flat.c)
target_link_libraries(flt ${M_LIBRARY})

add_executable(firdemo firdemo.c fir-dsm.c fir-flat.c fir-irs.c fir-lib.c fir-pso.c fir-tia.c fir-hirs.c fir-wb.c fir-msin.c fir-LP.c ../iir/iir-lib.c ../iir/iir-g712.c ../iir/iir-dir.c ../iir/iir-flat.c ../utl/ugst-utl.c ../utl/wav_io.c)
add_executable(firdemo firdemo.c fir-dsm.c fir-flat.c fir-irs.c fir-lib.c fir-pso.c fir-tia.c fir-hirs.c fir-wb.c fir-msin.c fir-LP.c fir-resamp.c ../iir/iir-lib.c ../iir/iir-g712.c ../iir/iir-dir.c ../iir/iir-flat.c ../utl/ugst-utl.c ../utl/wav_io.c)
target_link_libraries(firdemo ${M_LIBRARY})

#Test: FIR
Expand Down Expand Up @@ -177,3 +177,60 @@ add_test(filter30-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv

add_test(filter31 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q HP50_48KHZ test_data/test.src test_data/test-hp50-48khz.flt)
add_test(filter31-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/test-hp50-48khz.flt test_data/test-hp50-48khz.ref)

#Test: P863 resampling filters (raw PCM)
add_test(filter-p863-48to16 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -down P863_3 test_data/p863_48k_in.raw test_data/p863_48k_to_16k.tst)
add_test(filter-p863-48to16-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_16k.tst test_data/p863_48k_to_16k.raw)

add_test(filter-p863-48to8 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -down P863_6 test_data/p863_48k_in.raw test_data/p863_48k_to_8k.tst)
add_test(filter-p863-48to8-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_8k.tst test_data/p863_48k_to_8k.raw)

add_test(filter-p863-8to16 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -up P863_2 test_data/p863_8k_in.raw test_data/p863_8k_to_16k.tst)
add_test(filter-p863-8to16-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_16k.tst test_data/p863_8k_to_16k.raw)

add_test(filter-p863-8to48 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -up P863_6 test_data/p863_8k_in.raw test_data/p863_8k_to_48k.tst)
add_test(filter-p863-8to48-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_48k.tst test_data/p863_8k_to_48k.raw)

#Test: P863 resampling filters (WAV)
add_test(filter-p863-48to16-wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -down P863_3 test_data/p863_48k_in.wav test_data/p863_48k_to_16k_tst.wav)
add_test(filter-p863-48to16-wav-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_16k_tst.wav test_data/p863_48k_to_16k.wav)

add_test(filter-p863-48to8-wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -down P863_6 test_data/p863_48k_in.wav test_data/p863_48k_to_8k_tst.wav)
add_test(filter-p863-48to8-wav-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_8k_tst.wav test_data/p863_48k_to_8k.wav)

add_test(filter-p863-8to16-wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -up P863_2 test_data/p863_8k_in.wav test_data/p863_8k_to_16k_tst.wav)
add_test(filter-p863-8to16-wav-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_16k_tst.wav test_data/p863_8k_to_16k.wav)

add_test(filter-p863-8to48-wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/filter -q -up P863_6 test_data/p863_8k_in.wav test_data/p863_8k_to_48k_tst.wav)
add_test(filter-p863-8to48-wav-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_48k_tst.wav test_data/p863_8k_to_48k.wav)

set_tests_properties(
filter-p863-48to16 filter-p863-48to16-verify
filter-p863-48to8 filter-p863-48to8-verify
filter-p863-8to16 filter-p863-8to16-verify
filter-p863-8to48 filter-p863-8to48-verify
filter-p863-48to16-wav filter-p863-48to16-wav-verify
filter-p863-48to8-wav filter-p863-48to8-wav-verify
filter-p863-8to16-wav filter-p863-8to16-wav-verify
filter-p863-8to48-wav filter-p863-8to48-wav-verify
PROPERTIES WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

#Test: P863 cross-validation (raw output vs WAV reference, WAV output vs raw reference)
add_test(filter-p863-48to16-cross-raw2wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_16k.tst test_data/p863_48k_to_16k.wav)
add_test(filter-p863-48to16-cross-wav2raw ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_16k_tst.wav test_data/p863_48k_to_16k.raw)

add_test(filter-p863-48to8-cross-raw2wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_8k.tst test_data/p863_48k_to_8k.wav)
add_test(filter-p863-48to8-cross-wav2raw ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_48k_to_8k_tst.wav test_data/p863_48k_to_8k.raw)

add_test(filter-p863-8to16-cross-raw2wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_16k.tst test_data/p863_8k_to_16k.wav)
add_test(filter-p863-8to16-cross-wav2raw ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_16k_tst.wav test_data/p863_8k_to_16k.raw)

add_test(filter-p863-8to48-cross-raw2wav ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_48k.tst test_data/p863_8k_to_48k.wav)
add_test(filter-p863-8to48-cross-wav2raw ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -q -equiv 1 test_data/p863_8k_to_48k_tst.wav test_data/p863_8k_to_48k.raw)

set_tests_properties(
filter-p863-48to16-cross-raw2wav filter-p863-48to16-cross-wav2raw
filter-p863-48to8-cross-raw2wav filter-p863-48to8-cross-wav2raw
filter-p863-8to16-cross-raw2wav filter-p863-8to16-cross-wav2raw
filter-p863-8to48-cross-raw2wav filter-p863-8to48-cross-wav2raw
PROPERTIES WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
40 changes: 38 additions & 2 deletions src/fir/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,11 @@ int valid_filter (char *F_type, char modified_IRS) {
// FILTER_12k48k_HW
|| strncmp (F_type, "LP12", 4) == 0 || strncmp (F_type, "lp12", 4) == 0
// FILTER_12k48k_HW
|| strncmp (F_type, "LP14", 4) == 0 || strncmp (F_type, "lp14", 4) == 0 || strncmp (F_type, "LP20", 4) == 0 || strncmp (F_type, "lp20", 4) == 0 || strncmp (F_type, "hp50_32khz", 10) == 0 || strncmp (F_type, "HP50_32KHZ", 10) == 0 || strncmp (F_type, "hp50_48khz", 10) == 0 || strncmp (F_type, "HP50_48KHZ", 10) == 0)
|| strncmp (F_type, "LP14", 4) == 0 || strncmp (F_type, "lp14", 4) == 0 || strncmp (F_type, "LP20", 4) == 0 || strncmp (F_type, "lp20", 4) == 0 || strncmp (F_type, "hp50_32khz", 10) == 0 || strncmp (F_type, "HP50_32KHZ", 10) == 0 || strncmp (F_type, "hp50_48khz", 10) == 0 || strncmp (F_type, "HP50_48KHZ", 10) == 0
|| strncmp (F_type, "p863_2", 6) == 0 || strncmp (F_type, "P863_2", 6) == 0
|| strncmp (F_type, "p863_3", 6) == 0 || strncmp (F_type, "P863_3", 6) == 0
|| strncmp (F_type, "p863_4", 6) == 0 || strncmp (F_type, "P863_4", 6) == 0
|| strncmp (F_type, "p863_6", 6) == 0 || strncmp (F_type, "P863_6", 6) == 0)
valid = 1;

/* No MOD-IRS filter at 8 kHz */
Expand Down Expand Up @@ -297,7 +301,11 @@ void display_usage () {
printf (" HP50_32KHZ 50 Hz highpass FIR filter w/ factor 1:1 at sf=32kHz, 1119 coefs\n");
printf (" HP50_48KHZ 50 Hz highpass FIR filter w/ factor 1:1 at sf=48kHz, 1679 coefs\n");
printf (" SHQ2 FIR (Super High quality : 729 coefs, -80dB) low-pass for factor 1:2 (up) or 2:1(down)\n");
printf (" SHQ3 FIR (Super High quality : 729 coefs, -80dB) low-pass for factor 1:3 (up) or 3:1(down)\n\n");
printf (" SHQ3 FIR (Super High quality : 729 coefs, -80dB) low-pass for factor 1:3 (up) or 3:1(down)\n");
printf (" P863_2 P.863/P.863.2 resampling filter for factor 1:2 (up) or 2:1 (down)\n");
printf (" P863_3 P.863/P.863.2 resampling filter for factor 1:3 (up) or 3:1 (down)\n");
printf (" P863_4 P.863/P.863.2 resampling filter for factor 1:4 (up) or 4:1 (down)\n");
printf (" P863_6 P.863/P.863.2 resampling filter for factor 1:6 (up) or 6:1 (down)\n\n");

/* Quit program */
exit (-128);
Expand Down Expand Up @@ -685,6 +693,34 @@ int main (int argc, char *argv[]) {
fir_state = hp50_48khz_init ();
}

/*
* Filter type: P863 - P.863/P.863.2 resampling filters
* P863_2: factor 1:2 (up) or 2:1 (down)
* P863_3: factor 1:3 (up) or 3:1 (down)
* P863_4: factor 1:4 (up) or 4:1 (down)
* P863_6: factor 1:6 (up) or 6:1 (down)
*/
else if (strncmp (F_type, "p863_", 5) == 0 || strncmp (F_type, "P863_", 5) == 0) {
int f = atoi (&F_type[5]);
if (upsample) {
switch (f) {
case 2: fir_state = p863_up_1_to_2_init (); break;
case 3: fir_state = p863_up_1_to_3_init (); break;
case 4: fir_state = p863_up_1_to_4_init (); break;
case 6: fir_state = p863_up_1_to_6_init (); break;
default: error_terminate ("P863: factor must be 2, 3, 4, or 6\n", 15);
}
} else {
switch (f) {
case 2: fir_state = p863_down_2_to_1_init (); break;
case 3: fir_state = p863_down_3_to_1_init (); break;
case 4: fir_state = p863_down_4_to_1_init (); break;
case 6: fir_state = p863_down_6_to_1_init (); break;
default: error_terminate ("P863: factor must be 2, 3, 4, or 6\n", 15);
}
}
}

/*
* Filter type: PCM - Standard PCM quality 2:1 or 1:2 factor:
* . fs == 8000 -> upsample: 1:2
Expand Down
Loading