Ностальгия по Half Life — создаем приставку для радиостанции для получения голоса и звука окончания в стиле комбайнов


    Когда-то давным-давно, когда деревья были большие, был такой шутер Half-Life, продолжение которого ждут до сих пор — это уже притча во языцех.

    Были там такие противники как Combines (Combine Soldiers) — измененные захватчиками люди.
    Во время игры можно было слышать их переговоры по радио — и я просто мечтал о такой радиостанции, которая бы сделала голос похожим на них и имела такой-же звук окончания радиопередачи.

    Спустя много времени я таки решился осуществить свою мечту.

    Переговоры были типа вот такого:


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

    В игре тон его меняется в зависимости от солдата, вот что-то среднее:


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

    Сердцем данной схемы стал процессор от фирмы ATMEL — ATTINY85.

    И да — real time audio processing на крохотной ATTINY85 — это вполне возможно :)

    Результат работы на примере голоса Геральта из Ривии


    Оригинальный звук


    Модифицированный звук


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

    Можно сказать, что это все «just for fun», однако если убрать трансформацию голоса, то схема позволяет добавить roger beep любой радиостанции, если у нее есть разъем для аксессуаров типа «kenwood» (тот самый двойной разъем).

    Я тестировал это на Baofeng-888s, и как раз у нее roger beep-а в принципе нет — так что возможность сделать это, или, например, скрэмблинг — вполне себе не только забава.

    Как работает прошивка?


    На самом деле ничего сложного там нет.

    Используется низко-скоростной режим работы с периферией (через PLLCSR) — в этом случае питать ATTINY можно от 2.7 вольта и это дает частоту дискретизации около 9kHz.

    Можно было использовать и высокоскоростной режим, что дало бы частоту около 18kHz, но тогда пришлось бы использовать напряжение питания от 4.5 вольт, а с этим были проблемы.

    При нажатии на кнопку передачи на тангенте, генерируется прерывание и ATTINY выходит из сна, включает режим передачи на радиостанции и использует ADC на частоте примерно 8.9kHz чтобы оцифровывать голос с микрофона в циклический буфер:



    При занесении очередного значения в буфер, оно миксуется с предыдущим — находится среднее, т.е. формула такая: $(староеЗначение + новоеЗначение) / 2$.

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

    Памяти у ATTINY не много — всего 500 байт, в данном случае под кольцевой буфер будет использоваться 450 байт, т.к. память нужна еще для переменных и стэка.

    У буфера два указателя — по одному данные пишутся, по другому — читаются и коэффициент отношения этого как раз и задает скорость чтения относительно скорости записи.

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

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

    Но вернемся к нашей схеме: при отпускании кнопки, ATTINY все еще удерживает режим передачи, прекращает оцифровку, и отдает через PWM оцифрованный звук roger beep-а, затем выключает режим передачи и уходит в сон, чтобы снизить потребление электроэнергии.

    Звук, т.к. занимает достаточно много места — около 5 килобайт — занимает часть памяти под программу — т.к. данной памяти вполне достаточно для кода — это решает проблему с нехваткой памяти.

    Что касается степени замедления или убыстрения голоса, то нужный коэффициент должен быть записан в 0 адрес EEPROM ATTINY, и, соответственно, его можно менять в пределах от 0 до 255.

    Примеры значений:
    30 убыстрение голоса
    55 без изменений
    75 замедление голоса

    Схема


    Само устройство будет представлять собой тангенту (или правильней — манипулятор) к радиостанции и будет с ней работать через стандартный разъем для аксессуаров «Kenwood».

    Схема очень и очень простая, легко собирается «на коленке».

    Модуль микрофонного усилителя заказал на Aliexpress, причем рекомендую именно такой тип модуля, который здесь на фото. Питается от 3-5в, стоимость около 2$.

    Динамик требуется около 8 ом, 0.5-1 ватт.

    Кнопка — любая, работающая на замыкание. Светодиод любой с возможностью работы от 3 вольт, ну, или с соответствующим резистором.



    Есть одна особенность, которая не попала в эту схему — в разъеме для аксессуаров предусмотрено 5-вольтовое питание аксессуаров, но вот конкретно в Baofeng-888s что-то у китайцев сделано не так. Мало того, что там 3 вольта, так еще и при нагрузке оно падает до 0.7 вольта и, естественно, схема не работает.

    Для того, чтобы это обойти, был добавлен крохотный DC-DC преобразователь с 1.2 до 3.3 вольта с Aliexpress и внешний разъем для подключения любой AA-батарейки.

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

    Как выглядит схема в сборе:



    Виновник торжества:



    Как сделать двойной штекер (KENWOOD-разъем) для радиостанции:



    Два штекера 3.5 и 2.5, смотанных вместе изолентой — куда уж без нее.

    Корпус


    Тут особо ничего сложного нет, единственное, с чем пришлось повозиться — это с окошком в виде лямбды. Получилось достаточно криво, но чуть-чуть похоже :)

    Делал дремелем, затем с лицевой стороны заклеил скотчем, а с противоположной залил клей из клеевого пистолета, в него же утопил светодиод, который загорается, когда идет передача.

    Здесь еще нет разъема под внешнее питание.

    Снаружи:



    Внутри:



    Все вместе:



    Резюме


    Вобщем, детскую мечту я свою исполнил и хоть она и была иррациональна — ее исполнение греет мою взрослую душу. Надеюсь кто-то испытает схожие чувства. :)

    Прошивка


    FUSE-биты для ATTINY85 (8Mhz, питание >= 2.7в):

    0xE2 LOW
    0xDD HIGH
    0xFF EXTENDED

    Скачать файлы прошивки
    В ближайшее время постараюсь причесать и выложить исходники всего этого.



    Примечание


    Поскольку у моего брата не сложилось с НЛО, то я решил опубликовать на Хабре эту статью от своего имени. Когда я ее собрал — знаете — был счастлив как ребенок. И подумал что она достойна внимания хабрасообщества.

    У меня она живет совместно с радиостанцией YAESU, и отлично работает, питаясь от самой станции.

    Новые версии прошивки и файлы с ней связанные можно будет найти в блоге моего брата protocoder.ru.

    Ну а так как я принимал непосредственное участие в разработке и сам собрал такую-же штуку — то попытаюсь ответить на любые вопросы по ней.
    Share post

    Similar posts

    Comments 45

      +6

      Давным-давно был шутер Half Life, в котором не было никаких комбайнов. Потом вышло долгожданное продолжение Half Life 2, с комбайнами и гравипушкой, на совершенно другом движке и, я бы сказал, в другом жанре. Выросло, блин, поколение. Ностальгия, понимаишь.


      Беги, сейчас набигут более сложные комментаторы.

        +12

        А Half Life 2 это не Half Life? :)


        Я прошел все части и все фановские дополнения Half Life, можно, конечно, делить на версии, но для меня, например, это одна вселенная Half Life.


        Ну и статья ведь не об этом, правда?


        Ну и, справедливости ради, движок Source — это дальнейшее развитие GoldSrc, используемое в первой части.


        А жанры всех этих игр — шутеры.

          –7
          В оригинальном Half-Life были похожие звуки у военных, но они не такие интересные.

          Теперь я знаю кто будет работать на комбайнов :))))

          А за статью плюсанул бы, жаль что не могу, люди хабра не любят правду.
          Спасибо!
            +9
            В оригинальном Half-Life были похожие звуки у военных, но они не такие интересные.
            Это самое возмутительное заявление, что я видел сегодня. Звуки у них крайне интересны.

            В оригинальной Half-Life радиопереговоры военных — это не просто записанные заранее предложения, которые наговорил актёр. В игру встроен синтезатор речи. В файлах есть записи только отдельных слов, каждое записано в виде обычной речи и крика. Из них игра собирает реплики. Движок может менять тональность каждого из отдельных слов или целой реплики. От другой игры 1998 года такого ожидать было бы трудно, но это ведь Half-Life, где даже у тараканов есть игровой ИИ.

            0
            Фановские? Рискну предположить, что речь про остальные продукты — переиграть во все существующие пользовательские моды времени не хватит. То, что создали в Gearbox — это официальные продукты, созданные по лицензии. Вообще, в истории многих продуктов «Вэльва» участие принимали сторонние подрядчики. Сейчас некоторые ещё помнят, почему определённая локация de_train называются popdog (из-за граффити на первой версии карты), но никто не объяснит, что это граффити означало (это логотип Barking Dog Studios, у которой эту карту и заказали).
              0

              уточню:
              Во офф. дополнения типа blueshift, и фановские, доступные тогда, когда играл.
              Причём пошёл далеко не все — некоторые не понравились совсем. А из всех допов больше всего понравился именно blueshift, хотя это и офф.

                0
                Слово valve читается /vælv/ — не «вейлв»
                  0

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

            +1
            Беги, сейчас набигут более сложные комментаторы.

            («Беги, дядя Митя, беги...» (с) ) Не все так страшно.
            Другое дело, что просто люди не знают, что такое настоящий звук в настоящем боевом радиоканале при использовании ларингофонов. В игре, конечно, звук получен с помощью цифровой обработки, но он достаточно близок к тому, что происходит в эфире на самом деле, особенно если мы в диапазоне радиостанции начинаем сигнал шифровать. А тоновые сигналы — я их наслушался в начале 2000-х в такси, когда все ездили с радиостанциями и в начале передачи и в конце передачи радиостанция передавала тональный сигнал, который для диспетчера идентифицировал водителя.
            И у меня звук радиостанций в HL не вызвал какого-то особого восторга или удивления. В такси начала 2000-х, конечно, из радиостанции звук не такой рафинированный, и ларингофоны никто не использовал. И шифрования не было. Но достаточно близко и похоже по звучанию.

            PS: я тоже не знаю, как оно на самом деле звучит в боевых условиях, но когда где-нибудь в горах и на пределе, или реальные переговоры летчиков из 70-х во время воздушного боя, все это можно послушать в ютюбе. Хотя чисто со звуком при использовании ларингофонов — проблема. Как ни пытался, находятся исключительно длинющщие занудные обзоры про то, что «для надевания на шею нужно растянуть пружинную дугу, занести это за голову, надеть на шею» (как объяснение этого можно растянуть на 20 минут???)… И ни одного образца звука «на той стороне» при использовании такого микрофона.
              +3
              И ни одного образца звука «на той стороне» при использовании такого микрофона.

              Автор тоже не стал демонстрировать конечный результат.
              Геральда как то мало, можно же переговоры на видео заснять на минутку.
                +2
                Хотя чисто со звуком при использовании ларингофонов — проблема

                Не очень понял о чем речь, но, на всякий случай, купить для экспериментов на какой нибудь околооружейной барахолке танковый шлемофон с ларингофонами и наушниками можно совсем недорого. Было бы желание. Там даже радиостанцию танковую можно прикупить :)
                  0
                  реальные переговоры летчиков из 70-х во время воздушного боя, все это можно послушать в ютюбе

                  Не обязательно 70-х, можно и вполне современных, причём в изобилии.
                    0
                    Звук крайне паршивый, особенно когда и динамикам, и ларингофонам, и радиостанциям под полсотни лет. Слова нечёткие, голоса идентифицировать начинаешь в лучшем случае через несколько дней, и то не все, адовейшие помехи…
                    В боевых действиях не участвовал, но на учениях наслушался.
                    +6
                    Осталось ещё написать приложение на смартфон, которое голосом H.E.V. будет сообщать о подключении зарядного устройства, уровень заряда, сообщения и уведомления. И уже сбудется моя мечта. Правда, я её уже на Siemens c75 осуществлял.
                      +3

                      Если речь про андроид, и тел рутованный, то для осуществления вашей мечты нужно всего-лишь закинуть файлы со звуком в формате ogg в папку /root/system/media/audio/ui и перегрузить телефон. Никакое приложение писать не нужно.

                        0

                        А для чего при этом рутованность?

                          0

                          А это место разве доступно на запись без рута?6

                            0
                            Точно, был неправ. Спросонья из того адреса мозг вычленил только /media/audio
                          +1
                          На андроиде есть события подключения/отключения и окончания зарядки. А больше всего казалось полезным, что телефон прямо во время зарядки сообщает, что «уровень энергии достиг 70%» — если куда-то торопишься, то незаменимо.
                        +1
                        ФНЧ на входе не понадобился?
                          0

                          Вполне неплохо без него.

                          0
                          Если скорость записи обгоняет скорость чтения, то куски голоса должны пропадать, что должно быть слышно при близких скоростях, когда частота биения маленькая. Щелчек вы задавили ФНЧ (усреднением соседних семплов). Может имело смысл именно фильтром получить требуемый эффект? Тогда часть звука не будет пропадать…
                            0

                            Почему пропадать — там смешиваются сэмплы и откуда должны взяться щелчки?

                              0
                              А что происходит, когда указатель записи на полный круг начинает обгонять указатель чтения? Вы передавали в радиостанцию участок сигнала и тут вдруг раз и уже другие данные на следующем такте передаёте (совершенно другой уровень). Усреднение соседних семплов — это заметание проблемы под ковер, чтобы не сильно слышно было. Ну а что происходит с теми данными, которые мы не успели отправить в аналоговый тракт за время пока один указатель обгоняет другой? Они пропадают.
                                –1

                                Они не пропадают, а смешиваются с предыдущими. Щелчки при старте/окончании оцифровки лечатся на ходу рампингом.

                                  0
                                  Значит вы плохо объяснили ваш алгоритм в статье, и я не понял. Вы написали, что смешиваете только два соседних сэмпла (бегущее среднее?). А выдача данных на ЦАП (PWM) идет со скоростью меньше, чем идет запись с АЦП. Смотрите, если вы записываете с АЦП со скоростью 8.9kHz, а выводите на ЦАП со скоростью в два раза меньше, например, то ваш буфер 450 сэмплов «переполнится» через 450/8900*2 = 0,1 секунду. На данный момент времени на выход уйдет всего-лишь 450 сэмплов, а записано будет 900 сэмплов. После этого произойдет «обгон» указателя записи и воспроизводиться будет текущий сэмпл (усредненный с предыдущим, но это не важно). В результате каждые 100 миллисекунд будет происходить прыжок на 50 мс. Половина данных потеряна. Если у вас другой алгоритм, то я его не понимаю.
                                    0
                                    Попробую еще раз объяснить более подробно как идет алгоритм (два независимых цикла).

                                    Запись:
                                    1. получили байт с АЦП
                                    2. взяли байт по указателю записи, сложили его с полученным с АЦП байтом, разделили на 2, сделали &0xFF
                                    3. положили этот байт по указателю записи
                                    4. увеличили указатель записи
                                    5. если указатель вышел за размер буфера — обнулили его


                                    Чтение:
                                    1. взяли байт по указателю чтения
                                    2. отправили его в PWM
                                    3. увеличили указатель на чтение
                                    4. если указатель вышел за размер буфера — обнулили его


                                    Т.е. смешивание идет непрерывно. Грубо говоря, если длины буфера не хватает — полезный сигнал просто начинает затухать. Никаких щелчков и потерь кусков быть не должно. Ну или я что-то не понимаю.

                                    Чтобы не быть голословным — мы болтали вдвоем и на одной скорости и на убыстренной и на замедленной — никаких щелчков и вообще проблем (насколько это может давать радиостанция) не было слышно. Среднее время одного вещания — т.е. нажали PTT — говорим — отжали PTT было около 5 секунд.

                                    Рампинг (медленное возрастание/затухание до нужного уровня) используется только при начале передачи и ее окончании после Roger Beep.

                                    Как-то так.
                                      0
                                      Ваше усреднение соседних сэмплов — это просто частный случай цифрового ФНЧ. Никакого смешивания и накопления при этом не происходит. Если на вход подать низкочастотную синусоиду, то данное усреднение вообще мало повлияет на сигнал. А если чтение и запись идут на разной скорости, то рано или поздно один буфер циклически догонит другой.Если отношение скоростей небольшое, то это может происходить достаточно редко. Просто представьте что будет если на входе синусоида ну, например, 50 Гц. Воспроизведение из буфера в два раза медленней, чем запись. После 900 отсчетов запись будет производиться в то место, из которого читаем. Все оставшиеся в буфере 450 семплов уже никогда не будут воспроизведены, т.к. их будут перезаписывать новые данные. Если фаза новых данных не совпадет со старыми, то вы просто усредните эту точку и ослабите щелчок в два раза. Учитывая малую частоту воспроизведения вы это и не слышите особо, наверное, но стык там есть точно.
                                      А вот при ускорении получается обратный эффект. Там вы будете повторять эти ваши записанные сэмплы по два раза. Просто при таком алгоритме не может быть иначе.
                                      Начало воспроизведения и окончание — это вы все правильно делаете, но это не проблема. Вы их не слышите скорее всего потому, что частота воспроизведения и так маленькая, плюс вы еще фильтром срезаете верхние частоты.
                                        0
                                        Все оставшиеся в буфере 450 семплов уже никогда не будут воспроизведены, т.к. их будут перезаписывать новые данные

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

                                        Ну т.е. скажем в буфере лежит 1, 2, 3, предположим они перезаписываются с самого начала данными 4, 5, 6 => тогда в буфере окажутся данные (1+4)/2, (2+5)/2, (3+6)/2, затем они воспроизведутся.

                                        Т.е. с моей точки зрения единственное, чем многократное прохождение чревато — затуханием старого сигнала.

                                        Поправьте, если не так. Если можно — с примером.
                                          0
                                          А, я понял наконец-то. Вы не с предыдущим сэмплом из АЦП усредняете, а с тем, который был круг назад. Значит вы теряете только часть информации при перезаписи. Да, это меняет дело. Правда что при этом происходит со спектром уже сложно сказать. Вы давите те частоты, которые не входят целыми в ваш кольцевой буфер. Перевели потери из временнОй области в частотную. Это решение, да.
                                          Как пример потери информации: например наш полезный сигнал — синусоида, которая за время записи буфера проходит половину периода (на самом деле любое количество периодов с половинкой, главное — смена фазы на противоположную). Первый круг мы прошли и записали половину периода синусоиды, а при втором прохождении мы усредняем её с противофазной второй половинкой. Второе кольцо мы получим тишину.
                                          Ощутимое затухание возникнет, если скорость записи более чем в два раза выше, чем скорость воспроизведения. Тогда от некоторых участков данных останется 1/4 амплитуды (или меньше).
                                            0
                                            а с тем, который был круг назад

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

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

                                                    0
                                                    Для этого требуется переписывать отдаваемые данные
                                                    зачем их переписывать? если складывая с прошлыми это и есть эхо.
                                                    иметь гораздо большую задержку.
                                                    на сколько большую?
                                                    эхо это любая задержка больше 0.
                                                      0

                                                      Складывается он с предыдущим, но не так, как делается для эха или реверберации — тут наложение будет лишь части сигнала. Объяснить это на пальцах сложно. Можете попробовать программно сэмулировать такое и потом открыть в редакторе звука — будет понятно. В качестве доказательства послушайте приведённый здесь пример работы — там нет эха.

                                                        0
                                                        Складывается он с предыдущим, но не так, как делается для эха или реверберации — тут наложение будет лишь части сигнала.
                                                        да как не так-то? если скорости совпадают — будет именно сложение с сигналом задержанным на 450 отсчетов. если не совпадают то с какой-то периодичностью или 450 отсчетов повторно будет проиграно или будет пропущено.
                                                        Объяснить это на пальцах сложно.
                                                        давайте уже исходники :)
                                                        Можете попробовать программно сэмулировать такое и потом открыть в редакторе звука
                                                        а можно открыть исходный звук ресемплировать до 9КГц и добавить эхо с 50мс задержкой.
                                                        В качестве доказательства послушайте приведённый здесь пример работы — там нет эха.
                                                        или его не слышно за искажениями. такое себе доказательство. вы либо что-то упускаете, либо это искажения наложены шимом.
                                                        но судя по ютубчику шим на тиньке нормально играет.
                            0
                            А еще у вас на входе с микрофона нет аппаратного ФНЧ. Вероятней всего, ваш микрофон и его усилитель могут пропускать полосу частот намного больше 8,9кГц. При оцифровке с частотой 8,9кГц без аппаратного фильтра вы получаете алиасинг, т.е. вы отзеркалили частоты выше частоты Найквиста-Котельникова в интересующую вас область, что является искажением оригинального сигнала. Так делать не стОит.
                              0
                              На плате использована MAX9814, емнип там есть ФНЧ.

                              Но было бы интересно, чем это все чревато? Что за искажения га слух будет при оцифровке?

                              Я как бы не всамделишный сварщик: ) Т.е. я больше программист, чем электронщик.
                                0
                                ФНЧ даже если его там нет сам собой получается. Вопрос в том на какой частоте он задавит звук достаточно сильно. В английской вики есть пример звучания алиасинга на синусоиде. Все составляющие после частоты Найквиста (в вашем примере все, что больше 4,4кГц) копируется на основной частотный диапазон, в результате появляются неестественные звуки.
                                  0
                                  Понял, спасибо за ликбез.

                                  Ну здесь я не замечал такого, может быть потому, что радиостанция и так достаточно хорошо искажает :)
                            • UFO just landed and posted this here
                                0
                                Большое спасибо за статью! Правда радиостанции у меня нет, зато узнал много нового и интересного про свой любимый Half-Life. И не подозревал что в то время в игре была такая продвинутая работа со звуком.

                                Пытался понять как работает кольцевой буфер, но не осилил. За секунду получаем 8900 байт (если АЦП восьмиразрядное), а буфер всего 450 байт. То есть буфер на 50.5 миллисекунд. Как же это всё работает?!
                                  0
                                  Тут попытался подробнее расписать.

                                Only users with full accounts can post comments. Log in, please.