2016-09-02 4 views
1

Добрый день. У меня есть небольшая проблема, которая может быть частично математикой.Python PyAudio, выход немного взломанный. Возможно, математика

Дело в том, что я хочу играть в синусоидальную волну без фиксированной частоты. Поэтому, чтобы не сделать звук взломанным между переходами или во время фиксированной частоты, мне нужна синусоидальная волна, чтобы начать и закончить с нулевой амплитудой. Математически я понимаю, что нужно сделать.

Я выбрал способ, в котором я адаптирую «время» синусоидальной волны, чтобы у него было время, чтобы закончить все циклы. В основном y = sin (2 * pi f t) где f * t должно быть целым числом.

Проблема в том, что она работает, но не полностью. Все волны оказываются очень близкими к нулю, но не совсем там. Звук в порядке, изменяя частоту, но не идеально. Я не могу понять, почему последний элемент не может наступить на ноль.

Если вы пройдете через него и проверьте, что я был бы очень благодарен. Thx

  import pyaudio 
      import numpy as np 
      import matplotlib.pyplot as plt 

      p = pyaudio.PyAudio() 
      volume = 0.5  # range [0.0, 1.0] 
      fs = 44100*4  # sampling rate, Hz, must be integer 
      time = 0.1 # in seconds, may be float 
      f = 400  # sine frequency, Hz, may be float 
      k = np.arange(int(time*fs)) 
      t=np.arange(0,time,1/fs) 
      start=0 
      end=time 




      stream = p.open(format=pyaudio.paFloat32, 
          channels=1, 
          rate=fs, 
          output=True) 



      # generate samples, note conversion to float32 array 
      for i in range(1000): 

       start = 0 
       end = 40/f #time to acomplish whole whole cycles according to the give frequency - must be whole number 

       print(len(t)) 
       t = np.arange(start, end, 1/fs) 
       samples = (np.sin(2*np.pi*f*t)).astype(np.float32) 

       print(samples[0],samples[-1]) # The main problem. I need first and last elements in the sample to be zero. 
              # Problem is that last element is only close to zero, which make the sound not so smooth 

       #print(start+i,end+i) 
       #print(samples) # # # # # Shows first and last element 

       f+=1 

       # for paFloat32 sample values must be in range [-1.0, 1.0] 


      # play. May repeat with different volume values (if done interactively) 
       stream.write(volume*samples) 

      stream.stop_stream() 
      stream.close() 

      p.terminate() 
+0

Что делать, если вы допустите конец = (40/f) + 1/fs? Я думаю, ваша проблема в том, что np.arange не включает конечное значение, но вы хотите. –

+0

Это было первое, что пришло мне в голову, но ситуация не изменилась. Ошибка составляет от 1 сотой до 1 тысячной по сравнению с максимальной амплитудой 1. Его небольшая ошибка, но ее достаточно большая, чтобы ее можно было признать, и ее достаточно большая, чтобы быть ошибкой просто погрешности Pi. – Martin

+0

Предполагаю, вы посмотрели на регулировку всех 3 аранжировок и до сих пор нет Помогите. Это взломать, но вы можете добавить 0 в свой массив. Если это ошибка точности, возможно, использование float64 поможет, может быть, не только в значении синуса, но и при вычислении 1/fs. –

ответ

0

Синусоидальная функция повторяется каждый кратное 2*pi*N, где N представляет собой целое число. IOW, sin(2*pi) == sin(2*pi*2) == sin(2*pi*3) и так далее.

Типичным методом для генерации выборок определенной частоты является номер sin(2*pi*i*freq/sampleRate), где i - номер выборки.

Далее следует, что синус будет повторяться только при значениях i, так что i*freq/sampleRate точно равно целому числу (я не принимаю во внимание смещения фазы).

Конечный результат состоит в том, что некоторые комбинации частот/выборок могут повторяться только после одного цикла (1 кГц при 48 кГц), тогда как другие могут занять очень много времени (997 Гц @ 48 кГц).

Нет необходимости менять частоты при точном пересечении нуля, чтобы избежать сбоев. Лучший подход заключается в следующем:

  1. Вычислить приращение фазы для требуемой частоты как phaseInc = 2*pi*freq/sampleRate
  2. Для каждого выходного образца вычислить выходную выборку из текущей фазы. y = sin(phase)
  3. Обновление фазы путем приращения фазы: phase += phaseInc
  4. Повторите 2-3 для требуемого количества образцов.
  5. Goto шаг один, чтобы изменить частоту

Если вы настойчивы об изменении на пересечении нуля, просто сделать это в ближайшем образце, где фаза пересекает кратна 2 * пи.