生成DTMF音调

7
我想知道是否有办法在iPhone SDK中生成音调。我正在尝试生成DTMF音调,但似乎找不到什么实质性的东西。我想能够指定播放音调的持续时间(即模拟按住按钮而不是简单地按下它)。
我发现一个名为iPhreak的开源应用程序。据说它生成DTMF音调以欺骗公用电话(我向您保证这不是我的意图-我的公司处理基于电话的对讲系统)。该应用程序唯一的问题是开源项目中缺少文件。也许其他人过去已经让这个项目工作了?
如果有人知道我应该在哪里寻找类似的东西,我会非常感激您的投票 :)
3个回答

6

应该很容易自己生成。 考虑到硬件可以使用某些库函数或其他方式播放44.1 kHz的PCM缓冲区(16位采样),你只需要计算波形:

 const int PLAYBACKFREQ = 44100;
 const float PI2 = 3.14159265359f * 2;

 void generateDTMF(short *buffer, int length, float freq1, float freq2)
 {
      int i;
      short *dest = buffer;
      for(i=0; i<length; i++)
      {
           *(dest++) = (sin(i*(PI2*(PLAYBACKFREQ/freq1))) + sin(i (PI2*(PLAYBACKFREQ/freq2)))) * 16383;
      }
 }

由于我使用的是加法合成(将正弦波相加),因此16383已完成。 因此,最大结果为-2.0 - 2.0。 因此,在乘以16383之后,我获得了更多或更少的最大16位结果:-32768- +32767

编辑: 这两个频率是另一个回答中链接到的维基百科文章中的频率。 两个唯一的频率会产生DTMF声音。


好的,也许我在这方面有点落后了。你能给我一个例子吗(例如对于#3)?我理解频率,但不太明白缓冲区的概念。 - Dutchie432
你需要创建一个足够长度的16位有符号数据类型缓冲区(我不确定在Objective-C中如何实现)。然后,选择属于DTMF音调3的2个频率(697Hz和1477Hz)。使用指向缓冲区的指针以及您分配的长度调用我的函数,然后该函数将用DTMF音调的波形填充它。然后,您需要将此波形传递给iPhone库函数,该函数可以将缓冲区内容输出到音频硬件。 - Toad
请注意,缓冲区以44100个样本/序列呈现。因此,在播放波形时,音频硬件应使用相同的频率,否则DTMF频率将偏离。还要注意,如果您希望波形持续10秒,则缓冲区长度应为PLAYBACKFREQ * 10。我希望这解释了一些问题。有关PCM(计算机内存中存储波形的方式)的更多信息,请访问此处:http://en.wikipedia.org/wiki/Pulse-code_modulation - Toad
现在这个意思我懂了,但我还是不知道从哪里开始...去看文档了。非常感谢。 - Dutchie432
Reinier: 我相信 w 等于 2pif/c,所以公式中的 sin 部分不应该是 sin(i(PI2*(freq1/PLAYBACKFREQ))) 吗? - user180730

5
简单来说,答案如下:
soundArray = [[NSArray alloc] initWithObjects: 
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-0.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-1.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-2.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-3.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-4.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-5.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-6.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-7.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-8.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-9.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-0.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-pound.caf"] autorelease],
    [[[SoundEffect alloc] initWithContentsOfFile: @"/System/Library/Audio/UISounds/dtmf-star.caf"] autorelease],
              nil];

这就是标准电话键盘的所有声音,以数组形式呈现,随时为您所用。


1
这个例子有内存泄漏。请勿发布明显存在内存泄漏的代码。 - rpetrich
@rpetrich:什么意思?你是指在这段代码之后,数组对象的保留计数为2吗? - mahboudz
有人实际使用这个技术吗?苹果是否拒绝了它? - Axeva
嘿,@mahboudz!这个SoundEffect类是什么? - Danik
@danik:SoundEffect是许多苹果样本中包含的一个类。 - mahboudz
显示剩余6条评论

1

Swift DTMF声音

我正在尝试生成PCM数据,并用Swift编写了以下函数。此函数将生成一个[Float]数组,其中包含音频样本。您可以使用AVAudio播放它们。

每个DTMF由一对音调组成,一个标记长度(250毫秒),一个空格长度(250毫秒),当然您需要指定采样频率(8000赫兹)。标记和空格通常约为250毫秒,这是我所说的标准人类拨号时间。采样频率很有趣,但需要是最高频率的两倍。为了好玩,您可以将其降低到该频率以下以听取发生的情况。

public static func generateDTMF(frequency1 frequency1: Float, frequency2: Float, markSpace: MarkSpaceType, sampleRate: Float) -> [Float]
{
    let toneLengthInSamples = 10e-4 * markSpace.0 * sampleRate
    let silenceLengthInSamples = 10e-4 * markSpace.1 * sampleRate

    var sound = [Float](count: Int(toneLengthInSamples + silenceLengthInSamples), repeatedValue: 0)
    let twoPI = 2.0 * Float(M_PI)

    for i in 0 ..< Int(toneLengthInSamples) {
        // Add first tone at half volume
        let sample1 = 0.5 * sin(Float(i) * twoPI / (sampleRate / frequency1));

        // Add second tone at half volume
        let sample2 = 0.5 * sin(Float(i) * twoPI / (sampleRate / frequency2));

        sound[i] = sample1 + sample2
    }

    return sound
}

完整的 Playground 可以在 GitHub 上下载。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接