📄 soundspec.c
字号:
make_logspectrogram(values, work); set_draw_pixel(work, pixels); expose = 0; nze = 0; while(QLength(disp) || XPending(disp)) { XNextEvent(disp, &e); switch(e.type) { case Expose: expose++; break; case KeyPress: k = xlookup_key(&e.xkey); switch(k) {#ifdef XK_Down case XK_Up:#endif /* XK_Up */#ifdef XK_KP_Up case XK_KP_Up:#endif /* XK_KP_Up */ nze++; break;#ifdef XK_Down case XK_Down:#endif /* XK_Down */#ifdef XK_KP_Down case XK_KP_Down:#endif /* XK_KP_Down */ nze--; break;#ifdef XK_Left case XK_Left:#endif /* XK_Left */#ifdef XK_KP_Left case XK_KP_Left:#endif /* XK_KP_Left */ soundspec_update_interval = (int32)(soundspec_update_interval*1.1); break;#ifdef XK_Right case XK_Right:#endif /* XK_Right */#ifdef XK_KP_Right case XK_KP_Right:#endif /* XK_KP_Right */ soundspec_update_interval = (int32)(soundspec_update_interval/1.1); if(soundspec_update_interval < 0.01 * play_mode->rate) soundspec_update_interval = (int32)(0.01 * play_mode->rate); break; } break; case ClientMessage: if(wm_delete_window == e.xclient.data.l[0]) { mname = XGetAtomName(disp, e.xclient.message_type); if(mname != NULL && strcmp(mname, "WM_PROTOCOLS") == 0) { /* Delete message from WM */ ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Sound Spectrogram Window is closed"); close_soundspec(); XCloseDisplay(disp); disp = NULL; return; } } break; } } offset = call_cnt % SCROLL_THRESHOLD; if(offset == 0) { XCopyArea(disp, offscr, offscr, gc, SCROLL_THRESHOLD, 0, SCOPE_WIDTH - SCROLL_THRESHOLD, SCOPE_HEIGHT, 0, 0); XSetForeground(disp, gc, BlackPixel(disp, DefaultScreen(disp))); XFillRectangle(disp, offscr, gc, SCOPE_WIDTH - SCROLL_THRESHOLD, 0, SCROLL_THRESHOLD, SCOPE_HEIGHT); XCopyArea(disp, offscr, win, gc, 0, 0, SCOPE_WIDTH, SCOPE_HEIGHT, 0, 0); } img->data = (char *)pixels; XPutImage(disp, offscr, gc, img, 0, 0, SCOPE_WIDTH - SCROLL_THRESHOLD + offset, 0, 1, SCOPE_HEIGHT); if(!expose) XCopyArea(disp, offscr, win, gc, SCOPE_WIDTH - SCROLL_THRESHOLD + offset, 0, 1, SCOPE_HEIGHT, SCOPE_WIDTH - SCROLL_THRESHOLD + offset, 0); else { XCopyArea(disp, offscr, win, gc, 0, 0, SCOPE_WIDTH, SCOPE_HEIGHT, 0, 0); } XSync(disp, False); if(nze) initialize_exp_hz_table(soundspec_zoom - 4 * nze); call_cnt++;}struct drawing_queue{ double values[FFTSIZE/2 + 1]; struct drawing_queue *next;};static struct drawing_queue *free_queue_list = NULL;static struct drawing_queue *new_queue(void){ struct drawing_queue *p; if(free_queue_list) { p = free_queue_list; free_queue_list = free_queue_list->next; } else p = (struct drawing_queue *)safe_malloc(sizeof(struct drawing_queue)); p->next = NULL; return p;}static void free_queue(struct drawing_queue *p){ p->next = free_queue_list; free_queue_list = p;}static void trace_draw_scope(void *vp){ struct drawing_queue *q; q = (struct drawing_queue *)vp; if(!midi_trace.flush_flag) { if(view_soundspec_flag) draw_scope(q->values); if(ctl_speana_flag) { CtlEvent e; e.type = CTLE_SPEANA; e.v1 = (long)q->values; e.v2 = FFTSIZE/2; ctl->event(&e); } } free_queue(q);}static void decibelspec(double *from, double *to){ double p, hr; int i, j; static double *w_table = NULL; if(w_table == NULL) { double t; w_table = (double *)safe_malloc(FFTSIZE * sizeof(double)); t = -M_PI; for(i = 0; i < FFTSIZE; i++) { w_table[i] = 0.50 + 0.50 * cos(t); t += 2.0 * M_PI / FFTSIZE; } } for(i = 0; i < FFTSIZE; i++) from[i] *= w_table[i]; realfft(from, FFTSIZE); hr = AMP * NCOLOR; if(from[0] >= 0) p = from[0]; else p = -from[0]; to[0] = log(1.0 + (128.0 / FFTSIZE) * p) * hr; for(i = 1, j = FFTSIZE - 1; i < FFTSIZE/2; i++, j--) { double t, u; t = from[i]; u = from[j]; to[i] = log(1.0 + (128.0 / FFTSIZE) * sqrt(t*t + u*u)) * hr; } p = from[FFTSIZE/2]; to[FFTSIZE/2] = log(1.0 + (128.0 / FFTSIZE) * sqrt(2 * p*p)) * hr;}void close_soundspec(void){ XUnmapWindow(disp, win); XSync(disp, True); /* Discard all remained X Events */ view_soundspec_flag = 0;}void open_soundspec(void){ int scr; XGCValues gcv; if(disp != NULL) { XMapWindow(disp, win); XSync(disp, False); view_soundspec_flag = 1; return; } if((disp = XOpenDisplay(NULL)) == NULL) { ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Can't open display"); ctl->close(); exit(1); } set_color_ring(); scr = DefaultScreen(disp); depth = DefaultDepth(disp, scr); win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, SCOPE_WIDTH, SCOPE_HEIGHT, 0, 0, BlackPixel(disp, scr)); wm_delete_window = XInternAtom(disp, "WM_DELETE_WINDOW", False); XSetWMProtocols(disp, win, &wm_delete_window, 1); XSelectInput(disp, win, ExposureMask | KeyPressMask); XStoreName(disp, win, "Sound Spectrogram"); XSetIconName(disp, win, "Sound Spectrogram"); gcv.graphics_exposures = False; gc = XCreateGC(disp, win, GCGraphicsExposures, &gcv); offscr = XCreatePixmap(disp, win, SCOPE_WIDTH, SCOPE_HEIGHT, depth); XSetForeground(disp, gc, BlackPixel(disp, scr)); XFillRectangle(disp, offscr, gc, 0, 0, SCOPE_WIDTH, SCOPE_HEIGHT); img = XCreateImage(disp, DefaultVisual(disp, scr), depth, ZPixmap, 0, 0, 1, SCOPE_HEIGHT, 8, 0); XMapWindow(disp, win); XSync(disp, False); view_soundspec_flag = 1;}void soundspec_setinterval(double sec){ soundspec_update_interval = (int32)(sec * play_mode->rate);}static void ringsamples(double *x, int pos, int n){ int i, upper; double r; upper = ring_buffer_len; r = 1.0 / pow(2.0, 32.0); for(i = 0; i < n; i++, pos++) { if(pos >= upper) pos = 0; x[i] = (double)ring_buffer[pos] * r; }}void soundspec_update_wave(int32 *buff, int samples){ int i; if(buff == NULL) /* Initialize */ { ring_index = 0; if(samples == 0) { outcnt = 0; next_wakeup_samples = 0; } if(ring_buffer != NULL) memset(ring_buffer, 0, sizeof(int32)); return; } if(!view_soundspec_flag && !ctl_speana_flag) { outcnt += samples; return; } if(ring_buffer == NULL) { ring_buffer = safe_malloc(ring_buffer_len * sizeof(int32)); memset(ring_buffer, 0, sizeof(int32)); if(soundspec_update_interval == 0) soundspec_update_interval = (int32)(DEFAULT_UPDATE * play_mode->rate); realfft(NULL, FFTSIZE); initialize_exp_hz_table(soundspec_zoom); } if(ring_index + samples > ring_buffer_len) { int d; d = ring_buffer_len - ring_index; if(play_mode->encoding & PE_MONO) memcpy(ring_buffer + ring_index, buff, d * 4); else { int32 *p; int n; p = ring_buffer + ring_index; n = d * 2; for(i = 0; i < n; i += 2) *p++ = (buff[i] + buff[i + 1]) / 2; } ring_index = 0; outcnt += d; samples -= d; } if(play_mode->encoding & PE_MONO) memcpy(ring_buffer + ring_index, buff, samples * 4); else { int32 *p; int n; p = ring_buffer + ring_index; n = samples * 2; for(i = 0; i < n; i += 2) *p++ = (buff[i] + buff[i + 1]) / 2; } ring_index += samples; outcnt += samples; if(ring_index == ring_buffer_len) ring_index = 0; if(next_wakeup_samples < outcnt - (ring_buffer_len - FFTSIZE)) { /* next_wakeup_samples is too small */ next_wakeup_samples = outcnt - (ring_buffer_len - FFTSIZE); } while(next_wakeup_samples < outcnt - FFTSIZE) { double x[FFTSIZE]; struct drawing_queue *q; ringsamples(x, next_wakeup_samples % ring_buffer_len, FFTSIZE); q = new_queue(); decibelspec(x, q->values); push_midi_time_vp(midi_trace.offset + next_wakeup_samples, trace_draw_scope, q); next_wakeup_samples += soundspec_update_interval; }}/* Re-initialize something */void soundspec_reinit(void){ initialize_exp_hz_table(soundspec_zoom);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -