1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #include "smmain.hh"
4 #include "sminstrument.hh"
5 #include "sminsteditwindow.hh"
6 #include "smeventloop.hh"
7 #include "smproject.hh"
8 #include "smmidisynth.hh"
9 #include "smsynthinterface.hh"
10 
11 #include <jack/jack.h>
12 #include <jack/midiport.h>
13 
14 #include <stdio.h>
15 
16 using namespace SpectMorph;
17 
18 class JackSynth : public SignalReceiver
19 {
20   jack_port_t *input_port;
21   jack_port_t *output_port;
22 
23   Project project;
24 public:
25   static int
jack_process(jack_nframes_t nframes,void * arg)26   jack_process (jack_nframes_t nframes, void *arg)
27   {
28     JackSynth *instance = reinterpret_cast<JackSynth *> (arg);
29     return instance->process (nframes);
30   }
31 
32   int
process(jack_nframes_t nframes)33   process (jack_nframes_t nframes)
34   {
35     project.try_update_synth();
36 
37     float     *audio_out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
38     void      *port_buf = jack_port_get_buffer (input_port, nframes);
39     MidiSynth *midi_synth = project.midi_synth();
40 
41     jack_nframes_t event_count = jack_midi_get_event_count (port_buf);
42     for (jack_nframes_t event_index = 0; event_index < event_count; event_index++)
43       {
44         jack_midi_event_t    in_event;
45         jack_midi_event_get (&in_event, port_buf, event_index);
46 
47         midi_synth->add_midi_event (in_event.time, in_event.buffer);
48       }
49     midi_synth->process (audio_out, nframes);
50     return 0;
51   }
52 
JackSynth(jack_client_t * client)53   JackSynth (jack_client_t *client)
54   {
55     project.set_mix_freq (jack_get_sample_rate (client));
56     project.midi_synth()->set_inst_edit (true);
57 
58     jack_set_process_callback (client, jack_process, this);
59 
60     input_port = jack_port_register (client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
61     output_port = jack_port_register (client, "audio_out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
62 
63     if (jack_activate (client))
64       {
65         fprintf (stderr, "cannot activate client");
66         exit (1);
67       }
68   }
69 
70   Project *
get_project()71   get_project()
72   {
73     return &project;
74   }
75 };
76 
77 int
main(int argc,char ** argv)78 main (int argc, char **argv)
79 {
80   Main main (&argc, &argv);
81 
82   jack_client_t *client = jack_client_open ("sminstedit", JackNullOption, NULL);
83   if (!client)
84     {
85       fprintf (stderr, "%s: unable to connect to jack server\n", argv[0]);
86       exit (1);
87     }
88 
89   JackSynth jack_synth (client);
90 
91   bool quit = false;
92 
93   Instrument instrument;
94   if (argc > 1)
95     {
96       Error error = instrument.load (argv[1]);
97       if (error)
98         {
99           fprintf (stderr, "%s: %s: %s.\n", argv[0], argv[1], error.message());
100           return 1;
101         }
102     }
103 
104   EventLoop event_loop;
105   InstEditWindow window (event_loop, &instrument, jack_synth.get_project()->synth_interface());
106 
107   window.show();
108   window.set_close_callback ([&]() { quit = true; });
109 
110   while (!quit)
111     {
112       event_loop.wait_event_fps();
113       event_loop.process_events();
114     }
115   jack_client_close (client);
116 }
117