Java (J2SE) DTMF 音调检测

2024-01-23

我正在尝试执行以下操作

  • 我正在使用我的 java 应用程序给另一个人打电话(已经完成并且工作正常)。

  • 然后我正在播放录音,例如“请按 1 一继续英语”(已经完成且工作正常)。

  • 现在我想检测那个人按 1,根据我在 google 搜索中的研究,我发现这可以使用 DTMF 来完成。如果这个人按 1,我想根据我的情况执行操作。

我的问题是如何使用 java (J2SE) 中的 DTMF 检测该号码。我使用 ZTE USB 适配器拨打电话。拨号、挂断等控制采用AT指令+Java IO的方式实现。

这是我的示例代码,但它每次都没有给出正确的拨号号码及其循环。

public class zxczczz extends javax.swing.JFrame {

/**
 * Creates new form zxczczz
 */
public zxczczz() {
    initComponents();
}
float[] lowFreq = new float[]{697.0F, 770.0F, 852.0F, 941.0F};
float[] highFreq = new float[]{1209.0F, 1336.0F, 1477.0F, 1633.0F};
float[] dtmfTones = new float[]{697.0F, 770.0F, 852.0F, 941.0F, 1209.0F, 1336.0F, 1477.0F, 1633.0F};
int dtmfBoard[][] = {{1, 2, 3, 12}, {4, 5, 6, 13}, {7, 8, 9, 14}, {10, 0, 11, 15}};
byte[] buffer = new byte[2048];
static final char FRAME_SIZE = 160;
AudioFormat format = getAudioFormat();
int[] buf;
public boolean wait = false;
static boolean continueParsingDtmf = false;

public AudioFormat getAudioFormat() {
    //  float sampleRate = 8000.0F;         
    float sampleRate = 44100.0F;
    //int sampleSizeInBits = 16;            
    int sampleSizeInBits = 8;
    int channels = 1;
    boolean signed = true;
    boolean bigEndian = true;

    return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}

public class DtmfCapture extends Thread {

    public void run() {
        continueParsingDtmf = true;
        try {

            DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
            TargetDataLine out = (TargetDataLine) AudioSystem.getLine(info);

            out.open(format);
            out.drain();
            out.start();
            int count = 0;

            while (continueParsingDtmf) {
                byte[] buffer = new byte[2048];
                //grab audio data
                count = out.read(buffer, 0, buffer.length);
                if (count >= 0) {
                    zxczczz.DecodeDtmf dtmf = new zxczczz.DecodeDtmf(buffer);
                    if (!wait) {  

dtmf.start(); //look for dtmf
//  System.out.println("aaaaaa");
Thread.sleep(100);  
} else {  
Thread.sleep(1000);// wait before searching again
System.out.println(System.currentTimeMillis());
                        wait = false;
                    }
                }
            }
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}  
public class DecodeDtmf extends Thread {

    byte[] buffer;

    DecodeDtmf(byte[] buffer) {
        this.buffer = buffer;
    }

    public void run() {
        int[] buf;

        buf = new int[buffer.length / 2];

        for (int j = 0; j < buffer.length / 2 - 1; j++) {
            buf[j] = (int) ((buffer[j * 2 + 1] & 0xFF) + (buffer[j * 2] << 8));
        }
        int tone = findDTMF(buf);

        if (tone >= 0) {
            wait = true;
            if (tone < 10) {
                System.out.println(" THE TONE IS : " + tone);
            }  

if (tone == 12) {
//                    System.out.println(" THE TONE IS :  A");
//                }
//                if (tone == 13) {
//                    System.out.println(" THE TONE IS : B");
//                }
//                if (tone == 14) {
//                    System.out.println(" THE TONE IS : C");
//                }
//                if (tone == 15) {
//                    System.out.println(" THE TONE IS : D");
//                }
            if (tone == 10) {
                //      System.out.println(" THE TONE IS : *");
            }
            if (tone == 11) {
                //      System.out.println(" THE TONE IS : #");
            }
        }
    }

    /*
     Check if sample has dtmf tone
     */
    public int findDTMF(int[] samples) {
        double[] goertzelValues = new double[8];
        double lowFreqValue = 0;
        int lowFreq = 0;
        double sumLow = 0;
        double highFreqValue = 0;
        int highFreq = 0;
        double sumHigh = 0;

        for (int i = 0; i < 8; i++) {
            goertzelValues[i] = goertzel(samples, dtmfTones[i]);
        }
        // System.out.println("aa="+goertzelValues);

        for (int i = 0; i < 4; i++) // Find st?rste low frequency
        {
            sumLow += goertzelValues[i]; // Sum til signal-test
            if (goertzelValues[i] > lowFreqValue) {
                lowFreqValue = goertzelValues[i];
                lowFreq = i;
            }
            //      System.out.println("low = "+i);
        }
        for (int i = 4; i < 8; i++) // Find st?rste high frequency
        {
            sumHigh += goertzelValues[i]; // Sum til signal-test
            if (goertzelValues[i] > highFreqValue) {
                highFreqValue = goertzelValues[i];
                highFreq = i - 4;
            }
        }
        if (lowFreqValue < sumLow / 2 || highFreqValue < sumHigh / 2) // Test signalstyrke
        {
            return -1;
        }
        // System.out.println("aaa="+dtmfBoard[lowFreq][highFreq]);
        return dtmfBoard[lowFreq][highFreq]; // Returner DTMF tone
    }
}

public double goertzel(int[] samples, float freq) {
    double vkn = 0;
    double vkn1 = 0;
    double vkn2 = 0;

    for (int j = 0; j < samples.length - 1; j++) {
        vkn2 = vkn1;
        vkn1 = vkn;
        vkn = 2 * Math.cos(2 * Math.PI * (freq * samples.length / format.getSampleRate()) / samples.length) * vkn1 - vkn2 + samples[j];
    }
    double WNk = Math.exp(-2 * Math.PI * (freq * samples.length / format.getSampleRate()) / samples.length);
    //System.out.println(WNk);
    return Math.abs(vkn - WNk * vkn1);

}  
}

请帮我。


我正在为 ActionScript 中的 DTMF 检测寻找相同的东西 我发现了一些东西也许你可以用java重新编码

  package {
    import flash.utils.ByteArray;

    public class DTMFprocessor
    {

        /*
           The following constants are used to find the DTMF tones.  The COL1 is the column Hz that we
           are searching for, and the COL2 is the row Hz.  The DTMF_LAYOUT is the order that the cols and
           rows intersect at.
        */

        private static const COL1:Array = [697, 770, 852, 941];
        private static const COL2:Array = [1209, 1336, 1477, 1633];
        private static const DTMF_LAYOUT:Array = [ ["1","2","3","A"] ,
                                                   ["4","5","6","B"] ,
                                                   ["7","8","9","C"] ,
                                                   ["*","0","#","D"] ];

        private var sampleRate:int;
        private var lastFound:String = "";

        public var DTMFToneSensitivity:int = 15;

        /**
         * DTMF Processor Constructor
         * 
         * @param sampleRate  This is the sample rate, in frames per second that the application is operating in.
         * 
         */     
        public function DTMFprocessor(sampleRate:int = 44100)
        {
            this.sampleRate = sampleRate;
        }

        /**
         * Generates DTMF byteArrays that can be played by the Sound() object.
         *  
         * @param length  length, in ms that the tone will be generated for.
         * @param tone    the string representing the tone that will be generated [0-9, A-D, *, #]
         * @return        the byteArray that contains the DTMF tone.
         * 
         */     
        public function generateDTMF(length:int, tone:String):ByteArray
        {
            var mySound:ByteArray = new ByteArray();
            var neededSamples:int = Math.floor(length * sampleRate / 1000);
            var mySampleCol:Number = 0;
            var mySampleRow:Number = 0;

            var hz:Object = findDTMF(tone.charAt(0));

            for (var i:int = 0; i < neededSamples; i++)
            {
                mySampleCol = Math.sin(i * hz.col * Math.PI * 2 / sampleRate) * 0.5;
                mySampleRow = Math.sin(i * hz.row * Math.PI * 2 / sampleRate) * 0.5;
                mySound.writeFloat(mySampleRow + mySampleCol);

            }
            return mySound;
        }

        /**
         * Searches a ByteArray (from a Sound() object) for a valid DTMF tone.  
         *  
         * @param tone  ByteArray that should contain a valid DTMF tone.
         * @return      string representation of DTMF tones.  Will return a blank string ('') if nothing is found
         * 
         */     
        public function searchDTMF(tone:ByteArray):String
        {
            var position:int = 0;
            var charFound:String = "";

            // seed blank values for strongest tone to be found in the byteArray 
            var maxCol:int = -1;
            var maxColValue:int = 0;
            var maxRow:int = -1;
            var maxRowValue:int = 0;
            var foundTones:String = "";

            // reset the byteArray to the beginning, should we have gotten it in any other state.
            tone.position = position;

            // break up the byteArray in manageable chunks of 8192 bytes.  
            for (var bufferLoop:int =0; bufferLoop < tone.bytesAvailable; bufferLoop =+ 8192)
            {
                position = bufferLoop;

                // search for the column tone.
                for (var col:int = 0; col < 4; col++)
                {
                    if (powerDB(goertzel(tone,8192,COL1[col],position)) > maxColValue)
                    {
                        maxColValue = powerDB(goertzel(tone,8192,COL1[col],position));
                        maxCol = col;
                    }
                }

                // search for the row tone.
                for (var row:int = 0; row < 4; row++)
                {
                    if (powerDB(goertzel(tone,8192,COL2[row],position)) > maxRowValue)
                    {
                        maxRowValue = powerDB(goertzel(tone,8192,COL2[row],position));
                        maxRow = row;
                    }
                }

                // was there enough strength in both the column and row to be valid?
                if ((maxColValue < DTMFToneSensitivity) || (maxRowValue < DTMFToneSensitivity))
                {
                    charFound = "";
                }
                else
                {
                    charFound = DTMF_LAYOUT[maxCol][maxRow];
                }

                if (lastFound != charFound)
                {
                    trace("Found DTMF Tone:",charFound);
                    lastFound = charFound;  // this is so we don't have duplicates.
                    foundTones = foundTones + lastFound;
                }

            }
            return foundTones;
        }

        /**
         * Converts amplitude to dB (power).  
         *  
         * @param value  amplitude value
         * @return       dB
         * 
         */     
        private function powerDB(value:Number):Number
        {
            return 20 * Math.log(Math.abs(value))*Math.LOG10E;
        }

        /**
         * This function returns the amplitude of the a seeked wave in the buffer.
         *  
         * @param buffer      the byteArray that is being searched.
         * @param bufferSize  the size of the buffer that we wish to search.
         * @param frequency   the frequency (in Hz) that we are searching for.
         * @param bufferPos   the starting point that we want to search from.
         * @return            amplitude of the searched frequency, if any.
         * 
         */     
        private function goertzel(buffer:ByteArray, bufferSize:int, frequency:int, bufferPos:int):Number
        {
            var skn:Number = 0;
            var skn1:Number = 0;
            var skn2:Number = 0;

            buffer.position = bufferPos;

            for (var i:int=0; i < bufferSize; i++)
            {
                skn2 = skn1;
                skn1 = skn;
                if (buffer.bytesAvailable > 0)
                skn = 2 * Math.cos(2 * Math.PI * frequency / sampleRate) * skn1 - skn2 + buffer.readFloat();
            }

            var wnk:Number = Math.exp(-2 * Math.PI * frequency / sampleRate);

            return (skn - wnk * skn1);
        }

        /**
         * Returns the Hz of the string tone that is searched.
         *  
         * @param tone  character that is being search for
         * @return      an untyped object that has col and row properties that contain the Hz of the DTMF tone.
         * 
         */     
        private function findDTMF(tone:String):Object
        {
            var myDTMF:Object = new Object();   

            switch(tone)
            {
                case "1":
                    myDTMF.col = COL1[0];
                    myDTMF.row = COL2[0];
                    break;
                case "2":
                    myDTMF.col = COL1[0];
                    myDTMF.row = COL2[1];
                    break;
                case "3":
                    myDTMF.col = COL1[0];
                    myDTMF.row = COL2[2];
                    break;
                case "A":
                    myDTMF.col = COL1[0];
                    myDTMF.row = COL2[3];
                    break;
                case "4":
                    myDTMF.col = COL1[1];
                    myDTMF.row = COL2[0];
                    break;
                case "5":
                    myDTMF.col = COL1[1];
                    myDTMF.row = COL2[1];
                    break;
                case "6":
                    myDTMF.col = COL1[1];
                    myDTMF.row = COL2[2];
                    break;
                case "B":
                    myDTMF.col = COL1[1];
                    myDTMF.row = COL2[3];
                    break;
                case "7":
                    myDTMF.col = COL1[2];
                    myDTMF.row = COL2[0];
                    break;
                case "8":
                    myDTMF.col = COL1[2];
                    myDTMF.row = COL2[1];
                    break;
                case "9":
                    myDTMF.col = COL1[2];
                    myDTMF.row = COL2[2];
                    break;
                case "C":
                    myDTMF.col = COL1[2];
                    myDTMF.row = COL2[3];
                    break;  
                case "*":
                    myDTMF.col = COL1[3];
                    myDTMF.row = COL2[0];
                    break;
                case "0":
                    myDTMF.col = COL1[3];
                    myDTMF.row = COL2[1];
                    break;
                case "#":
                    myDTMF.col = COL1[3];
                    myDTMF.row = COL2[2];
                    break;
                case "D":
                    myDTMF.col = COL1[3];
                    myDTMF.row = COL2[2];
                    break;              
                default:
                    myDTMF.col = 0;
                    myDTMF.row = 0;
            }
            return myDTMF;
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java (J2SE) DTMF 音调检测 的相关文章

随机推荐

  • HTML/CSS:如何为 tr 创建滚动条

    有人可以告诉我如何为内表创建滚动条吗 内表不显示在容器内 我将容器的背景涂成黄色 桌子本身是蓝色的 我想在表格内看到一个滚动条 Source http nopaste info e51385254e html http nopaste in
  • java中如何实现国际化

    我有一堂课叫Info 我有一堆static String其中描述的变量 public class Info public static stringOne Hello public static stringTwo world 我希望访问这
  • 你明白这个僵局吗?

    我的 GUI 使用 wxPython 在里面AppLogic类我有一个工作线程 它在这个类的方法中运行 这是GUI class class GUI wx app None main window None app logic None de
  • SharpDX、DirectWrite 和 Windows 窗体

    可以使用 DirectWrite 将文本渲染到 WinForm 应用程序中的 PictureBox 中吗 我正在使用 SharpDX 并浏览了 DirectWrite 示例 试图构建最简单的工作案例 我创建了一个表单并只向其中添加了一个图片
  • 根据列值分割大型 csv 文本文件

    我的 CSV 文件有多列已排序 例如 我可能有这样的行 19980102 PLXS 10032 Q A 15 12500 15 00000 15 12500 2 19980105 PLXS 10032 Q A 14 93750 14 750
  • C++ 中单例的线程安全惰性构造

    有没有一种方法可以在 C 中实现单例对象 以线程安全的方式延迟构造 两个线程可能同时是单例的第一个用户 它仍然应该只构造一次 不依赖于预先构造的静态变量 因此在构造静态变量期间单例对象本身可以安全使用 我不太了解我的C 但是在执行任何代码之
  • 使用 maven-compiler-plugin 排除包适用于一个包,但不适用于另一个包

    我的项目具有以下包结构 src com my app school course Course java com my app school course free CourseFree java 我使用Maven来构建项目 在我的pom
  • 使用 Stateful Session Bean 来跟踪用户的会话

    这是我的第一个问题 我希望我做得对 我需要从事 Java EE 项目 因此 在开始之前 我尝试做一些简单的事情 看看是否能做到 我被困住了有状态会话 Bean 这是问题 我怎样才能使用SFSB跟踪用户的会话 我看到的所有例子最终都 放入 S
  • UIBezierPath:roundedRect:byRoundingCorners:cornerRadii:行为怪异

    我正在尝试将按钮的两个角变成圆形 如果我像这样选择 TopLeft 和 BottomLeft let bezierDisableAdsPath UIBezierPath roundedRect disableAdsButton bounds
  • Gitlab Pages:无法验证域所有权

    今天早上 我收到了针对托管在自定义域上的每个 Gitlab 页面的电子邮件 称域验证失败 没关系 因为我认为我一开始就没有验证过它们 Gitlab 很好地实现了这一点 当我转到每个存储库的 设置 gt 页面 gt Domain Detail
  • 一个 SVG 文件,里面有很多 SVG 渐变

    我正在制作一组使用动态渐变的按钮 我已经通过使用 Firefox 3 6 和 WebKit 专有的 CSS 扩展来处理它们 我所需要做的就是使用 background image url gradient svg 支持 Opera iOS
  • phpExcel:无法加载资源:net::ERR_CONNECTION_RESET

    我实际上使用 phpExcel 来获取一个 excel 文件 我用一个命令从用户那里恢复该文件
  • Shiny 未检测到shiny:inputchanged 事件

    如果应用程序能够检测到上次单击或更新的小部件的 ID 那么我为闪亮的应用程序设计所采用的方法将是最简单的 This https stackoverflow com q 72061061 7742981问题的出现解决了问题 然而 当我使用接受
  • 从 Rails3-jquery-autocomplete 自定义列表

    我有一个hotel模型及其属性是 id hotel name address searchable 当我设置可搜索时false对于特定酒店 当我在搜索字段中输入时 该酒店不应出现在下拉列表中 控制器是 class HotelsControl
  • 表情符号字符变灰(HTML / CSS)

    我当前的问题是我正在尝试将带有表情符号的按钮灰显 尽管如此 由于表情符号的性质 似乎无法使用 HTML CSS 属性更改颜色 I e
  • xib 文件的 iPhone 本地化

    我刚刚熟悉 xib 文件的本地化 想知道是否有一种方法可以通过直接引用 plist 来本地化 xib 中的字符串 欣赏一些想法 如果您不想直接本地化 xib 文件 则可以将它们包含的文本提取到 strings 文件中 并且在翻译 strin
  • 如何使用node.js测试文件权限?

    如何检查正在运行的 Node js 进程对给定文件的权限 读 写 执行 我希望fs Stats object http nodejs org docs latest api fs html fs class fs stats有一些有关权限的
  • Django 外键值的精确匹配

    class Sentence Model name CharField class Tokens Model token CharField sentence ForeignKey Sentence related name tokens
  • 如何在 android 中模拟 Kotlin 对象?

    我在 kotlin 中有一个对象控制当前用户的会话信息 我想模拟有回调的登录方法 在测试时 我需要在 SessionController 对象中模拟此方法 object SessionController fun signIn userna
  • Java (J2SE) DTMF 音调检测

    我正在尝试执行以下操作 我正在使用我的 java 应用程序给另一个人打电话 已经完成并且工作正常 然后我正在播放录音 例如 请按 1 一继续英语 已经完成且工作正常 现在我想检测那个人按 1 根据我在 google 搜索中的研究 我发现这可