diff --git a/doc/SETUP.rst b/doc/SETUP.rst index fd49bbc..57bef01 100644 --- a/doc/SETUP.rst +++ b/doc/SETUP.rst @@ -4,6 +4,61 @@ Setup Installation ------------ +Basic Installation +~~~~~~~~~~~~~~~~~~ + +.. _daemonized: + +Daemonizing +~~~~~~~~~~~ + +To make the server running in the background automatically on the RasPi startup, it's possible to daemonize it with a few steps. + +First, copy the ``be-server`` executable file to ``/opt/boites-electriques/``, and the ``be-server.sh`` script (located in the repo's ``share/`` directory) to ``/etc/init.d/be-server``:: + + sudo mkdir /opt/boites-electriques + sudo cp build/be-server /opt/boites-electriques/be-server + sudo cp share/be-server.sh /etc/init.d/be-server + +You can then edit the ``/etc/init.d/be-server`` to change the following values: + +``DAEMON`` + The full command. + Default : ``"/opt/boites-electriques/be-server"`` + +``daemon_OPT`` + The program's arguments (here, the path to a specific configuration file). + Default : ``""`` (empty, to use the default config file) + +``DAEMONUSER`` + The user running the program. + Default : ``"pi"`` (default ``sudo`` user of Raspbian) + +``daemon_NAME`` + Name of the program. + Default : ``"be-server"`` + +Then, we give the right permissions to the daemonizing script and reload the system's daemons:: + + sudo chmod 0755 /etc/init.d/be-server + sudo systemctl daemon-reload + +We can then test the script:: + + sudo /etc/init.d/be-server start + [ ok ] Starting be-server (via systemctl): be-server.service + + sudo /etc/init.d/be-server stop + [....] Stopping be-server (via systemctl): be-server.service + +And add it to the startup scripts:: + + sudo update-rc.d be-server defaults + +To remove it:: + + sudo update-rc.d -f be-server remove + Configuration ------------- @@ -19,59 +74,59 @@ The following options are available : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``threshold`` - Default threshold's value (integer) - Default : 200 + Default threshold's value (integer). + Default : ``200`` ``master`` - Default master volume's value (integer) - Default : 50 + Default master volume's value (integer). + Default : ``50`` ``volume`` - Default track's volume (integer) - Default : 50 + Default track's volume (integer). + Default : ``50`` ``pan`` - Default track's pan (integer) - Default : 0 + Default track's pan (integer). + Default : ``0`` ``activation`` - Default track's activation status (boolean : true or false) - Default : false + Default track's activation status (boolean : ``true`` or ``false``). + Default : ``false`` ``[files]`` section ~~~~~~~~~~~~~~~~~~~ ``folder`` - Files save/load folder (string : path, ending with '/') - Default : /home/pi/songs/ + Files save/load folder (string : path, ending with '``/``'). + Default : ``/home/pi/songs/`` ``extension`` - Songs files' extension (string : '*.') - Default : *.song + Songs files' extension (string : ``*.``). + Default : ``*.song`` ``[gpio]`` section ~~~~~~~~~~~~~~~~~~ ``led`` - LED's WiringPi identifier (to use with the ``gpio`` command) - Default : 6 + LED's WiringPi identifier (to use with the ``gpio`` command). + Default : ``6`` ``[osc]`` section ~~~~~~~~~~~~~~~~~ ``ip`` - Client's OSC IP address (integer) - Default : 192.170.0.17 + Client's OSC IP address (integer). + Default : ``192.170.0.17`` ``receiver`` - Server's OSC receiver port (integer) - Default : 9988 + Server's OSC receiver port (integer). + Default : ``9988`` ``sender`` - Server's OSC sender port (integer) - Default : 9989 + Server's OSC sender port (integer). + Default : ``9989`` Run --- -To start the server, just run ``./be-server`` +To start the server, just run ``./be-server``, or ``sudo /etc/init.d/be-server start`` if the server has been daemonized_. diff --git a/share/be-server.sh b/share/be-server.sh new file mode 100644 index 0000000..c539c74 --- /dev/null +++ b/share/be-server.sh @@ -0,0 +1,66 @@ +#!/bin/sh -e + +# Daemonizing script for be-server + +DAEMON="/opt/boites-electriques/be-server" # Command line +daemon_OPT="" # Arguments +DAEMONUSER="pi" # Program's user +daemon_NAME="be-server" # Program's name (same as the executable) + + +### BEGIN INIT INFO +# Provides: be-server +# Required-Start: $remote-fs $syslog +# Required-Stop: $remote-fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Run be-server at startup +# Description: Server for the Boites Electriques +### END INIT INFO + + +PATH="/sbin:/bin:/usr/sbin:/usr/bin" + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +d_start () { + log_daemon_msg "Starting system $daemon_NAME Daemon" + start-stop-daemon --background --name $daemon_NAME --start --quiet --chuid $DAEMONUSER --exec $DAEMON -- $daemon_OPT + log_end_msg $? +} + +d_stop () { + log_daemon_msg "Stopping system $daemon_NAME Daemon" + start-stop-daemon --name $daemon_NAME --stop --retry 5 --quiet --name $daemon_NAME + log_end_msg $? +} + +case "$1" in + + start|stop) + d_${1} + ;; + + restart|reload|force-reload) + d_stop + d_start + ;; + + force-stop) + d_stop + killall -q $daemon_NAME || true + sleep 2 + killall -q -9 $daemon_NAME || true + ;; + + status) + status_of_proc "$daemon_NAME" "$DAEMON" "system-wide $daemon_NAME" && exit 0 || exit $? + ;; + *) + echo "Usage: /etc/init.d/$daemon_NAME {start|stop|force-stop|restart|reload|force-reload|status}" + exit 1 + ;; +esac +exit 0 diff --git a/src/PlayThread.cpp b/src/PlayThread.cpp index 182c281..322acad 100644 --- a/src/PlayThread.cpp +++ b/src/PlayThread.cpp @@ -70,7 +70,9 @@ void PlayThread::timeHandle() { if(++m_bufferCount > m_maxBufferCount) m_bufferCount = 0; - emit actualBeatChanged(m_bufferCount * m_conf.bufferSize / double(m_conf.samplingRate)); + emit actualBeatChanged(m_bufferCount + * m_conf.bufferSize + / double(m_conf.samplingRate)); } void PlayThread::stop() { @@ -159,20 +161,32 @@ void PlayThread::load(const SongData& s) { m_maxBufferCount = file->v(0).size() / m_conf.bufferSize; emit beatCountChanged(file->v(0).size() / double(m_conf.samplingRate)); - chains[i] = Input_p(new SfxInputProxy(new StereoAdapter(new LoopInputProxy(file)), - new Sequence(m_conf, m_tracks[i]->getVolumePtr(), m_tracks[i]->getPanPtr(), m_tracks[i]->getMutePtr() ))); + chains[i] = Input_p(new SfxInputProxy( + new StereoAdapter( + new LoopInputProxy(file)), + new Sequence(m_conf, + m_tracks[i]->getVolumePtr(), + m_tracks[i]->getPanPtr(), + m_tracks[i]->getMutePtr() ))); emit songLoaded(i+1,track_count); } // Master - auto input = Input_p(new SfxInputProxy(new SummationProxy(new InputMultiplexer(m_conf, chains)), m_masterVolume)); + auto input = Input_p(new SfxInputProxy( + new SummationProxy( + new InputMultiplexer(m_conf, chains)), + m_masterVolume)); // Manager m_manager = std::make_shared>(std::move(input), - std::move(std::make_shared>(m_conf)), - std::bind(&PlayThread::timeHandle, this), - m_conf); + std::move( + std::make_shared>( + m_conf)), + std::bind( + &PlayThread::timeHandle, + this), + m_conf); } bool PlayThread::isValidTrack(unsigned int track) diff --git a/src/SaveManager.cpp b/src/SaveManager.cpp index 96369ce..8bc9b74 100644 --- a/src/SaveManager.cpp +++ b/src/SaveManager.cpp @@ -50,12 +50,19 @@ SongData SaveManager::load(const QString loadpath) { bool end = false; for(int i = 0; i < count; ++ i) { - sd.tracks.emplace_back(settings.value(QString("Track%1/name").arg(i)).toString().toStdString(), - (tempdir->path() + "/" + settings.value(QString("Track%1/filename").arg(i)).toString()).toStdString(), - settings.value(QString("Track%1/volume").arg(i)).toInt(), - settings.value(QString("Track%1/pan").arg(i)).toInt()); - - QString track_name = settings.value(QString("Track%1/name").arg(i)).toString(); + sd.tracks.emplace_back(settings.value( + QString("Track%1/name").arg(i)).toString().toStdString(), + (tempdir->path() + + "/" + + settings.value( + QString("Track%1/filename").arg(i)).toString()).toStdString(), + settings.value( + QString("Track%1/volume").arg(i)).toInt(), + settings.value( + QString("Track%1/pan").arg(i)).toInt()); + + QString track_name = + settings.value(QString("Track%1/name").arg(i)).toString(); temp = temp + track_name; t++; @@ -78,15 +85,20 @@ void SaveManager::save(const QString savepath, Server* manager) { //// Opening of .ini file in tempdir QStringList nameFilter("*.ini"); QDir directory(tempdir->path()); - QString iniFile = tempdir->path() + "/" + directory.entryList(nameFilter).first(); + QString iniFile = + tempdir->path() + "/" + directory.entryList(nameFilter).first(); //// Modification QSettings settings(iniFile, QSettings::IniFormat); int count = settings.value("General/trackCount").toInt(); for(int i = 0; i < count; ++ i) { - settings.setValue(QString("Track%1/volume").arg(i), manager->m_player->getTrack(i)->getVolume()); - settings.setValue(QString("Track%1/pan").arg(i), manager->m_player->getTrack(i)->getPan()); + settings.setValue( + QString("Track%1/volume").arg(i), + manager->m_player->getTrack(i)->getVolume()); + settings.setValue( + QString("Track%1/pan").arg(i), + manager->m_player->getTrack(i)->getPan()); } settings.sync(); diff --git a/src/SerialManager.cpp b/src/SerialManager.cpp index f6e1f90..1282ba0 100644 --- a/src/SerialManager.cpp +++ b/src/SerialManager.cpp @@ -46,7 +46,10 @@ void SerialManager::run() { if(port->canReadLine()) { numRead = port->readLine(txt, STR_SIZE); auto msg = QString(txt).simplified().split(' '); - if(numRead > 0) emit boxActivated(msg[0].toInt(), msg[1].toInt()); + + if(numRead > 0) + emit boxActivated(msg[0].toInt(), + msg[1].toInt()); } } } diff --git a/src/Server.cpp b/src/Server.cpp index 2e03f60..5e649f0 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -42,13 +42,17 @@ void Server::ledOn(){ std::system(c.toStdString().c_str()); } -void Server::ledOff(){ - //digitalWrite(LED_VALUE, LOW); +void Server::ledOff(int n){ + //digitalWrite(n, LOW); - QString c = QStringLiteral("gpio write %1 0").arg(m_options->value("gpio/led").toInt()); + QString c = QStringLiteral("gpio write %1 0").arg(n); std::system(c.toStdString().c_str()); } +void Server::ledOff(){ + ledOff(m_options->value("gpio/led").toInt()); +} + void Server::ledBlink(){ for(int i=0; i<2; i++) { ledOff(); @@ -148,6 +152,7 @@ Server::Server(QSettings* opt): } Server::~Server() { + int led = m_options->value("gpio/led").toInt(); qDebug() << "Stopping server..."; stop(); @@ -171,12 +176,12 @@ Server::~Server() { qDebug() << "Deleting pointers..."; delete m_player; - - ledOff(); delete m_options; qDebug() << "Stopping CoreApp..."; + QCoreApplication::exit(0); + ledOff(led); } int Server::getTempo() const { @@ -435,9 +440,9 @@ void Server::switchBox(unsigned int i, int val) { } void Server::play() { - if(!m_loaded) { - if(load()) return; - } + if(!m_loaded) + if(load()) + return; sendPlay(); m_player->start(); @@ -445,13 +450,13 @@ void Server::play() { } void Server::stop() { - if(!m_loaded || !m_playing) return; - - m_player->stop(); - m_previousBeat = 0; - m_playing = false; + if(m_loaded && m_playing){ + m_player->stop(); + m_previousBeat = 0; + m_playing = false; - updateBeat(0); + updateBeat(0); + } } void Server::updateBeat(double t) { // in seconds @@ -551,7 +556,7 @@ int Server::load() { try { stop(); - QString file = EXPORT_FOLDER + m_selSong; + QString file = m_options->value("files/folder").toString() + m_selSong; if(!file.isEmpty()) { m_currentFile = file; diff --git a/src/Server.h b/src/Server.h index 94bcbdb..afd953e 100644 --- a/src/Server.h +++ b/src/Server.h @@ -20,10 +20,8 @@ struct Settings { QString key; QVariant value; - Settings(QString k, QVariant v){ - key = k; - value = v; - } + Settings(QString k, QVariant v): + key(k), value(v){} }; /** @@ -258,15 +256,20 @@ class Server : public QObject { bool initConf(QSettings *c); /** - * @brief Activate the configured LED + * @brief Activate the configured LED defined in config file */ void ledOn(); /** - * @brief Deactivate the configured LED + * @brief Deactivate the LED on pos n + * @param n + */ + void ledOff(int n); + /** + * @brief Deactivate the LED defined in config file */ void ledOff(); /** - * @brief Make the LED blink + * @brief Make the LED defined in config file blink */ void ledBlink(); diff --git a/src/Track.cpp b/src/Track.cpp index 4ea2e25..a0ef7f5 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -10,7 +10,8 @@ Track::Track(): m_soloState(false), m_activatedState(false), m_options(NULL) {} -Track::Track(const TrackData& data, Parameters conf, QSettings* opt, int id): +Track::Track(const TrackData& data, Parameters conf, + QSettings* opt, int id): m_id(id), m_file(data.file), m_name(data.name), m_soloState(false), m_activatedState(false), m_options(opt) { diff --git a/src/Track.h b/src/Track.h index d6a8d3a..7ebbb95 100644 --- a/src/Track.h +++ b/src/Track.h @@ -50,7 +50,8 @@ class Track : public QObject * @param conf Default configuration data (volume, pan, mute) * @param id Track number (should be its position in the PlayThread's tracks vector) */ - Track(const TrackData& data, Parameters conf, QSettings* opt, int id); + Track(const TrackData& data, Parameters conf, + QSettings* opt, int id); std::string getName() const; std::string getFile() const;