Вопрос

Изменить 2 + ответ

Оказывается, мне нужно было завернуть между 0 а также Frequency*2*Math.pi.

Каждый, кто разместил, способствовал выяснению этой проблемы. Поскольку гость имела самую низкую репутацию, я просто отметил его пост в качестве ответа. Большое спасибо всем, это сводило меня с ума!

Редактировать 1

Вот мой метод WrapValue, должен был подумать, чтобы опубликовать это раньше. Это не так изощренно, как у Криса Тейлора, но это оказывает тот же эффект на мой взгляд.

public static double WrapValue(double value, double min, double max)
{
    if (value > max)
        return (value - max) + min;
    if (value < min)
        return max - (min - value);
    return value;
}

Это может быть подходящим для Gamedev, но это менее играет и более код и мат, поэтому я поместил его здесь.

Я пытаюсь превратить свой Xbox в цифровой инструмент, используя новый класс xna 4.0 DynamicSoundEffectinStance, и я получаю щелчок каждую секунду. Я определил, что это вызвана любой попыткой обернуть значение моего домена от 0 до 2*pi ..

Я написал небольшой класс под названием SineGenerator, который просто сохраняет динамику -давноэфектинзанс и подает его буферы для образцов, созданные с Math.Sin().

Поскольку я хочу быть точным и использовать скорость отбора проб 44,1 или 48 тыс. double x (Угол, который я кормлю Math.Sin()) и double step куда step является 2 * Math.PI / SAMPLING_FREQUENCY. Анкет Каждый раз, когда я генерирую данные для DynamicCoundEffectinStance.submitBuffer () I увеличение x по step и добавить sin(frequency * x) к моему буферу образца (усечен до short Поскольку XNA поддерживает только 16 -битную глубину образца).

Я полагаю, что мне лучше обернуть угол между 0 и 2*пи, поэтому я не теряю точность для x как это становится большим. Тем не менее, это представляет щелчок. Я написал свой собственный double WrapValue(double val, double min, double max) Метод в случае Mathhelper.wrapangle () был взволнованным. Ни обертывание между math.pi и -math.pi, ни 0 и 2*math.pi не избавятся от щелчка. Однако, если я не удосужился обернуть ценность и просто позволить ему расти, щелчок исчезает.

Я думаю, что это как -то связано с точностью функций .NET Trig, как грех (0)! = SIN (2*PI), но я не знаю достаточно, чтобы судить.

Мой вопрос: Почему это происходит, и должен ли я вообще беспокоиться о завершении угла?

Код:

using System;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;

namespace TestDynAudio
{
    class SineGenerator
    {
  // Sample rate and sample depth variables
  private const int BUFFER_SAMPLE_CAPACITY = 1024;
  private const int BIT_RATE = 16;
  private const int SAMPLING_FREQUENCY = 48000;
  private readonly int BYTES_PER_SAMPLE;
  private readonly int SAMPLE_BUFFER_SIZE;

        private DynamicSoundEffectInstance dynSound = new DynamicSoundEffectInstance(SAMPLING_FREQUENCY, AudioChannels.Mono);
  private double x = 0; // The domain or angle value
  private double step;  // 48k / 2pi, increment x by this for each sample generated
  private byte[] sampleData; // The sample buffer
  private double volume = 1.0f; // Volume scale value

  // Property for volume
  public double Volume
  {
   get { return volume; }
   set { if (value <= 1.0 && value >= 0.0) volume = value; }
  }

  // Property for frequency
  public double Frequency { get; set; }

        public SineGenerator()
        {
   Frequency = 440; // Default pitch set to A above middle C
   step = Math.PI * 2 / SAMPLING_FREQUENCY;
   BYTES_PER_SAMPLE = BIT_RATE / 8;
   SAMPLE_BUFFER_SIZE = BUFFER_SAMPLE_CAPACITY * BYTES_PER_SAMPLE;
   sampleData = new byte[SAMPLE_BUFFER_SIZE];

   // Use the pull-method, DynamicSoundEffectInstance will
   // raise an event when more samples are needed
   dynSound.BufferNeeded += GenerateAudioData;
        }

  private void buildSampleData()
  {
   // Generate a sample with sin(frequency * domain),
   //   Convert the sample from a double to a short,
   //   Then write the bytes to the sample buffer
   for (int i = 0; i < BUFFER_SAMPLE_CAPACITY; i++)
   {
    BitConverter.GetBytes((short)((Math.Sin(Frequency * x) * (double)short.MaxValue) * volume)).CopyTo(sampleData, i * 2);

    // Simple value wrapper method that takes into account the
    // different between the min/max and the passed value
    x = MichaelMath.WrapValue(x + step, 0, 2f * (Single)Math.PI);
   }
  }

  // Delegate for DynamicSoundInstance, generates samples then submits them
  public void GenerateAudioData(Object sender, EventArgs args)
  {
   buildSampleData();
   dynSound.SubmitBuffer(sampleData);
  }

  // Preloads a 3 sample buffers then plays the DynamicSoundInstance
  public void play()
  {
   for (int i = 0; i < 3; i++)
   {
    buildSampleData();
    dynSound.SubmitBuffer(sampleData);
   }
   dynSound.Play();
  }

  public void stop()
  {
   dynSound.Stop();
  }
    }
}
Это было полезно?

Решение

Я предполагаю, что ваша функция обертывания работает нормально, но вы не принимаете синус (x), вы принимаете синус (частота*x) - если частота*x не производит раунд с кратным 2*пи, тогда вы получите поп Анкет Попробуйте обернуть частоту*x, чтобы избавиться от поп -музыки.

Другие советы

Вы не показали свою функцию обертывания, я прошел быстрый тест на следующем, не дал никаких слышимых кликов.

Моя функция быстрой обертывания

public static float Wrap(float value, float lower, float upper)
{
  float distance = upper - lower;
  float times = (float)System.Math.Floor((value - lower) / distance);

  return value - (times * distance);
}

Называется таким

x = Wrap((float)(x + step), 0, 2 * (float)Math.PI);

Можно ли вызвать точные ошибки путем преобразования удвоений в поплавки для вашей функции обертывания? Какова цель этого в любом случае, так как вы изначально используете удвоение и получаете двойную спину. В конце концов, вы делаете 48 тыс. Конверсий в секунду, и ошибки будут накапливаться. Ваша функция обертывания также не сработала бы также, если Xstep когда -либо больше, чем 2PI, но я не вижу, как это может произойти ...

Если вы перестанете кастироваться как поплавки, и это не решает вашу проблему, я рекомендую вам создать переменную x2 и установить точку останова, чтобы понять, почему значения разные:

// declarations
private double x2 = 0;
private byte[] sampleData2 = new byte[BUFFER_SAMPLE_CAPACITY * BYTES_PER_SAMPLE];

// replace your for loop with this and set a breakpoint on
// the line with Console.WriteLine()
for (int i = 0; i < BUFFER_SAMPLE_CAPACITY; i++)
{
    BitConverter.GetBytes((short)((Math.Sin(Frequency * x) * (double)short.MaxValue) * volume)).CopyTo(sampleData, i * 2);
    BitConverter.GetBytes((short)((Math.Sin(Frequency * x2) * (double)short.MaxValue) * volume)).CopyTo(sampleData2, i * 2);

    if (sampleData[i * 2] != sampleData2[i * 2] || sampleData[i * 2 + 1] != sampleData2[i * 2 + 1]) {
        Console.WriteLine("DIFFERENT VALUES!");
    }

    // Simple value wrapper method that takes into account the
    // different between the min/max and the passed value
    x = MichaelMath.WrapValue(x + step, 0, 2f * (Single)Math.PI);
    x2 = x2 + step;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top