2 Copyright (C) 2002 Anthony Van Groningen
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "external_metro.h"
22 typedef jack_default_audio_sample_t sample_t
;
24 const double PI
= 3.14;
26 static void JackSleep(int sec
)
35 int ExternalMetro::process_audio (jack_nframes_t nframes
, void* arg
)
37 ExternalMetro
* metro
= (ExternalMetro
*)arg
;
38 sample_t
*buffer
= (sample_t
*) jack_port_get_buffer (metro
->output_port
, nframes
);
39 jack_nframes_t frames_left
= nframes
;
41 while (metro
->wave_length
- metro
->offset
< frames_left
) {
42 memcpy (buffer
+ (nframes
- frames_left
), metro
->wave
+ metro
->offset
, sizeof (sample_t
) * (metro
->wave_length
- metro
->offset
));
43 frames_left
-= metro
->wave_length
- metro
->offset
;
46 if (frames_left
> 0) {
47 memcpy (buffer
+ (nframes
- frames_left
), metro
->wave
+ metro
->offset
, sizeof (sample_t
) * frames_left
);
48 metro
->offset
+= frames_left
;
54 void ExternalMetro::shutdown (void* arg
)
56 printf("shutdown called..\n");
59 ExternalMetro::ExternalMetro(int freq
, double max_amp
, int dur_arg
, int bpm
, const char* client_name
)
62 int i
, attack_length
, decay_length
;
63 int attack_percent
= 1, decay_percent
= 10;
64 const char *bpm_string
= "bpm";
65 jack_options_t options
= JackNullOption
;
69 /* Initial Jack setup, get sample rate */
70 if ((client
= jack_client_open (client_name
, options
, &status
)) == 0) {
71 fprintf (stderr
, "jack server not running?\n");
75 jack_set_process_callback (client
, process_audio
, this);
76 jack_on_shutdown (client
, shutdown
, this);
77 output_port
= jack_port_register (client
, bpm_string
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
78 input_port
= jack_port_register (client
, "metro_in", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0);
80 sr
= jack_get_sample_rate (client
);
82 /* setup wave table parameters */
83 wave_length
= 60 * sr
/ bpm
;
84 tone_length
= sr
* dur_arg
/ 1000;
85 attack_length
= tone_length
* attack_percent
/ 100;
86 decay_length
= tone_length
* decay_percent
/ 100;
87 scale
= 2 * PI
* freq
/ sr
;
89 if (tone_length
>= wave_length
) {
91 fprintf (stderr, "invalid duration (tone length = %" PRIu32
92 ", wave length = %" PRIu32 "\n", tone_length,
97 if (attack_length
+ decay_length
> (int)tone_length
) {
98 fprintf (stderr
, "invalid attack/decay\n");
102 /* Build the wave table */
103 wave
= (sample_t
*) malloc (wave_length
* sizeof(sample_t
));
104 amp
= (double *) malloc (tone_length
* sizeof(double));
106 for (i
= 0; i
< attack_length
; i
++) {
107 amp
[i
] = max_amp
* i
/ ((double) attack_length
);
109 for (i
= attack_length
; i
< (int) tone_length
- decay_length
; i
++) {
112 for (i
= (int)tone_length
- decay_length
; i
< (int)tone_length
; i
++) {
113 amp
[i
] = - max_amp
* (i
- (double) tone_length
) / ((double) decay_length
);
115 for (i
= 0; i
< (int) tone_length
; i
++) {
116 wave
[i
] = amp
[i
] * sin (scale
* i
);
118 for (i
= tone_length
; i
< (int) wave_length
; i
++) {
122 if (jack_activate (client
)) {
123 fprintf (stderr
, "cannot activate client");
127 ExternalMetro::~ExternalMetro()
129 jack_deactivate(client
);
130 jack_port_unregister(client
, input_port
);
131 jack_port_unregister(client
, output_port
);
132 jack_client_close(client
);
137 int main (int argc
, char *argv
[])
139 ExternalMetro
* client1
= NULL
;
140 ExternalMetro
* client2
= NULL
;
141 ExternalMetro
* client3
= NULL
;
142 ExternalMetro
* client4
= NULL
;
143 ExternalMetro
* client5
= NULL
;
145 printf("Testing multiple Jack clients in one process: open 5 metro clients...\n");
146 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
147 client2
= new ExternalMetro(600, 0.4, 20, 150, "t2");
148 client3
= new ExternalMetro(1000, 0.4, 20, 110, "t3");
149 client4
= new ExternalMetro(400, 0.4, 20, 200, "t4");
150 client5
= new ExternalMetro(1500, 0.4, 20, 150, "t5");
152 printf("Type 'c' to close all clients and go to next test...\n");
153 while ((getchar() != 'c')) {
163 printf("Testing quitting the server while a client is running...\n");
164 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
166 printf("Now quit the server, shutdown callback should be called...\n");
167 printf("Type 'c' to move on...\n");
168 while ((getchar() != 'c')) {
172 printf("Closing client...\n");
175 printf("Now start the server again...\n");
176 printf("Type 'c' to move on...\n");
177 while ((getchar() != 'c')) {
181 printf("Opening a new client....\n");
182 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
184 printf("Now quit the server, shutdown callback should be called...\n");
185 printf("Type 'c' to move on...\n");
186 while ((getchar() != 'c')) {
190 printf("Simulating client not correctly closed...\n");
192 printf("Opening a new client....\n");
194 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
196 printf("Cannot open a new client since old one was not closed correctly... OK\n");
199 printf("Type 'q' to quit...\n");
200 while ((getchar() != 'q')) {