File: external_metro.cpp

package info (click to toggle)
jackd2 1.9.22~dfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,984 kB
  • sloc: cpp: 48,694; ansic: 23,970; python: 13,621; sh: 228; makefile: 31
file content (205 lines) | stat: -rw-r--r-- 6,372 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
 Copyright (C) 2002 Anthony Van Groningen

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "external_metro.h"
#include <stdio.h>

typedef jack_default_audio_sample_t sample_t;

const double PI = 3.14;

static void JackSleep(int sec)
{
	#ifdef WIN32
		Sleep(sec * 1000);
	#else
		sleep(sec);
	#endif
}

int ExternalMetro::process_audio (jack_nframes_t nframes, void* arg)
{
    ExternalMetro* metro = (ExternalMetro*)arg;
    sample_t *buffer = (sample_t *) jack_port_get_buffer (metro->output_port, nframes);
    jack_nframes_t frames_left = nframes;

    while (metro->wave_length - metro->offset < frames_left) {
        memcpy (buffer + (nframes - frames_left), metro->wave + metro->offset, sizeof (sample_t) * (metro->wave_length - metro->offset));
        frames_left -= metro->wave_length - metro->offset;
        metro->offset = 0;
    }
    if (frames_left > 0) {
        memcpy (buffer + (nframes - frames_left), metro->wave + metro->offset, sizeof (sample_t) * frames_left);
        metro->offset += frames_left;
    }

    return 0;
}

void ExternalMetro::shutdown (void* arg)
{
    printf("shutdown called..\n");
}

ExternalMetro::ExternalMetro(int freq, double max_amp, int dur_arg, int bpm, const char* client_name)
{
    sample_t scale;
    int i, attack_length, decay_length;
    int attack_percent = 1, decay_percent = 10;
    const char *bpm_string = "bpm";
    jack_options_t options = JackNullOption;
    jack_status_t status;
    offset = 0;

    /* Initial Jack setup, get sample rate */
    if ((client = jack_client_open (client_name, options, &status)) == 0) {
        fprintf (stderr, "jack server not running?\n");
        throw -1;
    }

    jack_set_process_callback (client, process_audio, this);
    jack_on_shutdown (client, shutdown, this);
    output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
    input_port = jack_port_register (client, "metro_in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);

    sr = jack_get_sample_rate (client);

    /* setup wave table parameters */
    wave_length = 60 * sr / bpm;
    tone_length = sr * dur_arg / 1000;
    attack_length = tone_length * attack_percent / 100;
    decay_length = tone_length * decay_percent / 100;
    scale = 2 * PI * freq / sr;

    if (tone_length >= wave_length) {
        /*
        fprintf (stderr, "invalid duration (tone length = %" PRIu32
        	 ", wave length = %" PRIu32 "\n", tone_length,
        	 wave_length);
        */
        return ;
    }
    if (attack_length + decay_length > (int)tone_length) {
        fprintf (stderr, "invalid attack/decay\n");
        return ;
    }

    /* Build the wave table */
    wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
    amp = (double *) malloc (tone_length * sizeof(double));

    for (i = 0; i < attack_length; i++) {
        amp[i] = max_amp * i / ((double) attack_length);
    }
    for (i = attack_length; i < (int) tone_length - decay_length; i++) {
        amp[i] = max_amp;
    }
    for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
        amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
    }
    for (i = 0; i < (int) tone_length; i++) {
        wave[i] = amp[i] * sin (scale * i);
    }
    for (i = tone_length; i < (int) wave_length; i++) {
        wave[i] = 0;
    }

    if (jack_activate (client)) {
        fprintf (stderr, "cannot activate client");
    }
}

ExternalMetro::~ExternalMetro()
{
    jack_deactivate(client);
    jack_port_unregister(client, input_port);
    jack_port_unregister(client, output_port);
    jack_client_close(client);
    free(amp);
    free(wave);
}

int main (int argc, char *argv[])
{
    ExternalMetro* client1 = NULL;
    ExternalMetro* client2 = NULL;
    ExternalMetro* client3 = NULL;
    ExternalMetro* client4 = NULL;
    ExternalMetro* client5 = NULL;

    printf("Testing multiple Jack clients in one process: open 5 metro clients...\n");
    client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1");
    client2 = new ExternalMetro(600, 0.4, 20, 150, "t2");
    client3 = new ExternalMetro(1000, 0.4, 20, 110, "t3");
	client4 = new ExternalMetro(400, 0.4, 20, 200, "t4");
    client5 = new ExternalMetro(1500, 0.4, 20, 150, "t5");

    printf("Type 'c' to close all clients and go to next test...\n");
    while ((getchar() != 'c')) {
        JackSleep(1);
    };

    delete client1;
    delete client2;
    delete client3;
    delete client4;
    delete client5;

    printf("Testing quitting the server while a client is running...\n");
    client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1");

    printf("Now quit the server, shutdown callback should be called...\n");
    printf("Type 'c' to move on...\n");
    while ((getchar() != 'c')) {
        JackSleep(1);
    };

    printf("Closing client...\n");
    delete client1;

    printf("Now start the server again...\n");
    printf("Type 'c' to move on...\n");
    while ((getchar() != 'c')) {
        JackSleep(1);
    };

    printf("Opening a new client....\n");
    client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1");
    
    printf("Now quit the server, shutdown callback should be called...\n");
    printf("Type 'c' to move on...\n");
    while ((getchar() != 'c')) {
        JackSleep(1);
    };

    printf("Simulating client not correctly closed...\n");
    
    printf("Opening a new client....\n"); 
    try {
        client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1");
    } catch (int num) {
        printf("Cannot open a new client since old one was not closed correctly... OK\n"); 
    }

    printf("Type 'q' to quit...\n");
    while ((getchar() != 'q')) {
        JackSleep(1);
    };
    delete client1;
    return 0;
}