0

I have the following problem: for the sake of amplitude modulation, I want to generate a sine wave with a given frequency. For lower frequencies (such as 440 Hz) the algorithm works well, but dealing with high frequencies (for example 20.000 Hz), I get additional noises of lower frequencies, increasing with the time - I mean longer I play the signal, more and more unwanted frequencies appear - and the signal is thus distorted.

Here's the essence of my algorithm

    let methodStart = NSDate()
    
    let n = vDSP_Length(1024)

    let page: [Float] = (0 ..< n).map {_ in
        let val: Float = sin(2.0 * .pi * 20000.0 / 44100 * Float(index))
        index += 1
        return val
    }
    
    let methodFinish = NSDate()
    let executionTime = methodFinish.timeIntervalSince(methodStart as Date)
    print("Execution time: \(executionTime)")  // 0.0005 s

As you can see, I work with a loop - later the page array is used to generate the correspondent tone.

I did measure the execution time which looks like this:

Execution time: 0.0004639625549316406
Execution time: 0.000661015510559082
Execution time: 0.0005699396133422852
Execution time: 0.00047194957733154297
Execution time: 0.0005259513854980469
Execution time: 0.00047194957733154297
Execution time: 0.0005289316177368164

When we talk about the signal frequency of 20.000 Hz, the execution time should not be an issue, as during approx. 0.0005 s, a signal period fits more or less 10 times into the execution time range -> 1 : 20.000 = 0.00005.

My question: how can I achieve a pure signal? Should I work with pointers? If so, how can I do so in my case?

Ulrich Vormbrock
  • 369
  • 2
  • 13
  • 1
    The problem is likely in your playing code (in my experience the issues usually occur when you don't line up the start and end of your buffers cleanly). It's not clear why you're timing the execution here; as you note that shouldn't be related to this problem at all. You should take the timing code out, and show how you play the tone. – Rob Napier Nov 30 '20 at 16:40
  • 1
    If you want an example of a tone generator in Swift, see https://github.com/rnapier/ToneGen. The equivalent of this code is in https://github.com/rnapier/ToneGen/blob/master/ToneGen/SineWaveAudioBuffer.swift The playing code is https://github.com/rnapier/ToneGen/blob/master/ToneGen/ToneGenerator.swift – Rob Napier Nov 30 '20 at 16:42
  • 1
    Hi Rob, thank you so much for your hints - I just did check out your GitHub project and I did run it with a frequency of 20000 Hz - I got a pure signal without distortions. Later on, I'll analyze your code in order to integrate the crucial parts into my code! – Ulrich Vormbrock Nov 30 '20 at 16:51
  • 1
    Just poking around with it, one problem you may have is rounding errors in your `val` calculation. You may want to perform the operation as a Double, and then convert to Float at the end. Also, I'm a little suspicious of your `index`. If it keeps growing without bound, you could start losing significant digits, leading to rounding errors, especially when `index` gets above 2^24 (which would take about 6 minutes at 44.1kHz). – Rob Napier Nov 30 '20 at 17:09
  • 1
    Thank you for the second hint: indeed I rectified my code, working now with Double. In addition, I did reset the index to zero after a certain time, avoiding that the routine becomes slow. I'm asking myself at which time (index = ?) I should reset it to zero. In any case, I now get a pure sine with only one peak at f=20.000 Hz. – Ulrich Vormbrock Nov 30 '20 at 17:27
  • You'd reset your counter when you get through one sampling interval (44_100 samples), since that's going to be when your ratio is 1, which is the same as 0 (sin 0 = sin 2π). – Rob Napier Dec 01 '20 at 13:10
  • Thank you Rob - it works as a charm now! – Ulrich Vormbrock Dec 01 '20 at 15:18

0 Answers0