TMRpcm: Arduino библиотека для воспроизведения PCM/WAV аудиофайлов напрямую с SD карты

Добавлено 23 декабря 2017 в 14:45

Содержание

О библиотеке

TMRpcm – Arduino библиотека для асинхронного воспроизведения PCM/WAV файлов напрямую с SD карты.

Использует стандартную библиотеку SD Arduino, SD карту и выходное устройство (громкоговоритель, наушники, усилитель и т.д.).

Поддерживаемые платы:

  • все платы на базе ATmega328: Arduino Uno, Nano, Duemilanove и т.д.;
  • платы Mega: 1280, 2560 и т.д..

Особенности

  • Воспроизведение PCM/WAV напрямую с SD карты.
  • Основные форматы: WAV файлы, 8-бит, частота дискретизации 8–32 кГц, моно.
  • Асинхронное воспроизведение: позволяет работать коду в основном цикле программы во время воспроизведения звука.
  • Работа на одном таймере: TIMER1 (Uno, Mega) или TIMER3, 4 или 5 (Mega).
  • Двухтактный выход или подключение двух динамиков.
  • Двойное увеличение частоты дискретизации.
  • Поддерживаемые устройства: Arduino Uno, Nano, Mega и т.д.

Подготовка аудиофайлов

Файлы конвертируются легко и просто:

  • с помощью iTunes:
    • кликнуть Edit > Preferences > Import Settings;
    • изменить значение в выпадающем списке на WAV Encoder и Setting: Custom > 16.000kHz to 32kHz, 8-bit, Mono;
    • правый клик на любом файле в in iTunes и выбрать "Create WAV Version";
  • с помощью Audacity:
    • Tracks > Stereo Track to Mono;
    • Project Rate (HZ) > установить 32000, 22050, 16000 или 11025;
    • File > Export > Save as type: Other uncompressed files > Options...;
    • выбрать WAV, Unsigned 8 bit PCM.

Затем с помощью компьютера скопируйте файл на SD карту.

Известные ограничения

Данная библиотека сильно нагружает процессор, и выполнение кода во время воспроизведения будет медленнее, чем обычно. Нагрузка от обработки аудиофайлов может быть уменьшена за счет использования аудио более низкого качества, кодированного с меньшей частотой дискретизации (с минимальным значением 8 кГц).

Возможно влияние на другие библиотеки, которые используют прерывания. Функции isPlaying(), disable() или noInterrupts() могут использоваться для предотвращения параллельного выполнения кода.

Управление громкостью допускает хороший диапазон регулировки громкости, но при большой громкости возможно появление искажений.

Загрузка

Также проект можно найти на GitHub: ссылка.

Функции

TMRpcm audio;
audio.play("filename");    // воспроизвести файл
audio.play("filename",30); // воспроизвести файл, начиная с 30-ой секунды
audio.speakerPin = 11;     // установить в значение 5, 6, 11 или 46 для Mega, 9 для Uno, Nano и т.д.
audio.disable();           // выключить таймер на выходном выводе и остановить воспроизведение
audio.stopPlayback();      // остановить воспроизведение, но таймер остается запущенным
audio.isPlaying();         // возвращает 1, если идет воспроизведение, в противном случае - 0
audio.pause();             // поставить воспроизведение на паузу / снять с паузы
audio.quality(1);          // установить 1 для удвоения частоты дискретизации
audio.volume(0);           // 1 (включить) или 0 ( выключить) для управления громкостью
audio.setVolume(0);        // от 0 до 7. Устанавливает уровень громкости.
audio.loop(1);             // 0 или 1. Может быть изменено во время воспроизведения для полного управления зацикливанием. 

Пример использования

Макет примера
Макет примера

Это простая схема для проигрывания wav файлов с помощью Arduino Nano v.3.0, она содержит 4 кнопки, при нажатии каждой из которых воспроизводится заданный wav файл, загруженный на SD карту.

Комплектующие

Комплектующие
Комплектующие
Arduino Nano
Arduino Nano
Arduino Nano
Arduino Nano
Адаптер SD карты для Arduino
Адаптер SD карты для Arduino
Адаптер SD карты для Arduino
Адаптер SD карты для Arduino
  1. Arduino Nano v3.0 (я использовал китайскую версию под названием Funduino Nano);
  2. модуль SD карты;
  3. SD карта;
  4. макетная плата;
  5. четыре кнопки;
  6. четыре резистора 22 кОм;
  7. один резистор 4,7 кОм;
  8. NPN транзистор BC546B;
  9. динамик;
  10. перемычки.

Подготовка SD карты

Адаптер SD карты
Адаптер SD карты
Форматирование SD карты
Форматирование SD карты
Конвертирование аудиофайлов
Конвертирование аудиофайлов
  1. Отформатируйте SD карту (убедитесь, что настройки форматирования совпадают с приведенными на скриншоте выше).
  2. Конвертируйте ваши аудиофайлы в .WAV файлы (я использовал программу Wav Sample rate converter) со следующими параметрами:
    • частота дискретизации: 16000 Гц;
    • количество каналов: моно;
    • количество бит на отсчет: 8.
  3. Wav файлы для примера приведены ниже.

Схема

Схема макета wav плеера на Arduino Nano
Схема макета wav плеера на Arduino Nano

Код

Перед написанием кода вам необходимо скачать (ссылка выше в разделе «Загрузка») и установить библиотеку TMRpcm.

#include <SD.h>             // необходимо включить SD библиотеку
#define SD_ChipSelectPin 4  // использование цифрового вывода 4 на arduino nano 328
#include <TMRpcm.h>         // также необходимо включить данную библиотеку...
 
TMRpcm tmrpcm;   // создать объект для использования в данном скетче

int SW1; 
int SW2;
int SW3;
int SW4;
 
void setup()
{
  pinMode(14,INPUT);  // Определить A0 как цифровой вход.
  pinMode(15,INPUT);  // Определить A1 как цифровой вход. 
  pinMode(16,INPUT);  // Определить A2 как цифровой вход.
  pinMode(17,INPUT);  // Определить A3 как цифровой вход.
 
  tmrpcm.speakerPin = 9; // 11 на Mega, 9 на Uno, Nano и т.д.
 
  if (!SD.begin(SD_ChipSelectPin)) // проверить, есть ли карта, и может ли она быть инициализирована:
  {  
    return;                        // если нет, то ничего не делать
  }
  
  tmrpcm.volume(1);
  tmrpcm.play("1.wav"); // звуковой файл "1" будет проигрываться при каждом включении или перезагрузке arduino
}
 
void loop()
{  
  SW1=digitalRead(14); 
  SW2=digitalRead(15);
  SW3=digitalRead(16);
  SW4=digitalRead(17);
  
  if (SW1 == LOW) 
  { // если SW1 нажата, то воспроизвести файл "6.wav"
    tmrpcm.play("6.wav");
  } 
  else if(SW2 == LOW)
  { // если SW2 нажата, то воспроизвести файл "4.wav"
    tmrpcm.play("4.wav");
  } 
  else if(SW3 == LOW)
  { // если SW3 нажата, то воспроизвести файл "5.wav"
    tmrpcm.play("5.wav");
  } 
  else if(SW4 == LOW)
  { // если SW4 нажата, то воспроизвести файл "3.wav"
    tmrpcm.play("3.wav");
  }
  
}

Поиск неисправностей

Если у вас не получилось заставить эту схему работать, то ниже приведены два тестовых скетча для поиска неисправностей. Код был протестирован на Arduino Nano, Uno и Mega.

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

Нет необходимости подключать транзистор, подключите небольшой динамик или наушники напрямую к выводу 9 платы Arduino Nano или к выводу 11 платы Arduino Mega.

Скачанные по ссылке выше аудиофайлы скопируйте в корневой каталог SD карты.

Arduinio Nano

Соединение выводов
Arduino NanoSD карта
12MISO
11MOSI
13SCK
4CS
9динамик
GNDGND
5VVCC
#include <SD.h>             // необходимо включить SD библиотеку
#define SD_ChipSelectPin 4  // использование цифрового вывода 4 на arduino nano 328
#include <TMRpcm.h>         // также необходимо включить данную библиотеку...
#include <SPI.h>

TMRpcm tmrpcm;   // создать объект для использования в данном скетче
 
void setup()
{
  tmrpcm.speakerPin = 9; // 11 на Mega, 9 на Uno, Nano и т.д.
 
  if (!SD.begin(SD_ChipSelectPin)) // проверить, есть ли карта, и может ли она быть инициализирована:
  {
    return;                        // если нет, то ничего не делать
  }
 
  tmrpcm.volume(1);
}
 
void loop()
{  

  tmrpcm.play("6.wav");
  delay(1000);
  tmrpcm.play("4.wav");
  delay(3000);
  tmrpcm.play("5.wav");
  delay(4000);
  tmrpcm.play("3.wav");
  delay(2000);
}

Arduino Mega

Соединение выводов
Arduino MegaSD карта
50MISO
51MOSI
52SCK
53CS
11динамик
GNDGND
5VVCC
#include <SD.h>              // необходимо включить SD библиотеку
#define SD_ChipSelectPin 53  // использование цифрового вывода 4 на arduino nano 328
#include <TMRpcm.h>          // также необходимо включить данную библиотеку...
#include <SPI.h>

TMRpcm tmrpcm;   // создать объект для использования в данном скетче
 
void setup()
{ 
  tmrpcm.speakerPin = 11; //11 on Mega, 9 on Uno, Nano, etc
 
  if (!SD.begin(SD_ChipSelectPin)) // проверить, есть ли карта, и может ли она быть инициализирована:
  {  
    return;                        // если нет, то ничего не делать
  }
  
  tmrpcm.volume(1);
}
 
void loop()
{  
     
  tmrpcm.play("6.wav");
  delay(1000);
  tmrpcm.play("4.wav");
  delay(3000);
  tmrpcm.play("5.wav");
  delay(4000);
  tmrpcm.play("3.wav");
  delay(2000);

}

Если тестовый код работает, то добавьте строку #include <SPI.h> в программу с кнопками.

Если звука всё равно нет, то добавьте задержку между командами воспроизведения delay(1000);.

Дополнительные возможности

Данная библиотека предназначалась для простого и удобного пользователю использования в качестве проигрывателя wav аудиофайлов, использующего стандартные библиотеки Arduino и воспроизводящего файлы в простейшем wav формате. Многие дополнительные функции были добавлены по запросам пользователей и включены в pcmConfig.h, чтобы сохранить изначальную простоту.

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

Смотрите pcmConfig.h для настройки следующих параметров:

Пользовательские определения

В pcmConfig.h настраиваются следующие параметры:

Настройка параметров TMRpcm
ПараметрОписание
#define buffSize 128Управляет размером двух буферов (или четырех в режиме MULTI).
#define DISABLE_SPEAKER2Выключает вывод по умолчанию второго динамика для совместимости с другими библиотеками (вывод 10 на Uno).
#define ENABLE_MULTIВключает режим воспроизведения нескольких треков (по умолчанию на одном таймере).
#define STEREO_OR_16BITВключает воспроизведение стерео или 16-битных файлов.
#define MODE2Включает режим двойного таймера для воспроизведения нескольких треков. Не доступен с TIMER2.
#define SDFATБиблиотека SdFat использует меньше памяти программ и RAM. Смотрите пример SDFAT в составе данной библиотеки.
#define HANDLE_TAGSПропускает теги WAV файлов, которые содержат метаданные.
#define USE_TIMER2Использует 8-разрядный TIMER2, вместо 16-разрядных таймеров.
#define rampMegaПринудительный ручной выбор включения/выключения метода линейного изменения ШИМ.
#define ENABLE_RFВключает стриминг аудио через радиоканал (NRF24L01+).

Второй громкоговоритель / двухтактный режим

Данная библиотека по умолчанию выводит данные на два вывода таймер, хотя по умолчанию полностью включен только один.

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

  • Arduino Uno (один выход): audio.speakerPin = 9;
  • Arduino Uno (двухтактный выход): audio.speakerPin = 9; pinMode(10,OUTPUT);

Чтобы полностью выключить второй выход, раскомментируйте в pcmConfig.h строку #define DISABLE_SPEAKER2.

Режим Multi

Режим Multi включает одновременное воспроизведение двух треков.

Функции множественного режима немного отличаются от функций стандартного режима:

audio.speakerPin2 = 5;        // То же действие, что и в стандартном режиме, используется только с 4-выводным выходом
audio.play("sound.wav");      // Воспроизвести файл на выходе 0
audio.play("sound.wav",30,1); // Воспроизвести файл, начиная с 30-ой секунды, на выходе 1
audio.play("sound.wav",0);    // play(имя_файла, выход 0 или 1) определяется speakerpin или speakerpin2
audio.stopPlayback(0);     // Может принимать номер выхода 0 или 1
audio.isPlaying(0);        // Может принимать номер выхода 0 или 1
audio.setVolume(4,0);      // Установить громкость на выходе 0
audio.volume(0,1);         // Уменьшить громкость на выходе 1  

Режимы:

  • по умолчанию: использует тот же таймер и выводы, что и в обычном режиме с двухтактным выходом;
  • MODE2: использует два 16-разрядных таймера и до 4-х выводов.

Использование:

  • рекомендуемая частота дискретизации 16–20 кГц;
  • размер буфера может быть увеличен для улучшения производительности;
  • звуки, воспроизводимые одновременно, должны иметь одинаковые частоты дискретизации;
  • для включения режима multi раскомментируйте определение в pcmConfig.h;
  • переменная audio.speakerPin2 должна быть установлена в 4-выводном режиме для выбора дополнительного таймера / вывода, которые будут использоваться.

Упрощенные режимы:

Стандартный режим (2 вывода, один трек)1 или 2 динамика
Стандартный режим стерео (2 вывода, один трек)2 динамика, не двухтактные (нагрузка между выводом и корпусом)
Стандартный режим стерео MODE2 (4 вывода, один трек)4 динамика ИЛИ двухтактные выходы (нагрузка между двумя выводами) на 2 динамика
Режим Multi (2 вывода, два трека)1 или 2 динамика
Режим Multi стерео (4 вывода, два трека)2 или 4 динамика, не двухтактные
Режим Multi MODE2 (4 вывода, два трека)2 динамика на двухтактных выходах или 4 динамика на не двухтактных выходах

Примечание: все 4-выводные режимы требуют платы с двумя и более 16-разрядными таймерами.

Воспроизведение стерео и 16-битного аудио

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

В стандартном режиме:

#define STEREO_OR_16BIT
В этом режиме стерео и 16-битные файлы обрабатываются одинаково, причем первый байт считывает на один выход, а второй байт – на другой. Это дает в результате стерео выход на двух динамиках, подключенных между выводом (выводами) динамика и корпусом, или один 16-разрядный выход, использующий резисторную матрицу.
#define MODE2
В стандартном режиме MODE2 позволяет выводить стерео или 16-разрядный звук, используя два дополнительных вывода таймера. Таймер и выводы указываются переменой speakerPin2. Двухтактные выводы таймера должны быть настроены на выход вручную.

В режиме Multi:

#define STEREO_OR_16BIT
Включение этой опции вместе с режимом MULTI позволит воспроизводить два стерео или 16-разрядных трека на отдельных выводах таймера. Это обеспечивает выход для четырех громкоговорителей, подключенных между выводом (выводами) и корпусом, или один 16-разрядный выход для каждого трека.
#define MODE2
Включение этой опции с режимом MULTI и STEREO_OR_16BIT ни на что не влияет.

Использование SDFAT

Библиотека SDFAT может использоваться для уменьшения использования оперативной памяти и памяти программ и для повышения производительности. Файлы должны быть включены в скетч. Смотрите пример в архиве с библиотекой.

Метаданные (теги ID3v2.3 и LIST)

Функции были добавлены для чтения данных о песне, артисте и альбоме из тегов ID3v2.3 и LIST в WAV файлах.

Примечание: добавление, модифицирование и редактирование метаданных поддерживает программа Audacity.

Функции:

listInfo
Прочитать теги LIST в символьный буфер, возвращает длину тега.
id3Info
Прочитать теги ID3 в символьный буфер, возвращает длину тега.
getInfo
Ищет оба тега и считывает в символьный буфер, возвращает длину тега. Первым ищется ID3.

Теги для запросов:

  1. 0 = название песни;
  2. 1 = имя артиста;
  3. 2 = название альбома.

Синтаксис:

byte length = audio.listInfo(<Song Name>,<buffer[]>,<tagToRequest>);
byte length = audio.id3Info(<Song Name>,<buffer[]>,<tagToRequest>);
byte length = audio.getInfo(<Song Name>,<buffer[]>,<tagToRequest>);

Примеры:

  1. Найти только информацию LIST и напечать название песни через последовательный порт.
    char info[32];
    audio.listInfo("song.wav",info,0);
    Serial.print(info);Serial.println(":");
  2. Найти информацию ID3v2.3 и LIST и напечатать информацию о песне, артисте и альбоме через последовательный порт.
    char info[40];
    char* titles[3] = {"Now Playing: ", "by: ", "Album: "};
    	
    for(int i=0; i<3; i++)
    {
      if(audio.getInfo("song1.wav",info,i) > 0)
      {
        Serial.print(titles[i]);
        Serial.println(info);
      }
    }
    audio.play("song1.wav");

Использование TIMER2

Часто данная библиотека используется с платами Uno, Nano и т.д. только с одним 16-разрядным таймером. Когда TIMER1 необходим для других целей, для воспроизведения аудио может быть использован TIMER2.

Выводы динамика – на Uno, Nano и т.д. только вывод 3.

Для включения использования 8-разрядного TIMER2 раскомментируйте строку #define USE_TIMER2 в секции пользовательских определений.

Примечания:

  1. этот вариант, как правило, является не самым лучшим решением;
  2. скорость воспроизведения будет слегка отличаться от использования 16-разрядных таймеров;
  3. воспроизведение на TIMER2 поддерживает нестандартные частоты дискретизации: 31,4 кГц, 23,5 кГц и 15,7 кГц;
  4. увеличение частоты дискретизации включено по умолчанию и в этом режиме не может быть изменено;
  5. рекомендуются частоты дискретизации 24–32 кГц при размере буфера 128.

ШИМ и опция rampMega

В попытках уменьшить шумы треска, создаваемые ШИМ, было опеределено четыре основных источника проблемы:

  1. включение ШИМ/таймеров на Arduino;
  2. выключение ШИМ/таймеров на Arduino;
  3. разница в значениях между треками;
  4. парсинг незвуковых данных.

Решения:

  • 1 и 2. При тестировании на платах Arduino Duemianove и Mega я обнаружил необходимость в разных методах линейного изменения при включении и выключении. Надеюсь, это решит проблему на большинстве других плат.
  • 3. Код линейного изменения между треками не меняется. При воспроизведении треков с разными частотами дискретизации используйте функцию disable() для выключения таймеров между изменениями. Смотрите также #4.
  • 4. Опция HANDLE_TAGS включена в pcmConfig.h, чтобы обеспечить правильное воспроизведение wav-файлов с включенными метаданными (ID3 или LIST).

Простое цифровое создание WAV файлов

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

Примечание: в дальнейшем будут добавлены и другие форматы wav.

Синтаксис:

audio.createWavTemplate(<Song Name>,<Sample Rate>);
audio.finalizeWavTemplate(<Song Name>);

Использование:

Смотрите пример, включенный в библиотеку. Создайте файл шаблона, затем запишите в него данные, начиная с 44 байта. Используйте команду finalizeWavTemplate, чтобы добавить данные о размере файла перед воспроизведением.

Примечания: Если указанный файл существует, он будет перезаписан при создании, но обновлен только при завершении. Эти функции при использовании функций записи вызываются автоматически.

Запись звука

Запись звука находится всё еще в тестировании и может работать не так, как ожидается.

Функции:

startRecording
Начать запись с указанного аналогового вывода.
stopRecording
Остановить запись и финализировать wav файл.

Проходной режим – во время записи выдает звук на динамик.

Режимы: 0 – нормальный/нет; 1 – динамик включен; 2 – записи нет, вывод только на динамик.

Синтаксис:

audio.startRecording(<Song Name>,<Sample Rate>, <analog pin>);
audio.startRecording(<Song Name>,<Sample Rate>, <analog pin>, <passthrough mode>);
audio.stopRecording(<Song Name>);

Использование:

  1. раскомментируйте #define buffSize 128 и #define ENABLE_RECORDING в pcmConfig.h;
  2. начните запись
    audio.startRecording("sound.wav",16000,A0);
  3. остановите запись
    audio.stopRecording("sound.wav");

Примечания:

  • для записи рекомендуется библиотека SdFat;
  • рекомендуются SD карты минимум класса 4;
  • возможно, понадобится увеличение buffSize.

Теги

ArduinoSD картаWAVВоспроизведение аудиофайловЗапись звука в аудиофайлПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.


  • 2020-05-27Evgen Malish

    Если не ошибаюсь на макете-схема стягивающие резисторы на кнопках по 220 Ом, но не как не 22 кОм, и если это 220 Ом тогда мало - будет "дребезг" при нажатии (1-2 кОм предостаточно). Хотя может их раскраска похожа и я ошибаюсь. Да ошибся, ведь у вас кнопки работают при значении LOW.