1 /* real-time phase vocoder with curses interface and JACK
2 * Copyright (C) 2007 Kengo Ichiki <kichiki@users.sourceforge.net>
3 * $Id: jack-pv.c,v 1.1 2007/10/29 02:48:41 kichiki Exp $
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 #include <stdio.h>
20 #include <unistd.h> // sleep()
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h> // pow()
24
25 #include <ao/ao.h>
26 #include "ao-wrapper.h"
27 #include <sndfile.h>
28 #include "pv-conventional.h" // get_scale_factor_for_window ()
29 #include <curses.h>
30
31 #include <jack/jack.h>
32 #include <jack/transport.h>
33
34 #include "pv-complex.h" // struct pv_complex
35 #include "hc.h" // HC_complex_phase_vocoder()
36 #include "memory-check.h" // CHECK_MALLOC
37
38 #include "jack-pv.h"
39
40 // check
41 FILE *err_log = NULL;
42
43 /*
44 * OUTPUT
45 * returned value : 1 if x[i] = 0 for i = 0 to n-1
46 * 0 otherwise
47 */
48 static int
check_zero(int n,const double * x)49 check_zero (int n, const double *x)
50 {
51 int i;
52
53 for (i = 0; i < n; i ++)
54 {
55 if (x[i] != 0.0) return 1;
56 }
57 return 0;
58 }
59
60 /* play one hop_in by the phase vocoder:
61 * phase vocoder by complex arithmetics with fixed hops.
62 * t_i - s_i = u_i - u_{i-1} = hop
63 * where s_i and t_i are the times for two analysis FFT
64 * and u_i is the time for the synthesis FFT at step i
65 * Reference: M.Puckette (1995)
66 * INPUT
67 * pv : struct pv_complex
68 * cur : current frame to play.
69 * you have to increment this by yourself.
70 * pv->flag_lock : 0 == no phase lock
71 * 1 == loose phase lock
72 * OUTPUT
73 * left[pv->hop_res], right[pv->hop_res] :
74 * returned value : hop_res (not hop_syn).
75 */
76 int
jack_pv_complex_play_step(struct pv_complex * pv,long cur,double * left,double * right)77 jack_pv_complex_play_step (struct pv_complex *pv,
78 long cur,
79 double *left, double *right)
80 {
81 static double *l_fs = NULL;
82 static double *r_fs = NULL;
83 static double *l_ft = NULL;
84 static double *r_ft = NULL;
85 static double *l_tmp = NULL;
86 static double *r_tmp = NULL;
87
88 if (l_fs == NULL)
89 {
90 l_fs = (double *)malloc (pv->len * sizeof (double));
91 r_fs = (double *)malloc (pv->len * sizeof (double));
92 CHECK_MALLOC (l_fs, "pv_complex_play_step");
93 CHECK_MALLOC (r_fs, "pv_complex_play_step");
94
95 l_ft = (double *)malloc (pv->len * sizeof (double));
96 r_ft = (double *)malloc (pv->len * sizeof (double));
97 CHECK_MALLOC (l_ft, "pv_complex_play_step");
98 CHECK_MALLOC (r_ft, "pv_complex_play_step");
99
100 l_tmp = (double *)malloc (pv->len * sizeof (double));
101 r_tmp = (double *)malloc (pv->len * sizeof (double));
102 CHECK_MALLOC (l_tmp, "pv_complex_play_step");
103 CHECK_MALLOC (r_tmp, "pv_complex_play_step");
104 }
105
106 long status;
107 // read the starting frame (cur)
108 status = read_and_FFT_stereo (pv, cur, l_fs, r_fs);
109 if (status != pv->len)
110 {
111 return 0; // no output
112 }
113
114 // read the terminal frame (cur + hop_syn)
115 status = read_and_FFT_stereo (pv, cur + pv->hop_syn, l_ft, r_ft);
116 if (status != pv->len)
117 {
118 return 0; // no output
119 }
120
121 int flag_left_cur;
122 int flag_right_cur;
123 if (check_zero (pv->len, l_fs) == 0 ||
124 check_zero (pv->len, l_ft) == 0)
125 {
126 flag_left_cur = 0; // inactive
127 }
128 else
129 {
130 flag_left_cur = 1; // active
131 }
132
133 if (check_zero (pv->len, r_fs) == 0 ||
134 check_zero (pv->len, r_ft) == 0)
135 {
136 flag_right_cur = 0; // inactive
137 }
138 else
139 {
140 flag_right_cur = 1; // active
141 }
142
143
144 int i;
145
146 // left channel
147 if (flag_left_cur == 1)
148 {
149 // check l_f_old[]
150 if (pv->flag_left == 0)
151 {
152 if (pv->flag_lock == 0) // no phase lock
153 {
154 for (i = 0; i < pv->len; i ++)
155 {
156 pv->l_f_old [i] = l_fs [i];
157 }
158 }
159 else // loose phase lock
160 {
161 // apply loose phase lock
162 HC_puckette_lock (pv->len, l_fs, pv->l_f_old);
163 }
164
165 pv->flag_left = 1;
166 }
167
168 // generate the frame (out_0 + (n+1) * hop_syn), that is, "u_i"
169 if (pv->flag_lock == 0) // no phase lock
170 {
171 // Y[u_i] = X[t_i] (Y[u_{i-1}]/X[s_i]) / |Y[u_{i-1}]/X[s_i]|
172 HC_complex_phase_vocoder (pv->len, l_fs, l_ft, pv->l_f_old,
173 pv->l_f_old);
174 // already backed up for the next step in [lr]_f_old[]
175 apply_invFFT_mono (pv, pv->l_f_old, pv->window_scale, pv->l_out);
176 }
177 else // loose phase lock
178 {
179 // Y[u_i] = X[t_i] (Z[u_{i-1}]/X[s_i]) / |Z[u_{i-1}]/X[s_i]|
180 HC_complex_phase_vocoder (pv->len, l_fs, l_ft, pv->l_f_old,
181 l_tmp);
182 // apply loose phase lock and store for the next step
183 HC_puckette_lock (pv->len, l_tmp, pv->l_f_old);
184
185 apply_invFFT_mono (pv, l_tmp, pv->window_scale, pv->l_out);
186 }
187 }
188
189
190 // right channel
191 if (flag_right_cur == 1)
192 {
193 // check l_f_old[]
194 if (pv->flag_right == 0)
195 {
196 if (pv->flag_lock == 0) // no phase lock
197 {
198 for (i = 0; i < pv->len; i ++)
199 {
200 pv->r_f_old [i] = r_fs [i];
201 }
202 }
203 else // loose phase lock
204 {
205 // apply loose phase lock
206 HC_puckette_lock (pv->len, r_fs, pv->r_f_old);
207 }
208 pv->flag_right = 1;
209 }
210
211 // generate the frame (out_0 + (n+1) * hop_syn), that is, "u_i"
212 if (pv->flag_lock == 0) // no phase lock
213 {
214 // Y[u_i] = X[t_i] (Y[u_{i-1}]/X[s_i]) / |Y[u_{i-1}]/X[s_i]|
215 HC_complex_phase_vocoder (pv->len, r_fs, r_ft, pv->r_f_old,
216 pv->r_f_old);
217 // already backed up for the next step in [lr]_f_old[]
218 apply_invFFT_mono (pv, pv->r_f_old, pv->window_scale, pv->r_out);
219 }
220 else // loose phase lock
221 {
222 // Y[u_i] = X[t_i] (Z[u_{i-1}]/X[s_i]) / |Z[u_{i-1}]/X[s_i]|
223 HC_complex_phase_vocoder (pv->len, r_fs, r_ft, pv->r_f_old,
224 r_tmp);
225 // apply loose phase lock and store for the next step
226 HC_puckette_lock (pv->len, r_tmp, pv->r_f_old);
227
228 apply_invFFT_mono (pv, r_tmp, pv->window_scale, pv->r_out);
229 }
230 }
231
232
233 // output
234 //status = pv_complex_play_resample (pv);
235 if (pv->hop_syn != pv->hop_res)
236 {
237 pv_complex_resample (pv, left, right);
238 }
239 else
240 {
241 for (i = 0; i < pv->hop_res; i ++)
242 {
243 left[i] = pv->l_out[i];
244 right[i] = pv->r_out[i];
245 }
246 }
247
248
249 /* shift [lr]_out by hop_syn */
250 for (i = 0; i < pv->len; i ++)
251 {
252 pv->l_out [i] = pv->l_out [i + pv->hop_syn];
253 pv->r_out [i] = pv->r_out [i + pv->hop_syn];
254 }
255 for (i = pv->len; i < pv->len + pv->hop_syn; i ++)
256 {
257 pv->l_out [i] = 0.0;
258 pv->r_out [i] = 0.0;
259 }
260
261 return (pv->hop_res);
262 }
263
264 /**
265 * The process callback for this JACK application is called in a
266 * special realtime thread once for each audio cycle.
267 *
268 * This client follows a simple rule: when the JACK transport is
269 * running, copy the input port to the output. When it stops, exit.
270 */
271 int
my_jack_process(jack_nframes_t nframes,void * arg)272 my_jack_process (jack_nframes_t nframes, void *arg)
273 {
274 static long play_cur = 0;
275
276 struct pv_jack *pv_jack = (struct pv_jack *)arg;
277
278 static jack_default_audio_sample_t *in = NULL;
279 static jack_nframes_t in_len = 0;
280 if (in == NULL)
281 {
282 in = (jack_default_audio_sample_t *)malloc
283 (sizeof (jack_default_audio_sample_t) * nframes);
284 in_len = nframes;
285 }
286 else if (in_len < nframes)
287 {
288 in = (jack_default_audio_sample_t *)realloc
289 (in,
290 sizeof (jack_default_audio_sample_t) * nframes);
291 in_len = nframes;
292 }
293
294 static double *left = NULL;
295 static double *right = NULL;
296 static int hop_res0 = 0;
297 static int cur = 0;
298 if (left == NULL)
299 {
300 left = (double *)malloc (sizeof (double) * pv_jack->pv->hop_res);
301 right = (double *)malloc (sizeof (double) * pv_jack->pv->hop_res);
302 CHECK_MALLOC (left, "my_jack_process");
303 CHECK_MALLOC (right, "my_jack_process");
304 hop_res0 = pv_jack->pv->hop_res;
305 cur = hop_res0; // no data left
306 }
307 else if (hop_res0 < pv_jack->pv->hop_res)
308 {
309 left = (double *)realloc (left, sizeof (double) * pv_jack->pv->hop_res);
310 right = (double *)realloc (right, sizeof (double) * pv_jack->pv->hop_res);
311 CHECK_MALLOC (left, "my_jack_process");
312 CHECK_MALLOC (right, "my_jack_process");
313 hop_res0 = pv_jack->pv->hop_res;
314 cur = hop_res0; // no data left
315 }
316
317 // check
318 extern FILE *err_log;
319 fprintf (err_log, "cur = %d\n", cur);
320
321 jack_transport_state_t ts = jack_transport_query (pv_jack->client, NULL);
322 if (ts == JackTransportRolling)
323 {
324 if (pv_jack->state == Init)
325 {
326 pv_jack->state = Run;
327 }
328
329 jack_default_audio_sample_t *out
330 = (jack_default_audio_sample_t *)
331 jack_port_get_buffer (pv_jack->out, nframes);
332
333 // the process for nframes
334 int i, j;
335 // paste the data left in left[] and right[] from cur to hop_res0
336 for (i = 0, j = cur;
337 (j < hop_res0) && (i < nframes);
338 i ++, j ++)
339 {
340 in[i] = (jack_default_audio_sample_t)(0.5*(left[j] + right[j]));
341 }
342 cur = j;
343 cur = cur % hop_res0;
344
345 // if the data is not enough,
346 while (i < nframes)
347 {
348 // process further data (next hop_res frames)
349 if (cur != 0)
350 {
351 fprintf (stderr, "cur update failed...\n");
352 fprintf (err_log, "cur update failed...\n");
353 fprintf (err_log, "cur = %d\n", cur);
354 fclose (err_log);
355 exit (1);
356 }
357 jack_pv_complex_play_step (pv_jack->pv, play_cur, left, right);
358 play_cur += pv_jack->pv->hop_ana;
359
360 // then, paste the data in left[] and right[] from 0 to hop_res0
361 int j;
362 for (j = 0;
363 (j < hop_res0) && (i < nframes);
364 j ++, i ++)
365 {
366 in[i] = (jack_default_audio_sample_t)(0.5*(left[j] + right[j]));
367 }
368 cur = j;
369 cur = cur % hop_res0;
370 }
371
372 // now, the data in in[] is enough to pass jack server
373 memcpy (out, in,
374 sizeof (jack_default_audio_sample_t) * nframes);
375 }
376 else if (ts == JackTransportStopped)
377 {
378 if (pv_jack->state == Run)
379 {
380 pv_jack->state = Exit;
381 }
382 }
383
384 return 0;
385 }
386
387 /**
388 * JACK calls this shutdown_callback if the server ever shuts down or
389 * decides to disconnect the client.
390 */
391 void
jack_shutdown(void * arg)392 jack_shutdown (void *arg)
393 {
394 exit (1);
395 }
396
397 /* start jack process for output (playback)
398 * INPUT
399 * OUTPUT
400 * returned value : struct pv_jack *pv_jack.
401 */
402 struct pv_jack *
pv_jack_init(struct pv_complex * pv)403 pv_jack_init (struct pv_complex *pv)
404 {
405 struct pv_jack *pv_jack
406 = (struct pv_jack *)malloc (sizeof (struct pv_jack));
407 CHECK_MALLOC (pv_jack, "main");
408
409 pv_jack->pv = pv;
410 pv_jack->state = Init;
411
412
413 char *client_name = (char *)malloc (sizeof (char) * 8);
414 strcpy (client_name, "jack-pv");
415
416 const char *server_name = NULL;
417
418 /* open a client connection to the JACK server */
419 jack_options_t options = JackNullOption;
420 jack_status_t jack_status;
421 pv_jack->client
422 = jack_client_open (client_name, options, &jack_status, server_name);
423 if (pv_jack->client == NULL)
424 {
425 fprintf (stderr, "jack_client_open() failed, "
426 "status = 0x%2.0x\n", jack_status);
427 if (jack_status & JackServerFailed)
428 {
429 fprintf (stderr, "Unable to connect to JACK server\n");
430 }
431 exit (1);
432 }
433 if (jack_status & JackServerStarted)
434 {
435 fprintf (stderr, "JACK server started\n");
436 }
437 if (jack_status & JackNameNotUnique)
438 {
439 free (client_name);
440 client_name = jack_get_client_name(pv_jack->client);
441 fprintf (stderr, "unique name `%s' assigned\n", client_name);
442 }
443
444 /* tell the JACK server to call `process()' whenever
445 there is work to be done.
446 */
447 jack_set_process_callback (pv_jack->client, my_jack_process, pv_jack);
448
449 /* tell the JACK server to call `jack_shutdown()' if
450 it ever shuts down, either entirely, or if it
451 just decides to stop calling us.
452 */
453 jack_on_shutdown (pv_jack->client, jack_shutdown, pv_jack);
454
455
456 /* display the current sample rate.
457 */
458 printf ("engine sample rate: %" PRIu32 "\n",
459 jack_get_sample_rate (pv_jack->client));
460
461 /* create the output ports */
462 pv_jack->out = jack_port_register (pv_jack->client, "output",
463 JACK_DEFAULT_AUDIO_TYPE,
464 JackPortIsOutput, 0);
465
466 if (pv_jack->out == NULL)
467 {
468 fprintf(stderr, "no more JACK ports available\n");
469 exit (1);
470 }
471
472 /* Tell the JACK server that we are ready to roll. Our
473 * process() callback will start running now. */
474 if (jack_activate (pv_jack->client))
475 {
476 fprintf (stderr, "cannot activate client");
477 exit (1);
478 }
479
480 /* Connect the ports. You can't do this before the client is
481 * activated, because we can't make connections to clients
482 * that aren't running. Note the confusing (but necessary)
483 * orientation of the driver backend ports: playback ports are
484 * "input" to the backend, and capture ports are "output" from
485 * it.
486 */
487 const char **ports;
488 ports = jack_get_ports (pv_jack->client, NULL, NULL,
489 JackPortIsPhysical|JackPortIsInput);
490 if (ports == NULL)
491 {
492 fprintf(stderr, "no physical playback ports\n");
493 exit (1);
494 }
495 if (jack_connect (pv_jack->client, jack_port_name (pv_jack->out), ports[0]))
496 {
497 fprintf (stderr, "cannot connect output ports\n");
498 }
499 free (ports);
500
501
502 return (pv_jack);
503 }
504
505 void
pv_jack_free(struct pv_jack * pv_jack)506 pv_jack_free (struct pv_jack *pv_jack)
507 {
508 if (pv_jack != NULL) free (pv_jack);
509 }
510
511
512 #define Y_file (1)
513 #define Y_frames (2)
514 #define Y_loop (3)
515
516 #define Y_rate (5)
517 #define Y_pitch (6)
518 #define Y_lock (8)
519 #define Y_window (10)
520 #define Y_len (11)
521 #define Y_hop_syn (12)
522 #define Y_hop_ana (13)
523 #define Y_hop_res (14)
524
525 #define Y_status (16)
526 #define Y_comment (18)
527
528 static void
curses_print_window(int flag_window)529 curses_print_window (int flag_window)
530 {
531 switch (flag_window)
532 {
533 case 0: // square (no window)
534 mvprintw (Y_window, 1, "window : square ");
535 break;
536 case 1: // parzen window
537 mvprintw (Y_window, 1, "window : parzen ");
538 break;
539 case 2: // welch window
540 mvprintw (Y_window, 1, "window : welch ");
541 break;
542 case 3: // hanning window
543 mvprintw (Y_window, 1, "window : hanning ");
544 break;
545 case 4: // hamming window
546 mvprintw (Y_window, 1, "window : hamming ");
547 break;
548 case 5: // blackman window
549 mvprintw (Y_window, 1, "window : blackman");
550 break;
551 case 6: // steeper 30-dB/octave rolloff window
552 mvprintw (Y_window, 1, "window : steeper ");
553 break;
554 }
555 }
556
557 static void
curses_print_pitch(int pv_pitch)558 curses_print_pitch (int pv_pitch)
559 {
560 int oct;
561 int key;
562 if (pv_pitch < 0)
563 {
564 oct = (-pv_pitch-1) / 12; // -12 == -2 octaves
565 oct = -oct-1;
566 key = (-pv_pitch-1) % 12;
567 key = 11-key;
568 }
569 else
570 {
571 oct = pv_pitch / 12;
572 key = pv_pitch % 12;
573 }
574
575 switch (key)
576 {
577 case 0: // 1 degree
578 mvprintw (Y_pitch, 1, "pitch : C %+2d (%+3d)", oct, pv_pitch);
579 break;
580 case 1: // 1.5
581 mvprintw (Y_pitch, 1, "pitch : C# %+2d (%+3d)", oct, pv_pitch);
582 break;
583 case 2: // +2nd
584 mvprintw (Y_pitch, 1, "pitch : D %+2d (%+3d)", oct, pv_pitch);
585 break;
586 case 3: // 2.5
587 mvprintw (Y_pitch, 1, "pitch : Eb %+2d (%+3d)", oct, pv_pitch);
588 break;
589 case 4: // +3
590 mvprintw (Y_pitch, 1, "pitch : E %+2d (%+3d)", oct, pv_pitch);
591 break;
592 case 5: // +4th
593 mvprintw (Y_pitch, 1, "pitch : F %+2d (%+3d)", oct, pv_pitch);
594 break;
595 case 6: // 4.5
596 mvprintw (Y_pitch, 1, "pitch : F# %+2d (%+3d)", oct, pv_pitch);
597 break;
598 case 7: // +5th
599 mvprintw (Y_pitch, 1, "pitch : G %+2d (%+3d)", oct, pv_pitch);
600 break;
601 case 8: // 5.5
602 mvprintw (Y_pitch, 1, "pitch : G# %+2d (%+3d)", oct, pv_pitch);
603 break;
604 case 9: // +6th
605 mvprintw (Y_pitch, 1, "pitch : A %+2d (%+3d)", oct, pv_pitch);
606 break;
607 case 10: // m7th
608 mvprintw (Y_pitch, 1, "pitch : Bb %+2d (%+3d)", oct, pv_pitch);
609 break;
610 case 11: // M7
611 mvprintw (Y_pitch, 1, "pitch : B %+2d (%+3d)", oct, pv_pitch);
612 break;
613 default:
614 break;
615 }
616 }
617
618 static void
curses_print_pv(const char * file,struct pv_complex * pv,int flag_play,long frame0,long frame1,double pv_pitch,double pv_rate)619 curses_print_pv (const char *file,
620 struct pv_complex *pv,
621 int flag_play,
622 long frame0, long frame1,
623 double pv_pitch,
624 double pv_rate)
625 {
626 mvprintw (0, 0, "========== pv ==========");
627 mvprintw (Y_file, 1, "file : %s", file);
628 mvprintw (Y_frames, 1, "current : %010ld / %010ld", 0, pv->sfinfo->frames);
629 mvprintw (Y_loop, 1, "loop : %010ld - %010ld", frame0, frame1);
630 //mvprintw (Y_pitch, 1, "pitch : %-5.0f", pv_pitch);
631 curses_print_pitch (pv_pitch);
632 mvprintw (Y_rate, 1, "rate : %-5.1f", pv_rate);
633 mvprintw (Y_len, 1, "fft-len : %06ld", pv->len);
634 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
635 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
636 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
637
638 if (flag_play == 0) mvprintw(Y_status, 1, "status : stop");
639 else mvprintw(Y_status, 1, "status : play");
640
641 if (pv->flag_lock == 0) mvprintw(Y_lock, 1, "phase-lock : off");
642 else mvprintw(Y_lock, 1, "phase-lock : on ");
643 curses_print_window (pv->flag_window);
644
645 // help message
646 mvprintw (Y_loop, 41, "< > by cur, [ { expand } ]");
647 mvprintw (Y_pitch, 41, "UP / DOWN");
648 mvprintw (Y_rate, 41, "LEFT / RIGHT");
649 mvprintw (Y_hop_syn, 41, "H / h");
650 mvprintw (Y_status, 41, "SPACE");
651 mvprintw (Y_lock, 41, "L");
652 mvprintw (Y_window, 41, "W");
653
654 mvprintw (Y_comment-1, 0, "----------------------------------------");
655 }
656
657 /* change rate and pitch (note that hop_syn is fixed)
658 * INPUT
659 * pv : struct pv_complex
660 * rate : rate of speed (1 == same speed, negative == backward)
661 * pitch : pitch-shift (0 == no-shift, +1(-1) = half-note up(down))
662 * OUTPUT
663 * pv->hop_res :
664 * pv->hop_ana :
665 */
666 void
pv_complex_change_rate_pitch_(struct pv_complex * pv,int sr_in,int sr_out,double rate,double pitch)667 pv_complex_change_rate_pitch_ (struct pv_complex *pv,
668 int sr_in, int sr_out,
669 double rate,
670 double pitch)
671 {
672 double rate0 = (double)sr_out / (double)sr_in;
673 pv->hop_res = (long)(rate0 * (double)pv->hop_syn * pow (2.0, - pitch / 12.0));
674 pv->hop_ana = (long)((double)pv->hop_res * rate);
675 }
676
677 /* phase vocoder by complex arithmetics with fixed hops.
678 */
pv_complex_curses_jack(const char * file,long len,long hop_syn)679 void pv_complex_curses_jack (const char *file,
680 long len, long hop_syn)
681 {
682 // ncurses initializing
683 initscr(); /* Start curses mode */
684 raw(); /* Line buffering disabled */
685 keypad(stdscr, TRUE); /* We get F1, F2 etc.. */
686 noecho(); /* Don't echo() while we do getch */
687 nodelay(stdscr, TRUE); /* Don't wait the key press */
688
689
690 int flag_window = 3;
691 struct pv_complex *pv
692 = pv_complex_init (len, hop_syn, flag_window);
693 CHECK_MALLOC (pv, "pv_complex_curses");
694
695 // open input file
696 SNDFILE *sf = NULL;
697 SF_INFO sfinfo;
698 memset (&sfinfo, 0, sizeof (sfinfo));
699 sf = sf_open (file, SFM_READ, &sfinfo);
700 if (sf == NULL)
701 {
702 fprintf (stderr, "fail to open %s\n", file);
703 exit (1);
704 }
705 //sndfile_print_info (&sfinfo);
706
707 pv_complex_set_input (pv, sf, &sfinfo);
708
709 /*
710 ao_device *ao = NULL;
711 ao = ao_init_16_stereo (sfinfo.samplerate, 0);
712 pv_complex_set_output_ao (pv, ao);
713 */
714
715 // jack initialization
716 struct pv_jack *pv_jack = pv_jack_init (pv);
717 int jack_sr = (int)jack_get_sample_rate (pv_jack->client);
718 extern FILE *err_log;
719 err_log = fopen ("jack-pv.log", "w");
720
721
722 // initial values
723 double pv_rate = 1.0;
724 double pv_pitch = 0.0;
725 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
726 pv_rate, pv_pitch);
727 fprintf (stderr, "# samplerates: %d %d\n", sfinfo.samplerate, jack_sr);
728
729 long frame0 = 0;
730 long frame1 = (long)pv->sfinfo->frames - 1;
731 pv->flag_lock = 0; // no phase-lock
732 int flag_play = 1;
733 long play_cur = 0;
734
735 long len_1sec = (long)(pv->sfinfo->samplerate /* Hz */);
736 long len_10sec = (long)(10 * pv->sfinfo->samplerate /* Hz */);
737
738 mvprintw (Y_comment, 1, "Welcome WaoN-pv in curses mode.");
739 curses_print_pv (file, pv, flag_play, frame0, frame1,
740 pv_pitch, pv_rate);
741
742 // main loop
743 //long status = 1; // TRUE
744 do
745 {
746 // scan keyboard
747 int ch = getch();
748 switch (ch)
749 {
750 case ERR: // no key event
751 break;
752
753 case ' ': // SPACE
754 flag_play++;
755 flag_play = flag_play % 2;
756 if (flag_play == 0) mvprintw(Y_status, 1, "status : stop");
757 else mvprintw(Y_status, 1, "status : play");
758 break;
759
760 case '>':
761 case '.':
762 frame1 = play_cur;
763 mvprintw (Y_loop, 1, "loop : %010ld - %010ld",
764 frame0, frame1);
765 break;
766
767 case '<':
768 case ',':
769 frame0 = play_cur;
770 mvprintw (Y_loop, 1, "loop : %010ld - %010ld",
771 frame0, frame1);
772 break;
773
774 case ']':
775 frame1 += len_10sec;
776 if (frame1 >= pv->sfinfo->frames - 1) frame1 = pv->sfinfo->frames - 1;
777 mvprintw (Y_loop, 1, "loop : %010ld - %010ld",
778 frame0, frame1);
779 break;
780
781 case '}':
782 frame1 += len_1sec;
783 if (frame1 >= pv->sfinfo->frames - 1) frame1 = pv->sfinfo->frames - 1;
784 mvprintw (Y_loop, 1, "loop : %010ld - %010ld",
785 frame0, frame1);
786 break;
787
788 case '[':
789 frame0 -= len_10sec;
790 if (frame0 < 0) frame0 = 0;
791 mvprintw (Y_loop, 1, "loop : %010ld - %010ld",
792 frame0, frame1);
793 break;
794
795 case '{':
796 frame0 -= len_1sec;
797 if (frame0 < 0) frame0 = 0;
798 mvprintw (Y_loop, 1, "loop : %010ld - %010ld",
799 frame0, frame1);
800 break;
801
802 case 'L':
803 case 'l':
804 pv->flag_lock++;
805 pv->flag_lock = pv->flag_lock % 2;
806
807 if (pv->flag_lock == 0) mvprintw(Y_lock, 1, "phase-lock : off");
808 else mvprintw(Y_lock, 1, "phase-lock : on ");
809 break;
810
811 case 'W':
812 case 'w':
813 pv->flag_window++;
814 pv->flag_window = pv->flag_window % 7; // 0 to 6
815
816 // reset scale factor
817 pv->window_scale
818 = get_scale_factor_for_window (pv->len, pv->hop_syn,
819 pv->flag_window);
820 curses_print_window (pv->flag_window);
821 break;
822
823 case 'H':
824 pv->hop_syn *= 2;
825 if (pv->hop_syn > len) pv->hop_syn = len;
826 // hop_res, hop_ana depend on hop_syn
827 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
828 pv_rate, pv_pitch);
829 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
830 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
831 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
832 break;
833
834 case 'h':
835 pv->hop_syn /= 2;
836 if (pv->hop_syn < 1) pv->hop_syn = 1;
837 // hop_res, hop_ana depend on hop_syn
838 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
839 pv_rate, pv_pitch);
840 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
841 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
842 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
843 break;
844
845 case KEY_UP:
846 pv_pitch += 1.0;
847 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
848 pv_rate, pv_pitch);
849 curses_print_pitch (pv_pitch);
850 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
851 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
852 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
853 break;
854
855 case KEY_DOWN:
856 pv_pitch -= 1.0;
857 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
858 pv_rate, pv_pitch);
859 curses_print_pitch (pv_pitch);
860 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
861 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
862 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
863 break;
864
865 case KEY_LEFT:
866 pv_rate -= 0.1;
867 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
868 pv_rate, pv_pitch);
869 mvprintw (Y_rate, 1, "rate : %-5.1f", pv_rate);
870 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
871 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
872 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
873 break;
874
875 case KEY_RIGHT:
876 pv_rate += 0.1;
877 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
878 pv_rate, pv_pitch);
879 mvprintw (Y_rate, 1, "rate : %-5.1f", pv_rate);
880 mvprintw (Y_hop_syn,1, "hop(syn) : %06ld", pv->hop_syn);
881 mvprintw (Y_hop_ana,1, "hop(ana) : %06ld", pv->hop_ana);
882 mvprintw (Y_hop_res,1, "hop(res) : %06ld", pv->hop_res);
883 break;
884
885 case KEY_HOME:
886 case 'R':
887 case 'r':
888 frame0 = 0;
889 frame1 = (long)pv->sfinfo->frames - 1;
890 pv_rate = 1.0;
891 pv_pitch = 0.0;
892 pv->hop_syn = hop_syn; // value in the argument
893 pv_complex_change_rate_pitch_ (pv, sfinfo.samplerate, jack_sr,
894 pv_rate, pv_pitch);
895 curses_print_pv (file, pv, flag_play, frame0, frame1,
896 pv_pitch, pv_rate);
897 mvprintw(Y_comment, 1, "reset everything");
898 break;
899
900 case 'Q':
901 case 'q':
902 //status = 0;
903 pv_jack->state = Exit;
904 mvprintw(Y_comment, 1, "good-bye!");
905 break;
906
907 /*
908 defaut :
909 break;
910 */
911 }
912 mvprintw (Y_frames, 1, "current : %010ld", play_cur);
913 refresh();
914 }
915 //while (status == 1);
916 while (pv_jack->state != Exit);
917
918 jack_client_close (pv_jack->client);
919 pv_jack_free (pv_jack);
920
921 pv_complex_free (pv);
922 sf_close (sf) ;
923
924
925 /* End ncurses mode */
926 endwin();
927 }
928