Materiali i artikullit është marrë nga kanali im .
Zbuluesi i tonit tonal
Në të kaluarën Ne krijuam një matës niveli sinjali. Në këtë, do të mësojmë se si të zbulojmë tonin tonal.
![]()
Në kohët e kaluara, kur nuk kishte televizorë në çdo familje, dhe një pjesë e madhe e tyre ndryshonte kanalet me plumb, në shqyrtimet e shtypit teknik të huaj doli një lajm intrigues se një nga prodhuesit e televizorëve kishte pajisur aparatet e tij me një telekomandë pa tel. Nga detajet dihej se telekomanda funksiononte pa bateri falë përdorimit të një qasjeje të pazakontë - telekomanda ishte mekanike dhe përbënte një hibrid të një instrumenti muzikor - metalofon dhe revolver. Në tamburin e revolverit ndodheshin cilindër metalikë, të ndryshëm në gjatësi, dhe kur goditësi godiste një prej tyre, cilindri fillonte të binte në frekuencën e tij të vetme. Supozohet se në ultratinguj. Elektronika në televizor dëgjonte këtë sinjal dhe, duke përcaktuar frekuencën e tij, kryente veprimin përkatës - ndryshimin e kanalit, rregullimin e volumit, ndalimin e televizorit.
Sot do të përpiqemi të bëjmë një rikonstruksion të këtij sistemi të transferimit të komandave, duke shfrytëzuar njohuritë tona mbi mediastreamerin.
Për të imituar telekomandën, do të përdorim tekstin e shembullit tonë të gjeneratorit tonal. Ne do të shtojmë në të kontrollin e frekuencës së gjeneratorit nga goditjet e tastierës dhe një marrës me dekoder, i cili do të nxjerrë në konsol komandat e pranuara. Pas ndryshimeve, gjeneratori duhet të japë sinjale tonale në 6 frekuenca, të cilat do të përdorim për të koduar komandat e rritjes/kësaj të volumin, ndryshimin e kanalit, ndërrimin/ndalimin e televizorit. Për të konfiguruar detektorin përdoret struktura:
struct _MSToneDetectorDef{
char tone_name[8];
int frequency; /**Frekuenca e pritur e tonit*/
int min_duration; /**Minimumi i kohëzgjatjes së tonit në milisekonda */
float min_amplitude; /**Amplituda minimale e tonit, 1.0 përputhet me nivelin e normalizuar 0dbm */
};
typedef struct _MSToneDetectorDef MSToneDetectorDef;Detektorit mund t'i kalohen 10 nga këto struktura, duke e bërë kështu një detektor të jetë i gatshëm për të zbuluar dhjetë sinjale dytonale. Por ne do të përdorim vetëm gjashtë sinjale njëtonale. Për të kaluar cilësimet tek detektori përdoret metoda MS_TONE_DETECTOR_ADD_SCAN.
Për t'i informuar detektori për sinjalin me përbërjet e kërkuara të frekuencës që mbërrijnë në hyrje, ne duhet t'i ofrojmë një funksion thirrje, të cilin ai do ta aktivizojë në këto raste. Kjo bëhet përmes funksionit ms_filter_set_notify_callback(). Si argumente, ai merr një tregues përdoruesi, një tregues në funksionin e thirrjes, dhe një tregues për të dhënat që do të doja t'i kaloj funksionit të thirrjes (të dhënat e përdoruesit).
Kur detektori aktivizohet, funksioni i thirrjes merr të dhënat e përdoruesit, treguesin në filtrin e detektorit, identifikuesin e ngjarjes, dhe një strukturë që përshkruan ngjarjen:
/** * 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;
Skema strukturore për përpunimin e sinjalit është e ilustruar në imazhin kryesor.
Tani, le të shohim kodin e programit me komente.
/* Файл 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);
}
}Kompilojmë dhe e ekzekutojmë programin. Nëse gjithçka funksionon siç duhet, pas ekzekutimit ne duhet të marrim një sjellje të tillë të programit:
$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Parametra të panjohur 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) CTL i pavlefshëm:0
ortp-warning-Nuk mund të lidhim mikserin me kartën: Argument i pavlefshëm
ALSA lib conf.c:4738:(snd_config_expand) Parametra të panjohur 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) PCM i panjohur:0
ALSA lib conf.c:4738:(snd_config_expand) Parametra të panjohur 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) PCM i panjohur:0
ortp-warning-Cuditërisht, karta e zërit Intel 82801AA-ICH nuk dukej se ishte e aftë për asgjë, duke provuar përsëri me plughw...
Shtypni butonin e komandës, pastaj enter.
Për të përfunduar programin, shkruani 0.
ortp-warning-alsa_set_params: sizesi i periudhës:256 Duke përdorur 256
ortp-warning-alsa_set_params: periudha:8 Duke përdorur 8
Shtypni çdo buton nga "1" në "6", duke e konfirmuar me butonin "Enter", duhej të merrni diçka si kjo:
2
Komanda e dërguar: 2
Komanda e pranuar: V-
1
Komanda e dërguar: 1
Komanda e pranuar: V+
3
Komanda e dërguar: 3
Komanda e pranuar: C+
4
Komanda e dërguar: 4
Komanda e pranuar: C-
0
$Shohim se tonet e komandave dërgohen me sukses dhe detektori i zbulojnë ato.
Në artikullin tjetër do të merremi me transmetimin e sinjalit të zërit përmes rrjetit Ethernet përmes protokollit RTP dhe menjëherë do ta aplikojmë atë në telekomandën tonë.
Burimi: habr.com
