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

Added AM example!

parent 805368ee
!*.*
examples/*/obj/
......@@ -18,8 +17,7 @@ gain.pd
liblo/
wav/
# *
# *~
*~
*.o
*html/
*latex/
......
# 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 = am_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)
#!/bin/sh
g++ -std=c++11 gain_example.cpp oscman.cpp -ljack -llo -o gain_example
port: 6666
path: "/shift"
dummy: "lsrg"
gain_example {#mainpage}
=======================
# BRIEF
This example introduces the basic
libraries and tools used in the
Sound Synthesis class. It passes
audio from the inputs to the outputs,
allowing to set the gain using an OSC
interface.
# Libraries
The following libraries are used within this project:
* jack
* YAML
* LIBLO
# OSC server config
The file 'config.yml' is read by
gain_example in order to set the port
and the OSC path used to set the gain.
\ No newline at end of file
PROJECT_NAME = "Gain_Example"
PROJECT_BRIEF = "Simple gain manipulation through OSC!"
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
/**
* \file am_example.cpp
* \class AmExample
*
* \brief Am example - modulates the audio
* iput of the interface with a OSC controlled sinusoid.
*
* \author Henrik von Coler
*
* \date $Date: 2019/05/18 $
*
*/
#include"am_example.h"
using std::cout;
using std::endl;
AmExample::AmExample(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);
carrier = new Sinusoid();
fs = jack_get_sample_rate(client);
carrier->init(100,1,0,fs);
// connect the callback function
jack_set_process_callback(this->client, this->callback_process, this);
// allocate array
input_port = new jack_port_t*[nChannels];
for (int i=0; i<nChannels; i++)
{
std::string tmp_str = "input_" + std::to_string(i+1);
input_port[i] = jack_port_register (client, tmp_str.c_str(),
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
}
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*;
in = new jack_default_audio_sample_t*;
jack_activate(this->client);
// connect inputs
jack_connect (client, "system:capture_1", jack_port_name(input_port[0]));
jack_connect (client, "system:capture_2", jack_port_name(input_port[1]));
// 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 AmExample::process(jack_nframes_t nframes)
{
// get the recent carrier frequency
// value from the OSC manager
double shift = oscman->get_shift();
// set sinusoid parameter
carrier->frequency(shift);
// get input 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));
in[i] = (jack_default_audio_sample_t *)
jack_port_get_buffer(this->input_port[i], jack_get_buffer_size(client));
}
for(int sampCNT=0; sampCNT<nframes; sampCNT++)
{
// get carrier value for this sample
double tmpVal = carrier->getNextSample();
// write all input samples to output
for(int chanCNT=0; chanCNT<nChannels; chanCNT++)
{
// apply AM
out[chanCNT][sampCNT] = in[chanCNT][sampCNT] * tmpVal ;
}
}
return 0;
}
int AmExample::callback_process(jack_nframes_t x, void* object)
{
return static_cast<AmExample*>(object)->process(x);
}
/**
* \file gain_example.h
* \class GainExample
*
* \brief Simple example, passing the input to the output
* with gain modification through OSC.
*
* \author Henrik von Coler
*
* \date $Date: 2019/03/18 $
*
*/
#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 AmExample{
private:
///
/// \brief yaml_manager
/// is used for reading the config file
YamlMan *yaml_manager;
int fs;
///
/// \brief carrier
///
Sinusoid *carrier;
///
/// \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 input_port
/// the jack input ports
jack_port_t **input_port;
///
/// \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
/// \param nframes
/// \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 GainExample
/// the constructor
/// \param yaml_manager
///
AmExample(YamlMan *yaml_manager);
};
/**
* \file main.cpp
*
* \brief Just the main file ...
*
* \author Henrik von Coler
*
* \date $Date: 2019/04/15 $
*
*/
#include"yamlman.h"
#include"am_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);
AmExample *t = new AmExample(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;
gain = 1.0;
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(), "f", gain_callback, this);
st->start();
std::cout << "Started OSC Server!" << std::endl;
}
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 volume to: " << argv[0]->f << std::endl;
statCast->gain = argv[0]->f;
}
double OscMan::get_shift()
{
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;
/// The actual gain value
double gain;
///
////// \brief OscMan::gain_callback
////// \param path
////// \param types
////// \param argv
////// \param argc
////// \param data
////// \param user_data
////// \return
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);
///
/// \brief OscMan::get_gain
/// \return the gain value [double]
///
double get_shift();
};
#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"
Sinusoid::Sinusoid()
{
}
void Sinusoid::init(double f, double a, double p, int fS)
{
freq = f;
amp = a;
phi = p;
fs = fS;
}
double Sinusoid::getNextSample()
{
/// This method gets the next sample of the sinusoid.
/// The amplitude is applied and the angle of the
/// sinusoid is increased, according to the sample rate.
// get sinusoidal value
double thisVal = sin(phi);
// apply amplitude
thisVal = thisVal*amp;
// rotate to next step
phi += 2.0 * M_PI * freq * (1.0/ (double) fs);
// wrap to 2 pi
if(phi>=2*M_PI)
{
phi -= 2*M_PI;
}
return thisVal;
}
double Sinusoid::frequency()
{
return freq;
}
double Sinusoid::amplitude()
{
return amp;
}
double Sinusoid::phase()
{
return phi;
}
void Sinusoid::frequency(double f)
{
freq = f;
}
void Sinusoid::amplitude(double a)
{
amp = a;
}
void Sinusoid::phase(double p)
{
phi = p;
}
#ifndef SINUSOID_H
#define SINUSOID_H
#define _USE_MATH_DEFINES
#include<vector>
#include<math.h>
class Sinusoid
{
public:
Sinusoid();
void init(double f, double a, double p, int fS);
void proceed(double ms);
/// getters
double frequency();
double amplitude();
double phase();
/// setters (override)
void frequency(double f);
void amplitude(double a);
void phase(double p);
double getNextSample();
private:
// PURE SINE STATE
double freq;
double amp;
double phi;
// SYSTEM RELATED
int nframes;
int fs;
double *t;
};
#endif // SINUSOID_H
/**
* \file yamlman.cpp
* \class YamlMan
*
* \author Henrik von Coler
*
* \version $Revision: 0.5 $
*
* \date $Date: 2016/08/18$
*
*/
#include "yamlman.h"
YamlMan::YamlMan(std::string filepath)
{
cout << "Loading config from YAML file: " << filepath << endl;
YAML::Node config = YAML::LoadFile(filepath);
// read values
port = config["port"].as<int>();
path = config["path"].as<std::string>();
}
int YamlMan::return_port()
{
return port;
}
std::string YamlMan::return_path()
{
return path;
}
/**
* \file yamlman.h
* \class YamlMan
*
* \brief Class which parses YAML files for parameters.
*
* YamlMan also keeps the parameter settings and offers
* getters for each, individually.