DEMO: ses karti test

Başlatan unixmania, 14 Ekim 2019 - 19:40:43

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

unixmania

Bu da C ile yazdigim ses karti test programi. O da kisa oldugundan direkt asagida veriyorum. Bu da her hangi bir harici kutuphaneye ihtiyac olmadan bir sey calarak karti test etmek icin kullanisli olabilir.

Mesela ses kartinin degisik cikislarini (kulaklik, line-out, HDMI , S/PDIF) test etmenize -ses veriyor mu vermiyor mu- olanak verir. Burada direkt ses aygitini acip icine baska bir dosyadan aldigimiz ses verisini yaziyoruz.

Ses aygitlari su dizinde bulunur: /dev/snd/   Bende bu klasorun icerigi soyle:


$ ls /dev/snd
by-path  controlC0  hwC0D0  hwC0D2  pcmC0D0c  pcmC0D0p  pcmC0D10p  pcmC0D3p  pcmC0D7p  pcmC0D8p  pcmC0D9p  seq  timer


Yukardaki ciktida dosyalardan ismi pcm ile baslayip p harfi ile bitenler - mesela pcmC0D0p - ses calma aygitlaridir. O sondaki p harfi ingilizce 'playback'  kelimesinden geliyor.

Dosyalardan ismi pcm ile baslayip c harfi ile bitenler - mesela pcmC0D0c - ses yakalama/kaydetme aygitlaridir. O sondaki c harfi ingilizce 'capture'  kelimesinden geliyor. mikrofon falan bunlar.

Dosyalardan ismi pcm ile baslayip p veya c harfi ile bitmeyenlerin hem calma hem yakalama kabiliyeti vardir. Benim sistemde boyle bir aygit yok.

Yukarda goruldugu gibi benim laptopta 6 adet playback aygiti var. Bunlarin birbirinden farki su: kimisi analog cikis(dahili laptop hoparloru) kimisi dijital (HDMI, S/PDIF) ses cikisi, baska farklarida var.


#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>

#include <sound/asound.h>

static struct snd_pcm_hw_params          hwp;
static struct snd_pcm_sync_ptr           ptr;
static int                               len, pcm_fd;
unsigned char                            *buf;


int main(int argc, char* argv[])
{
int fd=-1, i, j;

if(argc != 3)
{
printf("USAGE:\n\t%s device_path file_path\n\ndevice_path: A playback capable pcm device path something like /dev/snd/pcmCXDY or /dev/snd/pcmCXDYp where X, Y is a number into range [0, 15]\nfile_path  : Path of sound file. File must be little_endian-signed-16_bit pcm format otherwise you just hear random noise.\n", argv[0]);
return -1;
}

pcm_fd = open(argv[1], O_RDWR);

if(pcm_fd<1)
{
printf("ERROR: Cannot open device: %s\n", argv[1]);
return -1;
}

hwp.flags  = SNDRV_PCM_HW_PARAMS_NORESAMPLE | SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER | SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP;

for(i=0; i<12; i++)
{
hwp.intervals[i].max = 0xffffffff;
if(i<3)  hwp.masks[i].bits[0] = 0xffffffff;
}

hwp.rmask = 1 << SNDRV_PCM_HW_PARAM_BUFFER_BYTES;
len = ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_REFINE, &hwp);

if(len != 0)
{
printf("ERROR: ioctl failed. Are you sure device_path (%s) is a pcm device? it must be something like /dev/snd/pcmCXDY or /dev/snd/pcmCXDYp. Where X, Y is a number into range [0, 15]\n", argv[1]);
return -1;
}

printf("Device capabilities bitmask: 0x%x  NOT: See '/usr/include/sound/asound.h' file for meaning of particular bit.\n\n", hwp.info);

if(!(hwp.info & SNDRV_PCM_INFO_MMAP))
{
puts("ERROR: Device don't support mmap.");
return -1;
}

len = hwp.intervals[10].max;
hwp.intervals[10].min = len;
hwp.rmask = 1 << SNDRV_PCM_HW_PARAM_BUFFER_BYTES;

if(0 != ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_PARAMS, &hwp))
{
puts("ERROR: Can not set size of device buffer");
return -1;
}

hwp.masks[SNDRV_PCM_HW_PARAM_ACCESS].bits[0] = 1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
hwp.rmask = 1 << SNDRV_PCM_HW_PARAM_ACCESS;

if(0 != ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_PARAMS, &hwp))
{
puts("ERROR: Device access parameter can't set to 'SNDRV_PCM_ACCESS_MMAP_INTERLEAVED'. Maybe device not support this access.");
return -1;
}

hwp.masks[SNDRV_PCM_HW_PARAM_FORMAT].bits[0] = 1<<SNDRV_PCM_FORMAT_S16_LE;
hwp.rmask = 1 << SNDRV_PCM_HW_PARAM_FORMAT;

if(0 != ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_PARAMS, &hwp))
{
puts("ERROR: Format can't set to 'SNDRV_PCM_FORMAT_S16_LE'. Maybe device not support this format");
return -1;
}

hwp.masks[SNDRV_PCM_HW_PARAM_SUBFORMAT].bits[0] = 1<<SNDRV_PCM_SUBFORMAT_STD;
hwp.rmask = 1 << SNDRV_PCM_HW_PARAM_SUBFORMAT;
ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_PARAMS, &hwp);


for(i = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; i<= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; i++)
{
if(i==SNDRV_PCM_HW_PARAM_BUFFER_BYTES)  continue;

// j = i - 8;
hwp.rmask = 1 << i;
ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_REFINE, &hwp);
hwp.rmask = 1 << i;

if(0 != ioctl(pcm_fd, SNDRV_PCM_IOCTL_HW_PARAMS, &hwp))
{
printf("ERROR: Can not set interval parameter: interval: %d\n", i);
return -1;
}
// printf("min          : %u\nmax          : %u\nopenmin      : %u\nopenmax      : %u\ninteger      : %u\n\n", hwp.intervals[j].min, hwp.intervals[j].max, hwp.intervals[j].openmin, hwp.intervals[j].openmax, hwp.intervals[j].integer);
}

buf = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_NORESERVE | MAP_POPULATE, pcm_fd, SNDRV_PCM_MMAP_OFFSET_DATA);

if(buf<1)
{
printf("ERROR: failed to mmap device fd.\n");
return -1;
}

fd = open(argv[2], O_RDONLY);
if(fd<1)
{
printf("ERROR: Can not open sound file: %s\n", argv[2]);
return -1;
}
read(fd, buf, len>>1);

ioctl(pcm_fd, SNDRV_PCM_IOCTL_PREPARE);
ioctl(pcm_fd, SNDRV_PCM_IOCTL_LINK, pcm_fd);

ptr.c.control.appl_ptr  = len>>3;
ptr.c.control.avail_min = 0;
ioctl(pcm_fd, SNDRV_PCM_IOCTL_SYNC_PTR, &ptr);

if(0 != ioctl(pcm_fd, SNDRV_PCM_IOCTL_START))
{
puts("ERROR: ioctl failed: SNDRV_PCM_IOCTL_START");
return -1;
}

ptr.flags = SNDRV_PCM_SYNC_PTR_HWSYNC | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
j = 1;

for(;;)
{
if(0 != ioctl(pcm_fd, SNDRV_PCM_IOCTL_SYNC_PTR, &ptr))  break;

if(((ptr.s.status.hw_ptr % (len>>2)) < (len>>3)) && j)
{
j = 0;
i = read(fd, buf+(len>>1), len>>1);

if(i<=0)  break;
else  ptr.c.control.appl_ptr += i>>2;
}

else if(((ptr.s.status.hw_ptr % (len>>2)) > (len>>3)) && !j)
{
j = 1;
i = read(fd, buf, len>>1);

if(i<=0)  break;
else  ptr.c.control.appl_ptr += i>>2;

}
sleep(1);
}

ioctl(pcm_fd, SNDRV_PCM_IOCTL_DROP);
ioctl(pcm_fd, SNDRV_PCM_IOCTL_UNLINK);

munmap(buf, len);
    perror("FINAL");
return 0;
}


Kodu yukarda verdim. Derlemek icin yukardan hepsini birden secip bos bir dosyaya kaydedin. bu dosyaya istediginiz ismi verin farketmez. Sonra:


gcc -Wall dosyanin_ismi -o sestest


komutuyla derlenir ve ayni dizinde sestest adinda bir dosya olusacaktir sorunsuz derlenirse.Komutu soyle kullaniyorsunuz:


sestest ses_aygiti ses_dosyasi


komut 2 arguman aliyor. Birinci arguman kullanmak istediginiz aygitin yoludur. Mesela /dev/snd/pcmC0D0p
Ikinci arguman calmak istediginiz sarkinin yolu. Ornek kullanim:


sestest /dev/snd/pcmC0D0p /home/music/sarki.pcm


DIKKAT: Calmak istediginiz ses dosyasi s16le formatinda olmalidir, yoksa tuhaf cizirtilardan baska birsey duymazsiniz. ffplay ciktisina bakiniz:


$ ffplay -hide_banner -formats | grep PCM
DE alaw            PCM A-law
DE f32be           PCM 32-bit floating-point big-endian
DE f32le           PCM 32-bit floating-point little-endian
DE f64be           PCM 64-bit floating-point big-endian
DE f64le           PCM 64-bit floating-point little-endian
DE mulaw           PCM mu-law
DE s16be           PCM signed 16-bit big-endian
DE s16le           PCM signed 16-bit little-endian
DE s24be           PCM signed 24-bit big-endian
DE s24le           PCM signed 24-bit little-endian
DE s32be           PCM signed 32-bit big-endian
DE s32le           PCM signed 32-bit little-endian
DE s8              PCM signed 8-bit
DE u16be           PCM unsigned 16-bit big-endian
DE u16le           PCM unsigned 16-bit little-endian
DE u24be           PCM unsigned 24-bit big-endian
DE u24le           PCM unsigned 24-bit little-endian
DE u32be           PCM unsigned 32-bit big-endian
DE u32le           PCM unsigned 32-bit little-endian
DE u8              PCM unsigned 8-bit
DE vidc            PCM Archimedes VIDC
$


Uzulmeyin her turlu sesi ffmpeg programiyla bu formata donusturebilirsiniz. Mesela bir mp3 dosyasini donusturmek icin:


ffmpeg sarki.mp3 -f s16le sarki.pcm


Iste yukarda sarki.mp3 dosyasini aldi bu formata donusturup sarki.pcm olarak kaydetti. Orjinal dosyaya ellemez.

NOT: Bu program diger basligimdaki info demosuyla beraber kullanilirse daha yarayisli olur. O basligim: https://forum.ubuntu-tr.net/index.php?topic=61290

O basligimda ki info da isminde switch  veya volume iceren ozellikler oldugunu gorursunuz. Adinda switch/jack olanlar acma/kapama dugmesidir. O switch degerini 1 yaparsaniz acmis/devreye almis olursunuz.

O ciktida HDMI, hoparlor, kulaklik vs switch/jacklari gozukuyor, hangisinin acik hangisinin kapali oldugu gozukuyor.

Adinda volume olanlar sesi yukseltip kismaya yariyor. En yuksek ne kadar acabilirsiniz size soyluyor. Ordaki max degeri kadar.

NOT: Bu demoyu yazarken aklima bir fikir geldi: SESLI KOMUT TANIMA

Cok zor degil gibi duruyor. Kullanici yeni bir komut tanimlamak icin bir tusa basacak hemen ardindan bir harf konusacak 1 saniyeyi gecmeyecek, duzgun telaffuz edecek.

Mikrofon bu 1 saniyelik telaffuzu yakalayacak ve referans olarak saklayacak.

Mikrofon devamli dinlemede olacak. mikrofon bir ses duydugunda duydugu sesi referansindaki komutlarla karsilastiracak. Eslesme basarili olursa sese karsilik gelen komutu isletecek.

Algoritmasi basit. Ehh iste eslestirme fonksiyonunu yazmak biraz dise dokunur ;)

Usenmezsem ve basarirsam paylasirim.