Materiali i artikujt është marrë nga kanali im .
Detektori i sinjalit tonal
Në të kaluarën Ne krijuam një matës të nivelit të sinjalit. Në këtë, do të mësojmë të zbulojmë sinjalin tonal.
![]()
Në ditët e kaluara, kur jo çdo familje kishte televizor, dhe gjysma e tyre ndërronin kanalet me ndihmën e çiftëzave, në shqyrtimet e shtypit teknik të huaj u shfaq një lajm intriguese, që një nga prodhuesit e televizorëve pajisi aparatët e tij me një telekomandë pa tel. Nga detajet dihej se telekomanda funksiononte pa bateri falë një qasjeje të pazakontë - telekomanda ishte mekanike dhe përbënte një hibrid të instrumenteve muzikore - metalofon dhe revolver. Në tamburin e revolverit ndodheshin cilindrat metalikë, të ndryshëm në gjatësi, dhe kur goditësi godiste një prej tyre, cilindra fillonte të zëra në frekuencën e tij të vetme. Supozohet se ajo ndodhte në ultratinguj. Elektronika në televizor dëgjonte këtë sinjal dhe, pasi e identifikonte frekuencën, kryente veprimin përkatës - ndërronte kanal, rregullonte volumet, fikte televizorin.
Sot do të përpiqemi të bëjmë një rikonstruksion të këtij sistemi transmetimi urdhrash, duke përdorur njohuritë tona mbi multimedia.
Për të imituar telekomandën, do të përdorim tekstin e shembullit tonë të gjeneratorit tonal. Ne do të shtojmë menaxhimin e frekuencës së gjeneratorit nga goditjet e tastierës dhe një marrës me dekoder, i cili do të nxjerrë në konsolë urdhërat e marrë. Pas ndryshimit, gjeneratori duhet të nxjerrë sinjale tonale me 6 frekuenca, me të cilat do të kodifikojmë komandat për rritje/ule të volumit, ndërrim kanal, fikje/ndezje televizori. Për konfigurimin e detektorëve përdoret struktura:
struct _MSToneDetectorDef{
char tone_name[8];
int frequency;
/**< Frekuenca e pritur e tonit */
int min_duration;
/**< Koha minimale e tonit në milisekonda */
float min_amplitude;
/**< Amplituda minimale e tonit, 1.0 përkatëse me nivelin e normalizuar 0dbm */
};
typedef struct _MSToneDetectorDef MSToneDetectorDef;Mund t'i dërgoni detektorëve 10 të tilla struktura, kështu që një detektor mund të konfigurohet për të zbuluar dhjetë sinjale dy-tonesh. Por ne do të përdorim vetëm gjashtë sinjale një-tonale. Për të dërguar konfigurimet te detektori, përdoret metoda MS_TONE_DETECTOR_ADD_SCAN.
Për të lejuar që detektori të na informojë se një sinjal me komponentët frekuencave të kërkuara po hyn në hyrjen e tij, ne duhet t'i ofrojmë një funksion kthimi, të cilin ai do ta aktivizojë në këtë rast. Kjo bëhet përmes funksionit ms_filter_set_notify_callback(). Si argumente, ai merr një tregues në filtrin, një tregues në funksionin e kthimit dhe një tregues në të dhënat që dëshirojmë t'i dërgojmë funksionit të kthimit (të dhënat e përdoruesit).
Kur aktivizohet detektori, funksioni i kthimit do të marrë të dhënat e përdoruesit, një tregues 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 e përpunimit të sinjalit është e paraqitur në imazhin kryesor.
Tani le të kalojmë në 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 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 default:0
ortp-warning-Nuk arrita të bashkangjis mixer në kartelë: 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 pavlefshëm default:0
ALSA lib conf.c:4738:(snd_config_expand) Parametra të panjohur 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) PCM i pavlefshëm default:0
ortp-warning-Çudi, karta e audios Intel 82801AA-ICH nuk duket se është në gjendje të bëjë asgjë, duke u përpiquar me plughw...
Shtypni çelësin e komandës, pastaj Enter.
Për të përfunduar programin, shkruani 0.
ortp-warning-alsa_set_params: periodsize:256 Duke përdorur 256
ortp-warning-alsa_set_params: period:8 Duke përdorur 8
Shtypni çelësat nga "1" deri "6", duke e konfirmuar me "Enter", duhet të arrijmë një listim të tillë:
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 zbulohet ato.
Në artikullin e ardhshëm, do të flasim për dërgimin e sinjaleve audio përmes rrjetit Ethernet duke përdorur protokollin RTP dhe do ta aplikojmë atë menjëherë në kontrollin tonë të distancës.
Burimi: habr.com
