This GitLab instance reached the end of its service life. It won't be possible to create new users or projects.

Please read the deprecation notice for more information concerning the deprecation timeline

Visit migration.git.tu-berlin.de (internal network only) to import your old projects to the new GitLab platform 📥

Commit 119abd94 by Henrik von Coler

added physical modeling example

parent ed018781
# Parts of this Makefile (especially the explanations) are based on this
# StackOverflow answer:
# https://stackoverflow.com/a/31610364
# Specify the name of the executable that will be compiled:
EXECUTABLE = physical_example
# Specify source code directory:
SRC_DIR = src
# Get a list of all the source files:
SRC = $(wildcard $(SRC_DIR)/*.cpp)
# Specify where to put the object (.o) files:
OBJ_DIR = obj
# Get a list of the object files that correspond to the source files:
OBJ = $(SRC:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
# From the object file list, get the dependency file list to handle automatic
# recompilation when a header file is modified:
DEP = $(OBJ:.o=.d)
# Required flags to enable the automatic dependency generation by the compiler:
CPPFLAGS = -MMD -MP
# C++ compiler flags:
CXXFLAGS = -std=c++11 -Wall -I.
# Libraries to link (linker flags):
LDFLAGS = -ljack -llo -lyaml-cpp -lsndfile -lrtmidi
# Tell make that these target are not real files:
.PHONY: all clean
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJ)
$(CXX) $(LDFLAGS) $^ -o $@
# The build directory is custom so we need to tell make how to do it, also it
# must exist before trying to compile:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
# Create obj directory if it doesn't exist:
$(OBJ_DIR):
mkdir $@
# On clean, remove obj directory and executable
clean:
$(RM) -r $(OBJ_DIR) $(EXECUTABLE) *.o
-include $(DEP)
port: 6666
ctl1: 71
ctl2: 75
ctl3: 31
ctl4: 72
path1: "/trigger"
path2: "/gain"
path3: " "
path4: " "
\ No newline at end of file
physical_example {#mainpage}
=======================
# BRIEF
This example uses a fractional waveguide for physical modeling.
It can be controlled by OSC (MIDI not implemented).
# Libraries
The following libraries are used within this project:
* jack
* YAML
* LIBLO
* libRtMIDI
# OSC server config
The file 'config.yml' defines
the OSC and MIDI paths used
for controlling the synth:
```
# the OSC port:
port: 6666
# the OSC paths used:
path1: "/trigger"
path2: "/gain"
```
# Start physical example
The binary expects three arguments:
-c 'path to config file'
-ID 'id of the MIDI controller used'
-m 'the mode used (MIDI or OSC)'
```
./physical_example -c config.yml -ID 1 -m OSC
```
PROJECT_NAME = "Physical_Example"
PROJECT_BRIEF = "Waveguide Example with OSC control!"
OUTPUT_DIRECTORY = "./"
INPUT = "../" README.md
FILE_PATTERNS = *.cpp *.h
RECURSIVE = YES
FILTER_SOURCE_FILES = NO
# deactivate when done with major changes
EXTRACT_PRIVATE = YES
HAVE_DOT = YES
UML_LOOK = YES
USE_MOFILE_AS_MAINPAGE = README.md
\ No newline at end of file
#N canvas 1920 106 1920 974 10;
#X obj 913 751 netsend -u -b;
#X obj 913 614 list prepend send;
#X obj 913 637 list trim;
#X msg 1010 671 connect 10.11.12.1 6666;
#X msg 1011 714 disconnect;
#X obj 1010 647 loadbang;
#X floatatom 834 378 5 0 0 0 - - -, f 5;
#X obj 887 427 loadbang;
#X obj 344 250 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
1;
#X obj 569 550 loadbang;
#X msg 569 573 set trigger;
#X obj 569 596 oscformat -ff trigger;
#X obj 466 494 pack f f;
#X obj 344 303 metro 1000;
#X floatatom 481 353 5 0 0 0 - - -, f 5;
#X floatatom 401 275 5 0 0 0 - - -, f 5;
#X msg 466 465 \$1 \$2;
#X obj 466 413 f;
#X obj 466 436 pack f f;
#X floatatom 580 397 5 0 0 0 - - -, f 5;
#X obj 887 473 oscformat -f shift;
#X obj 392 398 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
-1 -1;
#X obj 534 105 osc~;
#X obj 534 128 snapshot~;
#X obj 629 110 metro 100;
#X obj 629 85 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X floatatom 534 64 5 0 0 0 - - -, f 5;
#X obj 534 151 + 1;
#X obj 534 174 *;
#X floatatom 607 157 5 0 0 0 - - -, f 5;
#X text 520 38 modulate the pluck position;
#X text 315 226 auto pluck;
#X text 365 249 pluck distance (ms);
#X msg 834 318 0.99;
#X obj 834 282 loadbang;
#X obj 580 330 loadbang;
#X text 564 418 shift factor (0...10);
#X text 788 379 gain;
#X msg 887 449 set gain;
#X msg 580 366 0.3;
#X obj 638 215 loadbang;
#X text 448 331 plucking position;
#X msg 638 251 0.7;
#X connect 1 0 2 0;
#X connect 2 0 0 0;
#X connect 3 0 0 0;
#X connect 4 0 0 0;
#X connect 5 0 3 0;
#X connect 6 0 20 0;
#X connect 7 0 38 0;
#X connect 8 0 13 0;
#X connect 9 0 10 0;
#X connect 10 0 11 0;
#X connect 11 0 1 0;
#X connect 12 0 11 0;
#X connect 13 0 17 0;
#X connect 14 0 17 1;
#X connect 15 0 13 1;
#X connect 16 0 12 0;
#X connect 17 0 18 0;
#X connect 18 0 16 0;
#X connect 19 0 18 1;
#X connect 20 0 1 0;
#X connect 21 0 17 0;
#X connect 22 0 23 0;
#X connect 23 0 27 0;
#X connect 24 0 23 0;
#X connect 25 0 24 0;
#X connect 26 0 22 0;
#X connect 27 0 28 0;
#X connect 28 0 14 0;
#X connect 29 0 28 1;
#X connect 33 0 6 0;
#X connect 34 0 33 0;
#X connect 35 0 39 0;
#X connect 38 0 20 0;
#X connect 39 0 19 0;
#X connect 40 0 42 0;
#X connect 42 0 14 0;
/**
* \struct noteMessage
*
*
* \brief Structure for holding Note (on,off) messages.
*
*
* \author Henrik von Coler
*
* \version $Revision: 0.5 $
*
* \date $Date: 2005/04/14 14:16:20 $
*
* Contact: von_coler@intelligent-noise-solutions.de
*
*
*/
#ifndef DATATYPES_H
#define DATATYPES_H
typedef struct {
int noteNumber = -1; /// @var noteNumber The note number
int velocity = -1;
bool hasBeenProcessed = false;
}noteMessage;
typedef struct {
int ctlNumber = -1; /// @var noteNumber The note number
int value = -1;
bool hasBeenProcessed = false;
}ctlMessage;
#endif // DATATYPES_H
/**
* \file main.cpp
*
* \brief Just the main file ...
*
* \author Henrik von Coler
*
* \date 2019-04-15
*
*/
#include"yamlman.h"
#include"physical_example.h"
#include<iostream>
#include<stdlib.h>
#include<unistd.h>
using std::cout;
using std::endl;
int main(int argc, char *argv[]){
if (argc < 3)
cout << "Need config file to start!" << endl;
else{
// process command line arguments
std::string configfile;
int id;
std::string mode;
for (int i = 1; i < argc; i++)
{
if (i + 1 != argc)
{
if (strcmp(argv[i], "-c") == 0)
{
configfile = argv[i + 1];
i++;
}
if (strcmp(argv[i], "-ID") == 0)
{
id = atoi(argv[i + 1]);
i++;
}
if (strcmp(argv[i], "-m") == 0)
{
mode = argv[i + 1];
i++;
}
}
}
// initialize objects
YamlMan *yaml_manager = new YamlMan(configfile);
PhysicalExample *t = new PhysicalExample(yaml_manager, id, mode);
}
}
#include "midiman.h"
MidiMan::MidiMan(int ID)
{
// rtmidid intit
midiin = new RtMidiIn(RtMidiIn::Api::UNSPECIFIED ,std::string("RtMidi Input Client"),(unsigned int) 100);
midiin->openPort(ID);
midiin->setCallback( &main_callback, this);
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );
}
void MidiMan::setVerbose()
{
isVerbose = true;
}
void MidiMan::main_callback(double deltatime, std::vector< unsigned char > *message, void *userData )
{
// static cast to this object
MidiMan* statCast = static_cast<MidiMan*>(userData);
// is this a note message?
int byte0 = (int)message->at(0);
if(byte0 == 144)
{
if(statCast->isVerbose==true)
std::cout << "Received MIDI note message! " << "(" << (int)message->at(1) << "-" << (int)message->at(2) << ")" << std::endl;
noteMessage tmpMes;
tmpMes.noteNumber = (int)message->at(1);
tmpMes.velocity = (int)message->at(2);
statCast->note_messages.push_back(tmpMes);
}
if(byte0 == 176)
{
if(statCast->isVerbose==true)
std::cout << "Received MIDI control message! " << "(" << (int)message->at(1) << "-" << (int)message->at(2) << ")" << std::endl;
ctlMessage tmpMes;
tmpMes.ctlNumber = (int)message->at(1);
tmpMes.value = (int)message->at(2);
statCast->ctl_messages.push_back(tmpMes);
}
}
std::vector<noteMessage>* MidiMan::get_noteMessages()
{
return &note_messages;
}
std::vector<ctlMessage> *MidiMan::get_ctlMessages()
{
return &ctl_messages;
}
void MidiMan::flush_all_messages()
{
note_messages.clear();
ctl_messages.clear();
}
/**
* \class MidiMan
*
*
* \brief Class which parses and stores the incoming MIDI messages.
*
*
* \author Henrik von Coler
*
* \version $Revision: 0.5 $
*
* \date $Date: 2005/04/14 14:16:20 $
*
* Contact: von_coler@tu-berlin.de
*
*
*/
#ifndef MIDIMAN_H
#define MIDIMAN_H
#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <jack/midiport.h>
#include <rtmidi/RtMidi.h>
#include "datatypes.h"
class MidiMan
{
public:
///
/// \brief a midi message
typedef struct {
int byte1 = -1;
int byte2 = -1;
double byte3 = -1;
bool hasBeenProcessed = false;
}midiMessage;
MidiMan(int ID);
~MidiMan();
std::vector<noteMessage> *get_noteMessages();
std::vector<ctlMessage> *get_ctlMessages();
void flush_all_messages();
void setVerbose();
private:
RtMidiIn *midiin;
bool isVerbose = true;
std::vector<noteMessage> note_messages;
std::vector<ctlMessage> ctl_messages;
static void main_callback( double deltatime, std::vector< unsigned char > *message, void *userData );
};
#endif // MIDIMAN_H
/**
* \file oscman.cpp
* \class OscMan
*
* \brief Class which parses the incoming OSC messages.
*
* \author Henrik von Coler
*
* \date 2019/03/18
*
*/
#include "oscman.h"
OscMan::OscMan(YamlMan *yaml_manager)
{
port = yaml_manager->return_port();
cout << "Receiving OSC on port: " << port << std::endl;
// set initial values
// used for triggering notes
position = 0.5;
shift = 1.0;
triggered = false;
try
{
st = new lo::ServerThread(port);
}
catch (int e)
{
std::cout << "Possibly a bad port!" << std::endl;
}
// Add the example handler to the server!
st->add_method(yaml_manager->return_path_1(), "ff", trigger_callback, this);
// Add the example handler to the server!
st->add_method(yaml_manager->return_path_2(), "f", gain_callback, this);
st->start();
std::cout << "Started OSC Server!" << std::endl;
}
int OscMan::trigger_callback(const char *path, const char *types, lo_arg ** argv,
int argc, void *data, void *user_data )
{
// Do a static cast
OscMan* statCast = static_cast<OscMan*>(user_data);
std::cout << "Received excitation at position: " << argv[0]->f << " with shift: " << argv[1]->f << std::endl;
statCast->position = argv[0]->f;
statCast->shift = argv[1]->f;
statCast->triggered = true;
}
int OscMan::gain_callback(const char *path, const char *types, lo_arg ** argv,
int argc, void *data, void *user_data )
{
// Do a static cast
OscMan* statCast = static_cast<OscMan*>(user_data);
std::cout << "Changed gain to: " << argv[0]->f << std::endl;
statCast->gain = argv[0]->f;
}
double OscMan::get_shift()
{
return shift;
}
double OscMan::get_position()
{
return position;
}
double OscMan::get_gain()
{
return gain;
}
bool OscMan::is_triggered()
{
bool t = triggered;
triggered = false;
return t;
}
/**
* \file oscman.h
* \class OscMan
*
* \brief Class which parses the incoming OSC messages.
*
* \author Henrik von Coler
*
* \date 2019/03/18$
*
*/
#ifndef OSCMAN_H
#define OSCMAN_H
// works with 'self built'
#include <lo/lo.h>
#include <lo/lo_cpp.h>
#include <algorithm>
#include "yamlman.h"
#include<iostream>
#include<vector>
#include<string>
class OscMan
{
private:
/// the IP port to be opened
int port;
/// a server thread
lo::ServerThread *st;
double gain;
double position;
double shift;
bool triggered;
// -------------------------------------------------------------------------
// All the callback functions
// -------------------------------------------------------------------------
static int trigger_callback(const char *path, const char *types, lo_arg ** argv,
int argc, void *data, void *user_data);
static int gain_callback(const char *path, const char *types, lo_arg ** argv,
int argc, void *data, void *user_data);
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
public:
///
/// \brief OscMan
/// constructor
/// \param yaml_manager
///
OscMan(YamlMan *yaml_manager);
///
double get_shift();
double get_position();
double get_gain();
bool is_triggered();
};
#endif
/**
*
* \file physical_example.cpp
* \class PhysicalExample
*
* \author Henrik von Coler
*
* \date 2019-05-14
*
*/
#include"physical_example.h"
using std::cout;
using std::endl;
PhysicalExample::PhysicalExample(YamlMan *ym, int ID, string m){
cout << "Starting Jack Client!" << endl;
this->client = jack_client_open("Subtractive_Example", JackNullOption, &status, NULL);
fs = jack_get_sample_rate(client);
mode = m;
yaml_manager = ym;