Xlibとasoundlibで生の音データをリアルタイム表示

2017-05-10

前回の方法で取った生の音データをXlibでリアルタイムに表示する。

Xlibの使い方はYoutubeでのチュートリアルを参考

https://www.youtube.com/watch?v=NWYwDXN7b_s

優しそうな英語のしゃべり方でパート7まであった。

うんコード


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>


#include <alsa/asoundlib.h>


int main()
{

     /* X11 */
     Display *dpy;
     int screen;
     Window win, root_win;
     XEvent event;

     unsigned int depth;
     XSetWindowAttributes attrs;

     int width, height;
     width = 1024;
     height = 720;

     dpy = XOpenDisplay(NULL);
     if(dpy == NULL)
     {
          printf("Failed open display");
          return 0;
     }


     screen = DefaultScreen(dpy);
     depth = DefaultDepth(dpy, screen);
     root_win = RootWindow(dpy, screen);

     attrs.border_pixel = BlackPixel(dpy, screen);
     attrs.background_pixel = WhitePixel(dpy, screen);
     attrs.override_redirect = True;
     attrs.colormap = CopyFromParent;
     attrs.event_mask = ExposureMask | KeyPressMask;

     /* Parent */
     win = XCreateWindow(dpy, root_win,
          0, 0, width, height,
          0, depth, InputOutput, CopyFromParent,
          CWBackPixel | CWColormap | CWBorderPixel | CWEventMask,
          &attrs);

     XMapWindow(dpy, win);

     
     /* draw graph */
     GC gc, gcfill; 
     XGCValues gcv, gcvfill;

     int blackpixel = BlackPixel(dpy, screen);
     int whitepixel = WhitePixel(dpy, screen);


     gcv.background = whitepixel;
     gcv.foreground = blackpixel;
     gc = XCreateGC(dpy, root_win,
          GCForeground | GCBackground, &gcv);

     gcvfill.background = whitepixel;
     gcvfill.foreground = whitepixel;
     gcfill = XCreateGC(dpy, root_win,
          GCForeground | GCBackground, &gcvfill);

     int x1, y1;
     int x2, y2;
     int data;
     int i;

     /* ALSA */
     int rc, val, dir, size;
     char *buffer;
     snd_pcm_t *handle;
     snd_pcm_hw_params_t *params;
     snd_pcm_uframes_t frames;

     rc = snd_pcm_open(&handle, "pulse", SND_PCM_STREAM_CAPTURE, 0);
     if(rc < 0)
     {
          printf("Failed open device\n");
          return 0;
     }

     snd_pcm_hw_params_alloca(&params);
     snd_pcm_hw_params_any(handle, params);
     snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
     snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
     snd_pcm_hw_params_set_channels(handle, params, 2);

     val = 44100;
     snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

     //frames = 32;
     frames = 1024;
     snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

     rc = snd_pcm_hw_params(handle, params);
     if(rc < 0)
     {
          printf("Failed to set params\n");
          return 0;
     }

     snd_pcm_hw_params_get_period_size(params, &frames, &dir);
     size = frames * 4;
     buffer = (char*) malloc(size);

     int scale = 30000;

     while(1)
     {
          //XNextEvent(dpy, &event);
          XCheckTypedEvent(dpy, KeyPress, &event);

          /* Fill Screen white */
          XFillRectangle(dpy, win, gcfill, 0, 0, width, height);

          /* Draw Cross */
          XDrawLine(dpy, win, gc, 0, height / 2, width, height / 2);
          XDrawLine(dpy, win, gc, width / 2, 0, width / 2, height);

          /* Capture sound */
          rc = snd_pcm_readi(handle, buffer, frames);
          if(rc == -EPIPE) // overrun
          {
               printf("overrun\n");
               snd_pcm_prepare(handle);
          }
          else if(rc < 0)
          {
               printf("error read %s\n", snd_strerror(rc));
          }
          else if(rc != (int)frames)
          {
               printf("short read, %d frames\n", rc);
          }

          for(i = 0; i < size - 4; i+=4)
          {
               data = (buffer[i+1] << 8) | (buffer[i] << 0);
               y1 = height * 0.5 + data * (height * 0.5)  / scale;
               x1 = (i/4) * (width / (int)frames) - (width / (int)frames) / 2;

               data = (buffer[i+1+4] << 8) | (buffer[i+4] << 0);
               y2 = height * 0.5 + data * (height * 0.5)  / scale;
               x2 = ((i/4) + 1) * (width / (int)frames) - (width / (int)frames) / 2;

               XDrawLine(dpy, win, gc, x1, y1, x2, y2);
          }

               

          if(event.type == Expose)
          {

          }
          else if(event.type == KeyPress)
          {
               XDestroyWindow(dpy, win);
               XCloseDisplay(dpy);
               break;
          }

//          usleep(1000000 / 60);

     }

     return 0;
}

                              

データ点(?)を1024個にするとスリープしなくても、ちょうどいい速さでできた。Pythonでグラフ描画のライブラリを使うよりこうやってXlibでやった方がヌルヌルで良いんじゃないでしょうか?