Remove dtmf2num - warvox - Unnamed repository; edit this file 'description' to … | |
Log | |
Files | |
Refs | |
README | |
--- | |
commit 3f4572631842f38da7c8020f2632b3238b6ae055 | |
parent edcebe28cb22ff7f9e7091638c88bd7c5ea4df84 | |
Author: HD Moore <[email protected]> | |
Date: Wed, 26 Dec 2012 23:15:36 -0600 | |
Remove dtmf2num | |
Diffstat: | |
M Gemfile.lock | 17 +++++++---------- | |
M Makefile | 9 +-------- | |
M app/views/analyze/view.html.erb | 6 ------ | |
M app/views/analyze/view_matches.htm… | 36 +++++++++++----------------… | |
M bin/verify_install.rb | 7 ------- | |
M config/warvox.conf | 5 ++--- | |
M db/schema.rb | 2 -- | |
M docs/ChangeLog | 1 + | |
M lib/warvox/jobs/analysis.rb | 22 ---------------------- | |
D src/dtmf2num/Makefile | 16 ---------------- | |
D src/dtmf2num/README | 5 ----- | |
D src/dtmf2num/dsp.c | 502 -----------------------------… | |
D src/dtmf2num/dtmf2num.c | 372 -----------------------------… | |
D src/dtmf2num/mywav.h | 244 -----------------------------… | |
D src/dtmf2num/resample2.c | 342 -----------------------------… | |
15 files changed, 23 insertions(+), 1563 deletions(-) | |
--- | |
diff --git a/Gemfile.lock b/Gemfile.lock | |
@@ -37,13 +37,10 @@ GEM | |
coffee-script-source | |
execjs | |
coffee-script-source (1.4.0) | |
- delayed_job (3.0.4) | |
- activesupport (~> 3.0) | |
- delayed_job_active_record (0.3.3) | |
- activerecord (>= 2.1.0, < 4) | |
- delayed_job (~> 3.0) | |
+ daemons (1.1.9) | |
dynamic_form (1.1.4) | |
erubis (2.7.0) | |
+ eventmachine (1.0.0) | |
execjs (1.4.0) | |
multi_json (~> 1.0) | |
hike (1.2.1) | |
@@ -88,7 +85,6 @@ GEM | |
rake (10.0.3) | |
rdoc (3.12) | |
json (~> 1.4) | |
- ref (1.0.2) | |
sass (3.2.4) | |
sass-rails (3.2.5) | |
railties (~> 3.2.0) | |
@@ -98,8 +94,10 @@ GEM | |
hike (~> 1.2) | |
rack (~> 1.0) | |
tilt (~> 1.1, != 1.3.0) | |
- therubyracer (0.11.0) | |
- ref | |
+ thin (1.5.0) | |
+ daemons (>= 1.0.9) | |
+ eventmachine (>= 0.12.6) | |
+ rack (>= 1.0.0) | |
thor (0.16.0) | |
tilt (1.3.3) | |
treetop (1.4.12) | |
@@ -116,7 +114,6 @@ PLATFORMS | |
DEPENDENCIES | |
coffee-rails (~> 3.2.1) | |
- delayed_job_active_record | |
dynamic_form | |
jquery-rails | |
kissfft | |
@@ -124,6 +121,6 @@ DEPENDENCIES | |
pg (= 0.11) | |
rails (= 3.2.8) | |
sass-rails (~> 3.2.3) | |
- therubyracer | |
+ thin | |
uglifier (>= 1.0.3) | |
will_paginate (~> 3.0) | |
diff --git a/Makefile b/Makefile | |
@@ -3,11 +3,7 @@ all: test | |
test: install | |
bin/verify_install.rb | |
-install: bundler dtmf2num | |
- cp -a src/dtmf2num/dtmf2num bin/ | |
- | |
-dtmf2num: | |
- make -C src/dtmf2num/ | |
+install: bundler | |
db: | |
@echo "Checking the database.." | |
@@ -22,6 +18,3 @@ bundler: | |
@echo "Installing missing gems as needed.." | |
bundle install | |
- | |
-clean: | |
- make -C src/dtmf2num/ clean | |
diff --git a/app/views/analyze/view.html.erb b/app/views/analyze/view.html.erb | |
@@ -38,12 +38,6 @@ | |
Provider: <%=h dial_result.provider.name %><br/> | |
Audio: <%=h dial_result.seconds %> Seconds<br/> | |
Ringer: <%=h dial_result.ringtime %> Seconds<br/> | |
- <% if(dial_result.dtmf and dial_result.dtmf.length > 0) %> | |
- DTMF: <%=h dial_result.dtmf %><br/> | |
- <% end %> | |
- <% if(dial_result.mf and dial_result.mf.length > 0) %> | |
- MF: <%=h dial_result.mf %><br/> | |
- <% end %> | |
</td> | |
<td align='center'> | |
<b><%=h dial_result.line_type.upcase %></b><br/> | |
diff --git a/app/views/analyze/view_matches.html.erb b/app/views/analyze/view_m… | |
@@ -10,10 +10,10 @@ | |
<tr> | |
<td align='center'> | |
- | |
+ | |
<object | |
type="application/x-shockwave-flash" | |
- data="/assets/musicplayer.swf?song_url=<%=resource_ana… | |
+ data="/assets/musicplayer.swf?song_url=<%=resource_ana… | |
width="20" | |
height="17" | |
style="margin-bottom: -5px;" | |
@@ -21,31 +21,25 @@ | |
<param name="movie" value="/assets/musicplayer.swf?son… | |
<param name="wmode" value="transparent"></param> | |
</object> | |
- | |
+ | |
<b><%= dial_result.number %></b> | |
<hr width='100%' size='1'/> | |
CallerID: <%= dial_result.cid%><br/> | |
Provider: <%=h dial_result.provider.name %><br/> | |
Audio: <%=h dial_result.seconds %> Seconds<br/> | |
Ringer: <%=h dial_result.ringtime %> Seconds<br/> | |
- <% if(dial_result.dtmf and dial_result.dtmf.length > 0) %> | |
- DTMF: <%=h dial_result.dtmf %><br/> | |
- <% end %> | |
- <% if(dial_result.mf and dial_result.mf.length > 0) %> | |
- MF: <%=h dial_result.mf %><br/> | |
- <% end %> | |
</td> | |
<td align='center'> | |
<b><%=h dial_result.line_type.upcase %></b><br/> | |
<a href="<%=resource_analyze_path(@job_id, dial_result.id, "bi… | |
<a href="<%=resource_analyze_path(@job_id, dial_result.id, "bi… | |
- <% (dial_result.signatures||"").split("\n").each do |s| | |
+ <% (dial_result.signatures||"").split("\n").each do |s| | |
sid,mat,name = s.split(':', 3) | |
str = [mat.to_i * 6.4, 255].min | |
col = ("%.2x" % (255 - str)) * 3 | |
%> | |
<div style="color: #<%= col%>;"><%=h name%> (<%=h sid … | |
- <% end %> | |
+ <% end %> | |
</td> | |
</tr> | |
</table><br/><br/> | |
@@ -61,12 +55,12 @@ | |
<% @results.each do |dial_result| %> | |
<tr> | |
<td align='center'> | |
- | |
+ | |
<br/><%= raw(fwd_match_html(dial_result.matchscore)) %><br/><b… | |
- | |
+ | |
<object | |
type="application/x-shockwave-flash" | |
- data="/assets/musicplayer.swf?song_url=<%=resource_ana… | |
+ data="/assets/musicplayer.swf?song_url=<%=resource_ana… | |
width="20" | |
height="17" | |
style="margin-bottom: -5px;" | |
@@ -74,34 +68,28 @@ | |
<param name="movie" value="/assets/musicplayer.swf?son… | |
<param name="wmode" value="transparent"></param> | |
</object> | |
- | |
+ | |
<b><%= dial_result.number %></b> | |
<hr width='100%' size='1'/> | |
CallerID: <%= dial_result.cid%><br/> | |
Provider: <%=h dial_result.provider.name %><br/> | |
Audio: <%=h dial_result.seconds %> Seconds<br/> | |
Ringer: <%=h dial_result.ringtime %> Seconds<br/> | |
- <% if(dial_result.dtmf and dial_result.dtmf.length > 0) %> | |
- DTMF: <%=h dial_result.dtmf %><br/> | |
- <% end %> | |
- <% if(dial_result.mf and dial_result.mf.length > 0) %> | |
- MF: <%=h dial_result.mf %><br/> | |
- <% end %> | |
</td> | |
<td align='center'> | |
<b><%=h dial_result.line_type.upcase %></b><br/> | |
<a href="<%=resource_analyze_path(@job_id, dial_result.id, "bi… | |
<a href="<%=resource_analyze_path(@job_id, dial_result.id, "bi… | |
- <% (dial_result.signatures||"").split("\n").each do |s| | |
+ <% (dial_result.signatures||"").split("\n").each do |s| | |
sid,mat,name = s.split(':', 3) | |
str = [mat.to_i * 6.4, 255].min | |
col = ("%.2x" % (255 - str)) * 3 | |
%> | |
<div style="color: #<%= col%>;"><%=h name%> (<%=h sid … | |
- <% end %> | |
+ <% end %> | |
<% if dial_result.fprint %> | |
<a href="<%=view_matches_path(dial_result.id)%>">View … | |
- <% end %> | |
+ <% end %> | |
</td> | |
</tr> | |
<% end %> | |
diff --git a/bin/verify_install.rb b/bin/verify_install.rb | |
@@ -56,13 +56,6 @@ end | |
puts "[*] The LAME binary appears to be available" | |
-if(not WarVOX::Config.tool_path('dtmf2num')) | |
- puts "[*] ERROR: The 'dtmf2num' binary could not be installed" | |
- exit | |
-end | |
-puts "[*] The DTMF2NUM binary appears to be available" | |
- | |
- | |
puts " " | |
puts "[*] Congratulations! You are almost ready to run WarVOX" | |
puts " " | |
diff --git a/config/warvox.conf b/config/warvox.conf | |
@@ -24,7 +24,6 @@ tools: | |
gnuplot: gnuplot | |
lame: lame | |
iaxrecord: "%BASE%/bin/iaxrecord.rb" | |
- dtmf2num: "%BASE%/bin/dtmf2num" | |
# | |
# Concurrent processing jobs, change this to | |
@@ -37,9 +36,9 @@ analysis_threads: 2 | |
# | |
# Configure the dial blacklist location | |
# | |
-blacklist: "%BASE%/etc/blacklist.txt" | |
+blacklist: "%BASE%/config/blacklist.txt" | |
# | |
# Configure the signature directory | |
# | |
-signatures: "%BASE%/etc/sigs" | |
+signatures: "%BASE%/config/sigs" | |
diff --git a/db/schema.rb b/db/schema.rb | |
@@ -50,8 +50,6 @@ ActiveRecord::Schema.define(:version => 20110801000003) do | |
t.text "line_type" | |
t.text "notes" | |
t.text "signatures" | |
- t.text "dtmf" | |
- t.text "mf" | |
t.string "fprint", :limit => nil | |
t.binary "audio" | |
t.binary "mp3" | |
diff --git a/docs/ChangeLog b/docs/ChangeLog | |
@@ -1,6 +1,7 @@ | |
2012-12-26 HD Moore <hdm[at]rapid7.com> | |
* overhauled, updated gems, merged directories with web | |
* swapped in Rapid7-licensed Highcharts for graphics | |
+ * remove dtmf2num (limited value, too inaccurate) | |
2011-02-23 HD Moore <hdm[at]rapid7.com> | |
* bumped the version number to 1.2.0 | |
diff --git a/lib/warvox/jobs/analysis.rb b/lib/warvox/jobs/analysis.rb | |
@@ -323,27 +323,6 @@ class Analysis < Base | |
[png_big, png_big_dots, png_big_freq, png_sig, png_sig_freq ].… | |
- | |
- # Detect DTMF and MF tones | |
- dtmf = '' | |
- mf = '' | |
- pfd = IO.popen("#{WarVOX::Config.tool_path('dtmf2num')} -r 800… | |
- pfd.each_line do |line| | |
- line = line.strip | |
- if(line.strip =~ /^- MF numbers:\s+(.*)/) | |
- next if $1 == 'none' | |
- mf = $1 | |
- end | |
- if(line.strip =~ /^- DTMF numbers:\s+(.*)/) | |
- next if $1 == 'none' | |
- dtmf = $1 | |
- end | |
- end | |
- pfd.close | |
- res[:dtmf] = dtmf | |
- res[:mf] = mf | |
- | |
- | |
tmp_wav = Tempfile.new("wav") | |
tmp_mp3 = Tempfile.new("mp3") | |
@@ -418,4 +397,3 @@ end | |
end | |
end | |
- | |
diff --git a/src/dtmf2num/Makefile b/src/dtmf2num/Makefile | |
@@ -1,16 +0,0 @@ | |
-EXE = dtmf2num | |
-CFLAGS += -O2 -s | |
-BINDIR = $(PREFIX)/bin | |
-LIBS = -lm | |
- | |
-all: | |
- $(CC) $(CFLAGS) -c dtmf2num.c | |
- $(CC) $(CFLAGS) -c dsp.c | |
- $(CC) $(CFLAGS) -c resample2.c | |
- $(CC) $(CFLAGS) -o $(EXE) dtmf2num.o dsp.o resample2.o $(LIBS) | |
- | |
-clean: | |
- @rm -f *.o $(EXE) | |
- | |
-.PHONY: | |
- install | |
diff --git a/src/dtmf2num/README b/src/dtmf2num/README | |
@@ -1,5 +0,0 @@ | |
-This is a barely tweaked copy of DTMF2NUM, developed by Luigi Auriemma | |
- - http://aluigi.org/mytoolz.htm#dtmf2num | |
- | |
-This tool is provided under the GPL: | |
- - http://www.gnu.org/licenses/gpl.txt | |
diff --git a/src/dtmf2num/dsp.c b/src/dtmf2num/dsp.c | |
@@ -1,502 +0,0 @@ | |
-/* | |
- * Asterisk -- An open source telephony toolkit. | |
- * | |
- * Copyright (C) 1999 - 2005, Digium, Inc. | |
- * | |
- * Mark Spencer <[email protected]> | |
- * | |
- * Goertzel routines are borrowed from Steve Underwood's tremendous work on the | |
- * DTMF detector. | |
- * | |
- * See http://www.asterisk.org for more information about | |
- * the Asterisk project. Please do not directly contact | |
- * any of the maintainers of this project for assistance; | |
- * the project provides a web site, mailing lists and IRC | |
- * channels for your use. | |
- * | |
- * This program is free software, distributed under the terms of | |
- * the GNU General Public License Version 2. See the LICENSE file | |
- * at the top of the source tree. | |
- */ | |
- | |
-/*! \file | |
- * | |
- * \brief Convenience Signal Processing routines | |
- * | |
- * \author Mark Spencer <[email protected]> | |
- * \author Steve Underwood <[email protected]> | |
- */ | |
- | |
-/* Some routines from tone_detect.c by Steven Underwood as published under the… | |
-/* | |
- tone_detect.c - General telephony tone detection, and specific | |
- detection of DTMF. | |
- | |
- Copyright (C) 2001 Steve Underwood <[email protected]> | |
- | |
- Despite my general liking of the GPL, I place this code in the | |
- public domain for the benefit of all mankind - even the slimy | |
- ones who might try to proprietize my work and use it to my | |
- detriment. | |
-*/ | |
- | |
-/* | |
- modifications for decoding also damaged audio by Luigi auriemma "// aluigi w… | |
-*/ | |
- | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <stdint.h> | |
-#include <math.h> | |
-#include <malloc.h> | |
- | |
-#define DSP_DIGITMODE_DTMF 0 … | |
-#define DSP_DIGITMODE_MF 1 … | |
- | |
-#define DSP_DIGITMODE_NOQUELCH (1 << 8) /*!< Do … | |
-#define DSP_DIGITMODE_RELAXDTMF (1 << 11) /*!< "… | |
- | |
-#define MAX_DTMF_DIGITS 1024 | |
- | |
-/* Basic DTMF specs: | |
- * | |
- * Minimum tone on = 40ms | |
- * Minimum tone off = 50ms | |
- * Maximum digit rate = 10 per second | |
- * Normal twist <= 8dB accepted | |
- * Reverse twist <= 4dB accepted | |
- * S/N >= 15dB will detect OK | |
- * Attenuation <= 26dB will detect OK | |
- * Frequency tolerance +- 1.5% will detect, +-3.5% will reject | |
- */ | |
- | |
-//#define DTMF_THRESHOLD 8.0e7 | |
-#define DTMF_THRESHOLD 800000000.0 // aluigi work-around | |
-#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ | |
-#ifdef RADIO_RELAX | |
-#define DTMF_REVERSE_TWIST ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 6… | |
-#else | |
-#define DTMF_REVERSE_TWIST ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 4… | |
-#endif | |
-#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ | |
-#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ | |
-#define DTMF_2ND_HARMONIC_ROW ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 1… | |
-#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ | |
-#define DTMF_TO_TOTAL_ENERGY 42.0 | |
- | |
-//#define BELL_MF_THRESHOLD 1.6e9 | |
-#define BELL_MF_THRESHOLD DTMF_THRESHOLD // aluigi work-around | |
-#define BELL_MF_TWIST 4.0 /* 6dB */ | |
-#define BELL_MF_RELATIVE_PEAK 12.6 /* 11dB */ | |
- | |
-static int SAMPLE_RATE = 8000; | |
- | |
-typedef struct { | |
- int v2; | |
- int v3; | |
- int chunky; | |
- int fac; | |
- int samples; | |
-} goertzel_state_t; | |
- | |
-typedef struct { | |
- int value; | |
- int power; | |
-} goertzel_result_t; | |
- | |
-typedef struct | |
-{ | |
- goertzel_state_t row_out[4]; | |
- goertzel_state_t col_out[4]; | |
- int lasthit; | |
- int current_hit; | |
- float energy; | |
- int current_sample; | |
-} dtmf_detect_state_t; | |
- | |
-typedef struct | |
-{ | |
- goertzel_state_t tone_out[6]; | |
- int current_hit; | |
- int hits[5]; | |
- int current_sample; | |
-} mf_detect_state_t; | |
- | |
-typedef struct | |
-{ | |
- char digits[MAX_DTMF_DIGITS + 1]; | |
- int current_digits; | |
- int detected_digits; | |
- int lost_digits; | |
- | |
- union { | |
- dtmf_detect_state_t dtmf; | |
- mf_detect_state_t mf; | |
- } td; | |
-} digit_detect_state_t; | |
- | |
-static float dtmf_row[] = | |
-{ | |
- 697.0, 770.0, 852.0, 941.0 | |
-}; | |
-static float dtmf_col[] = | |
-{ | |
- 1209.0, 1336.0, 1477.0, 1633.0 | |
-}; | |
- | |
-static float mf_tones[] = | |
-{ | |
- 700.0, 900.0, 1100.0, 1300.0, 1500.0, 1700.0 | |
-}; | |
- | |
-static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; | |
- | |
-static char bell_mf_positions[] = "1247C-358A--69*---0B----#"; | |
- | |
-static inline void goertzel_sample(goertzel_state_t *s, short sample) | |
-{ | |
- int v1; | |
- | |
- v1 = s->v2; | |
- s->v2 = s->v3; | |
- | |
- s->v3 = (s->fac * s->v2) >> 15; | |
- s->v3 = s->v3 - v1 + (sample >> s->chunky); | |
- if (abs(s->v3) > 32768) { | |
- s->chunky++; | |
- s->v3 = s->v3 >> 1; | |
- s->v2 = s->v2 >> 1; | |
- v1 = v1 >> 1; | |
- } | |
-} | |
- | |
-static inline void goertzel_update(goertzel_state_t *s, short *samps, int coun… | |
-{ | |
- int i; | |
- | |
- for (i=0;i<count;i++) | |
- goertzel_sample(s, samps[i]); | |
-} | |
- | |
-static inline float goertzel_result(goertzel_state_t *s) | |
-{ | |
- goertzel_result_t r; | |
- r.value = (s->v3 * s->v3) + (s->v2 * s->v2); | |
- r.value -= ((s->v2 * s->v3) >> 15) * s->fac; | |
- r.power = s->chunky * 2; | |
- return (float)r.value * (float)(1 << r.power); | |
-} | |
- | |
-static inline void goertzel_init(goertzel_state_t *s, float freq, int samples) | |
-{ | |
- s->v2 = s->v3 = s->chunky = 0.0; | |
- s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / SAMPLE_RATE)); | |
- s->samples = samples; | |
-} | |
- | |
-static inline void goertzel_reset(goertzel_state_t *s) | |
-{ | |
- s->v2 = s->v3 = s->chunky = 0.0; | |
-} | |
- | |
-static void ast_dtmf_detect_init (dtmf_detect_state_t *s) | |
-{ | |
- int i; | |
- | |
- s->lasthit = 0; | |
- s->current_hit = 0; | |
- for (i = 0; i < 4; i++) { | |
- goertzel_init (&s->row_out[i], dtmf_row[i], 102); | |
- goertzel_init (&s->col_out[i], dtmf_col[i], 102); | |
- s->energy = 0.0; | |
- } | |
- s->current_sample = 0; | |
-} | |
- | |
-static void ast_mf_detect_init (mf_detect_state_t *s) | |
-{ | |
- int i; | |
- s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0; | |
- for (i = 0; i < 6; i++) { | |
- goertzel_init (&s->tone_out[i], mf_tones[i], 160); | |
- } | |
- s->current_sample = 0; | |
- s->current_hit = 0; | |
-} | |
- | |
-static void ast_digit_detect_init(digit_detect_state_t *s, int mf) | |
-{ | |
- s->current_digits = 0; | |
- s->detected_digits = 0; | |
- s->lost_digits = 0; | |
- s->digits[0] = '\0'; | |
- | |
- if (mf) | |
- ast_mf_detect_init(&s->td.mf); | |
- else | |
- ast_dtmf_detect_init(&s->td.dtmf); | |
-} | |
- | |
-static void store_digit(digit_detect_state_t *s, char digit) | |
-{ | |
- s->detected_digits++; | |
- if (s->current_digits < MAX_DTMF_DIGITS) { | |
- s->digits[s->current_digits++] = digit; | |
- s->digits[s->current_digits] = '\0'; | |
- } else { | |
- //ast_log(LOG_WARNING, "Digit lost due to full buffer\n"); | |
- s->lost_digits++; | |
- } | |
-} | |
- | |
-static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, | |
- int digitmode, int *writeback) | |
-{ | |
- float row_energy[4]; | |
- float col_energy[4]; | |
- float famp; | |
- int i; | |
- int j; | |
- int sample; | |
- int best_row; | |
- int best_col; | |
- int hit; | |
- int limit; | |
- | |
- hit = 0; | |
- for (sample = 0; sample < samples; sample = limit) { | |
- /* 102 is optimised to meet the DTMF specs. */ | |
- if ((samples - sample) >= (102 - s->td.dtmf.current_sample)) | |
- limit = sample + (102 - s->td.dtmf.current_sample); | |
- else | |
- limit = samples; | |
- /* The following unrolled loop takes only 35% (rough estimate)… | |
- time of a rolled loop on the machine on which it was develo… | |
- for (j = sample; j < limit; j++) { | |
- famp = amp[j]; | |
- s->td.dtmf.energy += famp*famp; | |
- /* With GCC 2.95, the following unrolled code seems to… | |
- (rough estimate) as long as a neat little 0-3 loop … | |
- goertzel_sample(s->td.dtmf.row_out, amp[j]); | |
- goertzel_sample(s->td.dtmf.col_out, amp[j]); | |
- goertzel_sample(s->td.dtmf.row_out + 1, amp[j]); | |
- goertzel_sample(s->td.dtmf.col_out + 1, amp[j]); | |
- goertzel_sample(s->td.dtmf.row_out + 2, amp[j]); | |
- goertzel_sample(s->td.dtmf.col_out + 2, amp[j]); | |
- goertzel_sample(s->td.dtmf.row_out + 3, amp[j]); | |
- goertzel_sample(s->td.dtmf.col_out + 3, amp[j]); | |
- } | |
- s->td.dtmf.current_sample += (limit - sample); | |
- if (s->td.dtmf.current_sample < 102) { | |
- if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) { | |
- /* If we had a hit last time, go ahead and cle… | |
- will be another hit */ | |
- for (i=sample;i<limit;i++) | |
- amp[i] = 0; | |
- *writeback = 1; | |
- } | |
- continue; | |
- } | |
- /* We are at the end of a DTMF detection block */ | |
- /* Find the peak row and the peak column */ | |
- row_energy[0] = goertzel_result (&s->td.dtmf.row_out[0]); | |
- col_energy[0] = goertzel_result (&s->td.dtmf.col_out[0]); | |
- | |
- for (best_row = best_col = 0, i = 1; i < 4; i++) { | |
- row_energy[i] = goertzel_result (&s->td.dtmf.row_out[i… | |
- if (row_energy[i] > row_energy[best_row]) | |
- best_row = i; | |
- col_energy[i] = goertzel_result (&s->td.dtmf.col_out[i… | |
- if (col_energy[i] > col_energy[best_col]) | |
- best_col = i; | |
- } | |
- hit = 0; | |
- | |
- /* Basic signal level test and the twist test */ | |
- if (row_energy[best_row] >= DTMF_THRESHOLD && | |
- col_energy[best_col] >= DTMF_THRESHOLD && | |
-// col_energy[best_col] < row_energy[best_row] *DTMF_REVERS… | |
- col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_r… | |
- /* Relative peak test */ | |
- for (i = 0; i < 4; i++) { | |
- if ((i != best_col && | |
- col_energy[i]*DTMF_RELATIVE_PEAK_COL > col… | |
- (i != best_row | |
- && row_energy[i]*DTMF_RELATIVE_PEAK_ROW >… | |
- break; | |
- } | |
- } | |
- /* ... and fraction of total energy test */ | |
- if (i >= 4 /*&& | |
- (row_energy[best_row] + col_energy[best_col]) > DT… | |
- /* Got a hit */ | |
- hit = dtmf_positions[(best_row << 2) + best_co… | |
- if (!(digitmode & DSP_DIGITMODE_NOQUELCH)) { | |
- /* Zero out frame data if this is part… | |
- for (i=sample;i<limit;i++) | |
- amp[i] = 0; | |
- *writeback = 1; | |
- } | |
- } | |
- } | |
- | |
- /* The logic in the next test is: | |
- For digits we need two successive identical clean detects, … | |
- something different preceeding it. This can work with | |
- back to back differing digits. More importantly, it | |
- can work with nasty phones that give a very wobbly start | |
- to a digit */ | |
- if (hit != s->td.dtmf.current_hit) { | |
- if (hit && s->td.dtmf.lasthit == hit) { | |
- s->td.dtmf.current_hit = hit; | |
- store_digit(s, hit); | |
- } else if (s->td.dtmf.lasthit != s->td.dtmf.current_hi… | |
- s->td.dtmf.current_hit = 0; | |
- } | |
- } | |
- s->td.dtmf.lasthit = hit; | |
- | |
- /* Reinitialise the detector for the next block */ | |
- for (i = 0; i < 4; i++) { | |
- goertzel_reset(&s->td.dtmf.row_out[i]); | |
- goertzel_reset(&s->td.dtmf.col_out[i]); | |
- } | |
- s->td.dtmf.energy = 0.0; | |
- s->td.dtmf.current_sample = 0; | |
- } | |
- return (s->td.dtmf.current_hit); /* return the debounced hit */ | |
-} | |
- | |
-/* MF goertzel size */ | |
-#define MF_GSIZE 120 | |
- | |
-static int mf_detect(digit_detect_state_t *s, int16_t amp[], | |
- int samples, int digitmode, int *writeback) | |
-{ | |
- float energy[6]; | |
- int best; | |
- int second_best; | |
- float famp; | |
- int i; | |
- int j; | |
- int sample; | |
- int hit; | |
- int limit; | |
- | |
- hit = 0; | |
- for (sample = 0; sample < samples; sample = limit) { | |
- /* 80 is optimised to meet the MF specs. */ | |
- if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample)) | |
- limit = sample + (MF_GSIZE - s->td.mf.current_sample); | |
- else | |
- limit = samples; | |
- /* The following unrolled loop takes only 35% (rough estimate)… | |
- time of a rolled loop on the machine on which it was develo… | |
- for (j = sample; j < limit; j++) { | |
- famp = amp[j]; | |
- /* With GCC 2.95, the following unrolled code seems to… | |
- (rough estimate) as long as a neat little 0-3 loop … | |
- goertzel_sample(s->td.mf.tone_out, amp[j]); | |
- goertzel_sample(s->td.mf.tone_out + 1, amp[j]); | |
- goertzel_sample(s->td.mf.tone_out + 2, amp[j]); | |
- goertzel_sample(s->td.mf.tone_out + 3, amp[j]); | |
- goertzel_sample(s->td.mf.tone_out + 4, amp[j]); | |
- goertzel_sample(s->td.mf.tone_out + 5, amp[j]); | |
- } | |
- s->td.mf.current_sample += (limit - sample); | |
- if (s->td.mf.current_sample < MF_GSIZE) { | |
- if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) { | |
- /* If we had a hit last time, go ahead and cle… | |
- will be another hit */ | |
- for (i=sample;i<limit;i++) | |
- amp[i] = 0; | |
- *writeback = 1; | |
- } | |
- continue; | |
- } | |
- /* We're at the end of an MF detection block. */ | |
- /* Find the two highest energies. The spec says to look for | |
- two tones and two tones only. Taking this literally -ie | |
- only two tones pass the minimum threshold - doesn't work | |
- well. The sinc function mess, due to rectangular windowing | |
- ensure that! Find the two highest energies and ensure they | |
- are considerably stronger than any of the others. */ | |
- energy[0] = goertzel_result(&s->td.mf.tone_out[0]); | |
- energy[1] = goertzel_result(&s->td.mf.tone_out[1]); | |
- if (energy[0] > energy[1]) { | |
- best = 0; | |
- second_best = 1; | |
- } else { | |
- best = 1; | |
- second_best = 0; | |
- } | |
- /*endif*/ | |
- for (i=2;i<6;i++) { | |
- energy[i] = goertzel_result(&s->td.mf.tone_out[i]); | |
- if (energy[i] >= energy[best]) { | |
- second_best = best; | |
- best = i; | |
- } else if (energy[i] >= energy[second_best]) { | |
- second_best = i; | |
- } | |
- } | |
- /* Basic signal level and twist tests */ | |
- hit = 0; | |
- if (energy[best] >= BELL_MF_THRESHOLD && energy[second_best] >… | |
-// && energy[best] < energy[second_best]*BELL_MF_TWIST … | |
- && energy[best]*BELL_MF_TWIST > energy[second_best]) { | |
- /* Relative peak test */ | |
- hit = -1; | |
- for (i=0;i<6;i++) { | |
- if (i != best && i != second_best) { | |
- if (energy[i]*BELL_MF_RELATIVE_PEAK >=… | |
- /* The best two are not clearl… | |
- hit = 0; | |
- break; | |
- } | |
- } | |
- } | |
- } | |
- if (hit) { | |
- /* Get the values into ascending order */ | |
- if (second_best < best) { | |
- i = best; | |
- best = second_best; | |
- second_best = i; | |
- } | |
- best = best*5 + second_best - 1; | |
- hit = bell_mf_positions[best]; | |
- /* Look for two successive similar results */ | |
- /* The logic in the next test is: | |
- For KP we need 4 successive identical clean detects… | |
- two blocks of something different preceeding it. Fo… | |
- else we need two successive identical clean detects… | |
- two blocks of something different preceeding it. */ | |
- if (hit == s->td.mf.hits[4] && hit == s->td.mf.hits[3]… | |
- ((hit != '*' && hit != s->td.mf.hits[2] && hit != s… | |
- (hit == '*' && hit == s->td.mf.hits[2] && hit != s… | |
- hit != s->td.mf.hits[0]))) { | |
- store_digit(s, hit); | |
- } | |
- } | |
- | |
- | |
- if (hit != s->td.mf.hits[4] && hit != s->td.mf.hits[3]) { | |
- /* Two successive block without a hit terminate curren… | |
- s->td.mf.current_hit = 0; | |
- } | |
- | |
- s->td.mf.hits[0] = s->td.mf.hits[1]; | |
- s->td.mf.hits[1] = s->td.mf.hits[2]; | |
- s->td.mf.hits[2] = s->td.mf.hits[3]; | |
- s->td.mf.hits[3] = s->td.mf.hits[4]; | |
- s->td.mf.hits[4] = hit; | |
- /* Reinitialise the detector for the next block */ | |
- for (i = 0; i < 6; i++) | |
- goertzel_reset(&s->td.mf.tone_out[i]); | |
- s->td.mf.current_sample = 0; | |
- } | |
- | |
- return (s->td.mf.current_hit); /* return the debounced hit */ | |
-} | |
diff --git a/src/dtmf2num/dtmf2num.c b/src/dtmf2num/dtmf2num.c | |
@@ -1,372 +0,0 @@ | |
-/* | |
- Copyright 2008 Luigi Auriemma | |
- | |
- This program is free software; you can redistribute it and/or modify | |
- it under the terms of the GNU General Public License as published by | |
- the Free Software Foundation; either version 2 of the License, or | |
- (at your option) any later version. | |
- | |
- This program is distributed in the hope that it will be useful, | |
- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
- GNU General Public License for more details. | |
- | |
- You should have received a copy of the GNU General Public License | |
- along with this program; if not, write to the Free Software | |
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
- | |
- http://www.gnu.org/licenses/gpl.txt | |
-*/ | |
- | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <stdint.h> | |
-#include <sys/stat.h> | |
-#include "mywav.h" | |
-#include "dsp.c" | |
-//#include "resample2.c" | |
- | |
- | |
- | |
-typedef int8_t i8; | |
-typedef uint8_t u8; | |
-typedef int16_t i16; | |
-typedef uint16_t u16; | |
-typedef int32_t i32; | |
-typedef uint32_t u32; | |
- | |
- | |
- | |
-#define VER "0.1c" | |
- | |
- | |
- | |
-int mywav_fri24(FILE *fd, uint32_t *num); | |
-i16 *do_samples(FILE *fd, int wavsize, int *ret_samples, int bits); | |
-int do_mono(i16 *smp, int samples, int ch); | |
-void do_dcbias(i16 *smp, int samples); | |
-void do_normalize(i16 *smp, int samples); | |
-int do_8000(i16 *smp, int samples, int *freq); | |
-void my_err(u8 *err); | |
-void std_err(void); | |
- | |
- | |
- | |
-int main(int argc, char *argv[]) { | |
- digit_detect_state_t dtmf; | |
- mywav_fmtchunk fmt; | |
- struct stat xstat; | |
- FILE *fd; | |
- int i, | |
- wavsize, | |
- samples, | |
- writeback, | |
- raw = 0, | |
- optimize = 1; | |
- i16 *smp; | |
- u8 *fname, | |
- *outfile = NULL; | |
- | |
- setbuf(stdin, NULL); | |
- setbuf(stdout, NULL); | |
- | |
- fputs("\n" | |
- "DTMF2NUM "VER"\n" | |
- "by Luigi Auriemma\n" | |
- "e-mail: [email protected]\n" | |
- "web: aluigi.org\n" | |
- "\n", stderr); | |
- | |
- if(argc < 2) { | |
- printf("\n" | |
- "Usage: %s [options] <file.WAV>\n" | |
- "\n" | |
- "Options:\n" | |
- "-r F C B consider the file as raw headerless PCM data, you must … | |
- " Frequency, Channels and Bits like -r 44100 2 16\n" | |
- "-o disable the automatic optimizations: DC bias adjust and… | |
- " use this option only if your file is already clean and … | |
- "-w FILE debug option for dumping the handled samples from the m… | |
- "\n", argv[0]); | |
- exit(1); | |
- } | |
- | |
- argc--; | |
- for(i = 1; i < argc; i++) { | |
- if(((argv[i][0] != '-') && (argv[i][0] != '/')) || (strlen(argv[i]) !=… | |
- printf("\nError: wrong argument (%s)\n", argv[i]); | |
- exit(1); | |
- } | |
- switch(argv[i][1]) { | |
- case 'r': { | |
- memset(&fmt, 0, sizeof(fmt)); | |
- if(!argv[++i]) exit(1); | |
- fmt.dwSamplesPerSec = atoi(argv[i]); | |
- if(!argv[++i]) exit(1); | |
- fmt.wChannels = atoi(argv[i]); | |
- if(!argv[++i]) exit(1); | |
- fmt.wBitsPerSample = atoi(argv[i]); | |
- fmt.wFormatTag = 1; | |
- raw = 1; | |
- } break; | |
- case 'o': { | |
- optimize = 0; | |
- } break; | |
- case 'w': { | |
- if(!argv[++i]) exit(1); | |
- outfile = argv[i]; | |
- } break; | |
- default: { | |
- printf("\nError: wrong option (%s)\n", argv[i]); | |
- exit(1); | |
- } | |
- } | |
- } | |
- | |
- fname = argv[argc]; | |
- | |
- if(!strcmp(fname, "-")) { | |
- printf("- open stdin\n"); | |
- fd = stdin; | |
- } else { | |
- printf("- open %s\n", fname); | |
- fd = fopen(fname, "rb"); | |
- if(!fd) std_err(); | |
- } | |
- | |
- if(raw) { | |
- fstat(fileno(fd), &xstat); | |
- wavsize = xstat.st_size; | |
- } else { | |
- wavsize = mywav_data(fd, &fmt); | |
- } | |
- fprintf(stderr, | |
- " wave size %u\n" | |
- " format tag %hu\n" | |
- " channels: %hu\n" | |
- " samples/sec: %u\n" | |
- " avg/bytes/sec: %u\n" | |
- " block align: %hu\n" | |
- " bits: %hu\n", | |
- wavsize, | |
- fmt.wFormatTag, | |
- fmt.wChannels, | |
- fmt.dwSamplesPerSec, | |
- fmt.dwAvgBytesPerSec, | |
- fmt.wBlockAlign, | |
- fmt.wBitsPerSample); | |
- | |
- if(wavsize <= 0) my_err("corrupted WAVE file"); | |
- if(fmt.wFormatTag != 1) my_err("only the classical PCM WAVE files are supp… | |
- | |
- smp = do_samples(fd, wavsize, &samples, fmt.wBitsPerSample); | |
- fprintf(stderr, " samples: %d\n", samples); | |
- if(fd != stdin) fclose(fd); | |
- | |
- samples = do_mono(smp, samples, fmt.wChannels); | |
- if(optimize) { | |
- do_dcbias(smp, samples); | |
- do_normalize(smp, samples); | |
- } | |
- samples = do_8000(smp, samples, &fmt.dwSamplesPerSec); | |
- | |
- fmt.wFormatTag = 0x0001; | |
- fmt.wChannels = 1; | |
- fmt.wBitsPerSample = 16; | |
- fmt.wBlockAlign = (fmt.wBitsPerSample >> 3) * fmt.wChannels; | |
- fmt.dwAvgBytesPerSec = fmt.dwSamplesPerSec * fmt.wBlockAlign; | |
- wavsize = samples * sizeof(* smp); | |
- | |
- if(outfile) { | |
- fprintf(stderr, "- dump %s\n", outfile); | |
- fd = fopen(outfile, "wb"); | |
- if(!fd) std_err(); | |
- mywav_writehead(fd, &fmt, wavsize, NULL, 0); | |
- fwrite(smp, 1, wavsize, fd); | |
- fclose(fd); | |
- } | |
- | |
- SAMPLE_RATE = fmt.dwSamplesPerSec; | |
- | |
- ast_digit_detect_init(&dtmf, DSP_DIGITMODE_MF); | |
- mf_detect(&dtmf, smp, samples, DSP_DIGITMODE_NOQUELCH, &writeback); | |
- printf("\n- MF numbers: %s\n", dtmf.digits[0] ? dtmf.digits : "none"); | |
- | |
- ast_digit_detect_init(&dtmf, DSP_DIGITMODE_DTMF); | |
- dtmf_detect(&dtmf, smp, samples, DSP_DIGITMODE_NOQUELCH, &writeback); | |
- printf("\n- DTMF numbers: %s\n", dtmf.digits[0] ? dtmf.digits : "none"); | |
- | |
- return(0); | |
-} | |
- | |
- | |
- | |
-int mywav_fri24(FILE *fd, uint32_t *num) { | |
- uint32_t ret; | |
- uint8_t tmp; | |
- | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret = tmp; | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret |= (tmp << 8); | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret |= (tmp << 16); | |
- *num = ret; | |
- return(0); | |
-} | |
- | |
- | |
- | |
-i16 *do_samples(FILE *fd, int wavsize, int *ret_samples, int bits) { | |
- i32 tmp32; | |
- int i = 0, | |
- samples; | |
- i16 *smp; | |
- i8 tmp8; | |
- | |
- samples = wavsize / (bits >> 3); | |
- smp = malloc(sizeof(* smp) * samples); | |
- if(!smp) std_err(); | |
- | |
- if(bits == 8) { | |
- for(i = 0; i < samples; i++) { | |
- if(mywav_fri08(fd, &tmp8) < 0) break; | |
- smp[i] = (tmp8 << 8) - 32768; | |
- } | |
- | |
- } else if(bits == 16) { | |
- for(i = 0; i < samples; i++) { | |
- if(mywav_fri16(fd, &smp[i]) < 0) break; | |
- } | |
- | |
- } else if(bits == 24) { | |
- for(i = 0; i < samples; i++) { | |
- if(mywav_fri24(fd, &tmp32) < 0) break; | |
- smp[i] = tmp32 >> 8; | |
- } | |
- | |
- } else if(bits == 32) { | |
- for(i = 0; i < samples; i++) { | |
- if(mywav_fri32(fd, &tmp32) < 0) break; | |
- smp[i] = tmp32 >> 16; | |
- } | |
- | |
- } else { | |
- my_err("number of bits used in the WAVE file not supported"); | |
- } | |
- *ret_samples = i; | |
- return(smp); | |
-} | |
- | |
- | |
- | |
-int do_mono(i16 *smp, int samples, int ch) { | |
- i32 tmp; // max 65535 channels | |
- int i, | |
- j; | |
- | |
- if(!ch) my_err("the WAVE file doesn't have channels"); | |
- if(ch == 1) return(samples); | |
- | |
- for(i = 0; samples > 0; i++) { | |
- tmp = 0; | |
- for(j = 0; j < ch; j++) { | |
- tmp += smp[(i * ch) + j]; | |
- } | |
- smp[i] = tmp / ch; | |
- samples -= ch; | |
- } | |
- return(i); | |
-} | |
- | |
- | |
- | |
-void do_dcbias(i16 *smp, int samples) { | |
- int i; | |
- i16 bias, | |
- maxneg, | |
- maxpos; | |
- | |
- maxneg = 32767; | |
- maxpos = -32768; | |
- for(i = 0; i < samples; i++) { | |
- if(smp[i] < maxneg) { | |
- maxneg = smp[i]; | |
- } else if(smp[i] > maxpos) { | |
- maxpos = smp[i]; | |
- } | |
- } | |
- | |
- bias = (maxneg + maxpos) / 2; | |
- fprintf(stderr, " bias adjust: %d\n", bias); | |
- | |
- for(i = 0; i < samples; i++) { | |
- smp[i] -= bias; | |
- } | |
-} | |
- | |
- | |
- | |
-void do_normalize(i16 *smp, int samples) { | |
- int i; | |
- i16 bias, | |
- maxneg, | |
- maxpos; | |
- | |
- maxneg = 0; | |
- maxpos = 0; | |
- for(i = 0; i < samples; i++) { | |
- if(smp[i] < maxneg) { | |
- maxneg = smp[i]; | |
- } else if(smp[i] > maxpos) { | |
- maxpos = smp[i]; | |
- } | |
- } | |
- | |
- fprintf(stderr, " volume peaks: %d %d\n", maxneg, maxpos); | |
- | |
- if(maxneg < 0) maxneg = (-maxneg) - 1; | |
- if(maxneg > maxpos) { | |
- bias = maxneg; | |
- } else { | |
- bias = maxpos; | |
- } | |
- if(bias == 32767) return; | |
- | |
- fprintf(stderr, " normalize: %d\n", 32767 - bias); | |
- | |
- for(i = 0; i < samples; i++) { | |
- smp[i] = (smp[i] * 32767) / bias; | |
- } | |
-} | |
- | |
- | |
- | |
-int do_8000(i16 *smp, int samples, int *freq) { | |
- void *res; | |
- int consumed; | |
- | |
- if(*freq <= 8000) return(samples); | |
- | |
- fprintf(stderr, " resampling to: 8000hz\n"); | |
- res = av_resample_init(8000, *freq, 16, 10, 0, 0.8); | |
- samples = av_resample(res, smp, smp, &consumed, samples, samples, 1); | |
- av_resample_close(res); | |
- | |
- *freq = 8000; | |
- return(samples); | |
-} | |
- | |
- | |
- | |
-void my_err(u8 *err) { | |
- fprintf(stderr, "\nError: %s\n", err); | |
- exit(1); | |
-} | |
- | |
- | |
- | |
-void std_err(void) { | |
- perror("\nError"); | |
- exit(1); | |
-} | |
- | |
- | |
diff --git a/src/dtmf2num/mywav.h b/src/dtmf2num/mywav.h | |
@@ -1,244 +0,0 @@ | |
-/* | |
- MyWAV 0.1.1 | |
- by Luigi Auriemma | |
- e-mail: [email protected] | |
- web: aluigi.org | |
- | |
- Copyright 2005,2006 Luigi Auriemma | |
- | |
- This program is free software; you can redistribute it and/or modify | |
- it under the terms of the GNU General Public License as published by | |
- the Free Software Foundation; either version 2 of the License, or | |
- (at your option) any later version. | |
- | |
- This program is distributed in the hope that it will be useful, | |
- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
- GNU General Public License for more details. | |
- | |
- You should have received a copy of the GNU General Public License | |
- along with this program; if not, write to the Free Software | |
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
- | |
- http://www.gnu.org/licenses/gpl.txt | |
-*/ | |
- | |
-#include <string.h> | |
-#include <stdint.h> | |
- | |
- | |
- | |
-/* | |
-the functions return ever 0 if success, other values (-1) if error | |
-note that these functions have been written with compatibility in mind | |
-so don't worry if you see useless instructions | |
-*/ | |
- | |
- | |
- | |
-typedef struct { | |
- uint8_t id[4]; | |
- uint32_t size; | |
-} mywav_chunk; | |
- | |
-typedef struct { | |
- int16_t wFormatTag; | |
- uint16_t wChannels; | |
- uint32_t dwSamplesPerSec; | |
- uint32_t dwAvgBytesPerSec; | |
- uint16_t wBlockAlign; | |
- uint16_t wBitsPerSample; | |
-} mywav_fmtchunk; | |
- | |
- | |
- | |
- /* FILE WRITING */ | |
- | |
- // 8 bit | |
-int mywav_fwi08(FILE *fd, int num) { | |
- if(fputc((num ) & 0xff, fd) < 0) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // 16 bit | |
-int mywav_fwi16(FILE *fd, int num) { | |
- if(fputc((num ) & 0xff, fd) < 0) return(-1); | |
- if(fputc((num >> 8) & 0xff, fd) < 0) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // 32 bit | |
-int mywav_fwi32(FILE *fd, int num) { | |
- if(fputc((num ) & 0xff, fd) < 0) return(-1); | |
- if(fputc((num >> 8) & 0xff, fd) < 0) return(-1); | |
- if(fputc((num >> 16) & 0xff, fd) < 0) return(-1); | |
- if(fputc((num >> 24) & 0xff, fd) < 0) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // data | |
-int mywav_fwmem(FILE *fd, uint8_t *mem, int size) { | |
- if(size) { | |
- if(fwrite(mem, size, 1, fd) != 1) return(-1); | |
- } | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // chunk | |
-int mywav_fwchunk(FILE *fd, mywav_chunk *chunk) { | |
- if(mywav_fwmem(fd, chunk->id, 4)) return(-1); | |
- if(mywav_fwi32(fd, chunk->size)) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // fmtchunk | |
-int mywav_fwfmtchunk(FILE *fd, mywav_fmtchunk *fmtchunk) { | |
- if(mywav_fwi16(fd, fmtchunk->wFormatTag)) return(-1); | |
- if(mywav_fwi16(fd, fmtchunk->wChannels)) return(-1); | |
- if(mywav_fwi32(fd, fmtchunk->dwSamplesPerSec)) return(-1); | |
- if(mywav_fwi32(fd, fmtchunk->dwAvgBytesPerSec)) return(-1); | |
- if(mywav_fwi16(fd, fmtchunk->wBlockAlign)) return(-1); | |
- if(mywav_fwi16(fd, fmtchunk->wBitsPerSample)) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- /* FILE READING */ | |
- | |
- // 8 bit | |
-int mywav_fri08(FILE *fd, uint8_t *num) { | |
- if(fread(num, 1, 1, fd) != 1) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // 16 bit | |
-int mywav_fri16(FILE *fd, uint16_t *num) { | |
- uint16_t ret; | |
- uint8_t tmp; | |
- | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret = tmp; | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret |= (tmp << 8); | |
- *num = ret; | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // 32 bit | |
-int mywav_fri32(FILE *fd, uint32_t *num) { | |
- uint32_t ret; | |
- uint8_t tmp; | |
- | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret = tmp; | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret |= (tmp << 8); | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret |= (tmp << 16); | |
- if(fread(&tmp, 1, 1, fd) != 1) return(-1); ret |= (tmp << 24); | |
- *num = ret; | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // data | |
-int mywav_frmem(FILE *fd, uint8_t *mem, int size) { | |
- if(size) { | |
- if(fread(mem, size, 1, fd) != 1) return(-1); | |
- } | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // chunk | |
-int mywav_frchunk(FILE *fd, mywav_chunk *chunk) { | |
- if(mywav_frmem(fd, (void *)&chunk->id, 4)) return(-1); | |
- if(mywav_fri32(fd, (void *)&chunk->size)) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- | |
- // fmtchunk | |
-int mywav_frfmtchunk(FILE *fd, mywav_fmtchunk *fmtchunk) { | |
- if(mywav_fri16(fd, (void *)&fmtchunk->wFormatTag)) return(-1); | |
- if(mywav_fri16(fd, (void *)&fmtchunk->wChannels)) return(-1); | |
- if(mywav_fri32(fd, (void *)&fmtchunk->dwSamplesPerSec)) return(-1); | |
- if(mywav_fri32(fd, (void *)&fmtchunk->dwAvgBytesPerSec)) return(-1); | |
- if(mywav_fri16(fd, (void *)&fmtchunk->wBlockAlign)) return(-1); | |
- if(mywav_fri16(fd, (void *)&fmtchunk->wBitsPerSample)) return(-1); | |
- return(0); | |
-} | |
- | |
- | |
- /* MYWAV MAIN FUNCTIONS */ | |
- | |
-int mywav_seekchunk(FILE *fd, uint8_t *find) { | |
- mywav_chunk chunk; | |
- | |
- if(fseek(fd, sizeof(mywav_chunk) + 4, SEEK_SET) < 0) return(-1); | |
- | |
- while(!mywav_frchunk(fd, &chunk)) { | |
- if(!memcmp(chunk.id, find, 4)) return(chunk.size); | |
- if(fseek(fd, chunk.size, SEEK_CUR) < 0) break; | |
- } | |
- return(-1); | |
-} | |
- | |
- | |
- | |
-int mywav_data(FILE *fd, mywav_fmtchunk *fmt) { | |
- mywav_chunk chunk; | |
- uint8_t type[4]; | |
- | |
- if(mywav_frchunk(fd, &chunk) < 0) return(-1); | |
- if(mywav_frmem(fd, type, 4) < 0) return(-1); | |
- if(memcmp(type, "WAVE", 4)) return(-1); | |
- | |
- if(mywav_seekchunk(fd, "fmt ") < 0) return(-1); | |
- if(mywav_frfmtchunk(fd, fmt) < 0) return(-1); | |
- | |
- return(mywav_seekchunk(fd, "data")); | |
-} | |
- | |
- | |
- | |
-int mywav_writehead(FILE *fd, mywav_fmtchunk *fmt, uint32_t data_size, uint8_t… | |
- mywav_chunk chunk; | |
- | |
- memcpy(chunk.id, "RIFF", 4); | |
- chunk.size = | |
- 4 + | |
- sizeof(mywav_chunk) + | |
- sizeof(mywav_fmtchunk) + | |
- morelen + | |
- sizeof(mywav_chunk) + | |
- data_size; | |
- | |
- if(mywav_fwchunk(fd, &chunk) < 0) return(-1); | |
- if(mywav_fwmem(fd, "WAVE", 4) < 0) return(-1); | |
- | |
- memcpy(chunk.id, "fmt ", 4); | |
- chunk.size = sizeof(mywav_fmtchunk) + morelen; | |
- if(mywav_fwchunk(fd, &chunk) < 0) return(-1); | |
- if(mywav_fwfmtchunk(fd, fmt) < 0) return(-1); | |
- if(mywav_fwmem(fd, more, morelen) < 0) return(-1); | |
- | |
- memcpy(chunk.id, "data", 4); | |
- chunk.size = data_size; | |
- if(mywav_fwchunk(fd, &chunk) < 0) return(-1); | |
- return(0); | |
-} | |
- | |
diff --git a/src/dtmf2num/resample2.c b/src/dtmf2num/resample2.c | |
@@ -1,342 +0,0 @@ | |
-/* | |
- * audio resampling | |
- * Copyright (c) 2004 Michael Niedermayer <[email protected]> | |
- * | |
- * This file is part of FFmpeg. | |
- * | |
- * FFmpeg is free software; you can redistribute it and/or | |
- * modify it under the terms of the GNU Lesser General Public | |
- * License as published by the Free Software Foundation; either | |
- * version 2.1 of the License, or (at your option) any later version. | |
- * | |
- * FFmpeg is distributed in the hope that it will be useful, | |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
- * Lesser General Public License for more details. | |
- * | |
- * You should have received a copy of the GNU Lesser General Public | |
- * License along with FFmpeg; if not, write to the Free Software | |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
- */ | |
- | |
-/** | |
- * @file resample2.c | |
- * audio resampling | |
- * @author Michael Niedermayer <[email protected]> | |
- */ | |
- | |
-#include <stdio.h> | |
-#include <stdlib.h> | |
-#include <string.h> | |
-#include <stdint.h> | |
-#include <math.h> | |
-#include <malloc.h> | |
- | |
-#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) | |
-#define FFSIGN(a) ((a) > 0 ? 1 : -1) | |
-#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) | |
-#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) | |
-#define av_mallocz malloc | |
-#define av_freep free | |
- | |
-#ifndef CONFIG_RESAMPLE_HP | |
-#define FILTER_SHIFT 15 | |
- | |
-#define FELEM int16_t | |
-#define FELEM2 int32_t | |
-#define FELEML int64_t | |
-#define FELEM_MAX INT16_MAX | |
-#define FELEM_MIN INT16_MIN | |
-#define WINDOW_TYPE 9 | |
-#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE) | |
-#define FILTER_SHIFT 30 | |
- | |
-#define FELEM int32_t | |
-#define FELEM2 int64_t | |
-#define FELEML int64_t | |
-#define FELEM_MAX INT32_MAX | |
-#define FELEM_MIN INT32_MIN | |
-#define WINDOW_TYPE 12 | |
-#else | |
-#define FILTER_SHIFT 0 | |
- | |
-#define FELEM double | |
-#define FELEM2 double | |
-#define FELEML double | |
-#define WINDOW_TYPE 24 | |
-#endif | |
- | |
- | |
-typedef struct AVResampleContext{ | |
- FELEM *filter_bank; | |
- int filter_length; | |
- int ideal_dst_incr; | |
- int dst_incr; | |
- int index; | |
- int frac; | |
- int src_incr; | |
- int compensation_distance; | |
- int phase_shift; | |
- int phase_mask; | |
- int linear; | |
-}AVResampleContext; | |
- | |
-/** | |
- * 0th order modified bessel function of the first kind. | |
- */ | |
-static double bessel(double x){ | |
- double v=1; | |
- double t=1; | |
- int i; | |
- | |
- x= x*x/4; | |
- for(i=1; i<50; i++){ | |
- t *= x/(i*i); | |
- v += t; | |
- } | |
- return v; | |
-} | |
- | |
-static inline int av_clip(int a, int amin, int amax) | |
-{ | |
- if (a < amin) return amin; | |
- else if (a > amax) return amax; | |
- else return a; | |
-} | |
- | |
-/** | |
- * builds a polyphase filterbank. | |
- * @param factor resampling factor | |
- * @param scale wanted sum of coefficients for each filter | |
- * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser wind… | |
- */ | |
-void av_build_filter(FELEM *filter, double factor, int tap_count, int phase_co… | |
- int ph, i; | |
- double x, y, w, tab[tap_count]; | |
- const int center= (tap_count-1)/2; | |
- | |
- /* if upsampling, only need to interpolate, no filter */ | |
- if (factor > 1.0) | |
- factor = 1.0; | |
- | |
- for(ph=0;ph<phase_count;ph++) { | |
- double norm = 0; | |
- for(i=0;i<tap_count;i++) { | |
- x = M_PI * ((double)(i - center) - (double)ph / phase_count) * fac… | |
- if (x == 0) y = 1.0; | |
- else y = sin(x) / x; | |
- switch(type){ | |
- case 0:{ | |
- const float d= -0.5; //first order derivative = -0.5 | |
- x = fabs(((double)(i - center) - (double)ph / phase_count) * f… | |
- if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x… | |
- else y= d*(-4 + 8*x - 5*x*x + x*x*x… | |
- break;} | |
- case 1: | |
- w = 2.0*x / (factor*tap_count) + M_PI; | |
- y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0… | |
- break; | |
- default: | |
- w = 2.0*x / (factor*tap_count*M_PI); | |
- y *= bessel(type*sqrt(FFMAX(1-w*w, 0))); | |
- break; | |
- } | |
- | |
- tab[i] = y; | |
- norm += y; | |
- } | |
- | |
- /* normalize so that an uniform color remains the same */ | |
- for(i=0;i<tap_count;i++) { | |
-#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE | |
- filter[ph * tap_count + i] = tab[i] / norm; | |
-#else | |
- filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm)… | |
-#endif | |
- } | |
- } | |
-#if 0 | |
- { | |
-#define LEN 1024 | |
- int j,k; | |
- double sine[LEN + tap_count]; | |
- double filtered[LEN]; | |
- double maxff=-2, minff=2, maxsf=-2, minsf=2; | |
- for(i=0; i<LEN; i++){ | |
- double ss=0, sf=0, ff=0; | |
- for(j=0; j<LEN+tap_count; j++) | |
- sine[j]= cos(i*j*M_PI/LEN); | |
- for(j=0; j<LEN; j++){ | |
- double sum=0; | |
- ph=0; | |
- for(k=0; k<tap_count; k++) | |
- sum += filter[ph * tap_count + k] * sine[k+j]; | |
- filtered[j]= sum / (1<<FILTER_SHIFT); | |
- ss+= sine[j + center] * sine[j + center]; | |
- ff+= filtered[j] * filtered[j]; | |
- sf+= sine[j + center] * filtered[j]; | |
- } | |
- ss= sqrt(2*ss/LEN); | |
- ff= sqrt(2*ff/LEN); | |
- sf= 2*sf/LEN; | |
- maxff= FFMAX(maxff, ff); | |
- minff= FFMIN(minff, ff); | |
- maxsf= FFMAX(maxsf, sf); | |
- minsf= FFMIN(minsf, sf); | |
- if(i%11==0){ | |
- //av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:… | |
- minff=minsf= 2; | |
- maxff=maxsf= -2; | |
- } | |
- } | |
- } | |
-#endif | |
-} | |
- | |
-/** | |
- * Initializes an audio resampler. | |
- * Note, if either rate is not an integer then simply scale both rates up so t… | |
- */ | |
-AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_size… | |
- AVResampleContext *c= av_mallocz(sizeof(AVResampleContext)); | |
- double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); | |
- int phase_count= 1<<phase_shift; | |
- | |
- c->phase_shift= phase_shift; | |
- c->phase_mask= phase_count-1; | |
- c->linear= linear; | |
- | |
- c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); | |
- c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM)); | |
- av_build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<… | |
- memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c… | |
- c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_len… | |
- | |
- c->src_incr= out_rate; | |
- c->ideal_dst_incr= c->dst_incr= in_rate * phase_count; | |
- c->index= -phase_count*((c->filter_length-1)/2); | |
- | |
- return c; | |
-} | |
- | |
-void av_resample_close(AVResampleContext *c){ | |
- av_freep(&c->filter_bank); | |
- av_freep(&c); | |
-} | |
- | |
-/** | |
- * Compensates samplerate/timestamp drift. The compensation is done by changing | |
- * the resampler parameters, so no audible clicks or similar distortions ocur | |
- * @param compensation_distance distance in output samples over which the comp… | |
- * @param sample_delta number of output samples which should be output less | |
- * | |
- * example: av_resample_compensate(c, 10, 500) | |
- * here instead of 510 samples only 500 samples would be output | |
- * | |
- * note, due to rounding the actual compensation might be slightly different, | |
- * especially if the compensation_distance is large and the in_rate used durin… | |
- */ | |
-void av_resample_compensate(AVResampleContext *c, int sample_delta, int compen… | |
-// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensati… | |
- c->compensation_distance= compensation_distance; | |
- c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delt… | |
-} | |
- | |
-/** | |
- * resamples. | |
- * @param src an array of unconsumed samples | |
- * @param consumed the number of samples of src which have been consumed are r… | |
- * @param src_size the number of unconsumed samples available | |
- * @param dst_size the amount of space in samples available in dst | |
- * @param update_ctx if this is 0 then the context wont be modified, that way … | |
- * @return the number of samples written in dst or -1 if an error occured | |
- */ | |
-int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, i… | |
- int dst_index, i; | |
- int index= c->index; | |
- int frac= c->frac; | |
- int dst_incr_frac= c->dst_incr % c->src_incr; | |
- int dst_incr= c->dst_incr / c->src_incr; | |
- int compensation_distance= c->compensation_distance; | |
- | |
- if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){ | |
- int64_t index2= ((int64_t)index)<<32; | |
- int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; | |
- dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / … | |
- | |
- for(dst_index=0; dst_index < dst_size; dst_index++){ | |
- dst[dst_index] = src[index2>>32]; | |
- index2 += incr; | |
- } | |
- frac += dst_index * dst_incr_frac; | |
- index += dst_index * dst_incr; | |
- index += frac / c->src_incr; | |
- frac %= c->src_incr; | |
- }else{ | |
- for(dst_index=0; dst_index < dst_size; dst_index++){ | |
- FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mas… | |
- int sample_index= index >> c->phase_shift; | |
- FELEM2 val=0; | |
- | |
- if(sample_index < 0){ | |
- for(i=0; i<c->filter_length; i++) | |
- val += src[FFABS(sample_index + i) % src_size] * filter[i]; | |
- }else if(sample_index + c->filter_length > src_size){ | |
- break; | |
- }else if(c->linear){ | |
- FELEM2 v2=0; | |
- for(i=0; i<c->filter_length; i++){ | |
- val += src[sample_index + i] * (FELEM2)filter[i]; | |
- v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_le… | |
- } | |
- val+=(v2-val)*(FELEML)frac / c->src_incr; | |
- }else{ | |
- for(i=0; i<c->filter_length; i++){ | |
- val += src[sample_index + i] * (FELEM2)filter[i]; | |
- } | |
- } | |
- | |
-#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE | |
- dst[dst_index] = av_clip_int16(lrintf(val)); | |
-#else | |
- val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; | |
- dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 :… | |
-#endif | |
- | |
- frac += dst_incr_frac; | |
- index += dst_incr; | |
- if(frac >= c->src_incr){ | |
- frac -= c->src_incr; | |
- index++; | |
- } | |
- | |
- if(dst_index + 1 == compensation_distance){ | |
- compensation_distance= 0; | |
- dst_incr_frac= c->ideal_dst_incr % c->src_incr; | |
- dst_incr= c->ideal_dst_incr / c->src_incr; | |
- } | |
- } | |
- } | |
- *consumed= FFMAX(index, 0) >> c->phase_shift; | |
- if(index>=0) index &= c->phase_mask; | |
- | |
- if(compensation_distance){ | |
- compensation_distance -= dst_index; | |
- if(!(compensation_distance > 0)) return(-1); | |
- } | |
- if(update_ctx){ | |
- c->frac= frac; | |
- c->index= index; | |
- c->dst_incr= dst_incr_frac + c->src_incr*dst_incr; | |
- c->compensation_distance= compensation_distance; | |
- } | |
-#if 0 | |
- if(update_ctx && !c->compensation_distance){ | |
-#undef rand | |
- av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2); | |
-//av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->… | |
- } | |
-#endif | |
- | |
- return dst_index; | |
-} |