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
;
64 int attack_percent
= 1, decay_percent
= 10;
65 const char *bpm_string
= "bpm";
66 jack_options_t options
= JackNullOption
;
70 /* Initial Jack setup, get sample rate */
71 if ((client
= jack_client_open (client_name
, options
, &status
)) == 0) {
72 fprintf (stderr
, "jack server not running?\n");
76 jack_set_process_callback (client
, process_audio
, this);
77 jack_on_shutdown (client
, shutdown
, this);
78 output_port
= jack_port_register (client
, bpm_string
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
79 input_port
= jack_port_register (client
, "metro_in", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0);
81 sr
= jack_get_sample_rate (client
);
83 /* setup wave table parameters */
84 wave_length
= 60 * sr
/ bpm
;
85 tone_length
= sr
* dur_arg
/ 1000;
86 attack_length
= tone_length
* attack_percent
/ 100;
87 decay_length
= tone_length
* decay_percent
/ 100;
88 scale
= 2 * PI
* freq
/ sr
;
90 if (tone_length
>= wave_length
) {
92 fprintf (stderr, "invalid duration (tone length = %" PRIu32
93 ", wave length = %" PRIu32 "\n", tone_length,
98 if (attack_length
+ decay_length
> (int)tone_length
) {
99 fprintf (stderr
, "invalid attack/decay\n");
103 /* Build the wave table */
104 wave
= (sample_t
*) malloc (wave_length
* sizeof(sample_t
));
105 amp
= (double *) malloc (tone_length
* sizeof(double));
107 for (i
= 0; i
< attack_length
; i
++) {
108 amp
[i
] = max_amp
* i
/ ((double) attack_length
);
110 for (i
= attack_length
; i
< (int) tone_length
- decay_length
; i
++) {
113 for (i
= (int)tone_length
- decay_length
; i
< (int)tone_length
; i
++) {
114 amp
[i
] = - max_amp
* (i
- (double) tone_length
) / ((double) decay_length
);
116 for (i
= 0; i
< (int) tone_length
; i
++) {
117 wave
[i
] = amp
[i
] * sin (scale
* i
);
119 for (i
= tone_length
; i
< (int) wave_length
; i
++) {
123 if (jack_activate (client
)) {
124 fprintf (stderr
, "cannot activate client");
128 ExternalMetro::~ExternalMetro()
130 jack_deactivate(client
);
131 jack_port_unregister(client
, input_port
);
132 jack_port_unregister(client
, output_port
);
133 jack_client_close(client
);
136 int main (int argc
, char *argv
[])
138 ExternalMetro
* client1
= NULL
;
139 ExternalMetro
* client2
= NULL
;
140 ExternalMetro
* client3
= NULL
;
141 ExternalMetro
* client4
= NULL
;
142 ExternalMetro
* client5
= NULL
;
144 printf("Testing multiple Jack clients in one process: open 5 metro clients...\n");
145 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
146 client2
= new ExternalMetro(600, 0.4, 20, 150, "t2");
147 client3
= new ExternalMetro(1000, 0.4, 20, 110, "t3");
148 client4
= new ExternalMetro(400, 0.4, 20, 200, "t4");
149 client5
= new ExternalMetro(1500, 0.4, 20, 150, "t5");
151 printf("Type 'c' to close all clients and go to next test...\n");
152 while ((getchar() != 'c')) {
162 printf("Testing quitting the server while a client is running...\n");
163 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
165 printf("Now quit the server, shutdown callback should be called...\n");
166 printf("Type 'c' to move on...\n");
167 while ((getchar() != 'c')) {
171 printf("Closing client...\n");
174 printf("Now start the server again...\n");
175 printf("Type 'c' to move on...\n");
176 while ((getchar() != 'c')) {
180 printf("Opening a new client....\n");
181 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
183 printf("Now quit the server, shutdown callback should be called...\n");
184 printf("Type 'c' to move on...\n");
185 while ((getchar() != 'c')) {
189 printf("Simulating client not correctly closed...\n");
191 printf("Opening a new client....\n");
193 client1
= new ExternalMetro(1200, 0.4, 20, 80, "t1");
195 printf("Cannot open a new client since old one was not closed correctly... OK\n");
198 printf("Type 'q' to quit...\n");
199 while ((getchar() != 'q')) {