Fixing buffer allocation and midi osc messages in jitlib using processing and supercollider

Subject: Assistance with Buffer Allocation and Interaction in SuperCollider 3.13 using JITLib, Processing, and Xbox 360 Controller

Greetings,

I am currently working on a project in SuperCollider 3.13 and have encountered some challenges that I would greatly appreciate assistance with. Below is a detailed overview of what I’m trying to achieve:

1. Buffer Allocation in SuperCollider:

  • I am attempting to allocate five buffers in SuperCollider. These buffers will be used for audio processing tasks, and I intend to control their playback in real-time.
  • I am using JITLib for this purpose, aiming to streamline the process of managing these buffers dynamically.

2. Instance Creation with WarpOne:

  • I plan to create an instance that utilizes the WarpOne UGen in SuperCollider. This UGen will allow me to perform time-stretching and pitch-shifting on the audio buffers.
  • The goal is to warp the audio content in these buffers in real-time, adjusting playback characteristics based on external input.

3. Integration with Processing for XY Control:

  • I want to control the XY position of the scrubbing process within the buffers using the Processing environment. This will enable more intuitive and visual interaction with the audio material.
  • My intention is to send the XY coordinates from Processing to SuperCollider, which will then adjust the scrubbing position in the buffer playback accordingly.

4. Future Integration with Ableton Live:

  • Looking ahead, I plan to use Ableton Live for pre-processing tasks. This will likely involve preparing audio material that will be loaded into the buffers in SuperCollider.
  • I am exploring ways to integrate Ableton Live with SuperCollider, possibly using MIDI or OSC for synchronization and control.

5. Control Using Xbox 360 Controller:

  • I also plan to use an Xbox 360 controller to manage different states of the audio processing. Specifically, I aim to create five or six distinct states that can be triggered or manipulated using the controller.
  • This aspect will involve mapping the controller’s buttons, triggers, and joysticks to various parameters in SuperCollider.

6. Current Issues:

  • At this stage, I am facing difficulties with the initial setup, particularly with the buffer allocation and integration with Processing for XY control.
  • The communication between Processing and SuperCollider isn’t functioning as expected, and I’m unsure if the buffers are being allocated and accessed correctly.

Request for Assistance:

I would be extremely grateful for any guidance or assistance you could provide regarding:

  • Correctly allocating and managing buffers in SuperCollider using JITLib.
  • Creating a functional instance with WarpOne and controlling its parameters dynamically.
  • Setting up reliable communication between Processing and SuperCollider for XY control.
  • Any advice on integrating SuperCollider with Ableton Live and using an Xbox 360 controller for state management.

Thank you for your time and consideration. I look forward to any suggestions or insights you may have.

Cheers,
tmm881


This version is more detailed and provides a clearer picture of what you are trying to achieve, the tools you are using, and the specific problems you are facing. This will make it easier for others to understand your request and offer the assistance you need.

MIDIIn.connectAll;  // Connect to all available MIDI devices

(
  // Define the MIDI controller mapping
  ~midiControl = MIDIFunc.cc({ |val, num, chan|  // Remove unnecessary arguments
    var ccNumber = num, value = val;
    switch (ccNumber,
      1, { ~xControl = value.linlin(0, 127, 0, 1) }, // Map CC1 to X (0-1 range)
      2, { ~yControl = value.linlin(0, 127, 0, 1) }  // Map CC2 to Y (0-1 range)
    );
  });
)

// Initialize control values
~xControl = 0.5;  // Default X value
~yControl = 0.5;  // Default Y value

(
  // Define the buffers (consider making this more flexible)
  ~buffers = (
    buffer1: if (s.exists?("D:/Nova pasta/_/music/music/Peter Evans - Lifeblood-79570615.mp3")) {
      Buffer.read(s, "D:/Nova pasta/_/music/music/Peter Evans - Lifeblood-79570615.mp3")
    } else {
      postln("Error: File not found!");
      nil;  // Handle the case where file is not found
    }
  );
)

// Wait for all buffers to finish loading
s.sync;

// Define the synth (already fixed)
(
  SynthDef(\mySynth, {
    |bufnum = 0, numChannels = 2, xControl = 0.5, yControl = 0.5|
    var sound, x, y, pointer;
    x = xControl;  // Retrieve X coordinate
    y = yControl;  // Retrieve Y coordinate

    // Ensure that the pointer is in a valid range
    pointer = x + y;  // Perform the addition first
    pointer = pointer.clip(0, 1);  // Then clip the result

    sound = Limiter.ar(
      LeakDC.ar(
        Warp1.ar(
          numChannels, // Number of channels as a constant
          bufnum, // Buffer number
          pointer, // Use clipped value as the pointer
          1, 20, -1, 3, 1, 4, 0.6
        )
      )
    );
    Out.ar(0, sound);
  }).add;
)

// Play the synth
~synth = Synth(\mySynth);

(
  // Set up the OSC receiver to handle buffer changes
  OSCFunc({ |msg|
    var bufferKey = msg[1].asSymbol;
    if (~buffers.containsKey(bufferKey)) {
      ~synth.set(\bufnum, ~buffers[bufferKey].bufnum);
      ~synth.set(\numChannels, ~buffers[bufferKey].numChannels);
    } else {
      ("Buffer key %" + bufferKey + " not found").postln;
    }
  }, '/playBuffer');
)
(
{
	var in, del, out;
	in=SoundIn.ar(0,1,0);
	del=CombC.ar(in, 8, 8, 0, 1, 0);
	del=del+CombC.ar(in, 40, 40, 0, 1, 0);
	out=in+del;
	Out.ar(0,out);
}.play;
)
import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myAddress;

void setup() {
  size(200, 200);
  background(255);

  // Initialize OSC
  oscP5 = new OscP5(this, 57120);  // Port for receiving OSC messages in Processing
  myAddress = new NetAddress("127.0.0.1", 57121);  // IP and port where SuperCollider is listening
}

void draw() {
  // Drawing code here (if any)
}

void keyPressed() {
  if (key == '1') {
    sendBufferChange("/playBuffer", "buffer1");
  } else if (key == '2') {
    sendBufferChange("/playBuffer", "buffer2");
  } else if (key == '3') {
    sendBufferChange("/playBuffer", "buffer3");
  } else if (key == '4') {
    sendBufferChange("/playBuffer", "buffer4");
  } else if (key == '5') {
    sendBufferChange("/playBuffer", "buffer5");
  }
}

void sendBufferChange(String addr, String bufferKey) {
  OscMessage msg = new OscMessage(addr);
  msg.add(bufferKey);
  oscP5.send(msg, myAddress);
}

please help me to test this to see wether this works or not

import themidibus.*;

MidiBus myBus;

void setup() {
  size(200, 200);
  background(255);
  
  // Initialize MIDI bus
  MidiBus.list();  // List available MIDI devices
  myBus = new MidiBus(this, 0, 1);  // Connect to MIDI input and output ports
}

void draw() {
  // Drawing code here (if any)
}

void noteOn(int channel, int pitch, int velocity) {
  // Handle note on events (if needed)
}

void noteOff(int channel, int pitch, int velocity) {
  // Handle note off events (if needed)
}

void controllerChange(int channel, int controller, int value) {
  // Send MIDI CC messages to SuperCollider
  if (controller == 1 || controller == 2) {
    OscMessage msg = new OscMessage("/midiControl");
    msg.add(controller);
    msg.add(value);
    myBus.send(msg, "127.0.0.1", 57121);  // IP and port where SuperCollider is listening
  }
}

Consolidating Multiple Functionalities into a Single Class

In software development, it’s often beneficial to streamline and organize code to improve readability, maintainability, and efficiency. One approach to achieving this is by consolidating related functionalities into a single class. This method can help encapsulate behavior and data, making the code more modular and easier to manage.

Objective: Is there a method or strategy for combining various functionalities or components into a single class?

Detailed Approach:

  1. Identify Functionalities:

    • Begin by listing all the functionalities or methods you want to include in the class. These could be different operations, calculations, or data manipulations currently spread across various parts of your codebase.
  2. Analyze Dependencies:

    • Assess the relationships and dependencies between these functionalities. Understanding how they interact will help in designing a cohesive class structure.
  3. Define the Class Structure:

    • Create a class with attributes and methods that encapsulate all the desired functionalities. Ensure that the class has a clear responsibility and that its methods and attributes are logically grouped.
  4. Refactor Code:

    • Move the existing code into the class. This involves transferring methods and variables into the class and adjusting them to fit within the new structure. Ensure that the methods interact with class attributes as needed.
  5. Encapsulation and Access Control:

    • Utilize encapsulation to hide internal details and expose only necessary interfaces. Use access modifiers (e.g., private, protected, public) to control how the class’s attributes and methods can be accessed from outside the class.
  6. Test the Class:

    • After refactoring, thoroughly test the class to ensure that it functions correctly and that all functionalities are working as expected. Address any issues that arise during testing.
  7. Document the Class:

    • Provide clear documentation for the class, including its purpose, methods, and usage examples. Good documentation helps others (and yourself) understand and use the class effectively.
  8. Maintain and Update:

    • Continuously maintain and update the class as needed. Monitor its performance and make adjustments to accommodate new requirements or improvements.

We would greatly appreciate any additional assistance you can provide. Your support would be incredibly valuable to us as we work through this. Any comments, tips, or feedback you have are also highly appreciated. If you have further insights, resources, or guidance to offer, they would be warmly welcomed and highly beneficial. Thank you in advance for your continued help.


If you need to replace code written in Processing with Python code, it’s certainly possible to do so. Processing is a flexible software sketchbook and a language for learning how to code within the context of the visual arts, and Python is a versatile language that can also be used for graphical and visual projects.

(Edited)

Some issues in the code blocks:

  • there’s no { }.send in SC (and this isn’t how to do MIDI in SC anyway, see MIDIFunc)
  • x = ~xControl – this isn’t how synth inputs work – there needs to be a function argument in the SynthDef, or a NamedControl
  • numChannels can’t be a synth arg – needs to have a separate synthdef per buffer width
  • OSCFunc doesn’t .add – just OSCFunc({ ... }, '/path') is enough
  • OSCFunc message args usage is incorrect – where it says msg[0], should be msg[1]
  • Processing: myBus.send(msg, "127.0.0.1", 57121) – why is a MidiBus object sending open sound control? – if the goal is to send OSC, then the oscP5 model is the one to follow.

(removed editorial comments, sorry for that)

hjh

hey @tmm881

I don’t think it’s very clear what you want to do with this code. Maybe a text explaining what you want to do would be even more helpful for someone to point you in the right direction.

Is SC your first programming language? And computer music tools? The code contains several details that are a bit confusing, including some of the fundamentals of this environment. You need to share a few words to get some good feedback, even to indicate good references for you to check them out.

done sorry for my lazyness

Have you read those docs? Buffer allocation in SC is very, very trivial. You just use the Buffer class and assign to a variable. You don’t need to do anything more. Also OSC, the examples in OSCdef can be adapted to your setup.

https://doc.sccode.org/Classes/Buffer.html

https://doc.sccode.org/Classes/OSCdef.html

the supercollider documentation doesn’t explain how to do buffer allocation with jitlib

Subject: Request for Assistance with Code Correction and Optimization

Dear James Harkins,

I hope this message finds you well.

I am currently working on a coding project and have encountered some difficulties in getting things to work correctly. As someone who is still new to this kind of development, I am struggling to identify the issues and fully correct the code on my own.

I would greatly appreciate your assistance in reviewing the code I have written. Specifically, I am seeking guidance on how to identify and fix any errors, as well as advice on how to optimize the code to make it more efficient and maintainable.

Your expertise and insights would be invaluable to me, and I am eager to learn from your experience.

Thank you in advance for your time and consideration. I look forward to any help you can provide.

Best regards,

One reason for this is that there is only buffer allocation. There is no “JITLib buffer allocation.” Buffers work the same, everywhere.

Your ~buffers = ( ... ) statement looks fine to me.

Note, though, that SC can read mp3 files only if it’s built with a libsndfile that was compiled with mp3 support. I’m not certain if the official Windows release was built this way. So, if you’re having problems with buffer reading – the format of your code is fine, but maybe you need to convert the files to WAV.

With apologies: I’m not able at this time to commit to an open-ended code-improvement project without clear boundaries.

hjh

I might have found the solution. It seems Processing has integrated third-party libraries that allow for sending OSC data to SuperCollider, sending MIDI signals outside of Processing, creating user interfaces, and collecting data from controllers. It’s just a matter of experimenting and managing those tasks.