[BrlCV] My attempt of linking Linux to Eurorack

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[BrlCV] My attempt of linking Linux to Eurorack

Mario Lang
Hi.

As I was recently sucked into the Eurorack world,
I have begun to work on a small C++ project to create tools
for working with control voltages.  My ultimate plan
is to write a small software CV sequencer.

But until then, I am going for low hanging fruits, esp. so that I can
warm up to writing JACK code.  One of these is cv2midiclock.
It takes a CV signal (actually works with Line-In as well, but
my ultimate plan is to use an Expert Sleepers ES-8 to get
DC-coupled AD/DAC) from an audio port and outputs a synced
MIDI Clock on a MIDI port.  Very simple, very basic, but might
be useful, actually.

https://github.com/mlang/brlcv

Disclaimer: This repository will never implement any sort of GUI.
In fact, it is likely that the only user interface the control
voltage sequencer will ever have is going to be based on a Braille display.
You are welcome to fork the code to port it (once it works) to other
user interfaces.  Patches to implement visual UIs will be rejected, as
was the case with my patches to improve GTK Accessibility.

However, if you are fine with CLIs or OSC and have an interest
in CV tools on Linux, you are very welcome to join forces.

P.S.: This repo contains my version of a C++ wrapper for JACK clients.
While it is definitely not complete, it can be used to
implement simple JACK clients in very few lines of code.
If you are into modern C++ (C++14 and beyond), take a look.
If you like/dislike it, send feedback please.

Below is (totally useless) example client:

#include <jack.hpp>

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

template<typename... Features>
using AudioAccumulatorSet = boost::accumulators::accumulator_set<
  float, boost::accumulators::features<Features...>
>;

using Count = boost::accumulators::tag::count;
using Max = boost::accumulators::tag::max;
using Min = boost::accumulators::tag::min;
using Mean = boost::accumulators::tag::mean;
using Variance = boost::accumulators::tag::variance;

class Statistics final : public JACK::Client {
  JACK::AudioIn In;
  AudioAccumulatorSet<Count, Max, Mean, Min, Variance> Accumulator;

public:
  Statistics() : JACK::Client("Statistics"), In(createAudioIn("In")) {}
  int process(std::uint32_t FrameCount) override {
    for (auto &Value: In.buffer(FrameCount)) Accumulator(Value);
    return 0;
  }
  auto max() const { return boost::accumulators::max(Accumulator); }
  auto mean() const { return boost::accumulators::mean(Accumulator); }
  auto min() const { return boost::accumulators::min(Accumulator); }
  auto sampleCount() const { return boost::accumulators::count(Accumulator); }
  auto variance() const { return boost::accumulators::variance(Accumulator); }
};

#include <chrono>
#include <iostream>
#include <thread>

using namespace std::literals::chrono_literals;

int main() {
  Statistics Client;
  std::cout << "Rate: " << Client.sampleRate() << std::endl;

  Client.activate();
  std::this_thread::sleep_for(5s);
  Client.deactivate();

  std::cout << Client.sampleCount() << ": "
            << "mean=" << Client.mean()
            << ", variance=" << Client.variance()
            << ", min=" << Client.min()
            << ", max=" << Client.max()
            << std::endl;
}

--
Happy patching (pun intended),
  ⡍⠁⠗⠊⠕ | Blog: <https://blind.guru/>  GitHub: <https://github.com/mlang/>
  .''`. | Twitter: @blindbird23        FaceBook: disyled
 : :' : | SoundCloud: <soundcloud.com/mario-lang>
 `. `'  | YouTube: <youtube.com/user/mlang23>
   `-
_______________________________________________
Linux-audio-dev mailing list
[hidden email]
https://lists.linuxaudio.org/listinfo/linux-audio-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [BrlCV] My attempt of linking Linux to Eurorack

Kjetil Matheussen-2

Mario Lang:

#include <jack.hpp>

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

template<typename... Features>
using AudioAccumulatorSet = boost::accumulators::accumulator_set<
  float, boost::accumulators::features<Features...>
>;

using Count = boost::accumulators::tag::count;
using Max = boost::accumulators::tag::max;
using Min = boost::accumulators::tag::min;
using Mean = boost::accumulators::tag::mean;
using Variance = boost::accumulators::tag::variance;

class Statistics final : public JACK::Client {
  JACK::AudioIn In;
  AudioAccumulatorSet<Count, Max, Mean, Min, Variance> Accumulator;

public:
  Statistics() : JACK::Client("Statistics"), In(createAudioIn("In")) {}
  int process(std::uint32_t FrameCount) override {
    for (auto &Value: In.buffer(FrameCount)) Accumulator(Value);
    return 0;
  }
  auto max() const { return boost::accumulators::max(Accumulator); }
  auto mean() const { return boost::accumulators::mean(Accumulator); }
  auto min() const { return boost::accumulators::min(Accumulator); }
  auto sampleCount() const { return boost::accumulators::count(Accumulator); }
  auto variance() const { return boost::accumulators::variance(Accumulator); }
};


Nice code. But I wonder about one small thing related to C++.
Couldn't these max/mean/etc. methods in the Statististics class
be written shorter like this?:

  auto max() const { return Max(Accumulator); }
  auto mean() const { return Mean(Accumulator); }
  auto min() const { return Min(Accumulator); }
  auto sampleCount() const { return Count(Accumulator); }
  auto variance() const { return Variance(Accumulator); }


Sorry if it's a stupid question, but I haven't used "using" in C++ yet. :-)

Also thanks for demonstrating these things from boost.


_______________________________________________
Linux-audio-dev mailing list
[hidden email]
https://lists.linuxaudio.org/listinfo/linux-audio-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [BrlCV] My attempt of linking Linux to Eurorack

Mario Lang
Kjetil Matheussen <[hidden email]> writes:

>> Mario Lang:
>
>> #include <jack.hpp>
>>
>> #include <boost/accumulators/accumulators.hpp>
>> #include <boost/accumulators/statistics.hpp>
>>
>> template<typename... Features>
>> using AudioAccumulatorSet = boost::accumulators::accumulator_set<
>>   float, boost::accumulators::features<Features...>
>> >;
>>
>> using Count = boost::accumulators::tag::count;
>> using Max = boost::accumulators::tag::max;
>> using Min = boost::accumulators::tag::min;
>> using Mean = boost::accumulators::tag::mean;
>> using Variance = boost::accumulators::tag::variance;
>>
>> class Statistics final : public JACK::Client {
>>   JACK::AudioIn In;
>>   AudioAccumulatorSet<Count, Max, Mean, Min, Variance> Accumulator;
>>
>> public:
>>   Statistics() : JACK::Client("Statistics"), In(createAudioIn("In")) {}
>>   int process(std::uint32_t FrameCount) override {
>>     for (auto &Value: In.buffer(FrameCount)) Accumulator(Value);
>>     return 0;
>>   }
>>   auto max() const { return boost::accumulators::max(Accumulator); }
>>   auto mean() const { return boost::accumulators::mean(Accumulator); }
>>   auto min() const { return boost::accumulators::min(Accumulator); }
>>   auto sampleCount() const { return boost::accumulators::count(Accumulator); }
>>   auto variance() const { return boost::accumulators::variance(Accumulator); }
>> };
>
> Nice code. But I wonder about one small thing related to C++.
> Couldn't these max/mean/etc. methods in the Statististics class
> be written shorter like this?:
>
>   auto max() const { return Max(Accumulator); }
>   auto mean() const { return Mean(Accumulator); }
>   auto min() const { return Min(Accumulator); }
>   auto sampleCount() const { return Count(Accumulator); }
>   auto variance() const { return Variance(Accumulator); }

No, because boost::accumulators::tag::mean is not the same as
boost::accumulators::mean.  The first is a "tag" to let the accumulator_set
know (at compile time) which statistics it is supposed to collect,
and the second is a so-called "extractor" which is used to retrieve the result of a
particular statistics (obviously, at runtime).

> Sorry if it's a stupid question, but I haven't used "using" in C++ yet. :-)

Sorry for sort of overusing 'using' here, I was trying to make a point
(to me, mostly) of abstracting away overly long names without the big
hammer of just including a whole namespace.  I tend to prefer knowing
what parts of a namespace are actually actively called/used in my programs.

If you are into long lines, you could of course drop all the using
directives, and eliminate the convenience template AudioAccumulatorSet altogether,
which would give you:

  boost::accumulators::accumulator_set<float, boost::accumulators::features<boost::accumulators::tag::count, boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max, boost::accumulators::tag::variance>> Accumulator;

But now it doesn't look like an ad gig for C++ anymore :-)

But the point of that code was really just to make JACK::Client do
something.

--
CYa,
  ⡍⠁⠗⠊⠕
_______________________________________________
Linux-audio-dev mailing list
[hidden email]
https://lists.linuxaudio.org/listinfo/linux-audio-dev
Loading...