Merged stereo support, mostly coded by tczy <tczy@wre.ath.cx>.
authorStefan Westerfeld <stefan@space.twc.de>
Wed, 24 Nov 2010 19:07:57 +0000 (20:07 +0100)
committerStefan Westerfeld <stefan@space.twc.de>
Wed, 24 Nov 2010 19:07:57 +0000 (20:07 +0100)
src/jacksampler.cc

index 40bbdd8..b2634e8 100644 (file)
@@ -78,6 +78,7 @@ isNoteOff (const jack_midi_event_t& event)
 }
 
 JackSampler::JackSampler() :
+  n_output_ports (1),
   voices (256),
   instrument (1),
   pedal_down (false),
@@ -100,7 +101,9 @@ JackSampler::init (const Options& options, jack_client_t *client, int argc, char
   jack_mix_freq = jack_get_sample_rate (client);
 
   input_port = jack_port_register (client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
-  output_port = jack_port_register (client, "audio_out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+  output_port_1 = jack_port_register (client, "audio_out_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+  if (n_output_ports == 2)
+    output_port_2 = jack_port_register (client, "audio_out_2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
 
   if (jack_activate (client))
     {
@@ -112,8 +115,13 @@ JackSampler::init (const Options& options, jack_client_t *client, int argc, char
 int
 JackSampler::process (jack_nframes_t nframes)
 {
-  jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
+  jack_default_audio_sample_t *out_1;
+  jack_default_audio_sample_t *out_2;
+  out_1 = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port_1, nframes);
+  if (n_output_ports == 2)
+     out_2 = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port_2, nframes);
   void* port_buf = jack_port_get_buffer (input_port, nframes);
+
   jack_nframes_t event_count = jack_midi_get_event_count (port_buf);
   jack_midi_event_t in_event;
   jack_nframes_t event_index = 0;
@@ -214,22 +222,45 @@ JackSampler::process (jack_nframes_t nframes)
         }
 
       // generate one sample
-      out[i] = 0.0;
+      out_1[i] = 0.0;
+      if (n_output_ports == 2)
+       out_2[i] = 0.0;
       for (int v = 0; v < voices.size(); v++)
         {
           if (voices[v].state != Voice::UNUSED)
             {
-              voices[v].pos += voices[v].frequency / voices[v].sample->osc_freq *
-                               voices[v].sample->mix_freq / jack_mix_freq;
+             int ipos = voices[v].pos;
+             double dpos = voices[v].pos - ipos;
+
+             switch (voices[v].sample->channels)
+               {
+               case 1:
+                 if (ipos < (voices[v].sample->pcm_data.size() - 1))
+                   {
+                     double left = voices[v].sample->pcm_data[ipos];
+                     double right = voices[v].sample->pcm_data[ipos + 1];
+                      double out = (left * (1.0 - dpos) + right * dpos) * voices[v].env * voices[v].velocity;
+                     out_1[i] += out;
+                     if (n_output_ports == 2)
+                       out_2[i] += out;
+                   }
+                 break;
+               case 2:  // assert (n_output_ports == 2);
+                 if (ipos * 2 < (voices[v].sample->pcm_data.size() - 3))
+                   {
+                     double left = voices[v].sample->pcm_data[ipos * 2];
+                     double right = voices[v].sample->pcm_data[ipos * 2 + 2];
+                     out_1[i] += (left * (1.0 - dpos) + right * dpos) * voices[v].env * voices[v].velocity;
+
+                     left = voices[v].sample->pcm_data[ipos * 2 + 1];
+                     right = voices[v].sample->pcm_data[ipos * 2 + 3];
+                     out_2[i] += (left * (1.0 - dpos) + right * dpos) * voices[v].env * voices[v].velocity;
+                   }
+                 break;
+               }
 
-              int ipos = voices[v].pos;
-              double dpos = voices[v].pos - ipos;
-              if (ipos < (voices[v].sample->pcm_data.size() - 1))
-                {
-                  double left = voices[v].sample->pcm_data[ipos];
-                  double right = voices[v].sample->pcm_data[ipos + 1];
-                  out[i] += (left * (1.0 - dpos) + right * dpos) * voices[v].env * voices[v].velocity;
-                }
+              voices[v].pos += voices[v].frequency / voices[v].sample->osc_freq *
+                              voices[v].sample->mix_freq / jack_mix_freq;
             }
           if (voices[v].state == Voice::RELEASE_DELAY)
             {
@@ -247,8 +278,13 @@ JackSampler::process (jack_nframes_t nframes)
                 }
             }
         }
-      out[i] *= 0.333;    /* empiric */
-      mout = std::max (fabs (out[i]), mout);
+      out_1[i] *= 0.333;    /* empiric */
+      mout = std::max (fabs (out_1[i]), mout);
+      if (n_output_ports == 2)
+        {
+         out_2[i] *= 0.333;
+         mout = std::max (fabs (out_2[i]), mout);
+       }
     }
   return 0;
 }
@@ -260,7 +296,7 @@ JackSampler::jack_process (jack_nframes_t nframes, void *arg)
   return instance->process (nframes);
 }
 
-void
+int
 JackSampler::load_note (const Options& options, int note, const char *file_name, int instrument)
 {
   /* open input */
@@ -295,6 +331,7 @@ JackSampler::load_note (const Options& options, int note, const char *file_name,
     }
 
   Sample s;
+  s.channels = waveDsc->n_channels;
 
   vector<float> block (1024);
   uint64 pos = 0;
@@ -307,12 +344,14 @@ JackSampler::load_note (const Options& options, int note, const char *file_name,
         s.pcm_data.push_back (block[i]);
       pos += r;
     }
-  printf ("loaded sample, length = %ld\n", s.pcm_data.size());
+  printf ("loaded sample, length = %ld, channels = %d\n", s.pcm_data.size(), s.channels);
   s.mix_freq = gsl_data_handle_mix_freq (dhandle);
   s.osc_freq = freqFromNote (note);
   s.instrument = instrument;
   s.file_name = file_name;
   samples.push_back (s);
+
+  return s.channels;
 }
 
 void
@@ -328,7 +367,8 @@ JackSampler::parse_config (const Options& options, int instrument, const char *n
 
       if (cfg.command ("sample", note, file))
         {
-          load_note (options, note, file.c_str(), instrument);
+         if (load_note (options, note, file.c_str(), instrument) == 2)
+           n_output_ports = 2;
           printf ("NOTE %d FILE %s\n", note, file.c_str());
         }
       else if (cfg.command ("release_delay", d))
@@ -377,6 +417,7 @@ JackSampler::status()
         g_assert_not_reached();
     }
   printf ("sampling rate:   %.2f\n", jack_mix_freq);
+  printf ("output ports:    %d\n", n_output_ports);
   printf ("instruments:     %d\n", instrument_count);
   printf ("active instr.:   %d\n", instrument);
   printf ("total voices:    %d\n", voices.size());