Программно увеличивать высоту массива звуковых образцов

Привет, добрые люди в мире звуковых вычислений,

У меня есть массив образцов, которые представляют запись. Скажем, это 5 секунд при 44100 Гц. Как я смогу сыграть на этом фоне? И можно ли динамически увеличивать и уменьшать высоту тона? Подобно тому, как шаг медленно увеличивается, чтобы удвоить скорость, а затем отступить.

Другими словами, я хочу записать и воспроизвести его, как если бы он был "поцарапан" d.j.

Псевдокод всегда приветствуется. Я напишу это в C.

Спасибо,


РЕДАКТИРОВАТЬ 1

Позвольте мне уточнить мои намерения. Я хочу сохранить воспроизведение на частоте 44100 Гц, поэтому мне нужно управлять образцами перед воспроизведением. Это также связано с тем, что я хотел бы смешивать аудио с увеличенным шагом с аудио, которое работает с нормальной скоростью.

Выраженный по-другому, может быть, мне нужно как-то сжать звук над тем же количеством образцов? Таким образом, когда он будет воспроизводиться, он будет звучать быстрее?


РЕДАКТИРОВАТЬ 2

Кроме того, я хотел бы сделать это сам. Никаких библиотек, пожалуйста, (если вы не чувствуете, что я могу выбрать код и найти что-то интересное).


РЕДАКТИРОВАТЬ 3

Образец кода, написанный на C, который принимает 2 аргумента (массив выборок и коэффициент основного тона), а затем возвращает массив нового звука, будет фантастическим!


PS Я начал щедрость на этом не потому, что не думаю, что уже предоставленные ответы недействительны. Я просто подумал, что было бы хорошо получить больше отзывов по этому вопросу.



НАГРАЖДЕНИЕ BOUNTY

Честно говоря, я хотел бы распределить награду на несколько разных ответов, поскольку их было немало, что я считал очень полезным. Специальный крик Даниэлю для передачи мне кода и AShelly и Hotpaw2 для того, чтобы вложить такие подробные ответы.

В конечном счете, хотя я использовал ответ от другого вопроса SO, на который ссылается datageist, и поэтому награда присуждается ему.

Еще раз спасибо всем!

Ответ 1

Взгляните на бумагу "Слон" в Носредне, отвечая на этот (очень похожий) вопрос: Как вы выполняете бикубическую (или другую нелинейную) интерполяцию повторно отобранных аудиоданных?

Примеры реализации приведены на стр. 37, а для справки, AShelly ответ соответствует линейной интерполяции (на той же странице). При небольшой настройке любая из других формул в документе может быть подключена к этой структуре.

Для оценки качества данного метода интерполяции (и понимания потенциальных проблем с использованием "более дешевых" схем), взгляните на эту страницу:

http://www.discodsp.com/highlife/aliasing/

Для большей теории, чем вы, вероятно, хотите иметь дело (с исходным кодом), это также хорошая ссылка:

https://ccrma.stanford.edu/~jos/resample/

Ответ 2

Один из способов - поддерживать индекс с плавающей запятой в исходной волне и смешивать интерполированные отсчеты с выходной волной.

//Simulate scratching of `inwave`: 
// `rate` is the speedup/slowdown factor. 
// result mixed into `outwave`
// "Sample" is a typedef for the raw audio type.
void ScratchMix(Sample* outwave, Sample* inwave, float rate)
{
   float index = 0;
   while (index < inputLen)
   {
      int i = (int)index;          
      float frac = index-i;      //will be between 0 and 1
      Sample s1 = inwave[i];
      Sample s2 = inwave[i+1];
      *outwave++ += s1 + (s2-s1)*frac;   //do clipping here if needed
      index+=rate;
   }

}

Если вы хотите изменить rate на лету, вы тоже можете это сделать.

Если это создает шумные артефакты при скорости > 1, попробуйте заменить *outwave++ += s1 + (s2-s1)*frac; на эту технику (на этот вопрос)

*outwave++ = InterpolateHermite4pt3oX(inwave+i-1,frac);

где

public static float InterpolateHermite4pt3oX(Sample* x, float t)
{
    float c0 = x[1];
    float c1 = .5F * (x[2] - x[0]);
    float c2 = x[0] - (2.5F * x[1]) + (2 * x[2]) - (.5F * x[3]);
    float c3 = (.5F * (x[3] - x[0])) + (1.5F * (x[1] - x[2]));
    return (((((c3 * t) + c2) * t) + c1) * t) + c0;
}

Пример использования метода линейной интерполяции на "Windows Startup.wav" с коэффициентом 1,1. Оригинал находится сверху, ускоренная версия находится внизу:

Это может быть не математически совершенным, но звучит так, как должно, и должно хорошо работать для нужд OP.

Ответ 3

Да, это возможно.

Но это не небольшое количество псевдокодов. Вы просите алгоритм изменения времени, который представляет собой довольно большое и сложное количество кода DSP для достойных результатов.

Здесь Обзор растяжения по времени от DSP Dimensions. Вы также можете использовать Google для алгоритмов фазового вокодера.

ДОБАВЛЕНО:

Если вы хотите "поцарапать", поскольку DJ может работать с LP на физическом проигрывателе, вам не нужна модификация с шагом времени. Царапины изменяют высоту тона и скорость воспроизведения на ту же величину (не независимо, как это требует изменения по времени).

И результирующий массив не будет иметь одинаковую длину, но будет короче или длиннее с изменением высоты тона/скорости.

Вы можете изменить высоту тона, а также сделать звук более быстрым или медленным с помощью того же соотношения, просто передискретизировав сигнал с помощью правильно фильтрованной интерполяции. Просто переместите каждую точку выборки вместо 1.0, добавлением с плавающей запятой по желаемому изменению скорости, затем отфильтруйте и интерполируйте данные в этой точке. Интерполяция с использованием оконного интерполяционного ядра Sinc с частотой перехода фильтра нижних частот ниже нижней и исходной и интерполированной локальной частоты дискретизации будет работать достаточно хорошо. Поиск "оконной интерполяции Sinc" в Интернете возвращает много подходящего результата.

Вам нужен метод интерполяции, включающий фильтр нижних частот, иначе вы услышите ужасный шум сглаживания. (Исключением из этого может быть, если ваш исходный звуковой файл уже сильно фильтруется нижним проходом в течение десятилетия или более ниже частоты дискретизации.)

Ответ 4

Если вы хотите, чтобы это было сделано легко, см. предложение AShelly [edit: по сути, сначала попробуйте его]. Если вам нужно хорошее качество, вам в основном нужен фазовый вокодер .

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

  • запустить FFT
  • изменить все частоты в разном
  • запустить обратный FFT

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

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

Ответ 5

Уменьшение и увеличение высоты тона так же просто, как воспроизведение образца с меньшей или большей скоростью, чем 44,1 кГц. Это приведет к более медленному/более быстрому звуку записи, но вам нужно будет добавить "царапину" реальных записей.