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 f5696a78 by Henrik von Coler

Added FM example!

parent da8a5ad9
# 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 = fm_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
# 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
path1: "/carrier"
path2: "/modulator"
path3: "/index"
path4: "/gain"
\ No newline at end of file
fm_example {#mainpage}
=======================
# BRIEF
This example uses two sinusoids
with FM. Control is realized using OSC.
# Libraries
The following libraries are used within this project:
* jack
* YAML
* LIBLO
# OSC server config
The file 'config.yml' is read by
fm_example in order to set the port
and the OSC paths used.
\ No newline at end of file
PROJECT_NAME = "FM_Example"
PROJECT_BRIEF = "Simple FM 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 1921 105 1918 974 10;
#X obj 190 208 osc~;
#X obj 190 231 snapshot~;
#X obj 279 213 metro 10;
#X obj 279 172 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X floatatom 190 144 5 0 0 0 - - -, f 5;
#X floatatom 190 311 5 0 0 0 - - -, f 5;
#X obj 817 177 line;
#X obj 913 751 netsend -u -b;
#X obj 913 614 list prepend send;
#X obj 913 637 list trim;
#X msg 1183 413 set gain;
#X msg 1010 671 connect 10.11.12.1 6666;
#X msg 1011 714 disconnect;
#X floatatom 1130 341 5 0 0 0 - gain -, f 5;
#X obj 1183 436 oscformat -f gain;
#X obj 749 39 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X msg 848 136 1;
#X obj 733 94 delay 10;
#X obj 1183 390 loadbang;
#X obj 1010 647 loadbang;
#X floatatom 759 345 5 0 0 0 - modulator -, f 5;
#X obj 812 394 loadbang;
#X floatatom 559 346 5 0 0 0 - carrier -, f 5;
#X obj 612 395 loadbang;
#X msg 612 418 set carrier;
#X obj 612 441 oscformat -f carrier;
#X obj 812 440 oscformat -f modulator;
#X msg 812 417 set modulator;
#X floatatom 957 343 5 0 0 0 - index -, f 5;
#X obj 1010 438 oscformat -f index;
#X msg 1010 413 set index;
#X obj 1010 388 loadbang;
#X obj 190 276 * 1000;
#X obj 190 333 s index;
#X obj 671 183 line;
#X msg 704 130 0 2000;
#X obj 817 221 s gain;
#X obj 817 200 *;
#X msg 786 136 0 2000;
#X obj 671 206 s index;
#X text 781 34 bang to start sound;
#X text 522 318 carrier freq: 266;
#X text 737 317 mod freq: 450;
#X text 954 317 index;
#X text 1122 316 gain;
#X msg 636 131 set 2000;
#X text 256 147 modulate index;
#X connect 0 0 1 0;
#X connect 1 0 32 0;
#X connect 2 0 1 0;
#X connect 3 0 2 0;
#X connect 4 0 0 0;
#X connect 5 0 33 0;
#X connect 6 0 37 0;
#X connect 6 0 37 1;
#X connect 8 0 9 0;
#X connect 9 0 7 0;
#X connect 10 0 14 0;
#X connect 11 0 7 0;
#X connect 12 0 7 0;
#X connect 13 0 14 0;
#X connect 14 0 8 0;
#X connect 15 0 45 0;
#X connect 15 0 16 0;
#X connect 15 0 17 0;
#X connect 16 0 6 0;
#X connect 17 0 35 0;
#X connect 17 0 38 0;
#X connect 18 0 10 0;
#X connect 19 0 11 0;
#X connect 20 0 26 0;
#X connect 21 0 27 0;
#X connect 22 0 25 0;
#X connect 23 0 24 0;
#X connect 24 0 25 0;
#X connect 25 0 8 0;
#X connect 26 0 8 0;
#X connect 27 0 26 0;
#X connect 28 0 29 0;
#X connect 29 0 8 0;
#X connect 30 0 29 0;
#X connect 31 0 30 0;
#X connect 32 0 5 0;
#X connect 34 0 39 0;
#X connect 35 0 34 0;
#X connect 37 0 36 0;
#X connect 38 0 6 0;
#X connect 45 0 34 0;
/**
* \file fm_example.cpp
* \class FmExample
*
* \author Henrik von Coler
*
* \date $Date: 2019/05/14 $
*
*/
#include"fm_example.h"
using std::cout;
using std::endl;
FmExample::FmExample(YamlMan *yaml_manager){
// creating an OSC manager instance
oscman = new OscMan(yaml_manager);
cout << "Starting Jack Client!" << endl;
this->client = jack_client_open("Gain_Example", JackNullOption, &status, NULL);
fs = jack_get_sample_rate(client);
carrier = new Sinusoid();
modulator = new Sinusoid();
carrier->init(100,1,0,fs);
modulator->init(100,1,0,fs);
// default modulation index
IDX = 10;
// connect the callback function
jack_set_process_callback(this->client, this->callback_process, this);
// the output ports
output_port = new jack_port_t*[nChannels];
for (int i=0; i<nChannels; i++)
{
std::string tmp_str = "output_" + std::to_string(i+1);
output_port[i] = jack_port_register (client, tmp_str.c_str(),
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
}
out = new jack_default_audio_sample_t*;
jack_activate(this->client);
// connect outputs
jack_connect (client, jack_port_name(output_port[0]), "system:playback_1");
jack_connect (client, jack_port_name(output_port[1]), "system:playback_2");
// run forever
sleep (-1);
}
int FmExample::process(jack_nframes_t nframes)
{
// get the recent control
// values from the OSC manager
double tmpGain = oscman->get_gain();
double fm = oscman->get_mod();
double fc = oscman->get_carrier();
IDX = oscman->get_idx();
// set modulator frequency
modulator->frequency(fm);
// get output buffers
for ( int i=0 ; i<nChannels; i++)
{
out[i] = (jack_default_audio_sample_t *)
jack_port_get_buffer(this->output_port[i], jack_get_buffer_size(client));
}
// loop over all buffer samples
for(int sampCNT=0; sampCNT<nframes; sampCNT++)
{
// apply FM
carrier->frequency(fc + IDX * modulator->getNextSample());
// get output value for this sample
double tmpVal = carrier->getNextSample();
// write all input samples to output
for(int chanCNT=0; chanCNT<nChannels; chanCNT++)
{
out[chanCNT][sampCNT] = tmpVal * tmpGain;
}
}
return 0;
}
int FmExample::callback_process(jack_nframes_t x, void* object)
{
return static_cast<FmExample*>(object)->process(x);
}
/**
* \file fm_example.h
* \class FmExample
*
* \brief FM example, using two operators
* with OSC control.
*
* \author Henrik von Coler
*
* \date $Date: 2019/05/14 $
*
*/
#include<iostream>
#include<stdlib.h>
#include<unistd.h>
#include<jack/jack.h>
#include"yamlman.h"
#include"oscman.h"
#include"sinusoid.h"
using std::cout;
using std::endl;
class FmExample{
private:
///
/// \brief yaml_manager
/// is used for reading the config file
YamlMan *yaml_manager;
///
/// \brief fs
/// the sample rate of the jack server.
int fs;
///
/// \brief IDX
/// the modulation index
double IDX;
///
/// \brief carrier
/// a sinusoid acting as carrier
Sinusoid *carrier;
///
/// \brief modulator
/// a sinusoid acting as carrier
///
Sinusoid *modulator;
///
/// \brief nChannels
/// the number of audio channels @todo (should not be hard-coded)
int nChannels = 2;
///
/// \brief client
/// the jack client, obviously
jack_client_t *client;
///
/// \brief status
/// gets the status from the jack server
jack_status_t status;
///
/// \brief output_port
/// the jack output ports
jack_port_t **output_port;
///
/// \brief in
///
/// \brief out
jack_default_audio_sample_t **in, **out;
/// The OSC manager object
OscMan *oscman;
///
/// \brief process
/// The function where the actual
/// audio processing takes place.
/// \param nframes number of frames in the out buffer.
/// \return
///
int process (jack_nframes_t nframes);
///
/// \brief callback_process
/// is used to access the members of this
/// class in the static mode
/// \param x number of samples in the buffer
/// \param object void pointer
/// \return
///
static int callback_process(jack_nframes_t x, void* object);
public:
///
/// \brief FmExample
/// the constructor
/// \param yaml_manager
///
FmExample(YamlMan *yaml_manager);
};
/**
* \file main.cpp
*
* \brief Just the main file ...
*
* \author Henrik von Coler
*
* \date $Date: 2019/04/15 $
*
*/
#include"yamlman.h"
#include"fm_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;
for (int i = 1; i < argc; i++)
{
if (i + 1 != argc)
{
if (strcmp(argv[i], "-c") == 0)
{
configfile = argv[i + 1];
i++;
}
}
}
// initialize objects
YamlMan *yaml_manager = new YamlMan(configfile);
FmExample *t = new FmExample(yaml_manager);
}
}
/**
* \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;
f_m = 100;
f_c = 200;
idx = 10;
gain = 1;
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(), "f", mod_callback, this);
// Add the example handler to the server!
st->add_method(yaml_manager->return_path_2(), "f", car_callback, this);
// Add the example handler to the server!
st->add_method(yaml_manager->return_path_3(), "f", idx_callback, this);
// Add the example handler to the server!
st->add_method(yaml_manager->return_path_4(), "f", gain_callback, this);
st->start();
std::cout << "Started OSC Server!" << std::endl;
}
int OscMan::mod_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 modulator to: " << argv[0]->f << std::endl;
statCast->f_m = argv[0]->f;
}
int OscMan::car_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 carrier to: " << argv[0]->f << std::endl;
statCast->f_c = argv[0]->f;
}
int OscMan::idx_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 index to: " << argv[0]->f << std::endl;
statCast->idx = argv[0]->f;
}
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_mod()
{
return f_m;
}
double OscMan::get_carrier()
{
return f_c;
}
double OscMan::get_idx()
{
return idx;
}
double OscMan::get_gain()
{
return gain;
}
/**
* \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 "yamlman.h"
#include<iostream>
#include<vector>
#include<string>
class OscMan
{
private:
/// the IP port to be opened
int port;
///
lo::ServerThread *st;
double f_c;
double f_m;
double idx;
double gain;
// -------------------------------------------------------------------------
// All the callback functions
// -------------------------------------------------------------------------
///
////// \brief OscMan::gain_callback
////// \param path
////// \param types
////// \param argv
////// \param argc
////// \param data
////// \param user_data
////// \return
static int mod_callback(const char *path, const char *types, lo_arg ** argv,
int argc, void *data, void *user_data);
///
/// \brief car_callback
/// \param path
/// \param types
/// \param argv
/// \param argc
/// \param data
/// \param user_data
/// \return
///
static int car_callback(const char *path, const char *types, lo_arg ** argv,
int argc, void *data, void *user_data);
static int idx_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::OscMan
/// The constructor
/// \param yaml_manager
///
OscMan(YamlMan *yaml_manager);
///
double get_carrier();
///
/// \brief OscMan::get_gain
/// \return the gain value [double]
///
double get_mod();
double get_idx();
double get_gain();
};
#endif
/**
* \class Sinusoid
*
*
* \brief Simple sinusoid handler class.
*
*
*
* \author Henrik von Coler
*
* \version $Revision: 0.5 $
*
* \date $Date: 2016/08/01 14:16:20 $
*
* Contact: von_coler@intelligent-noise-solutions.de
*
*
*/
#include "sinusoid.h"