Воспроизведение звука на STM32-Discovery при помощи Speex

Многие уже воспользовались известным конкурсом, и заказали себе плату STM32-Discovery. Я тоже заказал себе такую. Захотелось сделать на ее основе какую либо конструкцию. Меня заинтересовал AN2812 от ST, в котором описывалось воспроизведение звука с использованием библиотеки Speex для STM32. Однако недостатком аппноута было то, что в нем использовалась stm32f103, более мощная чем stm32f100, установленная в discovery. Также аппноут рассчитан на работу с более сложной отладочной платой. Поскольку я только начинал изучать STM32 (это мой первый проект, до этого я только светодиодом мигал), я решил не пытаться запустить код аппноута, а собрать весь проект с нуля. Проект был создан в IAR.
Вид получившейся конструкции:


Собственно, что такое Speex? Это открытый аудиокодек, предназначенный для сжатия звука. Этот кодек был портиврован для STM32. Использование Speex дает достаточно высокую степень сжатия звука. В нашем случае мы используем частоту дискретизации 8 кГц и битрейт 8 кбит/сек. Практически это значит, что 1 секунда 16-битного звука с частотой дискретизации 8 кГц в закодированном виде занимает 1000 байт. Таким образом, получается сжатие в 16 раз по сравнению с несжатым звуком. Таким образом, в stm32f100 можно хранить примерно 90 секунд звука.
Декодер кодека требует 30 Кб Flash и 5 Кб ОЗУ, поэтому его можно запустить на discovery. Кодировщик более требователен и к ОЗУ, и к скорости процессора, и его нельзя запустить на discovery.

Как отличается мой проект от аппноута? Поскольку stm32f103 достаточно мощный контроллер, то разработчики реализовали в нем меню, возможность записи и воспроизведения звука(правда код получился достаточно навороченный). stm32f100 не обладает необходимой производительностью, поэтому я реализовал только воспроизведение закодированного звука. Для вывода звука вместо ШИМ, использованной разработчиками, и я использовал ЦАП, встроенный в контроллер.

Теперь о принципе работы программы.
Таймер TIM2 настраивается на генерирование прерывания с частотой 8 кГц.
Обработчик таймера выглядит таким образом:

void TIM2_IRQHandler(void)
{
  TIM2->SR &= ~TIM_SR_UIF;//сбросить флаг прерывания
  
    uint16_t tmp;
    //Читаем из текущего буфера значение
    //понижаем его разрядность и прибавляем 512, поскольку
    //в буфере число со знаком
    tmp = (uint16_t)(((*outBuffer>>5)) + 0x200);
    DAC_SetChannel1Data(DAC_Align_12b_R, tmp);
    
    //Если дошли до конца буфера, изменяем указатель на другой буфер
    //и начинаем декодировать данные
    
    if(outBuffer == &OUT_Buffer[1][159])
    {
      outBuffer = OUT_Buffer[0];
      Start_Decoding = 2;
    }
    else if(outBuffer == &OUT_Buffer[0][159])
    {
      outBuffer++;
      Start_Decoding = 1;
    }
    else
    {
      outBuffer++;
    }
       
}


OUT_Buffer[1][160]-это 2 буфера, в которые декодер помещает декодированные данные. В то время, пока данные из одного буфера в прерывании записываются в ЦАП, другой буфер заполняется новыми. При достижении конца буфера начинается воспроизведение из другого буфера и начинается новый цикл декодирования (присвоением глобальной переменной Start_Decoding нужного значения).

Для начала воспроизведения звука необходимо вызвать функцию инициализации декодера, после чего можно вызывать функцию воспроизведения звука. В качестве аргументов в нее передается указатель на начало массива аудио данных и размер аудио данных в фреймах. Важно: звук храниться в фреймах(блоках) по 20 байт, и считываются данные из массива аудио данных тоже блоками по 20 байт.
Вся задача функции воспроизведения состоит в том, чтобы при запросе декодирования (переменная Start_Decoding становится не равна 0) заполнить буфер input_bytes[i] данными из аудио данных, произвести декодирование (при этом декодированные данные в соответствии со значением Start_Decoding помещаются в необходимый буфер OUT_Buffer).
Пример заполнения одного из буферов — OUT_Buffer[0]:

    for(i=0;i<20; i++)
    {
      input_bytes[i] = array[sample_index];
      sample_index++;
    }
    speex_bits_read_from(&bits, input_bytes, ENCODED_FRAME_SIZE);//декодирование
    speex_decode_int(dec_state, &bits, (spx_int16_t*)OUT_Buffer[0]);
    
    NB_Frames++;

Переменная sample_index инкрементируется при каждом считывании байта из массива аудио данных. Переменная NB_Frames инкрементируется при каждом считывании фрейма из массива аудио данных. Декодирование идет до тех пор, пока не будут считаны все фреймы.

Как добавить свой звук в проект? Для меня это оказалось определенной проблемой — программа отлично воспроизводила тестовую фразу из аппноута, но подцепить свои данные не удавалось. Через некоторое время я все-таки нашел необходимую методику.
Приведу пример добавления файла 1.wav, взятого из навигационной программы для кпк, в свой код. (Файл лежит в папке voice)
Для начала нужно скачать и установить Speex кодек SpeexACM. Этот кодек позволяет сохранять закодированные данные в контейнер WAV (контейнер OGG, родной для speex, нам не подходит).
Используя любую программу для работы со звуком(я использую JetAudio), нужно сконвертировать исходный звуковой файл в speex. Кодировать нужно с параметром quality=4 (8kbit/s., 8kHz, Mono, Q4)

Получился файл spx.wav
Теперь от него необходимо отрезать в HEX редакторе первые 192 байт заголовка(звуковые данные начинаются с адреса 0x000000c0). В HEX редакторе заголовок занимает ровно 12 строк по 16 байт в каждой. У меня аудио данные обычно начинались числом 0x1b. Очень важно на этом этапе не ошибиться и не пропустить или удалить лишний байт. Если это произойдет, то все фреймы будут считываться не с того адреса, в результате чего при декодировании от исходного звука не останется и намека — только трещание и писк.
Отрезав заголовки(в них не должно упоминатся ogg, если упоминается, то конвертирование проведено неправильно),
сохраняем файл как spx.raw
Теперь нужно преобразовать получившийся бинарный файл в сишный хидер.
Для этого воспользуемся программой bin2h(лежит в папке voice). Программа работает из консоли, пример запуска программы:
bin2h.exe D:\spx.raw D:\spx.h 
(Что-то слеши не отображаются.)
В результате получается хидер spx.h. Его нужно скопировать в папку inc, или любую другую, в которой компилятор будет искать этот файл.
В main.c добавить этот файл
#include "spx.h"

Откроем этот файл из компилятора.
Он начинается так:

unsigned int spx_size=2820;
unsigned char spx[] = {

Обратите внимание на размер — он должен быть кратен 20.

Нужно переделать на такой вид

//unsigned int spx_size=2820;

const uint16_t spx_frames2=140;// 140=2820/20, последний фрейм не воспроизводим

const uint8_t spx_voice2[] = {


после чего сохранить этот хидер.
Вызов воспроизведения этого файла выглядит так:
play_message(&spx_voice2[0],spx_frames2);


Как видно из фотографии, я выводил сигнал с ЦАП(вывод PA4 контроллера) напрямую на 32 Ом динамик. Громкость получается неплохая.
При подаче питания устройство сразу же начинает поочередно воспроизводить 2 файла — тестовый из аппноута и вышеописанный файл из навигатора.
  • +8
  • 23 марта 2011, 23:10
  • citizen
  • 1
Файлы в топике: MY_SPEEX.zip

Комментарии (102)

RSS свернуть / развернуть
Первая мысль — собрать дверной квартирный звонок...:) На максимум мелодий… Ну, естессно предусмотреть из обновление :)
0
тогда втыкай MMC карточку с поддержкой FAT32 :)
citizen, а портов ФС в апноутах нет случаем?
0
Вроде нет. По поводу карточки — мне кажется, что 90 секунд и так хватит для звонка.
0
Speex вообще-то кодек голосовой, а вовсе не для мелодий. И то, на малых битрейтах даже голос искажается сильно. Разве что звонок будет орать «Хозяин, открой дверь!», «Эй, там пришел кто-то!» и т.п.
Кстати, а что мешало кодировать не в контейнер, а сразу в raw-поток? Да и из контейнера OGG при желании извлечь его можно.
0
А как кодировать сразу в RAW поток? И как извлечь данные из OGG контейнера?
0
Понятия не имею. Видимо, подобрать тулзу, способную выдать RAW-поток. Вроде можно для этого GraphEdit из поставки DirectShow использовать. Только нужен DS-кодек Speex'а.
0
С ACM драйвером speex, кстати, у меня на рабочем ПК с WinXP проблема какая-то — при энумерации, внутри acm-функций (например acmFormatEnum()) он вызывает исключение «Devision by Zero» :( Из-за этого мне пришлось забить на acm-вызовы и использовать libspeex.dll напрямую.
0
Вы написали — «Практически это значит, что 1 секунда 16-битного звука с частотой дискретизации 8 кГц в закодированном виде занимает 1000 байт. Таким образом, получается сжатие в 16 раз по сравнению с несжатым звуком. „
хочу поинтересоваться:
— как с качеством при воспросизведении?
— сколько рессурса контроллера используется на этот speex?
— реально ли в 1000байтах размещается 1сек? (проверяли)
0
как с качеством при воспросизведении?
Запишите звук с частотой дискретизации 8 кГц и послушайте. Качество сжатого звука не сильно отличается от не сжатого (если начальный был записан при 8 кГц)
сколько рессурса контроллера используется на этот speex?
Уже писал:
Декодер кодека требует 30 Кб Flash и 5 Кб ОЗУ
В аппноуте разработчики пишут, что при воспроизведении используется 8% процессорного времени, при рабочей частоте 72 Мгц. При частоте 24 Мгц, выходит 24%.

— реально ли в 1000байтах размещается 1сек? (проверяли)
Длительность 1.wav — 2.821 сек, размер аудио данных spx_size=2820 — байт
И по другому — 1000 байт — это 50 фреймов по 20 байт. 1 фрейм при декодировании преобразуется в 160 integer'ов. Таким образом, 1000 байт сжатых данных — 50*160=8000 — integer'ов.
Воспроизведение идет с частотой 8 кГц — вот секунда и получается.
0
Теперь я знаю чем нагрузить эту платку для интересу. А то лежит и руки до нее пока не доходят… Спасбо за статью.
0
моя приедет тоже попробую. Кстати кому сколько ехала плата с конкурса?
0
Мне шла примерно 3 недели.
0
Воспроизведения звука на Tiny85:
0
Что-то сцылку не видать, тогда без тэгов disorder.ru/archives/tag/sd-wav Вообще там, у чувака «непорядок, энтропия растет» :-) Может кто-нибудь «перепилит» в нормальную статью для сообщества?
0
А кто нить пробывал на AVR сотварить подобное?
0
AVR слишком слаб для этого :) Speex — достаточно жирный кодек в плане потребляемых ресурсов. А несжатый звук с низким битрейтом и на аврах пойдет. Если WAV скормить, например
0
Чем зашить HEX?
STM32 ST-Link Utility понимает только BIN файлы.
0
Есть же hex2bin. Еще WinHex умеет Intel HEX декодировать. А bin AFAIK — просто бинарный дамп, без метаинфы.
0
Я перед тем как спросить попробовал HEx2bin разумеется :-)
Он мне выдал

1.HEX ---> 1.BIN
** Object code error at source address 0000 **
** Error: specified address 0000 is too low, expected address 0002 **
** Object file corrupted, aborting **
0
Забавно. Покажи hex.
0
hex взял из архива который автор выложил

avrdevices.ru/1.hex
0
Похоже, hex2bin неправильно декодирует. Правда, там в начале такая забавная запись… WinHEX декодирует ее в 128-метровый файлик)
А хотя, все ясно. Флеш в этом МК начинается по адресу 0х08000000. Собственно, первая команда этот адрес и устанавливает стартовым. Попробуй просто выпилить ее.
И еще насчет предпоследней не уверен… Оно непосредственно к данным не относится, но что-то там записано. Если hex2bin Попытается и ее как данные интерпретировать — скорее всего выдаст ошибку, тогда ее тоже мона выпилить.
0
А кто нить пробывал на AVR сотварить подобное?
Требевания даже декодера достаточно высоки. Нужно большое количество памяти, ну и кроме того, вычислительные ресурсы. Все-таки STM32 — 32 разрядный контроллер.
Чем зашить HEX?
Я зашивал с помощью ST Visual Programmer.
Если кому-то нужна прошивка именно в bin, то вот
result.zip
0
Ыыы заработало! Прикольно!
0
У тебя какието не правильные утилиты. Мои спокойно схавали HEX автора, и бормочат теперь по английски и про спутник предупреждают — приятным, женским голосом.
Качество для речи — отличное.

to citizen:
Чтото я не врублюсь Кодек поставил но он не воспринимается никем Не VLC не Win Player не Qtime Какой программой с ним работать?
0
Сорри торможу — скачал JetAudio.
Но громкость слабовата, пришлось TDA7050 спаять — теперь орет :0)
0
Скачал кодек Speex, поставил JetAudio. Но чтото конвертор фигню выдает.
Ставлю все как написано но даже из твоих примеров(WAV) конвертирует в какуюто фигню.(WAV в файле присутствует, 8КГц 8кбит моно)

Если не затруднит выложи свою версию кодека.
Спасибо.
0
У меня установлен SpeexACM_1.0.1.1, легко гуглится. Правда, есть вариант, что jetaudio свой кодек ставит. А в чем проблема-то?
0
Проблема в кодировке. Я получаю файл, отнимаю от него 192 байта и на выходе чириканье :0( Взял ваш исходник конвертнул и он отличается от вашего же конвертированного — очевидно не тот кодек или не так, чтото делаю.
0
Выложите то, что получается после конвертирования, может, что-то смогу сказать.
0
Вот ваш оригинальный Wav после конвертации speex
depositfiles.com/folders/Y603YPD1A
0
Сам вдруг заметил, что вышеописанная процедура не работает! Что произошло, не знаю. Выяснил, что Sound Forge 7.0 продолжает нормально кодировать.
Правильный файл в заголовке содержит такую строчку «www.openacm.org fact *X data», неправильный — «www.openacm.org data». Данные при этом кодируются по разному. Если кто-нибудь знает, почему кодек ведет себя по разному, отзовитеь!
Пока что могу посоветовать лишь использовать Sound Forge или попробовать другую программу-конвертер. Если будет время, сам займусь этой проблемой.
Неплохо было бы проверить сами звуковые данные — можно ли их использовать или нет. Когда я писал программу, я определял место, откуда начинаются данные, таким способом: программа постоянно воспроизводила первую секунду звука, после чего воспроизведение начиналось с нового байта. Поскольку фреймы занимают 20 байт, то если звуковые данные правильно сконвертированы, то в определенный момент звук будет воспроизведен верно.
0
Ок, будем искать. А чем контейнер OGG плох?
0
Как я понял, там данные пакуются в собственные фреймы. В нам же нужен постоянный поток звуковых данных, не разделенных дополнительной информацией.
0
А почему бы не попробовать консольный конвертер, который ЕМНИП есть в оригинальной поставке libspeex? Он, скорее всего, умеет сжимать в raw-поток. Или закодировать в любой контейнер, к которому есть демультиплексор и демультиплексировать оттуда поток.
Демультиплексировать кстати можно GraphEdit'ом (майкрософтовская тулза для работы с DirectShow-графами, есть в K-Lite например). Перетащить в него файл, он автоматически создаст граф. Затем снести из графа все, начиная с декодера speex, а к пину, где висел декодер — повесить File Writer. И запустить граф на воспроизведение.
0
Кроме того, GraphEdit'ом можно и закодировать. Перетаскиваем в него файл под кодирование, цепляем вместо Audio Renderer кодер speex'а, его выход — на File Writer.
0
Думал я использовать тот конвертер, который к speex идет. Вот только не нашел нигде указания, что он может сырые данные выдавать. Только в OGG. Ну а про остальное — с демультеплексированием и графами никогда не работал.
0
Как сделать поддержку 16 кГц звука? где это настроить?
0
Надо залезать в настройки Speex, где именно, сам не знаю.
Судя по файлу modes.c в библиотеке speex, поддерживается только 8кгц.
0
К вопросу о подготовке файлов: пробовал скачать speexenc.exe для командной строки с оффсайта speex.org — после сжатия версией 1.2 файлы не воспроизводятся на микроконтроллере, а версия 1.0.4 не запускается на семерке, поэтому кодировал при помощи Cool Edit с плагином speex. Данные помещаются в контейнер Ogg, причем даже для одинаковой настройки качества, заголовок занимает разное кол-во байт. Для отрезания заголовка написал простенькую программу для Visual Studio 2005, программа с исходником здесь .
0
  • avatar
  • uvreg
  • 18 октября 2011, 06:54
почему то ссылка не вставилась — webfile.ru/5610579
0
Ссылка на код и готовый hex файл прошивки:
MY_SPEEX.zip
При открытии проекта пишет, что опции в проекте сбиты. Так и оказалось — ни одной строки инклудов в опциях препроцессора си. Забил вручную — все равно не компилится, говорит нужно задефайнить FIXED_POINT или FLOATING_POINT. Задефайнил — опять куча ошибок. Решил написать сюда.
0
Выложил файл с прошивкой и кодом сюда, а то были жалобы на проблемы со скачиванием с narod.ru.
0
IAR наверно версии 6.х?
0
Эта версия была написана в IAR 5.5.
0
Понятно. У меня 5.4. При открытии воркспэйса предупреждает:
Broken options were detected in the project file. A backup copy will be made.
А когда открывается, то внизу в логе несколько сообщений типа:
LOAD: Configuration 'Debug' in the project '1' contains broken options for tool 'ICCARM':
The format of this file is not supported by this version of the workbench. It appears to have been written by a newer version of the workbench.
0
Бро, дай код целиковый ПЛЗ. А то опять три дня буду сидеть маяться :-(
0
Все и так выложено.
0
А, увидел. Таааким махоньким шрифтиком эта ссылка сделана, что и под микроскопом не рассмотришь. Спасибо!
0
очень интересно! попробую на своем на досуге )
0
«контейнер OGG, родной для speex, нам не подходит»
почему нельзя использовать контейнер OGG? чем он хуже контейнера WAV?
0
Сложнее вытаскивать из него данные. Когда писалась статья, я только начинал программировать под STM32. Сейчас, вероятно, я смог бы реализовать декодирование OGG.
0
А чем конкретно отличаются способы размещения закодированных в Speex данных в OGG контейнере и в WAV контейнере?
0
В OGG данные разделяются заголовками, которые надо обнаруживать и перепрыгивать при воспроизведении. В WAV все данные идут сплошным потоком.
0
Скачал с сайта st.com библиотеку SPEEX.
Там есть сборка под KEIL. Качественна, компилируется без ошибок и предупреждений. И даже в настройках указан мой камень — STM32F103RB. Конкретная модель моего проца — STM32F103RBT6
Заливаю прошивку — жму старт — программа стартует и тут же останавливается. То есть это видно в самом KEIL, по кнопкам управления отладчиком.
Пытаюсь найти ошибку примитивным способом — просто закомментируя разный блоки кода. И вот на что я вышел:
клин в программу вбивает функция speex_bits_init, а именно строка в ней:
bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);

Что такого делает эта команда, что программа останавливается?
0
  • avatar
  • zheka
  • 08 декабря 2012, 20:36
Программа останавливается или входит в обработчик прерывания HardwareFault?
У меня была подобная проблема — если неправильно заданы размеры HEAP и STACK в настройках компилятора(изначально они маленькие), то происходила ошибка, и контроллер зависал в прерывании HardwareFault.
Как я понимаю, программа пытается выделить часть памяти в стеке, ей это не удается, что вызывает ошибку.
0
Скорее в хипе, а не в стеке.
0
Пытаюсь прикрутить speex в coocox к STM32F103RBT6
Уходит в HardwareFault
на
EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
{
   SpeexMode *mode = *(SpeexMode**)state;
   return (mode)->dec(state, bits, out);
}

настройка стека в startup_stm32f10x_md.c
/*----------Stack Configuration-----------------------------------------------*/  
#define STACK_SIZE       0x00000100      /*!< The Stack size suggest using even number     */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];      

HEAP настроек нет. Помогите советом что делать?
0
Есть такие решения:
www.coocox.org/forum/topic.php?id=917
0
Heap должен быть в остатке (за вычетом занятого и стэка) и если памяти мало то как ни крути
0
простите, а как это понять в KEIL?
0
  • avatar
  • zheka
  • 08 декабря 2012, 21:21
Я просто нажимаю на старт, а кнопка отжимается. Нигде в окне программы при этом изменений не происходит.
0
  • avatar
  • zheka
  • 08 декабря 2012, 21:25
Я сам в KEIL никогда не работал. Про стек есть здесь:

ziblog.ru/2011/01/06/pervyiy-start-s-stm32-discovery-chast-3.html
0
Еще здесь:
www.keil.com/support/man/docs/armlink/armlink_CJAJBEFD.htm
В общем, Google в помощь.
0
Нашел как это делать.
У меня stack равен 512 а HEAP 0
Сколько и чего нужно минимально поставить, если speex_alloc требует 2000 байт?
0
  • avatar
  • zheka
  • 08 декабря 2012, 22:26
Кстати, ваш проект в IAR 6.3 вообще не компилируется…
0
  • avatar
  • zheka
  • 08 декабря 2012, 22:44
Эта версия была написана в IAR 5.5.
В IAR CMSIS уже встроен, нужно в исходнике закомментировать строку.
0
Какую именно строку, в каком файле?
0
  • avatar
  • zheka
  • 09 декабря 2012, 00:54
Что-то вроде #include <cmsis.h>, вероятно. Впрочем, у иара есть аппнот на тему миграции с старых версий на шестую. Там подробно.
0
Спасибо разобрался. С кейловским проектом.
Осциллографом кой-что нащупываю.
Скажите, а не опасно это — динамик напрямую цеплять?
У меня вообще 8-омный валяется.
МОжет его последовательно с конденсатором разделительным включить?
Или пьезо поставить? У меня планируется усилитель, но хочется хотя бы послушать звук сейчас.
0
  • avatar
  • zheka
  • 09 декабря 2012, 01:27
Я использовал динамик от наушников, там 32 ома. Самое безопасное — пьезодинамик.
0
ЕЩЕ вопрос.
на плате STM32F103-EVAl очень хитрая схъема фильтра межды выходом PWM и входом усилителя.
Вопрос простой — что будет если ее выкинуть? Оставить только разделительный конденсатор?
0
  • avatar
  • zheka
  • 09 декабря 2012, 11:34
Спаял усилок на TD7052.
Запустил.
Микросхема заговорила приятным женским голосом. Все отлично. ТОлько тихо. Смотрю осциллографом — амплитуда колебаний достигает 3.3 вольт.
Подал на вход усилителя прямоугольные импульсы с GPIO — динамик заорал, у меня аж уши заболели. Хотя те же 3.3 вольт амплитуда.

Скажите, может ли быть причиной, что я не сделал как в предложенной в отладочной плате схеме — фильтр с кучей конденсаторов и резисторов, а просто прицепил разделительный конденсатор 0.1 мкф между выходом PWM и входом усилител? ведь с выхода контроллера идет не обычный аудиосигнал, а ШИМ. Или может быть дело в слишком маленькой емкости разделительного конденсатора? У меня под рукой других нет.
0
  • avatar
  • zheka
  • 09 декабря 2012, 18:50
Если вы про мою программу, то там используется ЦАП контроллера.
Маленькая емкость разделительного конденсатора действительно может ослабить сигнал.
Амплитуду сигнала нужно смотреть под нагрузкой.
0
Да нет, не в конденсаторе дело. НА динамике амплитуда почти 5 вольт (питание усилителя 5 вольт).Видимо и правда фильтр так важен.
0
  • avatar
  • zheka
  • 09 декабря 2012, 21:40
А ты про акустическое оформление не забыл?
0
в смысле?
0
  • avatar
  • zheka
  • 10 декабря 2012, 21:34
Голый динамик очень плохо излучает звук. Нужно акустическое оформление. Коробочка или хотя бы экран.
0
Vga, да что вы говорите?
А что вы подразумеваете под звуком? Меандр — это не звук, ему коробочка не нужна?
0
  • avatar
  • zheka
  • 11 декабря 2012, 06:14
zheka , будьте так добры, используйте кнопАчку ответить. Ибо каждый раз новую ветку открывать ответами на предыдущие сообщения не есть гуд. Нить разговора теряется, а агрессивность тех хто читает — возрастает. :)
+2
Во первых, у меандра выше мощность, чисто за счет коэффициента формы (ЕМНИП, из всех периодических сигналов он у него вообще самый жирный, а уж по сравнению с голосом меньшей аплитуды и подавно). Во вторых, большую роль играет частота — на нескольких килогерцах акустическое оформление роли уже особой не играет, да и на частоте меандра вполне может случайно сложиться оптимальное оформление — скажем, стол под динамиком будет отражать заднюю волну точно в фазе с передней. В третьих, если меандр на частоте около килогерца-двух — это в районе максимума чувствительности уха.
А в четвертых — просто возьми и попробуй с оформлением. Это тебе надо, а не мне.
0
Я пробовал с оформлением — естественно громче. Просто вы даете совет, как буд-то я жалуюсь на громкость, не соответствующую мощности динамика.
Я же сетую на то, что при прочих равных, без акустического оформления звук одной и той же амплитуды отличается по громкости в разы — от невозможности разобрать при постороннем лгком шуме до физического ощущения вибрации барабанных перепонок в метре от 1ваттного динамика. Кстати звук в динамике очень чистый.
В этом и есть мой вопрос — описании похожего проекта на АВР написано — «Фильтр убирает ВЧ составляющую», так может он и громкость повысит по аналогии с известным примером — в сети 220 вольт, если выпрямить и поставить конденсатор — будет 310 вольт. Может быть из-за того что без фильтра звук ШИМированный, действующая мощность оказывается ниже амплитудной?
Частота ШИМ 16 кГц.
0
Может быть, резистор RC-фильтра ограничивает ток?
0
Ну у меня есть еще один вариант — перестроить программу под DAC.
Но вот KEIL не берется компилить пример автора статьи, выдает кучу ошибок типа «undefined....» и все в подпрограмме инициализации DAC первая же строка, где объявляется новая переенная — жалуется на то, что неправильный (undefined) тип переменной.
Что у вас за версия StdPeriph?
0
Я предположил один вариант. На другие мне не хватает информации. Осциллограмму чтоль покажи, хотя бы. Может у тебя столь могучий фильтр НЧ, что срезает высокие частоты и на динамик идет 5В, но 30Гц, которые он и воспроизвести-то толком не может, а если и может — основная часть речевого сигнала где-то выше и пала жертвой фильтра. А может фильтра вообще нет и под амплитудой ты подразумеваешь амплитуду несущей ШИМ. Тогда возможно он в основном свистит на 16кГц (если опять же способен на это), а говорит на оставшееся. В этом случае стоит добавить хотя бы обычную интегрирующую RC-цепочку с частотой среза в районе 3.5кГц. Сложный фильтр вероятно затем, что запаса по частоте ШИМ нету (для нормального воспроизведения без фильтра нужен ШИМ в районе сотен килогерц, как в усилителях класса D), а у RC-цепи слишком мал наклон характеристики в области среза.
Да и потом — частота меандра — 1.5 кгц. Частота речи — 1-3 кГц
Диапазон частот в речевом сигнале — 300-3500Гц. Но это не значит, что верхняя часть этого спектра несет большую мощность.

P.S. Дочитал топик. Да, дело в том, что ты гнал ШИМ без выделения из него собственно звуковой составляющей и динамик тратил основную часть мощности на попытки свистеть 16-ю килогерцами. Если хочешь непосредственно ШИМом выдавать звук — повышай частоту хотя бы до сотни килогерц.
0
В третьих, если меандр на частоте около килогерца-двух — это в районе максимума чувствительности уха.
ну не настолько же. Да и потом — частота меандра — 1.5 кгц. Частота речи — 1-3 кГц
0
ВОН ЧЁ КРЕСТ ЖИВОТВОРЯЩИЙ ДЕЛАЕТ!!!

Я ведь так и думал, что ВЧ составляющая все портит. Просто тупо подсоединил конденсатор 0.33 мкф от выхода ШИМ на землю. Стало раза в 2 громче.
А если сделать полноценную цепочку фильтров — наверное все будет ОК.
0
  • avatar
  • zheka
  • 11 декабря 2012, 19:11
чисто из интереса пытаюсь попробовать с DAC.
Звука нет, на выходе PA4 — ноль.
Бросилось в глаза следующее:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);


зачем GPIO_Mode_AIN? разве DAC — это вход?
0
  • avatar
  • zheka
  • 12 декабря 2012, 07:09
Однако настраивать надо так, почитайте datasheet.
0
хм…
я заменил обработчик прерывания TIM2, заменил init'ы. Если бы забыл что-то с переменными — компилятор не пропустил бы. Не пашет DAC — какое-то шипение слабое. Что я еще мог не сделать?
0
  • avatar
  • zheka
  • 12 декабря 2012, 15:12
Debug в помощь — смотрите, что в прерывании контроллер делает.
0
ВО Я ЛОШАРА!!!
ШАманю с ЦАП, тыкаю осциллографом… А там нули…

А причина непоняток с ЦАП оказалась проста до безобразия:
В камне STM32F103RBT6 НЕТ ЦАПа!!!
0
  • avatar
  • zheka
  • 12 декабря 2012, 19:44
Таки УРА, товарищи!
Удалось передать SPEEX-закодированный звук по цифровому радиоканалу на сс2500.
Правда пока проблема с синхронизацией потоков, но я думаю, я ее решу.
0
  • avatar
  • zheka
  • 13 декабря 2012, 22:08
А что ты в итоге хочешь получить?
0
устройство для передачи телеметрии с возможностями рации.
0
а как повысить качество звука?
Я в SPEEXACM конвертере выбрал Q10, изменил это самое Q в тексте прошивки. Получилось число, которое на 20 не делится. ПОставил в ALL_FRAMES округленное число — естественно получил шум. Что еще надо сделать?
0
Я сам не знаю. Качество в первую очередь определяется частотой дискретизации, а с этим все сложно. Параметры используемой дискретизации определяются структурой speex_nb_mode, которая передается к декодер при инициализации. Если передавать какую-то другую, то возможно, и удастся улучшить качество. Плюс надо будет изменить настройки таймера и кучу переменных в самой программе.
0
Хотелось бы задать вопросы по теме — судя по инфе первоисточника Speex содержит следующие фичи:
Narrowband (8 kHz), wideband (16 kHz), and ultra-wideband (32 kHz) compression in the same bitstream
Intensity stereo encoding
Packet loss concealment
Variable bitrate operation (VBR)
Voice Activity Detection (VAD)
Discontinuous Transmission (DTX)
Fixed-point port
Acoustic echo canceller (AEC)
Noise suppression (NS)
Посему вопросы:
1) Можно ли использовать отдельно VAD, NS, AEC без кодирования сжатия в CELP, а использовать только как эхоподовитель для телефонной линии?
2) И из сходя из первого вопроса — Что для этого надо подправить в коде, если кто то разбирался в структуре кода, может кто то решал подобную задачу?
3) Можно ли подключить внешний звуковой кодек по I2S и что для этого потребуется изменить в коде?
Заранее спасибо.
0
3) Заменить кормление DAC'а данными в TIM2_IRQHandler на кормление ими же внешнего кодека. Но ответ настолько очевиден, что возникает вопрос — тебе что уже готовый код вставь-и-собери нужен?
Кодек подключить можно, но не ко всем МК — надо смотреть по даташиту, есть ли I2S на борту (ну или делать ее в софте).
0
Да готовый код и прошить за меня и собрать, но деньги не надо получать за работу- я сам получу… :)
Шутка конечно, по кодеку самый вопрос простой — сам конечно разберусь и с кодом то же, просто кто уже делал, ему проще по коду сказать, порекомендовать, а так сам расковыряю, сроки поджимают…
0
В свое время я воспроизводил звук, записанный при помощи speex, на STM32F4-DISCOVERY: habrahabr.ru/post/146501/ В тестовых проектах, приложенных к статье, вроде бы была реализация вывода звука на I2S аудиокодек DISCOVERY (проект speex_rec и speex_out). Только для воспроизведения звука я использовал библиотеку от ST, она довольно корявая.
0
Хе-хе)
Вообще, первый вопрос тоже быстрее решается заглядыванием в сорцы. Примерно все, что тебе нужно, лежит в модуле preprocess.c. Полагаю, его можно выудить из либы и юзать в своих гнусных целях без особых модификаций и проблем.
Ну и вообще, там довольно немного кода, найти в нем нужное несложно.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.