Artikelmaterialet är hämtat från min .
Tonsignal detektor
Tidigare vi har skapat en signalnivåmätare. I denna kommer vi att lära oss att upptäcka tonala signaler.
![]()
I gamla tider, när det inte fanns en TV i varje hem och hälften av dem bytte kanaler med hjälp av tänger, dök en fascinerande nyhet upp i utländska tekniska medier, att en av TV-tillverkarna utrustade sina apparater med en trådlös fjärrkontroll. Det framgick detaljer om att fjärrkontrollen fungerade utan batterier tack vare en ovanlig metod – fjärrkontrollen var mekanisk och var en hybrid av ett musikinstrument – en metallofon och en revolver. I revolverns trumma fanns metallcylindrar av olika längd, och när slagplåten slog en av dem, började cylindern att klocka på sin egen frekvens. Antagligen med ultraljud. Elektroniken i TV: n hörde denna signal och, genom att bestämma dess frekvens, utförde den motsvarande åtgärden – bytte kanal, justerade volymen, stängde av TV: n.
Idag kommer vi att försöka återskapa detta system för att överföra kommandon, med hjälp av våra kunskaper om mediastreamern.
För att imitera fjärrkontrollen kommer vi att använda texten från vårt exempel på en tongenerator. Vi kommer att lägga till kontroll av generatorns frekvens från tangenttryckningar och en mottagare med en dekoder som kommer att skriva ut mottagna kommandon i konsolen. Efter ändringen bör generatorn ge tonala signaler på 6 frekvenser, som vi kommer att koda kommandon för att öka/minska volymen, byta kanal, slå på/av TV: n. För att ställa in detektorn används strukturen:
struct _MSToneDetectorDef{
char tone_name[8];
int frequency;
/**<Expected frequency of the tone*/
int min_duration;
/**<Min duration of the tone in milliseconds */
float min_amplitude;
/**<Minimum amplitude of the tone, 1.0 corresponding to the normalized 0dbm level */
};
typedef struct _MSToneDetectorDef MSToneDetectorDef;Detektor kan ta emot 10 sådana strukturer, vilket innebär att en detektor kan ställas in för att upptäcka tio tvåtoniga signaler. Men vi kommer att använda bara sex enstaka tonala signaler. För att överföra inställningarna till detektorn används metoden MS_TONE_DETECTOR_ADD_SCAN.
För att detektorn ska kunna meddela oss att en signal med de önskade frekvenskomponenterna har kommit in, måste vi tillhandahålla en callback-funktion som den kommer att köra i detta fall. Detta görs med hjälp av funktionen ms_filter_set_notify_callback(). Som argument tar den en pekare till filtret, en pekare till callback-funktionen och en pekare till de data som vi vill överföra till callback-funktionen (användardata).
När detektorn utlöses får callback-funktionen användardata, en pekare till detektorns filter, ett händelse-ID och en struktur som beskriver händelsen:
/** * Structure carried as argument of the MS_TONE_DETECTOR_EVENT**/
struct _MSToneDetectorEvent{
char tone_name[8]; /* Имя тона которое мы ему назначили при настройке детектора. */
uint64_t tone_start_time; /* Время в миллисекундах, когда тон был обнаружен. */
};
typedef struct _MSToneDetectorEvent MSToneDetectorEvent;
Den strukturella schemat för signalbehandling visas i huvudbilden.
Nu är det dags för själva programkoden med kommentarer.
/* Файл mstest4.c Имитатор пульта управления и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
#include <mediastreamer2/mstonedetector.h>
/* Подключаем заголовочный файл с функциями управления событиями
* медиастримера. */
#include <mediastreamer2/mseventqueue.h>
/* Функция обратного вызова, она будет вызвана фильтром, как только он
* обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,
MSToneDetectorEvent *ev)
{
printf(" Принята команда: %sn", ev->tone_name);
}
int main()
{
ms_init();
/* Создаем экземпляры фильтров. */
MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
MSFilter *volume = ms_filter_new(MS_VOLUME_ID);
MSSndCard *card_playback =
ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
MSFilter *snd_card_write = ms_snd_card_create_writer(card_playback);
MSFilter *detector = ms_filter_new(MS_TONE_DETECTOR_ID);
/* Очищаем массив находящийся внутри детектора тонов, он описывает
* особые приметы разыскиваемых сигналов.*/
ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);
/* Создаем источник тактов - тикер. */
MSTicker *ticker=ms_ticker_new();
/* Соединяем фильтры в цепочку. */
ms_filter_link(voidsource, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, volume, 0);
ms_filter_link(volume, 0, detector, 0);
ms_filter_link(detector, 0, snd_card_write, 0);
/* Подключаем к фильтру функцию обратного вызова. */
ms_filter_set_notify_callback(detector,
(MSFilterNotifyFunc)tone_detected_cb, NULL);
/* Подключаем источник тактов. */
ms_ticker_attach(ticker,voidsource);
/* Создаем массив, каждый элемент которого описывает характеристику
* одного из тонов, который требуется обнаруживать: Текстовое имя
* данного элемента, частота в герцах, длительность в миллисекундах,
* минимальный уровень относительно 0,775В. */
MSToneDetectorDef scan[6]=
{
{"V+", 440, 100, 0.1}, /* Команда "Увеличить громкость". */
{"V-", 540, 100, 0.1}, /* Команда "Уменьшить громкость". */
{"C+", 640, 100, 0.1}, /* Команда "Увеличить номер канала". */
{"C-", 740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
{"ON", 840, 100, 0.1}, /* Команда "Включить телевизор". */
{"OFF", 940, 100, 0.1} /* Команда "Выключить телевизор". */
};
/* Передаем в детектор тонов приметы сигналов. */
int i;
for (i = 0; i < 6; i++)
{
ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,
&scan[i]);
}
/* Настраиваем структуру, управляющую выходным сигналом генератора.*/
MSDtmfGenCustomTone dtmf_cfg;
dtmf_cfg.tone_name[0] = 0;
dtmf_cfg.duration = 1000;
dtmf_cfg.frequencies[0] = 440;
/* Будем генерировать один тон, частоту второго тона установим в 0.*/
dtmf_cfg.frequencies[1] = 0;
dtmf_cfg.amplitude = 1.0;
dtmf_cfg.interval = 0.;
dtmf_cfg.repeat_count = 0.;
/* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
* цикл и работу программы. */
char key='9';
printf("Нажмите клавишу команды, затем ввод.n"
"Для завершения программы введите 0.n");
while(key != '0')
{
key = getchar();
if ((key >= 49) && (key <= 54))
{
printf("Отправлена команда: %cn", key);
/* Устанавливаем частоту генератора в соответствии с
* кодом нажатой клавиши.*/
dtmf_cfg.frequencies[0] = 440 + 100*(key-49);
/* Включаем звуковой генератор c обновленной частотой. */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
(void*)&dtmf_cfg);
}
ms_usleep(20000);
}
}Vi compilerar och kör programmet. Om allt fungerar korrekt efter starten bör vi få ett beteende ungefär som följande:
$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Okända parametrar 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Ogiltig CTL default:0
ortp-warning-Kunde inte koppla mixer till kort: Ogiltig argument
ALSA lib conf.c:4738:(snd_config_expand) Okända parametrar 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Okänd PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Okända parametrar 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Okänd PCM default:0
ortp-warning-Märkligt, ljudkortet Intel 82801AA-ICH verkar inte kunna något, försöker igen med plughw...
Tryck på kommandotangenten och tryck enter.
För att avsluta programmet, ange 0.
ortp-warning-alsa_set_params: periodsize:256 Använder 256
ortp-warning-alsa_set_params: period:8 Använder 8
Tryck på valfria tangenter från "1" till "6", bekräfta med "Enter", och du bör få en lista ungefär som följande:
2
Kommandot skickades: 2
Mottaget kommando: V-
1
Kommandot skickades: 1
Mottaget kommando: V+
3
Kommandot skickades: 3
Mottaget kommando: C+
4
Kommandot skickades: 4
Mottaget kommando: C-
0
$Vi ser att kommandotonerna skickas framgångsrikt och att detektorn upptäcker dem.
I nästa artikel kommer vi att titta på överföring av ljudsignal över Ethernet-nätverket med hjälp av RTP-protokollet och tillämpa det direkt i vår fjärrkontroll.
Källa: habr.com
