New upstream version 0.15.0+repack1
authorIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>
Wed, 9 May 2018 13:32:57 +0000 (15:32 +0200)
committerIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>
Wed, 9 May 2018 13:32:57 +0000 (15:32 +0200)
76 files changed:
.travis/after_success.sh [deleted file]
.travis/before_install.sh [deleted file]
.travis/before_script.sh [deleted file]
.travis/install.sh [deleted file]
.travis/script.sh [deleted file]
ChangeLog
Makefile.am
configure.ac
src/core/audioBuffer.cpp [new file with mode: 0644]
src/core/audioBuffer.h [new file with mode: 0644]
src/core/channel.cpp
src/core/channel.h
src/core/channelManager.cpp [new file with mode: 0644]
src/core/channelManager.h [new file with mode: 0644]
src/core/clock.cpp
src/core/clock.h
src/core/const.h
src/core/init.cpp
src/core/init.h
src/core/kernelAudio.cpp
src/core/kernelAudio.h
src/core/midiChannel.cpp
src/core/midiChannel.h
src/core/mixer.cpp
src/core/mixer.h
src/core/mixerHandler.cpp
src/core/mixerHandler.h
src/core/patch.cpp
src/core/pluginHost.cpp
src/core/pluginHost.h
src/core/recorder.cpp
src/core/recorder.h
src/core/sampleChannel.cpp
src/core/sampleChannel.h
src/core/wave.cpp
src/core/wave.h
src/core/waveFx.cpp
src/core/waveFx.h
src/core/waveManager.cpp
src/core/waveManager.h
src/glue/channel.cpp
src/glue/channel.h
src/glue/io.cpp
src/glue/main.cpp
src/glue/main.h
src/glue/recorder.cpp
src/glue/recorder.h
src/glue/sampleEditor.cpp
src/glue/storage.cpp
src/gui/dialogs/channelNameInput.cpp
src/gui/dialogs/gd_actionEditor.cpp
src/gui/dialogs/midiIO/midiInputChannel.cpp
src/gui/dialogs/sampleEditor.cpp
src/gui/elems/actionEditor/action.cpp
src/gui/elems/actionEditor/actionEditor.cpp
src/gui/elems/actionEditor/envelopeEditor.cpp
src/gui/elems/actionEditor/gridTool.cpp
src/gui/elems/actionEditor/muteEditor.cpp
src/gui/elems/actionEditor/pianoRoll.cpp
src/gui/elems/mainWindow/keyboard/channel.cpp
src/gui/elems/mainWindow/keyboard/channelStatus.cpp
src/gui/elems/mainWindow/keyboard/column.cpp
src/gui/elems/mainWindow/keyboard/midiChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannel.cpp
src/gui/elems/mainWindow/mainMenu.cpp
src/gui/elems/sampleEditor/boostTool.cpp
src/gui/elems/sampleEditor/pitchTool.cpp
src/gui/elems/sampleEditor/shiftTool.cpp
src/gui/elems/sampleEditor/volumeTool.cpp
src/gui/elems/sampleEditor/waveform.cpp
src/utils/gui.cpp
tests/audioBuffer.cpp [new file with mode: 0644]
tests/patch.cpp
tests/wave.cpp
tests/waveFx.cpp
tests/waveManager.cpp

diff --git a/.travis/after_success.sh b/.travis/after_success.sh
deleted file mode 100755 (executable)
index 64612e1..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-mkdir build
-
-if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
-
-  cp giada_osx ./build
-  upx --best ./build/giada_osx
-
-elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
-
-       : # null command - nothing to do 
-       
-       # TODO  
-  # cp giada_lin ./build
-
-fi
\ No newline at end of file
diff --git a/.travis/before_install.sh b/.travis/before_install.sh
deleted file mode 100755 (executable)
index 17d5a97..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
-
-       echo ""
-
-elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
-
-  sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y # for gcc 6
-  sudo apt-get update -qq
-
-fi
\ No newline at end of file
diff --git a/.travis/before_script.sh b/.travis/before_script.sh
deleted file mode 100755 (executable)
index 73e0df2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
-
-  ./autogen.sh
-  ./configure --target=osx --enable-vst
-
-elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
-
-  ./autogen.sh
-  ./configure --target=linux #--enable-vst
-
-fi
\ No newline at end of file
diff --git a/.travis/install.sh b/.travis/install.sh
deleted file mode 100755 (executable)
index 066b194..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
-
-  brew update
-  brew install rtmidi
-  brew install jansson
-  brew install libsamplerate
-  brew install fltk
-  brew install libsndfile
-  brew install upx
-
-  #ls Remove dynamic libraries to force static linking.
-
-  rm -rf /usr/local/lib/librtmidi.dylib
-  rm -rf /usr/local/lib/librtmidi.4.dylib
-  rm -rf /usr/local/lib/libjansson.dylib
-  rm -rf /usr/local/lib/libjansson.4.dylib
-  rm -rf /usr/local/lib/libsamplerate.dylib
-  rm -rf /usr/local/lib/libsamplerate.0.dylib
-  rm -rf /usr/local/lib/libfltk.1.3.dylib
-  rm -rf /usr/local/lib/libfltk.dylib
-  rm -rf /usr/local/lib/libfltk_forms.1.3.dylib
-  rm -rf /usr/local/lib/libfltk_forms.dylib
-  rm -rf /usr/local/lib/libfltk_forms.dylib
-  rm -rf /usr/local/lib/libfltk_gl.1.3.dylib
-  rm -rf /usr/local/lib/libfltk_gl.dylib 
-  rm -rf /usr/local/lib/libfltk_images.1.3.dylib
-  rm -rf /usr/local/lib/libfltk_images.dylib 
-  rm -rf /usr/local/lib/libsndfile.1.dylib 
-  rm -rf /usr/local/lib/libsndfile.dylib 
-  rm -rf /usr/local/lib/libFLAC++.6.dylib
-  rm -rf /usr/local/lib/libFLAC++.dylib
-  rm -rf /usr/local/lib/libFLAC.8.dylib
-  rm -rf /usr/local/lib/libFLAC.dylib
-  rm -rf /usr/local/lib/libogg.0.dylib
-  rm -rf /usr/local/lib/libogg.dylib
-  rm -rf /usr/local/lib/libvorbis.0.dylib
-  rm -rf /usr/local/lib/libvorbis.dylib
-  rm -rf /usr/local/lib/libvorbisenc.2.dylib
-  rm -rf /usr/local/lib/libvorbisenc.dylib
-
-  # TODO - what about midimaps?
-
-elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
-
-  sudo apt-get install -y gcc-6 g++-6 libsndfile1-dev libsamplerate0-dev \
-       libfltk1.3-dev libasound2-dev libxpm-dev libpulse-dev libjack-dev \
-       libxrandr-dev libx11-dev libxinerama-dev libxcursor-dev
-
-  # Symlink gcc in order to use the latest version
-
-  sudo ln -f -s /usr/bin/g++-6 /usr/bin/g++
-
-  # Download and build latest version of RtMidi
-
-  wget https://github.com/thestk/rtmidi/archive/master.zip
-  unzip master.zip
-  cd rtmidi-master && ./autogen.sh && ./configure --with-jack --with-alsa && make && sudo make install || true
-  cd ..
-
-  #wget http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-2.1.1.tar.gz
-  #tar -xvf rtmidi-2.1.1.tar.gz
-  #cd rtmidi-2.1.1 && ./configure --with-jack --with-alsa && make && sudo make install || true
-  #cd ..
-
-  # Download and install latest version of Jansson
-  # TODO - no longer needed! Use apt instead
-
-  wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz
-  tar -xvf jansson-2.7.tar.gz
-  cd jansson-2.7 && ./configure && make && sudo make install || true
-  sudo ldconfig
-  cd ..
-
-  # Download midimaps package for testing purposes
-
-  wget https://github.com/monocasual/giada-midimaps/archive/master.zip -O giada-midimaps-master.zip
-  unzip giada-midimaps-master.zip
-  mkdir -p $HOME/.giada/midimaps
-  cp giada-midimaps-master/midimaps/* $HOME/.giada/midimaps
-
-  # Download vst plugin for testing purposes
-
-  #- wget http://www.discodsp.com/download/?id=18 -O bliss-linux.zip
-  #- unzip bliss-linux.zip -d bliss-linux
-  #- cp bliss-linux/64-bit/Bliss64Demo.so .
-
-fi
\ No newline at end of file
diff --git a/.travis/script.sh b/.travis/script.sh
deleted file mode 100755 (executable)
index af3c70e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-
-make -j 2
-make rename
-
-if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
-       
-       xvfb-run make check -j 2
-
-else
-
-       make check -j 2
-
-fi
\ No newline at end of file
index 76388e384b9737a201059f440ebf0fc270f70d40..f593b9d8af52110225014dbb7aa2b38090945647 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
+0.15.0 --- 2018 . 04 . 18
+- Refactor audio engine into frame-based processing
+- Refactor channels readers/writers into channelManager namespace
+- Smarter Solo algorithm
+- Fix missing .wav extension on recorded audio takes
+- Fix wrong Channel status update after 'Clear all actions'
+
+
 0.14.6 --- 2018 . 03 . 15
 - MIDI velocity drives volume for one-shot sample channels
 - FLAC and Ogg support
index 9d0cfec070a11aae4504b0fdc4b27bfc66a6f8fa..f007a12bae2b1c71c6218fbedc9b82047d6a2ec7 100644 (file)
@@ -125,6 +125,8 @@ src/core/midiMapConf.h                 \
 src/core/midiMapConf.cpp               \
 src/core/midiEvent.h                   \
 src/core/midiEvent.cpp                 \
+src/core/audioBuffer.h                 \
+src/core/audioBuffer.cpp               \
 src/core/conf.h                        \
 src/core/conf.cpp                      \
 src/core/kernelAudio.h                 \
@@ -157,6 +159,8 @@ src/core/clock.h                       \
 src/core/clock.cpp                     \
 src/core/waveManager.h                 \
 src/core/waveManager.cpp               \
+src/core/channelManager.h              \
+src/core/channelManager.cpp            \
 src/glue/main.h                        \
 src/glue/main.cpp                      \
 src/glue/io.h                          \
@@ -389,6 +393,7 @@ tests/pluginHost.cpp         \
 tests/utils.cpp              \
 tests/recorder.cpp           \
 tests/waveFx.cpp             \
+tests/audioBuffer.cpp        \
 src/core/conf.cpp            \
 src/core/wave.cpp            \
 src/core/waveManager.cpp     \
@@ -398,6 +403,7 @@ src/core/patch.cpp           \
 src/core/plugin.cpp          \
 src/core/storager.cpp        \
 src/core/recorder.cpp        \
+src/core/audioBuffer.cpp     \
 src/utils/fs.cpp             \
 src/utils/string.cpp         \
 src/utils/time.cpp           \
index 9f6e959995e5b0abb53626b12b3aa1b5ec4bf38c..9f772f66ae689836b204f2f115ae7eced03b65b7 100644 (file)
@@ -4,7 +4,7 @@
 # prereq & init
 
 AC_PREREQ(2.60)
-AC_INIT([giada], [0.14], [giadaloopmachine@gmail.com])
+AC_INIT([giada], [0.15], [giadaloopmachine@gmail.com])
 AC_CONFIG_SRCDIR([src/main.cpp])
 AM_INIT_AUTOMAKE([subdir-objects])
 
diff --git a/src/core/audioBuffer.cpp b/src/core/audioBuffer.cpp
new file mode 100644 (file)
index 0000000..ac64df9
--- /dev/null
@@ -0,0 +1,127 @@
+#include <new>
+#include <cassert>
+#include <cstring>
+#include "audioBuffer.h"
+
+
+namespace giada {
+namespace m
+{
+AudioBuffer::AudioBuffer()
+       : m_data    (nullptr),
+         m_size    (0),
+         m_channels(0)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+AudioBuffer::~AudioBuffer()
+{
+       free();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+float* AudioBuffer::operator [](int offset) const
+{
+       assert(m_data != nullptr);
+       assert(offset < m_size);
+       return m_data + (offset * m_channels);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void AudioBuffer::clear(int a, int b)
+{
+       if (m_data == nullptr)
+               return;
+       if (b == -1) b = m_size;
+       memset(m_data + (a * m_channels), 0, (b - a) * m_channels * sizeof(float));     
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int AudioBuffer::countFrames()   const { return m_size; }
+int AudioBuffer::countSamples()  const { return m_size * m_channels; }
+int AudioBuffer::countChannels() const { return m_channels; }
+bool AudioBuffer::isAllocd()     const { return m_data != nullptr; }
+
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool AudioBuffer::alloc(int size, int channels) noexcept
+{
+       free();
+       m_size     = size;
+       m_channels = channels;
+       m_data     = new (std::nothrow) float[m_size * m_channels];     
+       clear(); // does nothing if m_data == nullptr
+       return m_data != nullptr;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void AudioBuffer::free()
+{
+       delete[] m_data;  // No check required, delete nullptr does nothing
+       setData(nullptr, 0, 0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void AudioBuffer::setData(float* data, int size, int channels)
+{
+       m_data     = data;
+       m_size     = size;
+       m_channels = channels;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void AudioBuffer::moveData(AudioBuffer& b)
+{
+       free();
+       m_data     = b[0];
+       m_size     = b.countFrames();
+       m_channels = b.countChannels();
+       b.setData(nullptr, 0, 0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void AudioBuffer::copyFrame(int frame, float* values)
+{
+       assert(m_data != nullptr);
+       memcpy(m_data + (frame * m_channels), values, m_channels * sizeof(float));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::copyData(float* data, int frames, int offset)
+{
+       assert(m_data != nullptr);
+       assert(frames <= m_size - offset);
+       memcpy(m_data + (offset * m_channels), data, frames * m_channels * sizeof(float));
+}
+
+}} // giada::m::
\ No newline at end of file
diff --git a/src/core/audioBuffer.h b/src/core/audioBuffer.h
new file mode 100644 (file)
index 0000000..702f77a
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef G_AUDIO_BUFFER_H
+#define G_AUDIO_BUFFER_H
+
+
+namespace giada {
+namespace m
+{
+class AudioBuffer
+{
+public:
+
+       AudioBuffer();
+       ~AudioBuffer();
+
+       /* operator []
+       Given a frame 'offset', returns a pointer to it. This is useful for digging 
+       inside a frame, i.e. parsing each channel. How to use it:
+
+               for (int k=0; k<buffer->countFrames(), k++)
+                       for (int i=0; i<buffer->countChannels(); i++)
+                               ... buffer[k][i] ...
+
+       Also note that buffer[0] will give you a pointer to the whole internal data
+       array. */
+
+       float* operator [](int offset) const;
+
+       int countFrames() const;
+       int countSamples() const;
+       int countChannels() const;
+       bool isAllocd() const;
+
+       bool alloc(int size, int channels) noexcept;
+       void free();
+
+       /* copyData
+       Copies 'frames' frames from the new 'data' into m_data, and fills m_data 
+       starting from frame 'offset'. It takes for granted that the new data contains 
+       the same number of channels than m_channels. */
+
+       void copyData(float* data, int frames, int offset=0);
+
+       /* copyFrame
+       Copies data pointed by 'values' into m_data[frame]. It takes for granted that
+       'values' contains the same number of channels than m_channels. */
+
+       void copyFrame(int frame, float* values);
+
+       /* setData
+       Borrow 'data' as new m_data. Makes sure not to delete the data 'data' points
+       to while using it. Set it back to nullptr when done. */
+
+       void setData(float* data, int size, int channels);
+
+       /* moveData
+       Moves data held by 'b' into this buffer. Then 'b' becomes an empty buffer. */
+        
+       void moveData(AudioBuffer& b);
+
+       /* clear
+       Clears the internal data by setting all bytes to 0.0f. Optional parameters
+       'a' and 'b' set the range. */
+       
+       void clear(int a=0, int b=-1);
+
+private:
+
+       float* m_data;
+       int    m_size;     // in frames    
+       int    m_channels;
+};
+
+}} // giada::m::
+
+#endif
\ No newline at end of file
index a1dda462b24bd2592c43ee79f6ca6168257a08af..906b18f8e9aec57b1d60269961c6ac565d303a93 100644 (file)
@@ -30,7 +30,7 @@
 #include "../utils/log.h"
 #include "../gui/elems/mainWindow/keyboard/channel.h"
 #include "const.h"
-#include "channel.h"
+#include "channelManager.h"
 #include "pluginHost.h"
 #include "plugin.h"
 #include "kernelMidi.h"
@@ -43,6 +43,7 @@
 #include "patch.h"
 #include "waveFx.h"
 #include "midiMapConf.h"
+#include "channel.h"
 
 
 using std::string;
@@ -51,25 +52,23 @@ using namespace giada::m;
 
 Channel::Channel(int type, int status, int bufferSize)
 : bufferSize     (bufferSize),
-       midiInFilter   (-1),
+       volume_i       (1.0f),
+       volume_d       (0.0f),
+       mute_i         (false),
+       guiChannel     (nullptr),
        previewMode    (G_PREVIEW_NONE),
        pan            (0.5f),
        volume         (G_DEFAULT_VOL),
-       volume_i       (1.0f),
-       volume_d       (0.0f),
        armed          (false),
        type           (type),
        status         (status),
        key            (0),
-       mute_i         (false),
-       mute_s         (false),
        mute           (false),
+       mute_s         (false),
        solo           (false),
        hasActions     (false),
        readActions    (false),
        recStatus      (REC_STOPPED),
-       vChan          (nullptr),
-       guiChannel     (nullptr),
        midiIn         (true),
        midiInKeyPress (0x0),
        midiInKeyRel   (0x0),
@@ -78,6 +77,7 @@ Channel::Channel(int type, int status, int bufferSize)
        midiInVolume   (0x0),
        midiInMute     (0x0),
        midiInSolo     (0x0),
+       midiInFilter   (-1),
        midiOutL       (false),
        midiOutLplaying(0x0),
        midiOutLmute   (0x0),
@@ -92,8 +92,6 @@ Channel::Channel(int type, int status, int bufferSize)
 Channel::~Channel()
 {
        status = STATUS_OFF;
-       if (vChan != nullptr)
-               delete[] vChan;
 }
 
 
@@ -102,12 +100,10 @@ Channel::~Channel()
 
 bool Channel::allocBuffers()
 {
-       vChan = new (std::nothrow) float[bufferSize];
-       if (vChan == nullptr) {
+       if (!vChan.alloc(bufferSize, G_MAX_IO_CHANS)) {
                gu_log("[Channel::allocBuffers] unable to alloc memory for vChan!\n");
                return false;
        }
-       std::memset(vChan, 0, bufferSize * sizeof(float));      
        return true;
 }
 
@@ -115,7 +111,7 @@ bool Channel::allocBuffers()
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
+void Channel::copy(const Channel* src, pthread_mutex_t* pluginMutex)
 {
        key             = src->key;
        volume          = src->volume;
@@ -153,7 +149,7 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
 
        for (unsigned i=0; i<recorder::global.size(); i++) {
                for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
-                       recorder::action *a = recorder::global.at(i).at(k);
+                       recorder::actiona = recorder::global.at(i).at(k);
                        if (a->chan == src->index) {
                                recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
                                hasActions = true;
@@ -196,140 +192,18 @@ bool Channel::isPlaying() const
 /* -------------------------------------------------------------------------- */
 
 
-int Channel::writePatch(int i, bool isProject)
+void Channel::writePatch(int i, bool isProject)
 {
-       patch::channel_t pch;
-       pch.type            = type;
-       pch.index           = index;
-       pch.size            = guiChannel->getSize();
-       pch.name            = name;
-       pch.key             = key;
-       pch.armed           = armed;
-       pch.column          = guiChannel->getColumnIndex();
-       pch.mute            = mute;
-       pch.mute_s          = mute_s;
-       pch.solo            = solo;
-       pch.volume          = volume;
-       pch.pan             = pan;
-       pch.midiIn          = midiIn;
-       pch.midiInKeyPress  = midiInKeyPress;
-       pch.midiInKeyRel    = midiInKeyRel;
-       pch.midiInKill      = midiInKill;
-       pch.midiInArm       = midiInArm;
-       pch.midiInVolume    = midiInVolume;
-       pch.midiInMute      = midiInMute;
-       pch.midiInFilter    = midiInFilter;
-       pch.midiInSolo      = midiInSolo;
-       pch.midiOutL        = midiOutL;
-       pch.midiOutLplaying = midiOutLplaying;
-       pch.midiOutLmute    = midiOutLmute;
-       pch.midiOutLsolo    = midiOutLsolo;
-
-       for (unsigned i=0; i<recorder::global.size(); i++) {
-               for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
-                       recorder::action* action = recorder::global.at(i).at(k);
-                       if (action->chan == index) {
-                               patch::action_t pac;
-                               pac.type   = action->type;
-                               pac.frame  = action->frame;
-                               pac.fValue = action->fValue;
-                               pac.iValue = action->iValue;
-                               pch.actions.push_back(pac);
-                       }
-               }
-       }
-
-#ifdef WITH_VST
-
-       unsigned numPlugs = pluginHost::countPlugins(pluginHost::CHANNEL, this);
-       for (unsigned i=0; i<numPlugs; i++) {
-               Plugin* pPlugin = pluginHost::getPluginByIndex(i, pluginHost::CHANNEL, this);
-               patch::plugin_t pp;
-               pp.path   = pPlugin->getUniqueId();
-               pp.bypass = pPlugin->isBypassed();
-               for (int k=0; k<pPlugin->getNumParameters(); k++)
-                       pp.params.push_back(pPlugin->getParameter(k));
-               for (unsigned k=0; k<pPlugin->midiInParams.size(); k++)
-                       pp.midiInParams.push_back(pPlugin->midiInParams.at(k));
-               pch.plugins.push_back(pp);
-       }
-
-#endif
-
-       patch::channels.push_back(pch);
-
-       return patch::channels.size() - 1;
+       channelManager::writePatch(this, isProject);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int Channel::readPatch(const string& path, int i, pthread_mutex_t* pluginMutex,
-       int samplerate, int rsmpQuality)
+void Channel::readPatch(const string& path, int i)
 {
-       int ret = 1;
-       patch::channel_t* pch = &patch::channels.at(i);
-       key             = pch->key;
-       armed           = pch->armed;
-       type            = pch->type;
-       name            = pch->name;
-       index           = pch->index;
-       mute            = pch->mute;
-       mute_s          = pch->mute_s;
-       solo            = pch->solo;
-       volume          = pch->volume;
-       pan             = pch->pan;
-       midiIn          = pch->midiIn;
-       midiInKeyPress  = pch->midiInKeyPress;
-       midiInKeyRel    = pch->midiInKeyRel;
-       midiInKill      = pch->midiInKill;
-       midiInVolume    = pch->midiInVolume;
-       midiInMute      = pch->midiInMute;
-       midiInFilter    = pch->midiInFilter;
-       midiInSolo      = pch->midiInSolo;
-       midiOutL        = pch->midiOutL;
-       midiOutLplaying = pch->midiOutLplaying;
-       midiOutLmute    = pch->midiOutLmute;
-       midiOutLsolo    = pch->midiOutLsolo;
-
-       for (const patch::action_t& ac : pch->actions) {
-               recorder::rec(index, ac.type, ac.frame, ac.iValue, ac.fValue);
-               hasActions = true;
-       }
-
-#ifdef WITH_VST
-
-       for (const patch::plugin_t& ppl : pch->plugins) {
-               
-               Plugin* plugin = pluginHost::addPlugin(ppl.path, pluginHost::CHANNEL,
-                       pluginMutex, this);
-               
-               if (plugin == nullptr) {
-                       ret &= 0;
-                       continue;
-               }
-
-               plugin->setBypass(ppl.bypass);
-               
-               for (unsigned j=0; j<ppl.params.size(); j++)
-                       plugin->setParameter(j, ppl.params.at(j));
-               
-               /* Don't fill Channel::midiInParam if Patch::midiInParams are 0: it would
-               wipe out the current default 0x0 values. */
-
-               if (!ppl.midiInParams.empty()) {
-                       plugin->midiInParams.clear();
-                       for (uint32_t midiInParam : ppl.midiInParams)
-                               plugin->midiInParams.push_back(midiInParam);
-               }
-
-               ret &= 1;
-       }
-
-#endif
-
-       return ret;
+       channelManager::readPatch(this, i);
 }
 
 
@@ -395,18 +269,6 @@ void Channel::receiveMidi(const MidiEvent& midiEvent)
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::setMidiInFilter(int c)
-{
-       midiInFilter = c;
-}
-
-
-int Channel::getMidiInFilter() const
-{
-       return midiInFilter;
-}
-
-
 bool Channel::isMidiInAllowed(int c) const
 {
        return midiInFilter == -1 || midiInFilter == c;
@@ -437,24 +299,12 @@ float Channel::getPan() const
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::setVolume(float v)
-{
-       volume = v;
-}
-
-
 void Channel::setVolumeI(float v)
 {
        volume_i = v;
 }
 
 
-float Channel::getVolume() const
-{
-       return volume;
-}
-
-
 /* -------------------------------------------------------------------------- */
 
 
@@ -487,36 +337,6 @@ bool Channel::isPreview() const
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::setArmed(bool b)
-{
-       armed = b;
-}
-
-
-bool Channel::isArmed() const
-{
-       return armed;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string Channel::getName() const
-{
-       return name;
-}
-
-
-void Channel::setName(const std::string& s)
-{
-       name = s;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 #ifdef WITH_VST
 
 juce::MidiBuffer &Channel::getPluginMidiEvents()
index d8394fbf34b9e1085380dbe9d0273882ab5d9204..8a78c558c3713ce8e5214319a397a600d34ef156 100644 (file)
@@ -35,6 +35,7 @@
 #include "midiMapConf.h"
 #include "midiEvent.h"
 #include "recorder.h"
+#include "audioBuffer.h"
 
 #ifdef WITH_VST
        #include "../deps/juce-config.h"
@@ -50,6 +51,8 @@ class Channel
 {
 protected:
 
+       Channel(int type, int status, int bufferSize);
+
        /* sendMidiLMessage
        Composes a MIDI message by merging bytes from MidiMap conf class, and sends it 
        to KernelMidi. */
@@ -61,6 +64,11 @@ protected:
 
        float calcPanning(int ch);
 
+       /* vChan
+       Virtual channel for internal processing. */
+       
+       giada::m::AudioBuffer vChan;
+
 #ifdef WITH_VST
 
        /* MidiBuffer contains MIDI events. When ready, events are sent to each plugin 
@@ -76,28 +84,17 @@ protected:
 
        int bufferSize;
 
-  /* midiInFilter
-  Which MIDI channel should be filtered out when receiving MIDI messages. -1
-  means 'all'. */
-
-  int midiInFilter;
-
-       /* previewMode
-       Whether the channel is in audio preview mode or not. */
-
-       int previewMode;
-
-       float pan;
-       float volume;   // global volume
-       float volume_i; // internal volume
-       float volume_d; // delta volume (for envelope)
-       bool armed;
-       std::string name;
+       /* volume_*
+       Internal volume variables: volume_i for envelopes, volume_d keeps track of
+       the delta during volume changes. */
+       
+       float volume_i;
+       float volume_d;
 
+       bool mute_i;                // internal mute
+       
 public:
 
-       Channel(int type, int status, int bufferSize);
-
        virtual ~Channel();
 
        /* copy
@@ -105,23 +102,17 @@ public:
 
        virtual void copy(const Channel* src, pthread_mutex_t* pluginMutex) = 0;
 
-       /* readPatch
-       Fills channel with data from patch. */
-
-       virtual int readPatch(const std::string& basePath, int i,
-    pthread_mutex_t* pluginMutex, int samplerate, int rsmpQuality);
-
        /* process
        Merges vChannels into buffer, plus plugin processing (if any). Warning:
        inBuffer might be nullptr if no input devices are available for recording. */
 
-       virtual void process(float* outBuffer, float* inBuffer) = 0;
+       virtual void process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in) = 0;
 
        /* Preview
        Makes itself audibile for audio preview, such as Sample Editor or other
        tools. */
 
-       virtual void preview(float* outBuffer) = 0;
+       virtual void preview(giada::m::AudioBuffer& in) = 0;
 
        /* start
        Action to do when channel starts. doQuantize = false (don't quantize)
@@ -160,10 +151,11 @@ public:
        virtual void stopBySeq(bool chansStopOnSeqHalt) = 0;
 
        /* quantize
-       Starts channel according to quantizer. Index = array index of mixer::channels, 
-       used by recorder. LocalFrame = frame within the current buffer.  */
+       Starts channel according to quantizer. Index = array index of mixer::channels 
+       used by recorder, localFrame = frame within the current buffer, 
+       globalFrame = frame within the whole sequencer loop.  */
 
-       virtual void quantize(int index, int localFrame) = 0;
+       virtual void quantize(int index, int localFrame, int globalFrame) = 0;
 
        /* onZero
        What to do when frame goes to zero, i.e. sequencer restart. */
@@ -204,11 +196,16 @@ public:
 
        virtual bool canInputRec() = 0;
 
+       /* readPatch
+       Fills channel with data from patch. */
+
+       virtual void readPatch(const std::string& basePath, int i);
+
        /* writePatch
        Fills a patch with channel values. Returns the index of the last 
        Patch::channel_t added. */
 
-       virtual int writePatch(int i, bool isProject);
+       virtual void writePatch(int i, bool isProject);
 
        /* receiveMidi
        Receives and processes midi messages from external devices. */
@@ -223,11 +220,7 @@ public:
 
        bool isPlaying() const;
        float getPan() const;
-       float getVolume() const;
-       bool isArmed() const;
-       std::string getName() const;
        bool isPreview() const;
-       int getMidiInFilter() const;
 
        /* isMidiAllowed
        Given a MIDI channel 'c' tells whether this channel should be allowed to receive
@@ -243,12 +236,8 @@ public:
        void sendMidiLplay();
 
        void setPan(float v);
-       void setVolume(float v);
        void setVolumeI(float v);
-       void setArmed(bool b);
-       void setName(const std::string& s);
        void setPreviewMode(int m);
-       void setMidiInFilter(int c);
 
 #ifdef WITH_VST
 
@@ -262,30 +251,43 @@ public:
 
 #endif
 
-       int    index;                 // unique id
-       int    type;                  // midi or sample
-       int    status;                // status: see const.h
-       int    key;                   // keyboard button
-       bool   mute_i;                // internal mute
-       bool     mute_s;                // previous mute status after being solo'd
-       bool   mute;                  // global mute
-       bool   solo;
-  bool   hasActions;            // has something recorded
-  bool   readActions;           // read what's recorded
-       int      recStatus;             // status of recordings (waiting, ending, ...)
-       float* vChan;                 // virtual channel
   geChannel* guiChannel;        // pointer to a gChannel object, part of the GUI
+       
+       /* previewMode
+       Whether the channel is in audio preview mode or not. */
 
-       // TODO - midi structs, please
+       int previewMode;
+
+       float       pan;
+       float       volume;   // global volume
+       bool        armed;
+       std::string name;
+       int         index;    // unique id
+       int         type;     // midi or sample
+       int         status;   // status: see const.h
+       int         key;      // keyboard button
+       bool        mute;     // global mute
+       bool        mute_s;   // previous mute status after being solo'd TODO - remove it with mute refactoring
+       bool        solo;
+
+  bool hasActions;      // has something recorded
+  bool readActions;     // read what's recorded
+       int  recStatus;       // status of recordings (waiting, ending, ...)
+  
+  bool      midiIn;               // enable midi input
+  uint32_t  midiInKeyPress;
+  uint32_t  midiInKeyRel;
+  uint32_t  midiInKill;
+  uint32_t  midiInArm;
+  uint32_t  midiInVolume;
+  uint32_t  midiInMute;
+  uint32_t  midiInSolo;
+
+  /* midiInFilter
+  Which MIDI channel should be filtered out when receiving MIDI messages. -1
+  means 'all'. */
 
-  bool     midiIn;              // enable midi input
-  uint32_t midiInKeyPress;
-  uint32_t midiInKeyRel;
-  uint32_t midiInKill;
-  uint32_t midiInArm;
-  uint32_t midiInVolume;
-  uint32_t midiInMute;
-  uint32_t midiInSolo;
+  int midiInFilter;
 
        /*  midiOutL*
         * Enable MIDI lightning output, plus a set of midi lighting event to be sent
diff --git a/src/core/channelManager.cpp b/src/core/channelManager.cpp
new file mode 100644 (file)
index 0000000..addc5cb
--- /dev/null
@@ -0,0 +1,314 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../gui/elems/mainWindow/keyboard/channel.h"
+#include "../utils/fs.h"
+#include "const.h"
+#include "channel.h"
+#include "patch.h"
+#include "mixer.h"
+#include "wave.h"
+#include "waveManager.h"
+#include "sampleChannel.h"
+#include "midiChannel.h"
+#include "pluginHost.h"
+#include "plugin.h"
+#include "channelManager.h"
+
+
+using std::string;
+
+
+namespace giada {
+namespace m {
+namespace channelManager
+{
+namespace
+{
+void writeActions_(int chanIndex, patch::channel_t& pch)
+{
+       recorder::forEachAction([&] (const recorder::action* a) {
+               if (a->chan != chanIndex) 
+                       return;
+               pch.actions.push_back(patch::action_t { 
+                       a->type, a->frame, a->fValue, a->iValue 
+               });
+       });
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void writePlugins_(const Channel* ch, patch::channel_t& pch)
+{
+#ifdef WITH_VST
+
+       pluginHost::forEachPlugin(pluginHost::CHANNEL, ch, [&] (const Plugin* p) {
+               patch::plugin_t pp;
+               pp.path   = p->getUniqueId();
+               pp.bypass = p->isBypassed();
+               for (int k=0; k<p->getNumParameters(); k++)
+                       pp.params.push_back(p->getParameter(k));
+               for (uint32_t param : p->midiInParams)
+                       pp.midiInParams.push_back(param);
+               pch.plugins.push_back(pp);
+       });
+
+#endif
+}
+} // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void readActions_(Channel* ch, const patch::channel_t& pch)
+{
+       for (const patch::action_t& ac : pch.actions) {
+               recorder::rec(ch->index, ac.type, ac.frame, ac.iValue, ac.fValue);
+               ch->hasActions = true;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void readPlugins_(Channel* ch, const patch::channel_t& pch)
+{
+#ifdef WITH_VST
+
+       for (const patch::plugin_t& ppl : pch.plugins) {
+               Plugin* plugin = pluginHost::addPlugin(ppl.path, pluginHost::CHANNEL,
+                       &mixer::mutex_plugins, ch);
+               if (plugin == nullptr)
+                       continue;
+
+               plugin->setBypass(ppl.bypass);
+               for (unsigned j=0; j<ppl.params.size(); j++)
+                       plugin->setParameter(j, ppl.params.at(j));
+
+               /* Don't fill Channel::midiInParam if Patch::midiInParams are 0: it would
+               wipe out the current default 0x0 values. */
+
+               if (!ppl.midiInParams.empty()) {
+                       plugin->midiInParams.clear();
+                       for (uint32_t midiInParam : ppl.midiInParams)
+                               plugin->midiInParams.push_back(midiInParam);
+               }
+       }
+
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+int create(int type, int bufferSize, bool inputMonitorOn, Channel** out)
+{
+       Channel* ch;
+       if (type == G_CHANNEL_SAMPLE)
+               ch = new SampleChannel(bufferSize, inputMonitorOn);
+       else
+               ch = new MidiChannel(bufferSize);
+
+       if (!ch->allocBuffers()) {
+               delete ch;
+               return G_RES_ERR_MEMORY;
+       }
+
+       *out = ch;
+
+       return G_RES_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int writePatch(const Channel* ch, bool isProject)
+{
+       patch::channel_t pch;
+       pch.type            = ch->type;
+       pch.index           = ch->index;
+       pch.size            = ch->guiChannel->getSize();
+       pch.name            = ch->name;
+       pch.key             = ch->key;
+       pch.armed           = ch->armed;
+       pch.column          = ch->guiChannel->getColumnIndex();
+       pch.mute            = ch->mute;
+       // pch.mute_s          = ch->mute_s;  TODO remove it with mute refactoring
+       pch.solo            = ch->solo;
+       pch.volume          = ch->volume;
+       pch.pan             = ch->pan;
+       pch.midiIn          = ch->midiIn;
+       pch.midiInKeyPress  = ch->midiInKeyPress;
+       pch.midiInKeyRel    = ch->midiInKeyRel;
+       pch.midiInKill      = ch->midiInKill;
+       pch.midiInArm       = ch->midiInArm;
+       pch.midiInVolume    = ch->midiInVolume;
+       pch.midiInMute      = ch->midiInMute;
+       pch.midiInFilter    = ch->midiInFilter;
+       pch.midiInSolo      = ch->midiInSolo;
+       pch.midiOutL        = ch->midiOutL;
+       pch.midiOutLplaying = ch->midiOutLplaying;
+       pch.midiOutLmute    = ch->midiOutLmute;
+       pch.midiOutLsolo    = ch->midiOutLsolo;
+
+       writeActions_(ch->index, pch);
+       writePlugins_(ch, pch);
+
+       patch::channels.push_back(pch);
+
+       return patch::channels.size() - 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void writePatch(const MidiChannel* ch, bool isProject, int index)
+{
+       patch::channel_t& pch = patch::channels.at(index);
+       pch.midiOut     = ch->midiOut;
+       pch.midiOutChan = ch->midiOutChan;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void writePatch(const SampleChannel* ch, bool isProject, int index)
+{
+       patch::channel_t& pch = patch::channels.at(index);
+
+       if (ch->wave != nullptr) {
+               pch.samplePath = ch->wave->getPath();
+               if (isProject)
+                       pch.samplePath = gu_basename(ch->wave->getPath());  // make it portable
+       }
+       else
+               pch.samplePath = "";
+
+       pch.mode              = ch->mode;
+       pch.begin             = ch->getBegin();
+       pch.end               = ch->getEnd();
+       pch.boost             = ch->getBoost();
+       pch.recActive         = ch->readActions;
+       pch.pitch             = ch->getPitch();
+       pch.inputMonitor      = ch->inputMonitor;
+       pch.midiInReadActions = ch->midiInReadActions;
+       pch.midiInPitch       = ch->midiInPitch;        
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void readPatch(Channel* ch, int i)
+{
+       const patch::channel_t& pch = patch::channels.at(i);
+
+       ch->key             = pch.key;
+       ch->armed           = pch.armed;
+       ch->type            = pch.type;
+       ch->name            = pch.name;
+       ch->index           = pch.index;
+       ch->mute            = pch.mute;
+       //ch->mute_s          = pch.mute_s;
+       ch->solo            = pch.solo;
+       ch->volume          = pch.volume;
+       ch->pan             = pch.pan;
+       ch->midiIn          = pch.midiIn;
+       ch->midiInKeyPress  = pch.midiInKeyPress;
+       ch->midiInKeyRel    = pch.midiInKeyRel;
+       ch->midiInKill      = pch.midiInKill;
+       ch->midiInVolume    = pch.midiInVolume;
+       ch->midiInMute      = pch.midiInMute;
+       ch->midiInFilter    = pch.midiInFilter;
+       ch->midiInSolo      = pch.midiInSolo;
+       ch->midiOutL        = pch.midiOutL;
+       ch->midiOutLplaying = pch.midiOutLplaying;
+       ch->midiOutLmute    = pch.midiOutLmute;
+       ch->midiOutLsolo    = pch.midiOutLsolo;
+
+       readActions_(ch, pch);
+       readPlugins_(ch, pch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void readPatch(SampleChannel* ch, const string& basePath, int i)
+{
+       const patch::channel_t& pch = patch::channels.at(i);
+
+       ch->mode              = pch.mode;
+       ch->readActions       = pch.recActive;
+       ch->recStatus         = pch.recActive ? REC_READING : REC_STOPPED;
+       ch->midiInVeloAsVol   = pch.midiInVeloAsVol;
+       ch->midiInReadActions = pch.midiInReadActions;
+       ch->midiInPitch       = pch.midiInPitch;
+  ch->inputMonitor      = pch.inputMonitor;
+       ch->setBoost(pch.boost);
+
+  Wave* w = nullptr;
+  int res = waveManager::create(basePath + pch.samplePath, &w); 
+
+       if (res == G_RES_OK) {
+               ch->pushWave(w);
+               ch->setBegin(pch.begin);
+               ch->setEnd(pch.end);
+               ch->setPitch(pch.pitch);
+       }
+       else {
+               if (res == G_RES_ERR_NO_DATA)
+                       ch->status = STATUS_EMPTY;
+               else
+               if (res == G_RES_ERR_IO)
+                       ch->status = STATUS_MISSING;
+               ch->sendMidiLplay();  // FIXME - why sending MIDI lightning if sample status is wrong?
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void readPatch(MidiChannel* ch, int i)
+{
+       const patch::channel_t& pch = patch::channels.at(i);
+
+       ch->midiOut     = pch.midiOut;
+       ch->midiOutChan = pch.midiOutChan;      
+}
+}}}; // giada::m::channelManager
diff --git a/src/core/channelManager.h b/src/core/channelManager.h
new file mode 100644 (file)
index 0000000..3e3a11c
--- /dev/null
@@ -0,0 +1,56 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef G_CHANNEL_MANAGER_H
+#define G_CHANNEL_MANAGER_H
+
+
+#include <string>
+
+
+class Channel;
+class SampleChannel;
+class MidiChannel;
+
+
+namespace giada {
+namespace m {
+namespace channelManager
+{
+int create(int type, int bufferSize, bool inputMonitorOn, Channel** out);
+
+int  writePatch(const Channel* ch, bool isProject);
+void writePatch(const SampleChannel* ch, bool isProject, int index);
+void writePatch(const MidiChannel* ch, bool isProject, int index);
+
+void readPatch(Channel* ch, int index);
+void readPatch(SampleChannel* ch, const std::string& basePath, int index);
+void readPatch(MidiChannel* ch, int index);
+}}}; // giada::m::channelManager
+
+
+#endif
\ No newline at end of file
index a62d0b04ff7015c7eb53df4af991072550313adf..9a38b6a19a19baba02c5bff3c4c1f1bc400defed 100644 (file)
@@ -46,13 +46,14 @@ float bpm      = G_DEFAULT_BPM;
 int   bars     = G_DEFAULT_BARS;
 int   beats    = G_DEFAULT_BEATS;
 int   quantize = G_DEFAULT_QUANTIZE;
-int   quanto   = 1;           // quantizer step
-int   framesPerBar      = 0;  // frames in one bar
-int   framesPerBeat     = 0;  // frames in one beat
-int   framesInSequencer = 0;  // frames in the whole sequencer
-int   totalFrames  = 0;       // frames in the selected range (e.g. 4/4)
-int   currentFrame = 0;
-int   currentBeat  = 0;
+int   quanto   = 1;            // quantizer step
+
+int framesInLoop = 0;
+int framesInBar  = 0;
+int framesInBeat = 0;
+int framesInSeq  = 0;
+int currentFrame = 0;
+int currentBeat  = 0;
 
 int midiTCrate    = 0;      // send MTC data every midiTCrate frames
 int midiTCframes  = 0;
@@ -67,10 +68,8 @@ kernelAudio::JackState jackStatePrev;
 
 void updateQuanto()
 {
-  if (quantize != 0)
-    quanto = framesPerBeat / quantize;
-  if (quanto % 2 != 0)
-    quanto++;
+       if (quantize != 0)
+               quanto = framesInBeat / quantize;
 }
 
 }; // {anonymous}
@@ -83,13 +82,13 @@ void updateQuanto()
 
 void init(int sampleRate, float midiTCfps)
 {
-  midiTCrate = (sampleRate / midiTCfps) * 2;  // stereo values
-  running    = false;
-  bpm        = G_DEFAULT_BPM;
-  bars       = G_DEFAULT_BARS;
-  beats      = G_DEFAULT_BEATS;
-  quantize   = G_DEFAULT_QUANTIZE;
-  updateFrameBars();
+       midiTCrate = (sampleRate / midiTCfps) * G_MAX_IO_CHANS;  // stereo values
+       running    = false;
+       bpm        = G_DEFAULT_BPM;
+       bars       = G_DEFAULT_BARS;
+       beats      = G_DEFAULT_BEATS;
+       quantize   = G_DEFAULT_QUANTIZE;
+       updateFrameBars();
 }
 
 
@@ -98,40 +97,40 @@ void init(int sampleRate, float midiTCfps)
 
 bool isRunning()
 {
-  return running;
+       return running;
 }
 
 
 bool quantoHasPassed()
 {
-  return currentFrame % (quanto) == 0;
+       return currentFrame % (quanto) == 0;
 }
 
 
 bool isOnBar()
 {
-  /* A bar cannot occur at frame 0. That's the first beat. */
-  return currentFrame % framesPerBar == 0 && currentFrame != 0;
+       /* A bar cannot occur at frame 0. That's the first beat. */
+       return currentFrame % framesInBar == 0 && currentFrame != 0;
 }
 
 
 bool isOnBeat()
 {
-  /* Skip frame 0: it is intended as 'first beat'. */
-  /* TODO - this is wrong! */
-  return currentFrame % framesPerBeat == 0 && currentFrame > 0;
+       /* Skip frame 0: it is intended as 'first beat'. */
+       /* TODO - this is wrong! */
+       return currentFrame % framesInBeat == 0 && currentFrame > 0;
 }
 
 
 bool isOnFirstBeat()
 {
-  return currentFrame == 0;
+       return currentFrame == 0;
 }
 
 
 void start()
 {
-  running = true;
+       running = true;
        if (conf::midiSync == MIDI_SYNC_CLOCK_M) {
                kernelMidi::send(MIDI_START, -1, -1);
                kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
@@ -141,79 +140,78 @@ void start()
 
 void stop()
 {
-  running = false;
-  if (conf::midiSync == MIDI_SYNC_CLOCK_M)
-       kernelMidi::send(MIDI_STOP, -1, -1);
+       running = false;
+       if (conf::midiSync == MIDI_SYNC_CLOCK_M)
+               kernelMidi::send(MIDI_STOP, -1, -1);
 }
 
 
 void setBpm(float b)
 {
-  if (b < G_MIN_BPM)
-    b = G_MIN_BPM;
-  bpm = b;
+       if (b < G_MIN_BPM)
+               b = G_MIN_BPM;
+       bpm = b;
        updateFrameBars();
 }
 
 
 void setBars(int newBars)
 {
-  /* Bars cannot be greater than beats and must be a sub multiple of beats. If
-  not, approximate to the nearest (and greater) value available. */
-
-  if (newBars > beats)
-    bars = beats;
-  else if (newBars <= 0)
-    bars = 1;
-  else if (beats % newBars != 0) {
-    bars = newBars + (beats % newBars);
-    if (beats % bars != 0) // it could be an odd value, let's check it (and avoid it)
-      bars = bars - (beats % bars);
-  }
-  else
-    bars = newBars;
+       /* Bars cannot be greater than beats and must be a sub multiple of beats. If
+       not, approximate to the nearest (and greater) value available. */
+
+       if (newBars > beats)
+               bars = beats;
+       else if (newBars <= 0)
+               bars = 1;
+       else if (beats % newBars != 0) {
+               bars = newBars + (beats % newBars);
+               if (beats % bars != 0) // it could be an odd value, let's check it (and avoid it)
+                       bars = bars - (beats % bars);
+       }
+       else
+               bars = newBars;
 }
 
 
 void setBeats(int b)
 {
-  if (b > G_MAX_BEATS)
+       if (b > G_MAX_BEATS)
                beats = G_MAX_BEATS;
        else if (b < 1)
-    beats = 1;
+               beats = 1;
        else
-    beats = b;
+               beats = b;
 }
 
 
 void setQuantize(int q)
 {
-  quantize = q;
-  updateQuanto();
+       quantize = q;
+       updateQuanto();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void incrCurrentFrame()
-{
-  currentFrame += 2;
-  if (currentFrame > totalFrames) {
+void incrCurrentFrame() {
+       currentFrame++;
+       if (currentFrame > framesInLoop) {
                currentFrame = 0;
                currentBeat  = 0;
        }
-  else
-  if (isOnBeat())
-    currentBeat++;
+       else
+       if (isOnBeat())
+               currentBeat++;
 }
 
 
 void rewind()
 {
-  currentFrame = 0;
-  currentBeat = 0;
-  sendMIDIrewind();
+       currentFrame = 0;
+       currentBeat  = 0;
+       sendMIDIrewind();
 }
 
 
@@ -222,29 +220,18 @@ void rewind()
 
 void updateFrameBars()
 {
-       /* seconds ....... total time of play (in seconds) of the whole
-        *                 sequencer. 60 / bpm == how many seconds lasts one bpm
-        * totalFrames ... loop length in frames, x2 because it's stereo
-        * framesPerBar .. n. of frames within a bar
-        * framesPerBeat . n. of frames within a beat
-   * framesInSeq ... number of frames in the whole sequencer */
-
-       float seconds     = (60.0f / bpm) * beats;
-       totalFrames       = conf::samplerate * seconds * 2;
-       framesPerBar      = totalFrames / bars;
-       framesPerBeat     = totalFrames / beats;
-       framesInSequencer = framesPerBeat * G_MAX_BEATS;
-
-       /* big troubles if frames are odd. */
-
-       if (totalFrames % 2 != 0)
-               totalFrames--;
-       if (framesPerBar % 2 != 0)
-               framesPerBar--;
-       if (framesPerBeat % 2 != 0)
-               framesPerBeat--;
-
-  updateQuanto();
+       /* framesInLoop ... loop length in frames, or samplerate * # frames per 
+        *                  current bpm * beats;
+        * framesInBar .... n. of frames within a bar;
+        * framesInBeat ... n. of frames within a beat;
+        * framesInSeq .... number of frames in the whole sequencer. */
+
+       framesInLoop = (conf::samplerate * (60.0f / bpm)) * beats;
+       framesInBar  = framesInLoop / bars;
+       framesInBeat = framesInLoop / beats;
+       framesInSeq  = framesInBeat * G_MAX_BEATS;
+
+       updateQuanto();
 }
 
 
@@ -253,13 +240,13 @@ void updateFrameBars()
 
 void sendMIDIsync()
 {
-  /* TODO - only Master (_M) is implemented so far. */
+       /* TODO - only Master (_M) is implemented so far. */
 
        if (conf::midiSync == MIDI_SYNC_CLOCK_M) {
-               if (currentFrame % (framesPerBeat/24) == 0)
+               if (currentFrame % (framesInBeat/24) == 0)
                        kernelMidi::send(MIDI_CLOCK, -1, -1);
-    return;
-  }
+               return;
+       }
 
        if (conf::midiSync == MIDI_SYNC_MTC_M) {
 
@@ -269,7 +256,7 @@ void sendMIDIsync()
                 * range 1-4, if odd send 5-8. */
 
                if (currentFrame % midiTCrate != 0)  // no timecode frame passed
-      return;
+                       return;
 
                /* frame low nibble
                 * frame high nibble
@@ -348,26 +335,26 @@ void sendMIDIrewind()
 
 void recvJackSync()
 {
-  kernelAudio::JackState jackState = kernelAudio::jackTransportQuery();
-
-  if (jackState.running != jackStatePrev.running) {
-    if (jackState.running) {
-      if (!isRunning())
-        glue_startSeq(false); // not from UI
-    }
-    else {
-      if (isRunning())
-        glue_stopSeq(false); // not from UI
-    }
-  }
-  if (jackState.bpm != jackStatePrev.bpm)
-    if (jackState.bpm > 1.0f)  // 0 bpm if Jack does not send that info
-      glue_setBpm(jackState.bpm);
-
-  if (jackState.frame == 0 && jackState.frame != jackStatePrev.frame)
-    glue_rewindSeq(false, false);  // not from UI, don't notify jack (avoid loop)
-
-  jackStatePrev = jackState;
+       kernelAudio::JackState jackState = kernelAudio::jackTransportQuery();
+
+       if (jackState.running != jackStatePrev.running) {
+               if (jackState.running) {
+                       if (!isRunning())
+                               glue_startSeq(false); // not from UI
+               }
+               else {
+                       if (isRunning())
+                               glue_stopSeq(false); // not from UI
+               }
+       }
+       if (jackState.bpm != jackStatePrev.bpm)
+               if (jackState.bpm > 1.0f)  // 0 bpm if Jack does not send that info
+                       glue_setBpm(jackState.bpm);
+
+       if (jackState.frame == 0 && jackState.frame != jackStatePrev.frame)
+               glue_rewindSeq(false, false);  // not from UI, don't notify jack (avoid loop)
+
+       jackStatePrev = jackState;
 }
 
 #endif
@@ -378,67 +365,67 @@ void recvJackSync()
 
 int getCurrentFrame()
 {
-  return currentFrame;
+       return currentFrame;
 }
 
 
-int getTotalFrames()
+int getFramesInLoop()
 {
-  return totalFrames;
+       return framesInLoop;
 }
 
 
 int getCurrentBeat()
 {
-  return currentBeat;
+       return currentBeat;
 }
 
 
 int getQuantize()
 {
-  return quantize;
+       return quantize;
 }
 
 
 float getBpm()
 {
-  return bpm;
+       return bpm;
 }
 
 
 int getBeats()
 {
-  return beats;
+       return beats;
 }
 
 
 int getBars()
 {
-  return bars;
+       return bars;
 }
 
 
 int getQuanto()
 {
-  return quanto;
+       return quanto;
 }
 
 
-int getFramesPerBar()
+int getFramesInBar()
 {
-  return framesPerBar;
+       return framesInBar;
 }
 
 
-int getFramesPerBeat()
+int getFramesInBeat()
 {
-  return framesPerBeat;
+       return framesInBeat;
 }
 
 
-int getFramesInSequencer()
+int getFramesInSeq()
 {
-  return framesInSequencer;
+       return framesInSeq;
 }
 
 
index de2972d24d92786331c7db80c1d8f0a612fa261a..c7dd35e72674bbce0b0b35cc2177ca5a35c03765 100644 (file)
 #define G_CLOCK_H
 
 
-class Conf;
-class KernelMidi;
-class KernelAudio;
-
-
 namespace giada {
 namespace m {
 namespace clock
@@ -57,17 +52,17 @@ void recvJackSync();
 float getBpm();
 int getBeats();
 int getBars();
-int getCurrentFrame();
 int getCurrentBeat();
-int getFramesPerBar();
-int getFramesPerBeat();
-int getTotalFrames();
-int getFramesInSequencer();
+int getCurrentFrame();
+int getFramesInBar();
+int getFramesInBeat();
+int getFramesInLoop();
+int getFramesInSeq();
 int getQuantize();
 int getQuanto();
 
 /* incrCurrentFrame
-Increases current frame of a stereo step (+2). */
+Increases current frame of a single step (+1). */
 
 void incrCurrentFrame();
 
index a587117618b5bf10ff165da1126e61974e4ff220..e93bcd04a95235f6c013a126e06b886e2a244174 100644 (file)
 
 /* -- version --------------------------------------------------------------- */
 #define G_APP_NAME      "Giada"
-#define G_VERSION_STR   "0.14.6"
+#define G_VERSION_STR   "0.15.0"
 #define G_VERSION_MAJOR 0
-#define G_VERSION_MINOR 14
-#define G_VERSION_PATCH 6
+#define G_VERSION_MINOR 15
+#define G_VERSION_PATCH 0
 
 #define CONF_FILENAME "giada.conf"
 
@@ -73,6 +73,7 @@
 #define G_GUI_CHANNEL_H_2    G_GUI_UNIT * 2
 #define G_GUI_CHANNEL_H_3    G_GUI_UNIT * 4
 #define G_GUI_CHANNEL_H_4    G_GUI_UNIT * 6
+#define G_GUI_ZOOM_FACTOR    2
 
 
 #define G_COLOR_RED       fl_rgb_color(28,  32,  80)
 #define G_MAX_BUF_SIZE      4096
 #define G_MIN_GUI_WIDTH     816
 #define G_MIN_GUI_HEIGHT    510
+#define G_MAX_IO_CHANS      2
 
 
 
 #define G_DEFAULT_BUFSIZE          1024
 #define G_DEFAULT_DELAYCOMP        0
 #define G_DEFAULT_BIT_DEPTH        32     // float
-#define G_DEFAULT_AUDIO_CHANS      2      // stereo for internal processing
 #define G_DEFAULT_VOL              1.0f
 #define G_DEFAULT_PITCH            1.0f
 #define G_DEFAULT_BOOST            1.0f
 
 
 /* -- channel types --------------------------------------------------------- */
-#define CHANNEL_SAMPLE 0x01
-#define CHANNEL_MIDI   0x02
+#define G_CHANNEL_SAMPLE 0x01
+#define G_CHANNEL_MIDI   0x02
 
 
 
index 5db174c0230ab9c5f04855235aaca42307641aae..1809e50b5fd416dc8c1c9f1d6e2b625ce5e9ccd8 100644 (file)
@@ -81,7 +81,7 @@ void init_prepareKernelAudio()
 {
   kernelAudio::openDevice();
   clock::init(conf::samplerate, conf::midiTCfps);
-       mixer::init(clock::getTotalFrames(), kernelAudio::getRealBufSize());
+       mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
        recorder::init();
 
 #ifdef WITH_VST
@@ -194,12 +194,6 @@ void init_shutdown()
        }
 
        recorder::clearAll();
-  for (unsigned i=0; i<mixer::channels.size(); i++) {
-               mixer::channels.at(i)->hasActions  = false;
-               mixer::channels.at(i)->readActions = false;
-               //if (mixer::channels.at(i)->type == CHANNEL_SAMPLE)
-               //      ((SampleChannel*)mixer::channels.at(i))->readActions = false;
-       }
        gu_log("[init] Recorder cleaned up\n");
 
 #ifdef WITH_VST
index b67058038068f43dd5186c9d74ea67c13ca54b4c..8e10de6f3e7af1eaafd00213d195b1df2d2f5765 100644 (file)
@@ -30,7 +30,7 @@
 
 
 void init_prepareParser();
-void init_startGUI(int argc, char **argv);
+void init_startGUI(int argc, char** argv);
 void init_prepareKernelAudio();
 void init_prepareKernelMIDI();
 void init_prepareMidiMap();
index 421eb02ab01f429844f141fd0396bf0e026d5bda..c1fa4e4b72ce9c8f5d37c115d31f94fae67faf53 100644 (file)
@@ -138,20 +138,16 @@ int openDevice()
        RtAudio::StreamParameters outParams;
        RtAudio::StreamParameters inParams;
 
-       if (conf::soundDeviceOut == G_DEFAULT_SOUNDDEV_OUT)
-               outParams.deviceId = getDefaultOut();
-       else
-               outParams.deviceId = conf::soundDeviceOut;
-
-       outParams.nChannels = 2;
-       outParams.firstChannel = conf::channelsOut * 2; // chan 0=0, 1=2, 2=4, ...
+       outParams.deviceId     = conf::soundDeviceOut == G_DEFAULT_SOUNDDEV_OUT ? getDefaultOut() : conf::soundDeviceOut;
+       outParams.nChannels    = G_MAX_IO_CHANS;
+       outParams.firstChannel = conf::channelsOut * G_MAX_IO_CHANS; // chan 0=0, 1=2, 2=4, ...
 
-       /* inDevice can be disabled */
+       /* inDevice can be disabled. */
 
        if (conf::soundDeviceIn != -1) {
                inParams.deviceId     = conf::soundDeviceIn;
-               inParams.nChannels    = 2;
-               inParams.firstChannel = conf::channelsIn * 2;   // chan 0=0, 1=2, 2=4, ...
+               inParams.nChannels    = G_MAX_IO_CHANS;
+               inParams.firstChannel = conf::channelsIn * G_MAX_IO_CHANS;   // chan 0=0, 1=2, 2=4, ...
                inputEnabled = true;
        }
        else
@@ -420,7 +416,7 @@ int getDefaultOut()
 /* -------------------------------------------------------------------------- */
 
 
-int    getDeviceByName(const char *name)
+int    getDeviceByName(const charname)
 {
        for (unsigned i=0; i<numDevs; i++)
                if (name == getDeviceName(i))
index 6dacf2944959096979bf4a0e320b43368016bf59..88dbc44d8bb59e7580c60666ab18279c9352c541 100644 (file)
@@ -74,7 +74,7 @@ unsigned getRealBufSize();
 unsigned countDevices();
 int getTotalFreqs(unsigned dev);
 int getFreq(unsigned dev, int i);
-int getDeviceByName(const char *name);
+int getDeviceByName(const charname);
 int getDefaultOut();
 int getDefaultIn();
 bool hasAPI(int API);
index 695fb3c1240073f5f31e78687bff4e98f6718176..4445d7533e5961a584db6a8785aa9e1efdfbc150 100644 (file)
 
 #include "../utils/log.h"
 #include "midiChannel.h"
+#include "channelManager.h"
 #include "channel.h"
 #include "patch.h"
 #include "const.h"
 #include "clock.h"
 #include "conf.h"
 #include "mixer.h"
-#ifdef WITH_VST
-       #include "pluginHost.h"
-#endif
+#include "pluginHost.h"
 #include "kernelMidi.h"
 
 
@@ -44,7 +43,7 @@ using namespace giada::m;
 
 
 MidiChannel::MidiChannel(int bufferSize)
-       : Channel    (CHANNEL_MIDI, STATUS_OFF, bufferSize),
+       : Channel    (G_CHANNEL_MIDI, STATUS_OFF, bufferSize),
                midiOut    (false),
                midiOutChan(MIDI_CHANS[0])
 {
@@ -60,10 +59,10 @@ MidiChannel::~MidiChannel() {}
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::copy(const Channel *_src, pthread_mutex_t *pluginMutex)
+void MidiChannel::copy(const Channel* src_, pthread_mutex_t* pluginMutex)
 {
-       Channel::copy(_src, pluginMutex);
-       MidiChannel *src = (MidiChannel *) _src;
+       Channel::copy(src_, pluginMutex);
+       const MidiChannel* src = static_cast<const MidiChannel*>(src_);
        midiOut     = src->midiOut;
        midiOutChan = src->midiOutChan;
 }
@@ -107,17 +106,17 @@ void MidiChannel::empty() {}
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::quantize(int index, int localFrame) {}
+void MidiChannel::quantize(int index, int localFrame, int globalFrame) {}
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::parseAction(recorder::action *a, int localFrame,
+void MidiChannel::parseAction(recorder::actiona, int localFrame,
                int globalFrame, int quantize, bool mixerIsRunning)
 {
        if (a->type == G_ACTION_MIDI)
-               sendMidi(a, localFrame/2);
+               sendMidi(a, localFrame);
 }
 
 
@@ -166,24 +165,23 @@ void MidiChannel::unsetMute(bool internal)
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::process(float *outBuffer, float *inBuffer)
+void MidiChannel::process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in)
 {
 #ifdef WITH_VST
        pluginHost::processStack(vChan, pluginHost::CHANNEL, this);
 #endif
 
        /* TODO - isn't this useful only if WITH_VST ? */
-       for (int j=0; j<bufferSize; j+=2) {
-               outBuffer[j]   += vChan[j]   * volume; // * panLeft;   future?
-               outBuffer[j+1] += vChan[j+1] * volume; // * panRight;  future?
-       }
+       for (int i=0; i<out.countFrames(); i++)
+               for (int j=0; j<out.countChannels(); j++)
+                       out[i][j] += vChan[i][j] * volume;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::preview(float *outBuffer)
+void MidiChannel::preview(giada::m::AudioBuffer& out)
 {
        // No preview for MIDI channels (for now).
 }
@@ -242,24 +240,17 @@ void MidiChannel::kill(int frame)
 /* -------------------------------------------------------------------------- */
 
 
-int MidiChannel::readPatch(const string &basePath, int i,
-               pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality)
+void MidiChannel::readPatch(const string& basePath, int i)
 {
-       Channel::readPatch("", i, pluginMutex, samplerate, rsmpQuality);
-
-       patch::channel_t *pch = &patch::channels.at(i);
-
-       midiOut     = pch->midiOut;
-       midiOutChan = pch->midiOutChan;
-
-       return G_RES_OK;
+       Channel::readPatch("", i);
+       channelManager::readPatch(this, i);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::sendMidi(recorder::action *a, int localFrame)
+void MidiChannel::sendMidi(recorder::actiona, int localFrame)
 {
        if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
                if (midiOut)
@@ -300,15 +291,10 @@ void MidiChannel::rewind()
 /* -------------------------------------------------------------------------- */
 
 
-int MidiChannel::writePatch(int i, bool isProject)
+void MidiChannel::writePatch(int i, bool isProject)
 {
-       int pchIndex = Channel::writePatch(i, isProject);
-       patch::channel_t *pch = &patch::channels.at(pchIndex);
-
-       pch->midiOut     = midiOut;
-       pch->midiOutChan = midiOutChan;
-
-       return 0;
+       Channel::writePatch(i, isProject);
+       channelManager::writePatch(this, isProject, i);
 }
 
 
index 4617c457b89b839f0a060dc097a0cd063b6ddcb0..3ecad62aecb401652e1dc437d6d99bd8031f7edd 100644 (file)
@@ -46,13 +46,10 @@ public:
        MidiChannel(int bufferSize);
        ~MidiChannel();
 
-  bool    midiOut;           // enable midi output
-  uint8_t midiOutChan;       // midi output channel
-
        void copy(const Channel* src, pthread_mutex_t* pluginMutex) override;
        void clear() override;
-       void process(float* outBuffer, float *inBuffer) override;
-       void preview(float* outBuffer) override;
+       void process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in) override;
+       void preview(giada::m::AudioBuffer& out) override;
        void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning,
                bool forceStart, bool isUserGenerated) override;
        void kill(int frame) override;
@@ -62,10 +59,9 @@ public:
        void rewind() override;
        void setMute(bool internal) override;
        void unsetMute(bool internal) override;
-       int readPatch(const std::string& basePath, int i, pthread_mutex_t* pluginMutex,
-    int samplerate, int rsmpQuality) override;
-       int writePatch(int i, bool isProject) override;
-       void quantize(int index, int localFrame) override;
+       void readPatch(const std::string& basePath, int i) override;
+       void writePatch(int i, bool isProject) override;
+       void quantize(int index, int localFrame, int globalFrame) override;
        void onZero(int frame, bool recsStopOnChanHalt) override;
        void onBar(int frame) override;
        void parseAction(giada::m::recorder::action* a, int localFrame, int globalFrame,
@@ -89,6 +85,9 @@ public:
        void addVstMidiEvent(uint32_t msg, int localFrame);
 
 #endif
+
+       bool    midiOut;           // enable midi output
+       uint8_t midiOutChan;       // midi output channel
 };
 
 
index f5ac5c8ae9d2f965d8a088677135b901452af047..7592927ab1fff5e609c45a98e455ebde734a9451 100644 (file)
@@ -40,6 +40,7 @@
 #include "channel.h"
 #include "sampleChannel.h"
 #include "midiChannel.h"
+#include "audioBuffer.h"
 #include "mixer.h"
 
 
@@ -74,29 +75,63 @@ float tick[TICKSIZE] = {
 };
 
 
+AudioBuffer vChanInput;   // virtual channel for recording
+AudioBuffer vChanInToOut; // virtual channel in->out bridge (hear what you're playin)
+
+int  tickTracker, tockTracker = 0;
+bool tickPlay, tockPlay = false; // 1 = play, 0 = stop
+
+/* inputTracker
+Sample position while recording. */
+
+int inputTracker = 0;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool isChannelAudible(Channel* ch)
+{
+       return !hasSolos || (hasSolos && ch->solo);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/* computePeak */
+
+void computePeak(const AudioBuffer& buf, float& peak, unsigned frame)
+{
+       for (int i=0; i<buf.countChannels(); i++)
+               if (buf[frame][i] > peak)
+                       peak = buf[frame][i];
+}
+
+
 /* -------------------------------------------------------------------------- */
 
 
 /* lineInRec
 Records from line in. */
 
-void lineInRec(float* inBuf, unsigned frame)
+void lineInRec(const AudioBuffer& inBuf, unsigned frame)
 {
        if (!mh::hasArmedSampleChannels() || !kernelAudio::isInputEnabled() || !recording)
                return;
 
-       /* Delay comp: wait until waitRec reaches delayComp. WaitRec
-        * returns to 0 in mixerHandler, as soon as the recording ends */
+       /* Delay comp: wait until waitRec reaches delayComp. WaitRec returns to 0 in 
+       mixerHandler, as soon as the recording ends. */
 
        if (waitRec < conf::delayComp) {
-               waitRec += 2;
+               waitRec++;
                return;
        }
 
-       vChanInput[inputTracker]   += inBuf[frame]   * inVol;
-       vChanInput[inputTracker+1] += inBuf[frame+1] * inVol;
-       inputTracker += 2;
-       if (inputTracker >= clock::getTotalFrames())
+       for (int i=0; i<vChanInput.countChannels(); i++)
+               vChanInput[inputTracker][i] += inBuf[frame][i] * inVol;  // adding: overdub!
+
+       inputTracker++;
+       if (inputTracker >= clock::getFramesInLoop())
                inputTracker = 0;
 }
 
@@ -106,23 +141,19 @@ void lineInRec(float* inBuf, unsigned frame)
 /* ProcessLineIn
 Computes line in peaks, plus handles "hear what you're playin'" thing. */
 
-void processLineIn(float* inBuf, unsigned frame)
+void processLineIn(const AudioBuffer& inBuf, unsigned frame)
 {
        if (!kernelAudio::isInputEnabled())
                return;
 
-       /* input peak calculation (left chan only so far). */
+       computePeak(inBuf, peakIn, frame);
 
-       if (inBuf[frame] * inVol > peakIn)
-               peakIn = inBuf[frame] * inVol;
+       /* "hear what you're playing" - process, copy and paste the input buffer onto 
+       the output buffer. */
 
-       /* "hear what you're playing" - process, copy and paste the input buffer
-        * onto the output buffer */
-
-       if (inToOut) {
-               vChanInToOut[frame]   = inBuf[frame]   * inVol;
-               vChanInToOut[frame+1] = inBuf[frame+1] * inVol;
-       }
+       if (inToOut)
+               for (int i=0; i<vChanInToOut.countChannels(); i++)
+                       vChanInToOut[frame][i] = inBuf[frame][i] * inVol;
 }
 
 
@@ -131,10 +162,10 @@ void processLineIn(float* inBuf, unsigned frame)
 /* clearAllBuffers
 Cleans up every buffer, both in Mixer and in channels. */
 
-void clearAllBuffers(float* outBuf, unsigned bufferSize)
+void clearAllBuffers(AudioBuffer& outBuf)
 {
-       memset(outBuf, 0, sizeof(float) * bufferSize);         // out
-       memset(vChanInToOut, 0, sizeof(float) * bufferSize);   // inToOut vChan
+       outBuf.clear();
+       vChanInToOut.clear();
 
        pthread_mutex_lock(&mutex_chans);
        for (Channel* channel : channels)
@@ -152,15 +183,14 @@ void readActions(unsigned frame)
 {
        pthread_mutex_lock(&mutex_recs);
        for (unsigned i=0; i<recorder::frames.size(); i++) {
-               if (recorder::frames.at(i) == clock::getCurrentFrame()) {
-                       for (unsigned j=0; j<recorder::global.at(i).size(); j++) {
-                               int index   = recorder::global.at(i).at(j)->chan;
-                               Channel *ch = mh::getChannelByIndex(index);
-                               ch->parseAction(recorder::global.at(i).at(j), frame,
-                                       clock::getCurrentFrame(), clock::getQuantize(), clock::isRunning());
-                       }
-                       break;
+               if (recorder::frames.at(i) != clock::getCurrentFrame())
+                       continue;
+               for (recorder::action* action : recorder::global.at(i)) {
+                       Channel* ch = mh::getChannelByIndex(action->chan);
+                       ch->parseAction(action, frame, clock::getCurrentFrame(), 
+                               clock::getQuantize(), clock::isRunning());
                }
+               break;
        }
        pthread_mutex_unlock(&mutex_recs);
 }
@@ -177,13 +207,15 @@ void doQuantize(unsigned frame)
 
        if (clock::getQuantize() == 0 || !clock::quantoHasPassed())
                return;
+
        if (rewindWait) {
                rewindWait = false;
                rewind();
        }
+
        pthread_mutex_lock(&mutex_chans);
        for (unsigned i=0; i<channels.size(); i++)
-               channels.at(i)->quantize(i, frame);
+               channels.at(i)->quantize(i, frame, clock::getCurrentFrame());
        pthread_mutex_unlock(&mutex_chans);
 }
 
@@ -192,15 +224,14 @@ void doQuantize(unsigned frame)
 
 /* sumChannels
 Sums channels, i.e. lets them add sample frames to their virtual channels.
-This is required for CHANNEL_SAMPLE only */
+This is required for G_CHANNEL_SAMPLE only */
 
 void sumChannels(unsigned frame)
 {
        pthread_mutex_lock(&mutex_chans);
-       for (unsigned k=0; k<channels.size(); k++) {
-               if (channels.at(k)->type == CHANNEL_SAMPLE)
-                       static_cast<SampleChannel*>(channels.at(k))->sum(frame, clock::isRunning());
-       }
+       for (Channel* ch : channels)
+               if (ch->type == G_CHANNEL_SAMPLE)
+                       static_cast<SampleChannel*>(ch)->sum(frame, clock::isRunning());
        pthread_mutex_unlock(&mutex_chans);
 }
 
@@ -210,11 +241,11 @@ void sumChannels(unsigned frame)
 /* renderMetronome
 Generates metronome when needed and pastes it to the output buffer. */
 
-void renderMetronome(float* outBuf, unsigned frame)
+void renderMetronome(AudioBuffer& outBuf, unsigned frame)
 {
        if (tockPlay) {
-               outBuf[frame]   += tock[tockTracker];
-               outBuf[frame+1] += tock[tockTracker];
+               for (int i=0; i<outBuf.countChannels(); i++)
+                       outBuf[frame][i] += tock[tockTracker];
                tockTracker++;
                if (tockTracker >= TICKSIZE-1) {
                        tockPlay    = false;
@@ -222,8 +253,8 @@ void renderMetronome(float* outBuf, unsigned frame)
                }
        }
        if (tickPlay) {
-               outBuf[frame]   += tick[tickTracker];
-               outBuf[frame+1] += tick[tickTracker];
+               for (int i=0; i<outBuf.countChannels(); i++)
+                       outBuf[frame][i] += tick[tickTracker];
                tickTracker++;
                if (tickTracker >= TICKSIZE-1) {
                        tickPlay    = false;
@@ -239,12 +270,13 @@ void renderMetronome(float* outBuf, unsigned frame)
 Final processing stage. Take each channel and process it (i.e. copy its
 content to the output buffer). Process plugins too, if any. */
 
-void renderIO(float* outBuf, float* inBuf)
+void renderIO(AudioBuffer& outBuf, const AudioBuffer& inBuf)
 {
        pthread_mutex_lock(&mutex_chans);
-       for (Channel* channel : channels) {
-               channel->process(outBuf, inBuf);
-               channel->preview(outBuf);
+       for (Channel* ch : channels) {
+               if (isChannelAudible(ch))
+                       ch->process(outBuf, inBuf);
+               ch->preview(outBuf);
        }
        pthread_mutex_unlock(&mutex_chans);
 
@@ -262,31 +294,13 @@ void renderIO(float* outBuf, float* inBuf)
 /* limitOutput
 Applies a very dumb hard limiter. */
 
-void limitOutput(float* outBuf, unsigned frame)
+void limitOutput(AudioBuffer& outBuf, unsigned frame)
 {
-       if (outBuf[frame] > 1.0f)
-               outBuf[frame] = 1.0f;
-       else
-       if (outBuf[frame] < -1.0f)
-               outBuf[frame] = -1.0f;
-
-       if (outBuf[frame+1] > 1.0f)
-               outBuf[frame+1] = 1.0f;
-       else
-       if (outBuf[frame+1] < -1.0f)
-               outBuf[frame+1] = -1.0f;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-/* computePeak */
-
-void computePeak(float* outBuf, unsigned frame)
-{
-       /* TODO it takes into account only left channel so far! */
-       if (outBuf[frame] > peakOut)
-               peakOut = outBuf[frame];
+       for (int i=0; i<outBuf.countChannels(); i++)
+               if      (outBuf[frame][i] > 1.0f)
+                       outBuf[frame][i] = 1.0f;
+               else if (outBuf[frame][i] < -1.0f)      
+                       outBuf[frame][i] = -1.0f;       
 }
 
 
@@ -296,16 +310,15 @@ void computePeak(float* outBuf, unsigned frame)
 Last touches after the output has been rendered: apply inToOut if any, apply
 output volume. */
 
-void finalizeOutput(float* outBuf, unsigned frame)
+void finalizeOutput(AudioBuffer& outBuf, unsigned frame)
 {
-       /* merge vChanInToOut, if enabled */
+       /* Merge vChanInToOut, if enabled. */
 
-       if (inToOut) {
-               outBuf[frame]   += vChanInToOut[frame];
-               outBuf[frame+1] += vChanInToOut[frame+1];
-       }
-       outBuf[frame]   *= outVol;
-       outBuf[frame+1] *= outVol;
+       if (inToOut)
+               outBuf.copyFrame(frame, vChanInToOut[frame]); 
+
+       for (int i=0; i<outBuf.countChannels(); i++)
+               outBuf[frame][i] *= outVol; 
 }
 
 
@@ -324,8 +337,8 @@ void testBar(unsigned frame)
                tickPlay = true;
 
        pthread_mutex_lock(&mutex_chans);
-       for (unsigned k=0; k<channels.size(); k++)
-               channels.at(k)->onBar(frame);
+       for (Channel* ch : channels)
+               ch->onBar(frame);
        pthread_mutex_unlock(&mutex_chans);
 }
 
@@ -338,8 +351,8 @@ void testFirstBeat(unsigned frame)
        if (!clock::isOnFirstBeat())
                return;
        pthread_mutex_lock(&mutex_chans);
-       for (unsigned k=0; k<channels.size(); k++)
-               channels.at(k)->onZero(frame, conf::recsStopOnChanHalt);
+       for (Channel* ch : channels)
+               ch->onZero(frame, conf::recsStopOnChanHalt);
        pthread_mutex_unlock(&mutex_chans);
 }
 
@@ -364,32 +377,17 @@ void testLastBeat()
 
 std::vector<Channel*> channels;
 
-bool   recording    = false;   // is recording something?
+bool   recording    = false;
 bool   ready        = true;
-float *vChanInput   = nullptr; // virtual channel for recording
-float *vChanInToOut = nullptr; // virtual channel in->out bridge (hear what you're playin)
 float  outVol       = G_DEFAULT_OUT_VOL;
 float  inVol        = G_DEFAULT_IN_VOL;
 float  peakOut      = 0.0f;
 float  peakIn       = 0.0f;
 bool    metronome    = false;
-int    waitRec      = 0;       // delayComp guard
-bool   docross      = false;    // crossfade guard
-bool   rewindWait   = false;    // rewind guard, if quantized
-
-int  tickTracker, tockTracker = 0;
-bool tickPlay, tockPlay = false; // 1 = play, 0 = stop
-
-/* inputTracker
- * position of the sample in the input side (recording) */
-
-int inputTracker = 0;
-
-/* inToOut
- * copy, process and paste the input into the output, in order to
- * obtain a "hear what you're playing" feature. */
-
-bool inToOut = false;
+int    waitRec      = 0;
+bool   rewindWait   = false;
+bool   hasSolos     = false;
+bool   inToOut      = false;
 
 pthread_mutex_t mutex_recs;
 pthread_mutex_t mutex_chans;
@@ -399,21 +397,24 @@ pthread_mutex_t mutex_plugins;
 /* -------------------------------------------------------------------------- */
 
 
-void init(int framesInSeq, int audioBufferSize)
+void init(int framesInSeq, int framesInBuffer)
 {
        /* Allocate virtual input channels. vChanInput has variable size: it depends
        on how many frames there are in sequencer. */
-
-       allocVirtualInput(framesInSeq);
-
-       if (vChanInToOut != nullptr)
-               delete[] vChanInToOut;
-       vChanInToOut = new (std::nothrow) float[audioBufferSize * 2];
-       if (!vChanInToOut) {
+       if (!allocVirtualInput(framesInSeq)) {
+               gu_log("[Mixer::init] vChanInput alloc error!\n");      
+               return;
+       }
+       if (!vChanInToOut.alloc(framesInBuffer, G_MAX_IO_CHANS)) {
                gu_log("[Mixer::init] vChanInToOut alloc error!\n");    
                return;
        }
 
+       gu_log("[Mixer::init] buffers ready - framesInSeq=%d, framesInBuffer=%d\n", 
+               framesInSeq, framesInBuffer);   
+
+       hasSolos = false;
+
        pthread_mutex_init(&mutex_recs, nullptr);
        pthread_mutex_init(&mutex_chans, nullptr);
        pthread_mutex_init(&mutex_plugins, nullptr);
@@ -425,21 +426,16 @@ void init(int framesInSeq, int audioBufferSize)
 /* -------------------------------------------------------------------------- */
 
 
-void allocVirtualInput(int frames)
+bool allocVirtualInput(int frames)
 {
-       if (vChanInput != nullptr)
-               delete[] vChanInput;
-       vChanInput = new (std::nothrow) float[frames];
-       if (!vChanInput)
-               gu_log("[Mixer::allocVirtualInput] vChanInput realloc error!\n");       
-       gu_log("[Mixer::allocVirtualInput] vChanInput ready, %d frames\n", frames);     
+       return vChanInput.alloc(frames, G_MAX_IO_CHANS);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int masterPlay(void* _outBuf, void* _inBuf, unsigned bufferSize,
+int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize, 
        double streamTime, RtAudioStreamStatus status, void* userData)
 {
        if (!ready)
@@ -449,18 +445,20 @@ int masterPlay(void* _outBuf, void* _inBuf, unsigned bufferSize,
        clock::recvJackSync();
 #endif
 
-       float* outBuf = (float*) _outBuf;
-       float* inBuf  = kernelAudio::isInputEnabled() ? (float*) _inBuf : nullptr;
-       bufferSize   *= 2;     // stereo
-       peakOut       = 0.0f;  // reset peak calculator
-       peakIn        = 0.0f;  // reset peak calculator
+       AudioBuffer out, in;
+       out.setData((float*) outBuf, bufferSize, G_MAX_IO_CHANS);
+       if (kernelAudio::isInputEnabled())
+               in.setData((float*) inBuf, bufferSize, G_MAX_IO_CHANS);
 
-       clearAllBuffers(outBuf, bufferSize);
+       peakOut = 0.0f;  // reset peak calculator
+       peakIn  = 0.0f;  // reset peak calculator
 
-       for (unsigned j=0; j<bufferSize; j+=2) {
-               processLineIn(inBuf, j);
+       clearAllBuffers(out);
+
+       for (unsigned j=0; j<bufferSize; j++) {
+               processLineIn(in, j);
                if (clock::isRunning()) {
-                       lineInRec(inBuf, j);
+                       lineInRec(in, j);
                        doQuantize(j);
                        testBar(j);
                        testFirstBeat(j);
@@ -472,18 +470,22 @@ int masterPlay(void* _outBuf, void* _inBuf, unsigned bufferSize,
                sumChannels(j);
        }
 
-       renderIO(outBuf, inBuf);
-
-       /* post processing */
+       renderIO(out, in);
 
-       for (unsigned j=0; j<bufferSize; j+=2) {
-               finalizeOutput(outBuf, j);
+       /* Post processing. */
+       for (unsigned j=0; j<bufferSize; j++) {
+               finalizeOutput(out, j); 
                if (conf::limitOutput)
-                       limitOutput(outBuf, j);
-               computePeak(outBuf, j);
-               renderMetronome(outBuf, j);
+                       limitOutput(out, j);
+               computePeak(out, peakOut, j); 
+               renderMetronome(out, j);
        }
 
+       /* Unset data in buffers. If you don't do this, buffers go out of scope and
+       destroy memory allocated by RtAudio ---> havoc. */
+       out.setData(nullptr, 0, 0);
+       in.setData(nullptr, 0, 0);
+
        return 0;
 }
 
@@ -491,21 +493,11 @@ int masterPlay(void* _outBuf, void* _inBuf, unsigned bufferSize,
 /* -------------------------------------------------------------------------- */
 
 
-int close()
+void close()
 {
        clock::stop();
        while (channels.size() > 0)
                mh::deleteChannel(channels.at(0));
-
-       if (vChanInput != nullptr) {
-               delete[] vChanInput;
-               vChanInput = nullptr;
-       }
-       if (vChanInToOut != nullptr) {
-               delete[] vChanInToOut;
-               vChanInToOut = nullptr;
-       }
-       return 1;
 }
 
 
@@ -514,8 +506,8 @@ int close()
 
 bool isSilent()
 {
-       for (unsigned i=0; i<channels.size(); i++)
-               if (channels.at(i)->status == STATUS_PLAY)
+       for (const Channel* ch : channels)
+               if (ch->status == STATUS_PLAY)
                        return false;
        return true;
 }
@@ -536,18 +528,26 @@ void rewind()
 /* -------------------------------------------------------------------------- */
 
 
-void mergeVirtualInput()
+void startInputRec()
 {
-       assert(vChanInput != nullptr);
+       /* Start inputTracker from the current frame, not the beginning. */
+       recording    = true;
+       inputTracker = clock::getCurrentFrame();
+}
+
+/* -------------------------------------------------------------------------- */
+
 
+void mergeVirtualInput()
+{
        for (Channel* ch : channels) {
-               if (ch->type == CHANNEL_MIDI)
+               if (ch->type == G_CHANNEL_MIDI)
                        continue;
                SampleChannel* sch = static_cast<SampleChannel*>(ch);
-               if (sch->isArmed())
-                       memcpy(sch->wave->getData(), vChanInput, clock::getTotalFrames() * sizeof(float));
+               if (sch->armed)
+                       sch->wave->copyData(vChanInput[0], vChanInput.countFrames());
        }
-       memset(vChanInput, 0, clock::getTotalFrames() * sizeof(float)); // clear vchan
+       vChanInput.clear();
 }
 
 
index 87aef5ea56f29244e6b840c5a948bda9a9acb353..36c566b7b9482e2dd67b0c8172c193be3caf03b9 100644 (file)
@@ -41,21 +41,21 @@ namespace giada {
 namespace m {
 namespace mixer
 {
-void init(int framesInSeq, int audioBufferSize);
+void init(int framesInSeq, int framesInBuffer);
 
 /* allocVirtualInput
 Allocates new memory for the virtual input channel. Call this whenever you 
 shrink or resize the sequencer. */
 
-void allocVirtualInput(int frames);
+bool allocVirtualInput(int frames);
 
-int close();
+void close();
 
 /* masterPlay
 Core method (callback) */
 
-int masterPlay(void *outBuf, void *inBuf, unsigned bufferSize, double streamTime,
-  RtAudioStreamStatus status, void *userData);
+int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize, double streamTime,
+  RtAudioStreamStatus status, voiduserData);
 
 /* isSilent
 Is mixer silent? */
@@ -67,6 +67,11 @@ Rewinds sequencer to frame 0. */
 
 void rewind();
 
+/* startInputRec
+Starts input recording on frame clock::getCurrentFrame(). */
+
+void startInputRec();
+
 /* mergeVirtualInput
 Copies the virtual channel input in the channels designed for input recording. 
 Called by mixerHandler on stopInputRec(). */
@@ -88,29 +93,18 @@ extern std::vector<Channel*> channels;
 
 extern bool   recording;         // is recording something?
 extern bool   ready;
-extern float *vChanInput;        // virtual channel for recording
-extern float *vChanInToOut;      // virtual channel in->out bridge (hear what you're playin)
-extern int    frameSize;
 extern float  outVol;
 extern float  inVol;
 extern float  peakOut;
 extern float  peakIn;
-extern bool     metronome;
-extern int    waitRec;      // delayComp guard
-extern bool  docross;                   // crossfade guard
-extern bool  rewindWait;          // rewind guard, if quantized
-
-extern int  tickTracker, tockTracker;
-extern bool tickPlay, tockPlay; // 1 = play, 0 = stop
-
-/* inputTracker
- * position of the sample in the input side (recording) */
-
-extern int inputTracker;
+extern bool      metronome;
+extern int    waitRec;       // delayComp guard
+extern bool   rewindWait;         // rewind guard, if quantized
+extern bool   hasSolos;      // more than 0 channels soloed
 
 /* inToOut
- * copy, process and paste the input into the output, in order to
- * obtain a "hear what you're playing" feature. */
+Copy, process and paste the input into the output, in order to obtain a "hear 
+what you're playing" feature. */
 
 extern bool inToOut;
 
index 119f95ee28b3a2c0ec53318d8f5089f062276564..ecbf42f9a51de8a806b59bb2f11a9a4b4c01b3ea 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <vector>
+#include <algorithm>
 #include "../utils/fs.h"
 #include "../utils/string.h"
 #include "../utils/log.h"
@@ -49,6 +50,7 @@
 #include "midiChannel.h"
 #include "wave.h"
 #include "waveManager.h"
+#include "channelManager.h"
 #include "mixerHandler.h"
 
 
@@ -87,7 +89,7 @@ int readPatchPlugins(vector<patch::plugin_t>* list, int type)
 #endif
 
 
-/* ------------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int getNewChanIndex()
@@ -118,7 +120,7 @@ int getNewChanIndex()
 bool uniqueSamplePath(const SampleChannel* skip, const string& path)
 {
        for (const Channel* ch : mixer::channels) {
-               if (skip == ch || ch->type != CHANNEL_SAMPLE) // skip itself and MIDI channels
+               if (skip == ch || ch->type != G_CHANNEL_SAMPLE) // skip itself and MIDI channels
                        continue;
                const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
                if (sch->wave != nullptr && path == sch->wave->getPath())
@@ -133,18 +135,11 @@ bool uniqueSamplePath(const SampleChannel* skip, const string& path)
 
 Channel* addChannel(int type)
 {
-       Channel* ch;
-       int bufferSize = kernelAudio::getRealBufSize() * 2;
-
-       if (type == CHANNEL_SAMPLE)
-               ch = new SampleChannel(bufferSize, conf::inputMonitorDefaultOn);
-       else
-               ch = new MidiChannel(bufferSize);
-
-       if (!ch->allocBuffers()) {
-               delete ch;
+       Channel* ch = nullptr;
+       channelManager::create(type, kernelAudio::getRealBufSize(), 
+               conf::inputMonitorDefaultOn, &ch);
+       if (ch == nullptr)
                return nullptr;
-       }
 
        while (true) {
                if (pthread_mutex_trylock(&mixer::mutex_chans) != 0)
@@ -164,27 +159,16 @@ Channel* addChannel(int type)
 /* -------------------------------------------------------------------------- */
 
 
-int deleteChannel(Channel* ch)
+void deleteChannel(Channel* target)
 {
-       int index = -1;
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               if (mixer::channels.at(i) == ch) {
-                       index = i;
-                       break;
-               }
-       }
-       if (index == -1) {
-               gu_log("[deleteChannel] unable to find channel %d for deletion!\n", ch->index);
-               return 0;
-       }
-
        while (true) {
                if (pthread_mutex_trylock(&mixer::mutex_chans) != 0)
                        continue;
-               mixer::channels.erase(mixer::channels.begin() + index);
-               delete ch;
+               auto it = std::find(mixer::channels.begin(), mixer::channels.end(), target);
+               if (it != mixer::channels.end()) 
+                       mixer::channels.erase(it);
                pthread_mutex_unlock(&mixer::mutex_chans);
-               return 1;
+               return;
        }
 }
 
@@ -194,9 +178,9 @@ int deleteChannel(Channel* ch)
 
 Channel* getChannelByIndex(int index)
 {
-       for (unsigned i=0; i<mixer::channels.size(); i++)
-               if (mixer::channels.at(i)->index == index)
-                       return mixer::channels.at(i);
+       for (Channel* ch : mixer::channels)
+               if (ch->index == index)
+                       return ch;
        gu_log("[getChannelByIndex] channel at index %d not found!\n", index);
        return nullptr;
 }
@@ -207,11 +191,11 @@ Channel* getChannelByIndex(int index)
 
 bool hasLogicalSamples()
 {
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
+       for (const Channel* ch : mixer::channels) {
+               if (ch->type != G_CHANNEL_SAMPLE)
                        continue;
-               SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
-               if (ch->wave && ch->wave->isLogical())
+               const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
+               if (sch->wave != nullptr && sch->wave->isLogical())
                        return true;
        }
        return false;
@@ -223,12 +207,11 @@ bool hasLogicalSamples()
 
 bool hasEditedSamples()
 {
-       for (unsigned i=0; i<mixer::channels.size(); i++)
-       {
-               if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
+       for (const Channel* ch : mixer::channels) {
+               if (ch->type != G_CHANNEL_SAMPLE)
                        continue;
-               SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
-               if (ch->wave && ch->wave->isEdited())
+               const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
+               if (sch->wave != nullptr && sch->wave->isEdited())
                        return true;
        }
        return false;
@@ -241,23 +224,22 @@ bool hasEditedSamples()
 void stopSequencer()
 {
        clock::stop();
-       for (unsigned i=0; i<mixer::channels.size(); i++)
-               mixer::channels.at(i)->stopBySeq(conf::chansStopOnSeqHalt);
+       for (Channel* ch : mixer::channels)
+               ch->stopBySeq(conf::chansStopOnSeqHalt);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-bool uniqueSolo(Channel* ch)
+void updateSoloCount()
 {
-       int solos = 0;
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               Channel *ch = mixer::channels.at(i);
-               if (ch->solo) solos++;
-               if (solos > 1) return false;
-       }
-       return true;
+       for (Channel* ch : mixer::channels)
+               if (ch->solo) {
+                       mixer::hasSolos = true;
+                       return;
+               }
+       mixer::hasSolos = false;
 }
 
 
@@ -289,7 +271,7 @@ void readPatch()
        very likely). */
 
        mixer::rewind();
-       mixer::allocVirtualInput(clock::getTotalFrames());
+       mixer::allocVirtualInput(clock::getFramesInLoop());
        mixer::ready = true;
 }
 
@@ -313,40 +295,38 @@ bool startInputRec()
 {
        int channelsReady = 0;
 
-       for (Channel* channel : mixer::channels) {
+       for (Channel* ch : mixer::channels) {
 
-               if (!channel->canInputRec())
+               if (!ch->canInputRec())
                        continue;
 
-               SampleChannel* ch = static_cast<SampleChannel*>(channel);
+               SampleChannel* sch = static_cast<SampleChannel*>(ch);
 
                /* Allocate empty sample for the current channel. */
 
-               Wave* wave = nullptr;
-               int result = waveManager::createEmpty(clock::getTotalFrames(), 
-                       conf::samplerate, string("TAKE-" + gu_iToString(patch::lastTakeId)), &wave); 
-               if (result != G_RES_OK) {
-                       gu_log("[startInputRec] unable to allocate new Wave in chan %d!\n",
-                               ch->index);
+               Wave*  wave = nullptr;
+               string name = string("TAKE-" + gu_iToString(patch::lastTakeId++)); // Increase lastTakeId 
+
+               int result = waveManager::createEmpty(clock::getFramesInLoop(), G_MAX_IO_CHANS,
+                       conf::samplerate, name + ".wav", &wave); 
+               if (result != G_RES_OK)
                        continue;
-               }
 
-               ch->pushWave(wave);
-               ch->setName("TAKE-" + gu_iToString(patch::lastTakeId++)); // Increase lastTakeId 
+               sch->pushWave(wave);
+               sch->name = name; 
                channelsReady++;
 
                gu_log("[startInputRec] start input recs using chan %d with size %d "
-                       "frame=%d\n", ch->index, clock::getTotalFrames(), mixer::inputTracker);
+                       "on frame=%d\n", sch->index, clock::getFramesInLoop(), clock::getCurrentFrame());
        }
 
-       if (channelsReady > 0) {
-               mixer::recording = true;
-               /* start to write from the currentFrame, not the beginning */
-               /** FIXME: this should be done before wave allocation */
-               mixer::inputTracker = clock::getCurrentFrame();
-               return true;
-       }
-       return false;
+       /** FIXME: mixer::startInputRec() should be called before wave allocation */
+       /** FIXME: mixer::startInputRec() should be called before wave allocation */
+       /** FIXME: mixer::startInputRec() should be called before wave allocation */
+       if (channelsReady == 0)
+               return false;
+       mixer::startInputRec();
+       return true;
 }
 
 
@@ -367,11 +347,9 @@ void stopInputRec()
 
 bool hasArmedSampleChannels()
 {
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               Channel *ch = mixer::channels.at(i);
-               if (ch->type == CHANNEL_SAMPLE && ch->isArmed())
+       for (const Channel* ch : mixer::channels)
+               if (ch->type == G_CHANNEL_SAMPLE && ch->armed)
                        return true;
-       }
        return false;
 }
 
index c1cd2baec91a5154d644851c9b846f02ce337b1d..ae160a9d8e4369463d32052fa8c6b6d34090810f 100644 (file)
@@ -48,7 +48,7 @@ Channel* addChannel(int type);
 /* deleteChannel
 Completely removes a channel from the stack. */
 
-int deleteChannel(Channel* ch);
+void deleteChannel(Channel* ch);
 
 /* getChannelByIndex
 Returns channel with given index 'i'. */
@@ -72,10 +72,10 @@ void stopSequencer();
 
 void rewindSequencer();
 
-/* uniqueSolo
- * true if ch is the only solo'd channel in mixer. */
+/* updateSoloCount
+Updates the number of solo-ed channels in mixer. */
 
-bool uniqueSolo(Channel* ch);
+void updateSoloCount();
 
 /* loadPatch
 Loads a path or a project (if isProject) into Mixer. If isProject, path must 
index dfdc9dc0f009cb7fe6f68d0cf4671e08613a254d..a834775b83708b8d1058c859d9d4eacb01d1415e 100644 (file)
@@ -49,28 +49,44 @@ Internal sanity check. */
 
 void sanitize()
 {
-  bpm          = bpm < G_MIN_BPM || bpm > G_MAX_BPM ? G_DEFAULT_BPM : bpm;
-  bars         = bars <= 0 || bars > G_MAX_BARS ? G_DEFAULT_BARS : bars;
-  beats        = beats <= 0 || beats > G_MAX_BEATS ? G_DEFAULT_BEATS : beats;
-  quantize     = quantize < 0 || quantize > G_MAX_QUANTIZE ? G_DEFAULT_QUANTIZE : quantize;
-  masterVolIn  = masterVolIn < 0.0f || masterVolIn > 1.0f ? G_DEFAULT_VOL : masterVolIn;
-  masterVolOut = masterVolOut < 0.0f || masterVolOut > 1.0f ? G_DEFAULT_VOL : masterVolOut;
-  samplerate   = samplerate <= 0 ? G_DEFAULT_SAMPLERATE : samplerate;
-
-  for (unsigned i=0; i<columns.size(); i++) {
-    column_t* col = &columns.at(i);
-    col->index = col->index < 0 ? 0 : col->index;
-    col->width = col->width < G_MIN_COLUMN_WIDTH ? G_MIN_COLUMN_WIDTH : col->width;
-  }
-
-  for (unsigned i=0; i<channels.size(); i++) {
-    channel_t* ch = &channels.at(i);
-    ch->size   = ch->size < G_GUI_CHANNEL_H_1 || ch->size > G_GUI_CHANNEL_H_4 ? G_GUI_CHANNEL_H_1 : ch->size;
-    ch->volume = ch->volume < 0.0f || ch->volume > 1.0f ? G_DEFAULT_VOL : ch->volume;
-    ch->pan    = ch->pan < 0.0f || ch->pan > 1.0f ? 1.0f : ch->pan;
-    ch->boost  = ch->boost < 1.0f ? G_DEFAULT_BOOST : ch->boost;
-    ch->pitch  = ch->pitch < 0.1f || ch->pitch > G_MAX_PITCH ? G_DEFAULT_PITCH : ch->pitch;
-  }
+       bpm          = bpm < G_MIN_BPM || bpm > G_MAX_BPM ? G_DEFAULT_BPM : bpm;
+       bars         = bars <= 0 || bars > G_MAX_BARS ? G_DEFAULT_BARS : bars;
+       beats        = beats <= 0 || beats > G_MAX_BEATS ? G_DEFAULT_BEATS : beats;
+       quantize     = quantize < 0 || quantize > G_MAX_QUANTIZE ? G_DEFAULT_QUANTIZE : quantize;
+       masterVolIn  = masterVolIn < 0.0f || masterVolIn > 1.0f ? G_DEFAULT_VOL : masterVolIn;
+       masterVolOut = masterVolOut < 0.0f || masterVolOut > 1.0f ? G_DEFAULT_VOL : masterVolOut;
+       samplerate   = samplerate <= 0 ? G_DEFAULT_SAMPLERATE : samplerate;
+
+       for (unsigned i=0; i<columns.size(); i++) {
+               column_t* col = &columns.at(i);
+               col->index = col->index < 0 ? 0 : col->index;
+               col->width = col->width < G_MIN_COLUMN_WIDTH ? G_MIN_COLUMN_WIDTH : col->width;
+       }
+
+       for (unsigned i=0; i<channels.size(); i++) {
+               channel_t* ch = &channels.at(i);
+               ch->size   = ch->size < G_GUI_CHANNEL_H_1 || ch->size > G_GUI_CHANNEL_H_4 ? G_GUI_CHANNEL_H_1 : ch->size;
+               ch->volume = ch->volume < 0.0f || ch->volume > 1.0f ? G_DEFAULT_VOL : ch->volume;
+               ch->pan    = ch->pan < 0.0f || ch->pan > 1.0f ? 1.0f : ch->pan;
+               ch->boost  = ch->boost < 1.0f ? G_DEFAULT_BOOST : ch->boost;
+               ch->pitch  = ch->pitch < 0.1f || ch->pitch > G_MAX_PITCH ? G_DEFAULT_PITCH : ch->pitch;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/* modernize
+Makes sure an older patch is compatible with the current version. */
+
+void modernize()
+{
+       /* Starting from 0.15.0 actions are recorded on frames, not samples. */
+       if (versionMajor <= 0 && versionMinor < 15) {
+               for (channel_t& ch : channels)
+                       for (action_t& a : ch.actions)
+                               a.frame /= 2;
+       }
 }
 
 
@@ -81,8 +97,8 @@ Helper function used to return invalid status while reading. */
 
 int setInvalid(json_t* jRoot)
 {
-  json_decref(jRoot);
-  return PATCH_INVALID;
+       json_decref(jRoot);
+       return PATCH_INVALID;
 }
 
 
@@ -91,22 +107,22 @@ int setInvalid(json_t* jRoot)
 
 bool readCommons(json_t* jContainer)
 {
-  if (!storager::setString(jContainer, PATCH_KEY_HEADER, header))  return 0;
-  if (!storager::setString(jContainer, PATCH_KEY_VERSION, version)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_VERSION_MAJOR, versionMajor)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_VERSION_MINOR, versionMinor)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_VERSION_PATCH, versionPatch)) return 0;
-  if (!storager::setString(jContainer, PATCH_KEY_NAME, name)) return 0;
-  if (!storager::setFloat (jContainer, PATCH_KEY_BPM, bpm)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_BARS, bars)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_BEATS, beats)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_QUANTIZE, quantize)) return 0;
-  if (!storager::setFloat (jContainer, PATCH_KEY_MASTER_VOL_IN, masterVolIn)) return 0;
-  if (!storager::setFloat (jContainer, PATCH_KEY_MASTER_VOL_OUT, masterVolOut)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_METRONOME, metronome)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_LAST_TAKE_ID, lastTakeId)) return 0;
-  if (!storager::setInt   (jContainer, PATCH_KEY_SAMPLERATE, samplerate)) return 0;
-  return 1;
+       if (!storager::setString(jContainer, PATCH_KEY_HEADER, header))  return 0;
+       if (!storager::setString(jContainer, PATCH_KEY_VERSION, version)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_VERSION_MAJOR, versionMajor)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_VERSION_MINOR, versionMinor)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_VERSION_PATCH, versionPatch)) return 0;
+       if (!storager::setString(jContainer, PATCH_KEY_NAME, name)) return 0;
+       if (!storager::setFloat (jContainer, PATCH_KEY_BPM, bpm)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_BARS, bars)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_BEATS, beats)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_QUANTIZE, quantize)) return 0;
+       if (!storager::setFloat (jContainer, PATCH_KEY_MASTER_VOL_IN, masterVolIn)) return 0;
+       if (!storager::setFloat (jContainer, PATCH_KEY_MASTER_VOL_OUT, masterVolOut)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_METRONOME, metronome)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_LAST_TAKE_ID, lastTakeId)) return 0;
+       if (!storager::setInt   (jContainer, PATCH_KEY_SAMPLERATE, samplerate)) return 0;
+       return 1;
 }
 
 
@@ -117,44 +133,44 @@ bool readCommons(json_t* jContainer)
 
 bool readPlugins(json_t* jContainer, vector<plugin_t>* container, const char* key)
 {
-  json_t* jPlugins = json_object_get(jContainer, key);
-  if (!storager::checkArray(jPlugins, key))
-    return 0;
+       json_t* jPlugins = json_object_get(jContainer, key);
+       if (!storager::checkArray(jPlugins, key))
+               return 0;
 
-  size_t pluginIndex;
-  json_t* jPlugin;
-  json_array_foreach(jPlugins, pluginIndex, jPlugin) {
+       size_t pluginIndex;
+       json_t* jPlugin;
+       json_array_foreach(jPlugins, pluginIndex, jPlugin) {
 
-    if (!storager::checkObject(jPlugin, "")) // TODO pass pluginIndex as string
-      return 0;
+               if (!storager::checkObject(jPlugin, "")) // TODO pass pluginIndex as string
+                       return 0;
 
-    plugin_t plugin;
-    if (!storager::setString(jPlugin, PATCH_KEY_PLUGIN_PATH,   plugin.path)) return 0;
-    if (!storager::setBool  (jPlugin, PATCH_KEY_PLUGIN_BYPASS, plugin.bypass)) return 0;
+               plugin_t plugin;
+               if (!storager::setString(jPlugin, PATCH_KEY_PLUGIN_PATH,   plugin.path)) return 0;
+               if (!storager::setBool  (jPlugin, PATCH_KEY_PLUGIN_BYPASS, plugin.bypass)) return 0;
 
-    /* read plugin params */
+               /* read plugin params */
 
-    json_t* jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS);
-    if (!storager::checkArray(jParams, PATCH_KEY_PLUGIN_PARAMS)) return 0;
+               json_t* jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS);
+               if (!storager::checkArray(jParams, PATCH_KEY_PLUGIN_PARAMS)) return 0;
 
-    size_t paramIndex;
-    json_t* jParam;
-    json_array_foreach(jParams, paramIndex, jParam)
-      plugin.params.push_back(json_real_value(jParam));
+               size_t paramIndex;
+               json_t* jParam;
+               json_array_foreach(jParams, paramIndex, jParam)
+                       plugin.params.push_back(json_real_value(jParam));
 
-    /* read midiIn params (midi learning on plugins' parameters) */
+               /* read midiIn params (midi learning on plugins' parameters) */
 
-    json_t* jMidiInParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS);
-    if (!storager::checkArray(jMidiInParams, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS)) return 0;
+               json_t* jMidiInParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS);
+               if (!storager::checkArray(jMidiInParams, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS)) return 0;
 
-    size_t midiInParamIndex;
-    json_t* jMidiInParam;
-    json_array_foreach(jMidiInParams, midiInParamIndex, jMidiInParam)
-      plugin.midiInParams.push_back(json_integer_value(jMidiInParam));
+               size_t midiInParamIndex;
+               json_t* jMidiInParam;
+               json_array_foreach(jMidiInParams, midiInParamIndex, jMidiInParam)
+                       plugin.midiInParams.push_back(json_integer_value(jMidiInParam));
 
-    container->push_back(plugin);
-  }
-  return 1;
+               container->push_back(plugin);
+       }
+       return 1;
 }
 
 #endif
@@ -164,25 +180,25 @@ bool readPlugins(json_t* jContainer, vector<plugin_t>* container, const char* ke
 
 bool readActions(json_t* jContainer, channel_t* channel)
 {
-  json_t* jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
-  if (!storager::checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS))
-    return 0;
-
-  size_t actionIndex;
-  json_t* jAction;
-  json_array_foreach(jActions, actionIndex, jAction) {
-
-    if (!storager::checkObject(jAction, "")) // TODO pass actionIndex as string
-      return 0;
-
-    action_t action;
-    if (!storager::setInt   (jAction, PATCH_KEY_ACTION_TYPE,    action.type)) return 0;
-    if (!storager::setInt   (jAction, PATCH_KEY_ACTION_FRAME,   action.frame)) return 0;
-    if (!storager::setFloat (jAction, PATCH_KEY_ACTION_F_VALUE, action.fValue)) return 0;
-    if (!storager::setUint32(jAction, PATCH_KEY_ACTION_I_VALUE, action.iValue)) return 0;
-    channel->actions.push_back(action);
-  }
-  return 1;
+       json_t* jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
+       if (!storager::checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS))
+               return 0;
+
+       size_t actionIndex;
+       json_t* jAction;
+       json_array_foreach(jActions, actionIndex, jAction) {
+
+               if (!storager::checkObject(jAction, "")) // TODO pass actionIndex as string
+                       return 0;
+
+               action_t action;
+               if (!storager::setInt   (jAction, PATCH_KEY_ACTION_TYPE,    action.type)) return 0;
+               if (!storager::setInt   (jAction, PATCH_KEY_ACTION_FRAME,   action.frame)) return 0;
+               if (!storager::setFloat (jAction, PATCH_KEY_ACTION_F_VALUE, action.fValue)) return 0;
+               if (!storager::setUint32(jAction, PATCH_KEY_ACTION_I_VALUE, action.iValue)) return 0;
+               channel->actions.push_back(action);
+       }
+       return 1;
 }
 
 
@@ -191,67 +207,67 @@ bool readActions(json_t* jContainer, channel_t* channel)
 
 bool readChannels(json_t* jContainer)
 {
-  json_t* jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS);
-  if (!storager::checkArray(jChannels, PATCH_KEY_CHANNELS))
-    return 0;
-
-  size_t channelIndex;
-  json_t* jChannel;
-  json_array_foreach(jChannels, channelIndex, jChannel) {
-
-    string channelIndexStr = "channel " + gu_iToString(channelIndex);
-    if (!storager::checkObject(jChannel, channelIndexStr.c_str()))
-      return 0;
-
-    channel_t channel;
-
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_TYPE,                 channel.type)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_INDEX,                channel.index)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_SIZE,                 channel.size)) return 0;
-    if (!storager::setString(jChannel, PATCH_KEY_CHANNEL_NAME,                 channel.name)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_COLUMN,               channel.column)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MUTE,                 channel.mute)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MUTE_S,               channel.mute_s)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_SOLO,                 channel.solo)) return 0;
-    if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_VOLUME,               channel.volume)) return 0;
-    if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_PAN,                  channel.pan)) return 0;
-    if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_IN,              channel.midiIn)) return 0;
-    if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VELO_AS_VOL,  channel.midiInVeloAsVol)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS,     channel.midiInKeyPress)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL,       channel.midiInKeyRel)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL,         channel.midiInKill)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM,          channel.midiInArm)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       channel.midiInVolume)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         channel.midiInMute)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         channel.midiInSolo)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MIDI_IN_FILTER,       channel.midiInFilter)) return 0;
-    if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L,           channel.midiOutL)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING,   channel.midiOutLplaying)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE,      channel.midiOutLmute)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO,      channel.midiOutLsolo)) return 0;
-    if (!storager::setString(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH,          channel.samplePath)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_KEY,                  channel.key)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MODE,                 channel.mode)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_BEGIN,                channel.begin)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_END,                  channel.end)) return 0;
-    if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_BOOST,                channel.boost)) return 0;
-    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE,           channel.recActive)) return 0;
-    if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_PITCH,                channel.pitch)) return 0;
-    if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_INPUT_MONITOR,        channel.inputMonitor)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, channel.midiInReadActions)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH,        channel.midiInPitch)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT,             channel.midiOut)) return 0;
-    if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN,        channel.midiOutChan)) return 0;
-    if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_ARMED,                channel.armed)) return 0;
-
-    readActions(jChannel, &channel);
+       json_t* jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS);
+       if (!storager::checkArray(jChannels, PATCH_KEY_CHANNELS))
+               return 0;
+
+       size_t channelIndex;
+       json_t* jChannel;
+       json_array_foreach(jChannels, channelIndex, jChannel) {
+
+               string channelIndexStr = "channel " + gu_iToString(channelIndex);
+               if (!storager::checkObject(jChannel, channelIndexStr.c_str()))
+                       return 0;
+
+               channel_t channel;
+
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_TYPE,                 channel.type)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_INDEX,                channel.index)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_SIZE,                 channel.size)) return 0;
+               if (!storager::setString(jChannel, PATCH_KEY_CHANNEL_NAME,                 channel.name)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_COLUMN,               channel.column)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MUTE,                 channel.mute)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MUTE_S,               channel.mute_s)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_SOLO,                 channel.solo)) return 0;
+               if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_VOLUME,               channel.volume)) return 0;
+               if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_PAN,                  channel.pan)) return 0;
+               if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_IN,              channel.midiIn)) return 0;
+               if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VELO_AS_VOL,  channel.midiInVeloAsVol)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS,     channel.midiInKeyPress)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL,       channel.midiInKeyRel)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL,         channel.midiInKill)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM,          channel.midiInArm)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       channel.midiInVolume)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         channel.midiInMute)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         channel.midiInSolo)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MIDI_IN_FILTER,       channel.midiInFilter)) return 0;
+               if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L,           channel.midiOutL)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING,   channel.midiOutLplaying)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE,      channel.midiOutLmute)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO,      channel.midiOutLsolo)) return 0;
+               if (!storager::setString(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH,          channel.samplePath)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_KEY,                  channel.key)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MODE,                 channel.mode)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_BEGIN,                channel.begin)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_END,                  channel.end)) return 0;
+               if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_BOOST,                channel.boost)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE,           channel.recActive)) return 0;
+               if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_PITCH,                channel.pitch)) return 0;
+               if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_INPUT_MONITOR,        channel.inputMonitor)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, channel.midiInReadActions)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH,        channel.midiInPitch)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT,             channel.midiOut)) return 0;
+               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN,        channel.midiOutChan)) return 0;
+               if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_ARMED,                channel.armed)) return 0;
+
+               readActions(jChannel, &channel);
 
 #ifdef WITH_VST
-    readPlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS);
+               readPlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS);
 #endif
-    channels.push_back(channel);
-  }
-  return 1;
+               channels.push_back(channel);
+       }
+       return 1;
 }
 
 
@@ -260,25 +276,25 @@ bool readChannels(json_t* jContainer)
 
 bool readColumns(json_t* jContainer)
 {
-  json_t* jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS);
-  if (!storager::checkArray(jColumns, PATCH_KEY_COLUMNS))
-    return 0;
+       json_t* jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS);
+       if (!storager::checkArray(jColumns, PATCH_KEY_COLUMNS))
+               return 0;
 
-  size_t columnIndex;
-  json_t* jColumn;
-  json_array_foreach(jColumns, columnIndex, jColumn) {
+       size_t columnIndex;
+       json_t* jColumn;
+       json_array_foreach(jColumns, columnIndex, jColumn) {
 
-    string columnIndexStr = "column " + gu_iToString(columnIndex);
-    if (!storager::checkObject(jColumn, columnIndexStr.c_str()))
-      return 0;
+               string columnIndexStr = "column " + gu_iToString(columnIndex);
+               if (!storager::checkObject(jColumn, columnIndexStr.c_str()))
+                       return 0;
 
-    column_t column;
-    if (!storager::setInt(jColumn, PATCH_KEY_COLUMN_INDEX, column.index)) return 0;
-    if (!storager::setInt(jColumn, PATCH_KEY_COLUMN_WIDTH, column.width)) return 0;
+               column_t column;
+               if (!storager::setInt(jColumn, PATCH_KEY_COLUMN_INDEX, column.index)) return 0;
+               if (!storager::setInt(jColumn, PATCH_KEY_COLUMN_WIDTH, column.width)) return 0;
 
-    columns.push_back(column);
-  }
-  return 1;
+               columns.push_back(column);
+       }
+       return 1;
 }
 
 
@@ -288,29 +304,29 @@ bool readColumns(json_t* jContainer)
 
 void writePlugins(json_t* jContainer, vector<plugin_t>* plugins, const char* key)
 {
-  json_t* jPlugins = json_array();
-  for (unsigned j=0; j<plugins->size(); j++) {
-    json_t*  jPlugin = json_object();
-    plugin_t plugin  = plugins->at(j);
-    json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PATH,   json_string(plugin.path.c_str()));
-    json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_BYPASS, json_boolean(plugin.bypass));
-    json_array_append_new(jPlugins, jPlugin);
-
-    /* plugin params */
-
-    json_t* jPluginParams = json_array();
-    for (unsigned z=0; z<plugin.params.size(); z++)
-      json_array_append_new(jPluginParams, json_real(plugin.params.at(z)));
-    json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PARAMS, jPluginParams);
-
-    /* midiIn params (midi learning on plugins' parameters) */
-
-    json_t* jPluginMidiInParams = json_array();
-    for (unsigned z=0; z<plugin.midiInParams.size(); z++)
-      json_array_append_new(jPluginMidiInParams, json_integer(plugin.midiInParams.at(z)));
-    json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS, jPluginMidiInParams);
-  }
-  json_object_set_new(jContainer, key, jPlugins);
+       json_t* jPlugins = json_array();
+       for (unsigned j=0; j<plugins->size(); j++) {
+               json_t*  jPlugin = json_object();
+               plugin_t plugin  = plugins->at(j);
+               json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PATH,   json_string(plugin.path.c_str()));
+               json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_BYPASS, json_boolean(plugin.bypass));
+               json_array_append_new(jPlugins, jPlugin);
+
+               /* plugin params */
+
+               json_t* jPluginParams = json_array();
+               for (unsigned z=0; z<plugin.params.size(); z++)
+                       json_array_append_new(jPluginParams, json_real(plugin.params.at(z)));
+               json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PARAMS, jPluginParams);
+
+               /* midiIn params (midi learning on plugins' parameters) */
+
+               json_t* jPluginMidiInParams = json_array();
+               for (unsigned z=0; z<plugin.midiInParams.size(); z++)
+                       json_array_append_new(jPluginMidiInParams, json_integer(plugin.midiInParams.at(z)));
+               json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS, jPluginMidiInParams);
+       }
+       json_object_set_new(jContainer, key, jPlugins);
 }
 
 #endif
@@ -321,15 +337,15 @@ void writePlugins(json_t* jContainer, vector<plugin_t>* plugins, const char* key
 
 void writeColumns(json_t* jContainer, vector<column_t>* columns)
 {
-  json_t* jColumns = json_array();
-  for (unsigned i=0; i<columns->size(); i++) {
-    json_t*  jColumn = json_object();
-    column_t column  = columns->at(i);
-    json_object_set_new(jColumn, PATCH_KEY_COLUMN_INDEX, json_integer(column.index));
-    json_object_set_new(jColumn, PATCH_KEY_COLUMN_WIDTH, json_integer(column.width));
-    json_array_append_new(jColumns, jColumn);
-  }
-  json_object_set_new(jContainer, PATCH_KEY_COLUMNS, jColumns);
+       json_t* jColumns = json_array();
+       for (unsigned i=0; i<columns->size(); i++) {
+               json_t*  jColumn = json_object();
+               column_t column  = columns->at(i);
+               json_object_set_new(jColumn, PATCH_KEY_COLUMN_INDEX, json_integer(column.index));
+               json_object_set_new(jColumn, PATCH_KEY_COLUMN_WIDTH, json_integer(column.width));
+               json_array_append_new(jColumns, jColumn);
+       }
+       json_object_set_new(jContainer, PATCH_KEY_COLUMNS, jColumns);
 }
 
 
@@ -338,17 +354,17 @@ void writeColumns(json_t* jContainer, vector<column_t>* columns)
 
 void writeActions(json_t*jContainer, vector<action_t>*actions)
 {
-  json_t* jActions = json_array();
-  for (unsigned k=0; k<actions->size(); k++) {
-    json_t*  jAction = json_object();
-    action_t action  = actions->at(k);
-    json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE,    json_integer(action.type));
-    json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME,   json_integer(action.frame));
-    json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue));
-    json_object_set_new(jAction, PATCH_KEY_ACTION_I_VALUE, json_integer(action.iValue));
-    json_array_append_new(jActions, jAction);
-  }
-  json_object_set_new(jContainer, PATCH_KEY_CHANNEL_ACTIONS, jActions);
+       json_t* jActions = json_array();
+       for (unsigned k=0; k<actions->size(); k++) {
+               json_t*  jAction = json_object();
+               action_t action  = actions->at(k);
+               json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE,    json_integer(action.type));
+               json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME,   json_integer(action.frame));
+               json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue));
+               json_object_set_new(jAction, PATCH_KEY_ACTION_I_VALUE, json_integer(action.iValue));
+               json_array_append_new(jActions, jAction);
+       }
+       json_object_set_new(jContainer, PATCH_KEY_CHANNEL_ACTIONS, jActions);
 }
 
 
@@ -357,18 +373,18 @@ void writeActions(json_t*jContainer, vector<action_t>*actions)
 
 void writeCommons(json_t* jContainer)
 {
-  json_object_set_new(jContainer, PATCH_KEY_HEADER,         json_string(header.c_str()));
-  json_object_set_new(jContainer, PATCH_KEY_VERSION,        json_string(version.c_str()));
-  json_object_set_new(jContainer, PATCH_KEY_VERSION_MAJOR,  json_integer(versionMajor));
-  json_object_set_new(jContainer, PATCH_KEY_VERSION_MINOR,  json_integer(versionMinor));
-  json_object_set_new(jContainer, PATCH_KEY_VERSION_PATCH,  json_integer(versionPatch));
-  json_object_set_new(jContainer, PATCH_KEY_NAME,           json_string(name.c_str()));
-  json_object_set_new(jContainer, PATCH_KEY_BPM,            json_real(bpm));
-  json_object_set_new(jContainer, PATCH_KEY_BARS,           json_integer(bars));
-  json_object_set_new(jContainer, PATCH_KEY_BEATS,          json_integer(beats));
-  json_object_set_new(jContainer, PATCH_KEY_QUANTIZE,       json_integer(quantize));
-  json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_IN,  json_real(masterVolIn));
-  json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_OUT, json_real(masterVolOut));
+       json_object_set_new(jContainer, PATCH_KEY_HEADER,         json_string(header.c_str()));
+       json_object_set_new(jContainer, PATCH_KEY_VERSION,        json_string(version.c_str()));
+       json_object_set_new(jContainer, PATCH_KEY_VERSION_MAJOR,  json_integer(versionMajor));
+       json_object_set_new(jContainer, PATCH_KEY_VERSION_MINOR,  json_integer(versionMinor));
+       json_object_set_new(jContainer, PATCH_KEY_VERSION_PATCH,  json_integer(versionPatch));
+       json_object_set_new(jContainer, PATCH_KEY_NAME,           json_string(name.c_str()));
+       json_object_set_new(jContainer, PATCH_KEY_BPM,            json_real(bpm));
+       json_object_set_new(jContainer, PATCH_KEY_BARS,           json_integer(bars));
+       json_object_set_new(jContainer, PATCH_KEY_BEATS,          json_integer(beats));
+       json_object_set_new(jContainer, PATCH_KEY_QUANTIZE,       json_integer(quantize));
+       json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_IN,  json_real(masterVolIn));
+       json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_OUT, json_real(masterVolOut));
        json_object_set_new(jContainer, PATCH_KEY_METRONOME,      json_integer(metronome));
        json_object_set_new(jContainer, PATCH_KEY_LAST_TAKE_ID,   json_integer(lastTakeId));
        json_object_set_new(jContainer, PATCH_KEY_SAMPLERATE,     json_integer(samplerate));
@@ -380,59 +396,59 @@ void writeCommons(json_t* jContainer)
 
 void writeChannels(json_t* jContainer, vector<channel_t>* channels)
 {
-  json_t* jChannels = json_array();
-  for (unsigned i=0; i<channels->size(); i++) {
-    json_t*   jChannel = json_object();
-    channel_t channel  = channels->at(i);
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_TYPE,                 json_integer(channel.type));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INDEX,                json_integer(channel.index));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SIZE,                 json_integer(channel.size));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_NAME,                 json_string(channel.name.c_str()));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_COLUMN,               json_integer(channel.column));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE,                 json_integer(channel.mute));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE_S,               json_integer(channel.mute_s));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SOLO,                 json_integer(channel.solo));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_VOLUME,               json_real(channel.volume));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PAN,                  json_real(channel.pan));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN,              json_boolean(channel.midiIn));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VELO_AS_VOL,  json_boolean(channel.midiInVeloAsVol));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS,     json_integer(channel.midiInKeyPress));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL,       json_integer(channel.midiInKeyRel));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL,         json_integer(channel.midiInKill));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM,          json_integer(channel.midiInArm));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       json_integer(channel.midiInVolume));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         json_integer(channel.midiInMute));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_FILTER,       json_integer(channel.midiInFilter));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         json_integer(channel.midiInSolo));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L,           json_boolean(channel.midiOutL));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING,   json_integer(channel.midiOutLplaying));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE,      json_integer(channel.midiOutLmute));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO,      json_integer(channel.midiOutLsolo));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH,          json_string(channel.samplePath.c_str()));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_KEY,                  json_integer(channel.key));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MODE,                 json_integer(channel.mode));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BEGIN,                json_integer(channel.begin));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_END,                  json_integer(channel.end));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BOOST,                json_real(channel.boost));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE,           json_integer(channel.recActive));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PITCH,                json_real(channel.pitch));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INPUT_MONITOR,        json_boolean(channel.inputMonitor));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, json_integer(channel.midiInReadActions));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH,        json_integer(channel.midiInPitch));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT,             json_integer(channel.midiOut));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN,        json_integer(channel.midiOutChan));
-    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_ARMED,                json_boolean(channel.armed));
-    json_array_append_new(jChannels, jChannel);
-
-    writeActions(jChannel, &channel.actions);
+       json_t* jChannels = json_array();
+       for (unsigned i=0; i<channels->size(); i++) {
+               json_t*   jChannel = json_object();
+               channel_t channel  = channels->at(i);
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_TYPE,                 json_integer(channel.type));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INDEX,                json_integer(channel.index));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SIZE,                 json_integer(channel.size));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_NAME,                 json_string(channel.name.c_str()));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_COLUMN,               json_integer(channel.column));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE,                 json_integer(channel.mute));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE_S,               json_integer(channel.mute_s));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SOLO,                 json_integer(channel.solo));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_VOLUME,               json_real(channel.volume));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PAN,                  json_real(channel.pan));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN,              json_boolean(channel.midiIn));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VELO_AS_VOL,  json_boolean(channel.midiInVeloAsVol));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS,     json_integer(channel.midiInKeyPress));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL,       json_integer(channel.midiInKeyRel));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL,         json_integer(channel.midiInKill));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM,          json_integer(channel.midiInArm));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       json_integer(channel.midiInVolume));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         json_integer(channel.midiInMute));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_FILTER,       json_integer(channel.midiInFilter));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         json_integer(channel.midiInSolo));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L,           json_boolean(channel.midiOutL));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING,   json_integer(channel.midiOutLplaying));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE,      json_integer(channel.midiOutLmute));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO,      json_integer(channel.midiOutLsolo));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH,          json_string(channel.samplePath.c_str()));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_KEY,                  json_integer(channel.key));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MODE,                 json_integer(channel.mode));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BEGIN,                json_integer(channel.begin));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_END,                  json_integer(channel.end));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BOOST,                json_real(channel.boost));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE,           json_integer(channel.recActive));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PITCH,                json_real(channel.pitch));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INPUT_MONITOR,        json_boolean(channel.inputMonitor));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, json_integer(channel.midiInReadActions));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH,        json_integer(channel.midiInPitch));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT,             json_integer(channel.midiOut));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN,        json_integer(channel.midiOutChan));
+               json_object_set_new(jChannel, PATCH_KEY_CHANNEL_ARMED,                json_boolean(channel.armed));
+               json_array_append_new(jChannels, jChannel);
+
+               writeActions(jChannel, &channel.actions);
 
 #ifdef WITH_VST
 
-    writePlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS);
+               writePlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS);
 
 #endif
-  }
-  json_object_set_new(jContainer, PATCH_KEY_CHANNELS, jChannels);
+       }
+       json_object_set_new(jContainer, PATCH_KEY_CHANNELS, jChannels);
 }
 
 }; // {anonymous}
@@ -473,15 +489,15 @@ std::vector<plugin_t> masterOutPlugins;
 
 void init()
 {
-  columns.clear();
-  channels.clear();
+       columns.clear();
+       channels.clear();
 #ifdef WITH_VST
-  masterInPlugins.clear();
-  masterOutPlugins.clear();
+       masterInPlugins.clear();
+       masterOutPlugins.clear();
 #endif
-  header     = "GIADAPTC";
-  lastTakeId = 0;
-  samplerate = G_DEFAULT_SAMPLERATE;
+       header     = "GIADAPTC";
+       lastTakeId = 0;
+       samplerate = G_DEFAULT_SAMPLERATE;
 }
 
 
@@ -490,21 +506,21 @@ void init()
 
 int write(const string& file)
 {
-  json_t* jRoot = json_object();
+       json_t* jRoot = json_object();
 
-  writeCommons(jRoot);
-  writeColumns(jRoot, &columns);
-  writeChannels(jRoot, &channels);
+       writeCommons(jRoot);
+       writeColumns(jRoot, &columns);
+       writeChannels(jRoot, &channels);
 #ifdef WITH_VST
-  writePlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS);
-  writePlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS);
+       writePlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS);
+       writePlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS);
 #endif
 
-  if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) {
-    gu_log("[patch::write] unable to write patch file!\n");
-    return 0;
-  }
-  return 1;
+       if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) {
+               gu_log("[patch::write] unable to write patch file!\n");
+               return 0;
+       }
+       return 1;
 }
 
 
@@ -513,34 +529,35 @@ int write(const string& file)
 
 int read(const string& file)
 {
-  json_error_t jError;
-  json_t* jRoot = json_load_file(file.c_str(), 0, &jError);
-  if (!jRoot) {
-    gu_log("[patch::read] unable to read patch file! Error on line %d: %s\n", 
-       jError.line, jError.text);
-    return PATCH_UNREADABLE;
-  }
+       json_error_t jError;
+       json_t* jRoot = json_load_file(file.c_str(), 0, &jError);
+       if (!jRoot) {
+               gu_log("[patch::read] unable to read patch file! Error on line %d: %s\n", 
+                       jError.line, jError.text);
+               return PATCH_UNREADABLE;
+       }
 
-  if (!storager::checkObject(jRoot, "root element"))
-    return PATCH_INVALID;
+       if (!storager::checkObject(jRoot, "root element"))
+               return PATCH_INVALID;
 
-  init();
+       init();
 
-  /* TODO json_decref also when PATCH_INVALID */
+       /* TODO json_decref also when PATCH_INVALID */
 
-  if (!readCommons(jRoot))  return setInvalid(jRoot);
-  if (!readColumns(jRoot))  return setInvalid(jRoot);
-  if (!readChannels(jRoot)) return setInvalid(jRoot);
+       if (!readCommons(jRoot))  return setInvalid(jRoot);
+       if (!readColumns(jRoot))  return setInvalid(jRoot);
+       if (!readChannels(jRoot)) return setInvalid(jRoot);
 #ifdef WITH_VST
-  if (!readPlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS))   return setInvalid(jRoot);
-  if (!readPlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS)) return setInvalid(jRoot);
+       if (!readPlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS))   return setInvalid(jRoot);
+       if (!readPlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS)) return setInvalid(jRoot);
 #endif
 
-  json_decref(jRoot);
+       json_decref(jRoot);
 
-  sanitize();
+       sanitize();
+       modernize();
 
-  return PATCH_READ_OK;
+       return PATCH_READ_OK;
 }
 
 
index f7faccb74188712e6b116b983d83405c36b1f1b0..153b149670760c5afe9a425a859ef641deb3dc1b 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef WITH_VST
 
 
+#include <cassert>
 #include "../utils/log.h"
 #include "../utils/fs.h"
 #include "../utils/string.h"
@@ -146,20 +147,20 @@ void close()
 /* -------------------------------------------------------------------------- */
 
 
-void init(int _buffersize, int _samplerate)
+void init(int buffersize_, int samplerate_)
 {
-       gu_log("[pluginHost::init] initialize with buffersize=%d, samplerate=%d\n",
-               _buffersize, _samplerate);
-
        messageManager = juce::MessageManager::getInstance();
-       audioBuffer.setSize(2, _buffersize);
-       samplerate = _samplerate;
-       buffersize = _buffersize;
+       audioBuffer.setSize(G_MAX_IO_CHANS, buffersize_);
+       samplerate = samplerate_;
+       buffersize = buffersize_;
        missingPlugins = false;
        //unknownPluginList.empty();
        loadList(gu_getHomePath() + G_SLASH + "plugins.xml");
 
        pthread_mutex_init(&mutex_midi, nullptr);
+
+       gu_log("[pluginHost::init] initialized with buffersize=%d, samplerate=%d\n",
+       buffersize, samplerate);
 }
 
 
@@ -343,12 +344,12 @@ pluginHost::PluginInfo getAvailablePluginInfo(int i)
 {
        juce::PluginDescription* pd = knownPluginList.getType(i);
        PluginInfo pi;
-       pi.uid = pd->fileOrIdentifier.toStdString();
-       pi.name = pd->name.toStdString();
-       pi.category = pd->category.toStdString();
+       pi.uid              = pd->fileOrIdentifier.toStdString();
+       pi.name             = pd->name.toStdString();
+       pi.category         = pd->category.toStdString();
        pi.manufacturerName = pd->manufacturerName.toStdString();
-       pi.format = pd->pluginFormatName.toStdString();
-       pi.isInstrument = pd->isInstrument;
+       pi.format           = pd->pluginFormatName.toStdString();
+       pi.isInstrument     = pd->isInstrument;
        return pi;
 }
 
@@ -397,7 +398,7 @@ void freeStack(int stackType, pthread_mutex_t* mutex, Channel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-void processStack(float* buffer, int stackType, Channel* ch)
+void processStack(AudioBuffer& outBuf, int stackType, Channel* ch)
 {
        vector<Plugin*>* pStack = getStack(stackType, ch);
 
@@ -406,17 +407,18 @@ void processStack(float* buffer, int stackType, Channel* ch)
        if (pStack == nullptr || pStack->size() == 0)
                return;
 
+       assert(outBuf.countFrames() == audioBuffer.getNumSamples());
+
        /* MIDI channels must not process the current buffer: give them an empty one. 
        Sample channels and Master in/out want audio data instead: let's convert the 
        internal buffer from Giada to Juce. */
 
-       if (ch != nullptr && ch->type == CHANNEL_MIDI) 
+       if (ch != nullptr && ch->type == G_CHANNEL_MIDI) 
                audioBuffer.clear();
        else
-               for (int i=0; i<buffersize; i++) {
-                       audioBuffer.setSample(0, i, buffer[i*2]);
-                       audioBuffer.setSample(1, i, buffer[(i*2)+1]);
-               }
+               for (int i=0; i<outBuf.countFrames(); i++)
+                       for (int j=0; j<outBuf.countChannels(); j++)
+                               audioBuffer.setSample(j, i, outBuf[i][j]);
 
        /* Hardcore processing. At the end we swap input and output, so that he N-th
        plugin will process the result of the plugin N-1. Part of this loop must be
@@ -443,12 +445,11 @@ void processStack(float* buffer, int stackType, Channel* ch)
                set of MIDI events. */
 
                if (ch != nullptr && plugin->acceptsMidi()) {
-                       juce::AudioBuffer<float> tmp(2, buffersize);
+                       juce::AudioBuffer<float> tmp(audioBuffer.getNumChannels(), buffersize);
                        plugin->process(tmp, ch->getPluginMidiEvents());
-                       for (int i=0; i<buffersize; i++) {
-                               audioBuffer.addSample(0, i, tmp.getSample(0, i));
-                               audioBuffer.addSample(1, i, tmp.getSample(1, i));
-                       }
+                       for (int i=0; i<audioBuffer.getNumSamples(); i++)
+                               for (int j=0; j<audioBuffer.getNumChannels(); j++)
+                                       audioBuffer.addSample(j, i, tmp.getSample(j, i));       
                }
                else
                        plugin->process(audioBuffer, juce::MidiBuffer()); // Empty MIDI buffer
@@ -462,10 +463,9 @@ void processStack(float* buffer, int stackType, Channel* ch)
        /* Converting buffer from Juce to Giada. A note for the future: if we 
        overwrite (=) (as we do now) it's SEND, if we add (+) it's INSERT. */
 
-       for (int i=0; i<buffersize; i++) {
-               buffer[i*2]     = audioBuffer.getSample(0, i);
-               buffer[(i*2)+1] = audioBuffer.getSample(1, i);
-       }
+       for (int i=0; i<outBuf.countFrames(); i++)
+               for (int j=0; j<outBuf.countChannels(); j++)    
+                       outBuf[i][j] = audioBuffer.getSample(j, i);
 }
 
 
@@ -612,6 +612,20 @@ void sortPlugins(int method)
        }
 }
 
+
+/* -------------------------------------------------------------------------- */
+
+
+void forEachPlugin(int stackType, const Channel* ch, std::function<void(const Plugin* p)> f)
+{
+       /* TODO - Remove const is ugly. This is a temporary workaround until all
+       PluginHost functions params will be const-correct. */
+       vector<Plugin*>* stack = getStack(stackType, const_cast<Channel*>(ch));
+       for (const Plugin* p : *stack)
+               f(p);
+}
+
+
 }}}; // giada::m::pluginHost::
 
 
index a98cb02f02842be72c850392dc415e4dd93d1cfe..dcb749fffc7651f6f8d29d8be5747c98063260b0 100644 (file)
@@ -34,6 +34,7 @@
 #include <functional>
 #include <pthread.h>
 #include "../deps/juce-config.h"
+#include "audioBuffer.h"
 
 
 class Plugin;
@@ -69,7 +70,9 @@ struct PluginInfo
        bool isInstrument;
 };
 
-void init(int bufSize, int frequency);
+extern pthread_mutex_t mutex_midi;
+
+void init(int bufSize, int samplerate);
 void close();
 
 /* scanDirs
@@ -129,9 +132,9 @@ std::string getUnknownPluginInfo(int index);
 void freeStack(int stackType, pthread_mutex_t* mutex, Channel* ch=nullptr);
 
 /* processStack
- * apply the fx list to the buffer. */
+Applies the fx list to the buffer. */
 
-void processStack(float* buffer, int stackType, Channel* ch=nullptr);
+void processStack(AudioBuffer& outBuf, int stackType, Channel* ch=nullptr);
 
 /* getStack
 * Return a std::vector <Plugin *> given the stackType. If stackType == CHANNEL
@@ -180,7 +183,7 @@ bool hasMissingPlugins();
 
 void sortPlugins(int sortMethod);
 
-extern pthread_mutex_t mutex_midi;
+void forEachPlugin(int stackType, const Channel* ch, std::function<void(const Plugin* p)> f);
 
 }}}; // giada::m::pluginHost::
 
index ff319ad5d649561e9f176981d04610aa6007e2f0..7dddda1f512d91b452b87187216d4a0824ba04f8 100644 (file)
@@ -111,7 +111,7 @@ bool canRec(Channel* ch, bool clockRunning, bool mixerRecording)
        if (!active         ||
                  !clockRunning   ||
                         mixerRecording ||
-                       (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == nullptr)
+                       (ch->type == G_CHANNEL_SAMPLE && static_cast<SampleChannel*>(ch)->wave == nullptr)
                )
                return false;
        return true;
@@ -123,14 +123,9 @@ bool canRec(Channel* ch, bool clockRunning, bool mixerRecording)
 
 void rec(int index, int type, int frame, uint32_t iValue, float fValue)
 {
-       /* make sure frame is even */
-
-       if (frame % 2 != 0)
-               frame++;
-
        /* allocating the action */
 
-       action *a = (action*) malloc(sizeof(action));
+       actiona = (action*) malloc(sizeof(action));
        a->chan   = index;
        a->type   = type;
        a->frame  = frame;
@@ -164,7 +159,7 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue)
                /* no duplicates, please */
 
                for (unsigned t=0; t<global.at(frameToExpand).size(); t++) {
-                       action *ac = global.at(frameToExpand).at(t);
+                       actionac = global.at(frameToExpand).at(t);
                        if (ac->chan   == index  &&
                            ac->type   == type   &&
                            ac->frame  == frame  &&
@@ -195,7 +190,7 @@ void clearChan(int index)
                unsigned j=0;
                while (true) {
                        if (j == global.at(i).size()) break;      // for each action j of frame i
-                       action *a = global.at(i).at(j);
+                       actiona = global.at(i).at(j);
                        if (a->chan == index)   {
                                free(a);
                                global.at(i).erase(global.at(i).begin() + j);
@@ -220,7 +215,7 @@ void clearAction(int index, char act)
                while (true) {                                   // for each action j of frame i
                        if (j == global.at(i).size())
                                break;
-                       action *a = global.at(i).at(j);
+                       actiona = global.at(i).at(j);
                        if (a->chan == index && (act & a->type) == a->type)     { // bitmask
                                free(a);
                                global.at(i).erase(global.at(i).begin() + j);
@@ -240,11 +235,6 @@ void clearAction(int index, char act)
 void deleteAction(int chan, int frame, char type, bool checkValues,
        pthread_mutex_t* mixerMutex, uint32_t iValue, float fValue)
 {
-       /* make sure frame is even */
-
-       if (frame % 2 != 0)
-               frame++;
-
        /* find the frame 'frame' */
 
        bool found = false;
@@ -256,7 +246,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues,
                        /* find the action in frame i */
 
                for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action *a = global.at(i).at(j);
+                       actiona = global.at(i).at(j);
 
                        /* action comparison logic */
 
@@ -388,18 +378,13 @@ void updateBpm(float oldval, float newval, int oldquanto)
                        if (scarto > 0 && scarto <= 6)
                                frames.at(i) = frames.at(i) + scarto;
                }
-
-               /* never ever have odd frames. */
-
-               if (frames.at(i) % 2 != 0)
-                       frames.at(i)++;
        }
 
        /* update structs */
 
        for (unsigned i=0; i<frames.size(); i++) {
                for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action *a = global.at(i).at(j);
+                       actiona = global.at(i).at(j);
                        a->frame = frames.at(i);
                }
        }
@@ -431,9 +416,6 @@ void updateSamplerate(int systemRate, int patchRate)
 
                frames.at(i) = (int) newFrame;
 
-               if (frames.at(i) % 2 != 0)
-                       frames.at(i)++;
-
                gu_log(", newFrame = %d\n", frames.at(i));
        }
 
@@ -441,7 +423,7 @@ void updateSamplerate(int systemRate, int patchRate)
 
        for (unsigned i=0; i<frames.size(); i++) {
                for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action *a = global.at(i).at(j);
+                       actiona = global.at(i).at(j);
                        a->frame = frames.at(i);
                }
        }
@@ -469,7 +451,7 @@ void expand(int old_fpb, int new_fpb)
                        frames.push_back(newframe);
                        global.push_back(actions);
                        for (unsigned k=0; k<global.at(i).size(); k++) {
-                               action *a = global.at(i).at(k);
+                               actiona = global.at(i).at(k);
                                rec(a->chan, a->type, newframe, a->iValue, a->fValue);
                        }
                }
@@ -611,7 +593,7 @@ void startOverdub(int index, char actionMask, int frame, unsigned bufferSize)
 
        rec(index, cmp.a1.type, frame);
 
-       action *act = nullptr;
+       actionact = nullptr;
        int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act);
        if (res == 1) {
                if (act->type == cmp.a2.type) {
@@ -674,4 +656,15 @@ void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t* mixerMutex)
        rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame);
   fixOverdubTruncation(cmp, mixerMutex);
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void forEachAction(std::function<void(const action*)> f)
+{
+       for (const vector<action*> actions : recorder::global)
+               for (const action* action : actions)
+                       f(action);
+}
 }}}; // giada::m::recorder::
index 49a43a24c1c46ed03f988cbef443f8c03c084720..0f0b0e579f1557a3e532c8b565ab4701d668a323 100644 (file)
 #define G_RECORDER_H
 
 
-#ifdef __APPLE__  // our Clang still doesn't know about cstdint (c++11 stuff)
-       #include <stdint.h>
-#else
-       #include <cstdint>
-#endif
+#include <cstdint>
 #include <vector>
+#include <functional>
 #include <pthread.h>
 
 
@@ -100,7 +97,7 @@ bool hasActions(int chanIndex);
 /* canRec
  * can a channel rec an action? Call this one BEFORE rec(). */
 
-bool canRec(Channel *ch, bool clockRunning, bool mixerRecording);
+bool canRec(Channelch, bool clockRunning, bool mixerRecording);
 
 /* rec
  * record an action. */
@@ -121,14 +118,14 @@ void clearAction(int chan, char action);
  * delete ONE action. Useful in the action editor. 'type' can be a mask. */
 
 void deleteAction(int chan, int frame, char type, bool checkValues,
-  pthread_mutex_t *mixerMutex, uint32_t iValue=0, float fValue=0.0);
+  pthread_mutex_tmixerMutex, uint32_t iValue=0, float fValue=0.0);
 
 /* deleteActions
 Deletes A RANGE of actions from frame_a to frame_b in channel 'chan' of type
 'type' (can be a bitmask). Exclusive range (frame_a, frame_b). */
 
 void deleteActions(int chan, int frame_a, int frame_b, char type,
-  pthread_mutex_t *mixerMutex);
+  pthread_mutex_tmixerMutex);
 
 /* clearAll
  * delete everything. */
@@ -183,6 +180,11 @@ pressing Mute button on a channel with some existing mute actions. */
 
 void startOverdub(int chan, char action, int frame, unsigned bufferSize);
 void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t *mixerMutex);
+
+/* forEachAction
+Applies a read-only callback on each action recorded. */
+
+void forEachAction(std::function<void(const action*)> f);
 }}}; // giada::m::recorder::
 
 #endif
index 4ab37001f8c1f227c286ce647a4e67482681a414..0a696323be7f47cec894015ebaa908771f167f0d 100644 (file)
@@ -32,6 +32,7 @@
 #include "../utils/fs.h"
 #include "../utils/string.h"
 #include "patch.h"
+#include "channelManager.h"
 #include "const.h"
 #include "conf.h"
 #include "clock.h"
@@ -51,27 +52,25 @@ using namespace giada::m;
 
 
 SampleChannel::SampleChannel(int bufferSize, bool inputMonitor)
-       : Channel          (CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize),
+       : Channel          (G_CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize),
                rsmp_state       (nullptr),
-               pChan            (nullptr),
-               vChanPreview     (nullptr),
                frameRewind      (-1),
                begin            (0),
                end              (0),
-               boost            (G_DEFAULT_BOOST),
                pitch            (G_DEFAULT_PITCH),
-               trackerPreview   (0),
-               shift            (0),
-               wave             (nullptr),
-               tracker          (0),
-               mode             (G_DEFAULT_CHANMODE),
-               qWait              (false),
+               boost            (G_DEFAULT_BOOST),
                fadeinOn         (false),
                fadeinVol        (1.0f),
                fadeoutOn        (false),
                fadeoutVol       (1.0f),
                fadeoutTracker   (0),
                fadeoutStep      (G_DEFAULT_FADEOUT_STEP),
+               wave             (nullptr),
+               tracker          (0),
+               trackerPreview   (0),
+               shift            (0),
+               mode             (G_DEFAULT_CHANMODE),
+               qWait              (false),
                inputMonitor     (inputMonitor),
                midiInReadActions(0x0),
                midiInPitch      (0x0)
@@ -88,10 +87,6 @@ SampleChannel::~SampleChannel()
                delete wave;
        if (rsmp_state != nullptr)
                src_delete(rsmp_state);
-       if (pChan != nullptr)
-               delete[] pChan; 
-       if (vChanPreview != nullptr)
-               delete[] vChanPreview;
 }
 
 
@@ -103,20 +98,18 @@ bool SampleChannel::allocBuffers()
        if (!Channel::allocBuffers())
                return false;
 
-       rsmp_state = src_new(SRC_LINEAR, 2, nullptr);
+       rsmp_state = src_new(SRC_LINEAR, G_MAX_IO_CHANS, nullptr);
        if (rsmp_state == nullptr) {
                gu_log("[SampleChannel::allocBuffers] unable to alloc memory for SRC_STATE!\n");
                return false;
        }
 
-       pChan = new (std::nothrow) float[bufferSize];
-       if (pChan == nullptr) {
+       if (!pChan.alloc(bufferSize, G_MAX_IO_CHANS)) {
                gu_log("[SampleChannel::allocBuffers] unable to alloc memory for pChan!\n");
                return false;
        }
 
-       vChanPreview = new (std::nothrow) float[bufferSize];
-       if (vChanPreview == nullptr) {
+       if (!vChanPreview.alloc(bufferSize, G_MAX_IO_CHANS)) {
                gu_log("[SampleChannel::allocBuffers] unable to alloc memory for vChanPreview!\n");
                return false;
        }
@@ -128,10 +121,10 @@ bool SampleChannel::allocBuffers()
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::copy(const Channel* _src, pthread_mutex_t* pluginMutex)
+void SampleChannel::copy(const Channel* src_, pthread_mutex_t* pluginMutex)
 {
-       Channel::copy(_src, pluginMutex);
-       const SampleChannel* src = static_cast<const SampleChannel*>(_src);
+       Channel::copy(src_, pluginMutex);
+       const SampleChannel* src = static_cast<const SampleChannel*>(src_);
        tracker         = src->tracker;
        begin           = src->begin;
        end             = src->end;
@@ -158,11 +151,11 @@ void SampleChannel::copy(const Channel* _src, pthread_mutex_t* pluginMutex)
 
 void SampleChannel::clear()
 {
-       /** TODO - these memsets may be done only if status PLAY (if below),
+       /** TODO - these clear() may be done only if status PLAY | ENDING (if below),
         * but it would require extra clearPChan calls when samples stop */
 
-       std::memset(vChan, 0, sizeof(float) * bufferSize);
-       std::memset(pChan, 0, sizeof(float) * bufferSize);
+       vChan.clear();
+       pChan.clear();
 
        if (status & (STATUS_PLAY | STATUS_ENDING)) {
                tracker = fillChan(vChan, tracker, 0);
@@ -181,8 +174,8 @@ void SampleChannel::calcVolumeEnv(int frame)
 {
        /* method: check this frame && next frame, then calculate delta */
 
-       recorder::action *a0 = nullptr;
-       recorder::action *a1 = nullptr;
+       recorder::actiona0 = nullptr;
+       recorder::actiona1 = nullptr;
        int res;
 
        /* get this action on frame 'frame'. It's unlikely that the action
@@ -203,7 +196,7 @@ void SampleChannel::calcVolumeEnv(int frame)
                res = recorder::getAction(index, G_ACTION_VOLUME, 0, &a1);
 
        volume_i = a0->fValue;
-       volume_d = ((a1->fValue - a0->fValue) / ((a1->frame - a0->frame) / 2)) * 1.003f;
+       volume_d = ((a1->fValue - a0->fValue) / (a1->frame - a0->frame)) * 1.003f;
 }
 
 
@@ -212,8 +205,8 @@ void SampleChannel::calcVolumeEnv(int frame)
 
 void SampleChannel::hardStop(int frame)
 {
-       if (frame != 0)        // clear data in range [frame, bufferSize-1]
-               clearChan(vChan, frame);
+       if (frame != 0)        
+               vChan.clear(frame); // clear data in range [frame, [end]]
        status = STATUS_OFF;
        sendMidiLplay();
        reset(frame);
@@ -226,12 +219,12 @@ void SampleChannel::hardStop(int frame)
 void SampleChannel::onBar(int frame)
 {
        ///if (mode == LOOP_REPEAT && status == STATUS_PLAY)
-       ///     //setXFade(frame);
-       ///     reset(frame);
+       ///     //setXFade(frame * 2);
+       ///     reset(frame * 2);
 
        if (mode == LOOP_REPEAT) {
                if (status == STATUS_PLAY)
-                       //setXFade(frame);
+                       //setXFade(frame * 2);
                        reset(frame);
        }
        else
@@ -250,19 +243,16 @@ void SampleChannel::onBar(int frame)
 
 void SampleChannel::setBegin(int f)
 {
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove * wave->getChannels() stuff. */
-
        if (f < 0)
                begin = 0;
        else
        if (f > wave->getSize())
-               begin = wave->getSize() * wave->getChannels();
+               begin = wave->getSize();
        else
        if (f >= end)
-               begin = end - wave->getChannels();
+               begin = end - 1;
        else
-               begin = f * wave->getChannels();
+               begin = f;
 
        tracker = begin;
        trackerPreview = begin;
@@ -274,69 +264,24 @@ void SampleChannel::setBegin(int f)
 
 void SampleChannel::setEnd(int f)
 {
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove * wave->getChannels() stuff. */
-       
        if (f < 0)
                end = begin + wave->getChannels();
        else
        if (f >= wave->getSize())
-               end = (wave->getSize() - 1) * wave->getChannels();
+               end = wave->getSize() - 1;
        else
-       if (f * wave->getChannels() <= begin)
-               end = begin + wave->getChannels();
+       if (f <= begin)
+               end = begin + 1;
        else
-               end = f * wave->getChannels();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::getBegin()
-{
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove / wave->getChannels() stuff. */
-       
-       return begin / wave->getChannels();
-}
-
-
-int SampleChannel::getEnd()
-{
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove / wave->getChannels() stuff. */
-
-       return end / wave->getChannels();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleChannel::setTrackerPreview(int f)
-{
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove * wave->getChannels() stuff. */
-       
-       trackerPreview = f * wave->getChannels();
-}
-
-
-int SampleChannel::getTrackerPreview() const
-{
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove / wave->getChannels() stuff. */
-
-       return trackerPreview / wave->getChannels();
+               end = f;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::getShift() const { return shift; }
-void SampleChannel::setShift(int s) { shift = s; }
+int SampleChannel::getBegin() const { return begin; }
+int SampleChannel::getEnd() const   { return end; }
 
 
 /* -------------------------------------------------------------------------- */
@@ -361,10 +306,7 @@ void SampleChannel::setPitch(float v)
 }
 
 
-float SampleChannel::getPitch()
-{
-       return pitch;
-}
+float SampleChannel::getPitch() const { return pitch; }
 
 
 /* -------------------------------------------------------------------------- */
@@ -421,10 +363,6 @@ void SampleChannel::parseAction(recorder::action* a, int localFrame,
 
 void SampleChannel::sum(int frame, bool running)
 {
-       // TODO - Opaque channels' processing
-       // TODO - Opaque channels' processing
-       // TODO - Opaque channels' processing
-       
        if (wave == nullptr || status & ~(STATUS_PLAY | STATUS_ENDING))
                return;
 
@@ -448,14 +386,14 @@ void SampleChannel::sum(int frame, bool running)
                 * volume envelope. */
 
                if (mute || mute_i) {
-                       vChan[frame]   = 0.0f;
-                       vChan[frame+1] = 0.0f;
+                       for (int i=0; i<vChan.countChannels(); i++)
+                               vChan[frame][i] = 0.0f;
                }
                else
                if (fadeinOn) {
                        if (fadeinVol < 1.0f) {
-                               vChan[frame]   *= fadeinVol * volume_i;
-                               vChan[frame+1] *= fadeinVol * volume_i;
+                               for (int i=0; i<vChan.countChannels(); i++)
+                                       vChan[frame][i] *= fadeinVol * volume_i;
                                fadeinVol += 0.01f;
                        }
                        else {
@@ -467,14 +405,12 @@ void SampleChannel::sum(int frame, bool running)
                if (fadeoutOn) {
                        if (fadeoutVol > 0.0f) { // fadeout ongoing
                                if (fadeoutType == XFADE) {
-                                       vChan[frame]   *= volume_i;
-                                       vChan[frame+1] *= volume_i;
-                                       vChan[frame]    = pChan[frame]   * fadeoutVol * volume_i;
-                                       vChan[frame+1]  = pChan[frame+1] * fadeoutVol * volume_i;
+                                       for (int i=0; i<vChan.countChannels(); i++)
+                                               vChan[frame][i] = pChan[frame][i] * fadeoutVol * volume_i;
                                }
                                else {
-                                       vChan[frame]   *= fadeoutVol * volume_i;
-                                       vChan[frame+1] *= fadeoutVol * volume_i;
+                                       for (int i=0; i<vChan.countChannels(); i++)
+                                               vChan[frame][i] *= fadeoutVol * volume_i;
                                }
                                fadeoutVol -= fadeoutStep;
                        }
@@ -499,8 +435,8 @@ void SampleChannel::sum(int frame, bool running)
                        }
                }
                else {
-                       vChan[frame]   *= volume_i;
-                       vChan[frame+1] *= volume_i;
+                       for (int i=0; i<vChan.countChannels(); i++)
+                               vChan[frame][i] *= volume_i;
                }
        }
        else { // at this point the sample has reached the end */
@@ -525,8 +461,8 @@ void SampleChannel::sum(int frame, bool running)
                                status = STATUS_WAIT;
                }
 
-               /* check for end of samples. SINGLE_ENDLESS runs forever unless
-                * it's in ENDING mode. */
+               /* Check for end of samples. SINGLE_ENDLESS runs forever unless it's in 
+               ENDING mode. */
 
                reset(frame);
        }
@@ -549,9 +485,9 @@ void SampleChannel::onZero(int frame, bool recsStopOnChanHalt)
                if (status == STATUS_PLAY) {
                        /*
                        if (mute || mute_i)
-                               reset(frame);
+                               reset(frame * 2);
                        else
-                               setXFade(frame);
+                               setXFade(frame * 2);
                        */
                        reset(frame);
                }
@@ -581,7 +517,7 @@ void SampleChannel::onZero(int frame, bool recsStopOnChanHalt)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::quantize(int index, int localFrame)
+void SampleChannel::quantize(int index, int localFrame, int globalFrame)
 {
        /* skip if LOOP_ANY or not in quantizer-wait mode */
 
@@ -598,7 +534,7 @@ void SampleChannel::quantize(int index, int localFrame)
                tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ???
        }
        else
-               //setXFade(localFrame);
+               //setXFade(localFrame * 2);
                reset(localFrame);
 
        /* this is the moment in which we record the keypress, if the
@@ -606,12 +542,12 @@ void SampleChannel::quantize(int index, int localFrame)
 
        if (recorder::canRec(this, clock::isRunning(), mixer::recording)) {
                if (mode == SINGLE_PRESS) {
-                       recorder::startOverdub(index, G_ACTION_KEYS, clock::getCurrentFrame(),
-        kernelAudio::getRealBufSize());
+                       recorder::startOverdub(index, G_ACTION_KEYS, globalFrame, 
+                               kernelAudio::getRealBufSize());
       readActions = false;   // don't read actions while overdubbing
     }
                else
-                       recorder::rec(index, G_ACTION_KEYPRESS, clock::getCurrentFrame());
+                       recorder::rec(index, G_ACTION_KEYPRESS, globalFrame);
     hasActions = true;
        }
 }
@@ -622,11 +558,8 @@ void SampleChannel::quantize(int index, int localFrame)
 
 int SampleChannel::getPosition()
 {
-       /* TODO - Opaque channel's count - everything in SampleChannel should be
-       frame-based, not sample-based. I.e. Remove / wave->getChannels() stuff. */
-
        if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...)
-               return (tracker - begin) / wave->getChannels();
+               return tracker - begin;
        else
                return -1;
 }
@@ -729,8 +662,8 @@ float SampleChannel::getBoost() const
 
 void SampleChannel::calcFadeoutStep()
 {
-       if (end - tracker < (1 / G_DEFAULT_FADEOUT_STEP) * 2)
-               fadeoutStep = ceil((end - tracker) / volume) * 2; /// or volume_i ???
+       if (end - tracker < (1 / G_DEFAULT_FADEOUT_STEP))
+               fadeoutStep = ceil((end - tracker) / volume); /// or volume_i ???
        else
                fadeoutStep = G_DEFAULT_FADEOUT_STEP;
 }
@@ -750,15 +683,6 @@ void SampleChannel::setReadActions(bool v, bool killOnFalse)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setOnEndPreviewCb(std::function<void()> f)
-{
-       onPreviewEnd = f;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 void SampleChannel::setFadeIn(bool internal)
 {
        if (internal) mute_i = false;  // remove mute before fading in
@@ -799,13 +723,6 @@ void SampleChannel::setXFade(int frame)
 
 /* -------------------------------------------------------------------------- */
 
-/* On reset, if frame > 0 and in play, fill again pChan to create something like 
-this:
-
-       |abcdefabcdefab*abcdefabcde|
-       [old data-----]*[new data--]
-
-*/
 
 void SampleChannel::reset(int frame)
 {
@@ -813,6 +730,13 @@ void SampleChannel::reset(int frame)
        tracker = begin;
        mute_i  = false;
        qWait   = false;  // Was in qWait mode? Reset occured, no more qWait now.
+
+       /* On reset, if frame > 0 and in play, fill again pChan to create something 
+       like this:
+
+               |abcdefabcdefab*abcdefabcde|
+               [old data-----]*[new data--] */
+
        if (frame > 0 && status & (STATUS_PLAY | STATUS_ENDING))
                tracker = fillChan(vChan, tracker, frame);
 }
@@ -847,7 +771,7 @@ void SampleChannel::pushWave(Wave* w)
        wave   = w;
        status = STATUS_OFF;
        begin  = 0;
-       end    = (wave->getSize() - 1) * wave->getChannels(); // TODO - Opaque channels' count
+       end    = wave->getSize() - 1;
        name   = wave->getBasename();
 }
 
@@ -855,38 +779,40 @@ void SampleChannel::pushWave(Wave* w)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::process(float* outBuffer, float* inBuffer)
+void SampleChannel::process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in)
 {
+       assert(out.countSamples() == vChan.countSamples());
+       assert(in.countSamples()  == vChan.countSamples());
+
        /* If armed and inbuffer is not nullptr (i.e. input device available) and
   input monitor is on, copy input buffer to vChan: this enables the input
   monitoring. The vChan will be overwritten later by pluginHost::processStack,
   so that you would record "clean" audio (i.e. not plugin-processed). */
 
-       if (armed && inBuffer && inputMonitor)
-    for (int i=0; i<bufferSize; i++)
-      vChan[i] += inBuffer[i]; // add, don't overwrite (no raw memcpy)
+       if (armed && in.isAllocd() && inputMonitor)
+               for (int i=0; i<vChan.countFrames(); i++)
+                       for (int j=0; j<vChan.countChannels(); j++)
+                               vChan[i][j] += in[i][j];   // add, don't overwrite
 
 #ifdef WITH_VST
        pluginHost::processStack(vChan, pluginHost::CHANNEL, this);
 #endif
 
-       // TODO - Opaque channels' processing
-  for (int j=0; j<bufferSize; j+=2) {
-               outBuffer[j]   += vChan[j]   * volume * calcPanning(0) * boost;
-               outBuffer[j+1] += vChan[j+1] * volume * calcPanning(1) * boost;
-       }
+               for (int i=0; i<out.countFrames(); i++)
+                       for (int j=0; j<out.countChannels(); j++)
+                               out[i][j] += vChan[i][j] * volume * calcPanning(j) * boost;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::preview(float* outBuffer)
+void SampleChannel::preview(giada::m::AudioBuffer& out)
 {
        if (previewMode == G_PREVIEW_NONE)
                return;
 
-       std::memset(vChanPreview, 0, sizeof(float) * bufferSize);
+       vChanPreview.clear();
 
        /* If the tracker exceedes the end point and preview is looped, split the 
        rendering as in SampleChannel::reset(). */
@@ -907,11 +833,9 @@ void SampleChannel::preview(float* outBuffer)
        else
                trackerPreview = fillChan(vChanPreview, trackerPreview, 0, false);
 
-       // TODO - Opaque channels' processing
-       for (int j=0; j<bufferSize; j+=2) {
-               outBuffer[j]   += vChanPreview[j]   * volume * calcPanning(0) * boost;
-               outBuffer[j+1] += vChanPreview[j+1] * volume * calcPanning(1) * boost;
-       }
+       for (int i=0; i<out.countFrames(); i++)
+               for (int j=0; j<out.countChannels(); j++)
+                       out[i][j] += vChanPreview[i][j] * volume * calcPanning(j) * boost;
 }
 
 
@@ -980,45 +904,10 @@ void SampleChannel::stop()
 /* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::readPatch(const string& basePath, int i,
-               pthread_mutex_t* pluginMutex, int samplerate, int rsmpQuality)
+void SampleChannel::readPatch(const string& basePath, int i)
 {
-       /* load channel's data first: if the sample is missing or wrong, the channel
-        * is not completely blank. */
-
-       Channel::readPatch("", i, pluginMutex, samplerate, rsmpQuality);
-
-       const patch::channel_t* pch = &patch::channels.at(i);
-
-       mode              = pch->mode;
-       boost             = pch->boost;
-       readActions       = pch->recActive;
-       recStatus         = readActions ? REC_READING : REC_STOPPED;
-       midiInVeloAsVol   = pch->midiInVeloAsVol;
-       midiInReadActions = pch->midiInReadActions;
-       midiInPitch       = pch->midiInPitch;
-  inputMonitor      = pch->inputMonitor;
-
-  Wave* w = nullptr;
-  int res = waveManager::create(basePath + pch->samplePath, &w); 
-
-       if (res == G_RES_OK) {
-               pushWave(w);
-               setName(pch->name);
-               setBegin(pch->begin);
-               setEnd(pch->end);
-               setPitch(pch->pitch);
-       }
-       else {
-               if (res == G_RES_ERR_NO_DATA)
-                       status = STATUS_EMPTY;
-               else
-               if (res == G_RES_ERR_IO)
-                       status = STATUS_MISSING;
-               sendMidiLplay();  // FIXME - why sending MIDI lightning if sample status is wrong?
-       }
-
-       return res;
+       Channel::readPatch("", i);
+       channelManager::readPatch(this, basePath, i);
 }
 
 
@@ -1109,91 +998,58 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize,
 /* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::writePatch(int i, bool isProject)
+void SampleChannel::writePatch(int i, bool isProject)
 {
-       // TODO - this code belongs to an upper level (glue)
-
-       int pchIndex = Channel::writePatch(i, isProject);
-       patch::channel_t *pch = &patch::channels.at(pchIndex);
-
-       if (wave != nullptr) {
-               pch->samplePath = wave->getPath();
-               if (isProject)
-                       pch->samplePath = gu_basename(wave->getPath());  // make it portable
-       }
-       else
-               pch->samplePath = "";
-
-       pch->mode              = mode;
-       pch->begin             = begin;
-       pch->end               = end;
-       pch->boost             = boost;
-       pch->recActive         = readActions;
-       pch->pitch             = pitch;
-       pch->inputMonitor      = inputMonitor;
-       pch->midiInReadActions = midiInReadActions;
-       pch->midiInPitch       = midiInPitch;
-
-       return 0;
+       Channel::writePatch(i, isProject);
+       channelManager::writePatch(this, isProject, i);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::clearChan(float *dest, int start)
-{
-       memset(dest+start, 0, sizeof(float)*(bufferSize-start));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind)
+int SampleChannel::fillChan(giada::m::AudioBuffer& dest, int start, int offset, bool rewind)
 {
        int position;  // return value: the new position
 
        if (pitch == 1.0f) {
 
-               /* case 1: 'dest' lies within the original sample boundaries (start-
-                * end) */
+               /* Fill 'dest' buffer with a chunk of data of size 'buffersize - offset'. 
+               Case 1: there is enough data in Wave. Case2: not enough data or Wave is 
+               smaller than the buffer. */
+
+               int chunkSize = bufferSize - offset;
 
-               if (start+bufferSize-offset <= end) {
-                       memcpy(dest+offset, wave->getData()+start, (bufferSize-offset)*sizeof(float));
-                       position = start+bufferSize-offset;
+               if (start + chunkSize <= end) {
+                       position = start + chunkSize;
                        if (rewind)
                                frameRewind = -1;
                }
-
-               /* case2: 'dest' lies outside the end of the sample, OR the sample
-                * is smaller than 'dest' */
-
                else {
-                       memcpy(dest+offset, wave->getData()+start, (end-start)*sizeof(float));
-                       position = end;
+                       chunkSize = end - start;
+                       position  = end;
                        if (rewind)
-                               frameRewind = end-start+offset;
+                               frameRewind = chunkSize + offset;
                }
+               dest.copyData(wave->getFrame(start), chunkSize, offset);
        }
        else {
-               // TODO - Opaque channels count
-               rsmp_data.data_in       = wave->getData()+start;    // source data
-               rsmp_data.input_frames  = (end-start)/2;            // how many readable bytes
-               rsmp_data.data_out      = dest+offset;              // destination (processed data)
-               rsmp_data.output_frames = (bufferSize-offset)/2;    // how many bytes to process
+               rsmp_data.data_in       = wave->getFrame(start);    // source data
+               rsmp_data.input_frames  = end - start;              // how many readable bytes
+               rsmp_data.data_out      = dest[offset];             // destination (processed data)
+               rsmp_data.output_frames = bufferSize - offset;      // how many bytes to process
                rsmp_data.end_of_input  = false;
 
                src_process(rsmp_state, &rsmp_data);
-               int gen = rsmp_data.output_frames_gen*2;            // frames generated by this call
 
-               position = start + rsmp_data.input_frames_used*2;   // position goes forward of frames_used (i.e. read from wave)
+               position = start + rsmp_data.input_frames_used;     // position goes forward of frames_used (i.e. read from wave)
 
                if (rewind) {
-                       if (gen == bufferSize-offset)
+                       int gen = rsmp_data.output_frames_gen;            // frames generated by this call
+                       if (gen == bufferSize - offset)
                                frameRewind = -1;
                        else
-                               frameRewind = gen+offset;
+                               frameRewind = gen + offset;
                }
        }
        return position;
index b290640f841b2b4c7d065b90928e87374b4f6001..11af92e91db3c0072293b26260f90924fb01d00c 100644 (file)
@@ -47,56 +47,66 @@ private:
        rewind=false don't rewind internal tracker. Returns new sample position, 
        in frames. It resamples data if pitch != 1.0f. */
 
-       int fillChan(float* dest, int start, int offset, bool rewind=true);
-
-       /* clearChan
-        * set data to zero from start to bufferSize-1. */
-
-       void clearChan(float* dest, int start);
+       int fillChan(giada::m::AudioBuffer& dest, int start, int offset, bool rewind=true);
 
        /* calcFadeoutStep
-        * how many frames are left before the end of the sample? Is there
-        * enough room for a complete fadeout? Should we shorten it? */
+       How many frames are left before the end of the sample? Is there enough room 
+       for a complete fadeout? Should we shorten it? */
 
        void calcFadeoutStep();
 
        /* calcVolumeEnv
-        * compute any changes in volume done via envelope tool */
+       Computes any changes in volume done via envelope tool. */
 
        void calcVolumeEnv(int frame);
 
+       /* reset
+       Rewinds tracker to the beginning of the sample. */
+
+       void reset(int frame);
+
+       /* fade methods
+       Prepare channel for fade, mixer will take care of the process during master 
+       play. */
+
+       void setFadeIn(bool internal);
+       void setFadeOut(int actionPostFadeout);
+       void setXFade(int frame);
+
        /* rsmp_state, rsmp_data
-        * structs from libsamplerate */
+       Structs from libsamplerate. */
 
        SRC_STATE* rsmp_state;
        SRC_DATA   rsmp_data;
 
-       /* pChan
-       Extra virtual channel for processing resampled data. */
+       /* pChan, vChanPreview
+       Extra virtual channel for processing resampled data and for audio preview. */
 
-       float* pChan;
-
-       /* pChan
-       Extra virtual channel for audio preview. */
-
-       float* vChanPreview;
+       giada::m::AudioBuffer pChan;
+       giada::m::AudioBuffer vChanPreview;
 
        /* frameRewind
        Exact frame in which a rewind occurs. */
 
        int frameRewind;
 
-       int   begin;
-       int   end;
-       float boost;
-       float pitch;
-       int   trackerPreview;  // chan position for audio preview
-       int   shift;
+       /* begin, end
+       Begin/end point to read wave data from/to. */
 
-       /* onPreviewEnd
-       A callback fired when audio preview ends. */
+       int begin;
+       int end;
+       
+       float pitch;
+       float boost;
 
-       std::function<void()> onPreviewEnd;
+       bool  fadeinOn;
+       float fadeinVol;
+       bool  fadeoutOn;
+       float fadeoutVol;      // fadeout volume
+       int   fadeoutTracker;  // tracker fadeout, xfade only
+       float fadeoutStep;     // fadeout decrease
+  int   fadeoutType;     // xfade or fadeout
+  int          fadeoutEnd;      // what to do when fadeout ends
 
 public:
 
@@ -105,8 +115,8 @@ public:
 
        void copy(const Channel* src, pthread_mutex_t* pluginMutex) override;
        void clear() override;
-       void process(float* outBuffer, float* inBuffer) override;
-       void preview(float* outBuffer) override;
+       void process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in) override;
+       void preview(giada::m::AudioBuffer& out) override;
        void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning,
                bool forceStart, bool isUserGenerated) override;
        void kill(int frame) override;
@@ -116,10 +126,9 @@ public:
        void rewind() override;
        void setMute(bool internal) override;
        void unsetMute(bool internal) override;
-  int readPatch(const std::string& basePath, int i, pthread_mutex_t* pluginMutex,
-    int samplerate, int rsmpQuality) override;
-       int writePatch(int i, bool isProject) override;
-       void quantize(int index, int localFrame) override;
+  void readPatch(const std::string& basePath, int i) override;
+       void writePatch(int i, bool isProject) override;
+       void quantize(int index, int localFrame, int globalFrame) override;
        void onZero(int frame, bool recsStopOnChanHalt) override;
        void onBar(int frame) override;
        void parseAction(giada::m::recorder::action* a, int localFrame, int globalFrame,
@@ -127,21 +136,10 @@ public:
        bool canInputRec() override;
        bool allocBuffers() override;
 
-       int getTrackerPreview() const;
-       int getShift() const;
        float getBoost() const; 
-
-       void setShift(int s);
-
-       void reset(int frame);
-
-       /* fade methods
-        * prepare channel for fade, mixer will take care of the process
-        * during master play. */
-
-       void setFadeIn(bool internal);
-       void setFadeOut(int actionPostFadeout);
-       void setXFade(int frame);
+       int   getBegin() const;
+       int   getEnd() const;
+       float getPitch() const;
 
        /* pushWave
        Adds a new wave to an existing channel. */
@@ -149,28 +147,23 @@ public:
        void pushWave(Wave* w);
 
        /* getPosition
-        * returns the position of an active sample. If EMPTY o MISSING
-        * returns -1. */
+       Returns the position of an active sample. If EMPTY o MISSING returns -1. */
 
        int getPosition();
 
        /* sum
-        * add sample frames to virtual channel. Frame = processed frame in
-        * Mixer. Running = is Mixer in play? */
+       Adds sample frames to virtual channel. Frame = processed frame in Mixer. 
+       Running == is Mixer in play? */
 
        void sum(int frame, bool running);
 
-
        void setPitch(float v);
-       float getPitch();
        void setBegin(int f);
-       int getBegin();
        void setEnd(int f);
-       int getEnd();
-       void setTrackerPreview(int f);
+       void setBoost(float v);
 
        /* hardStop
-        * stop the channel immediately, no further checks. */
+       Stops the channel immediately, no further checks. */
 
        void hardStop(int frame);
 
@@ -180,22 +173,17 @@ public:
 
        void setReadActions(bool v, bool killOnFalse);
 
-       void setBoost(float v);
+       /* onPreviewEnd
+       A callback fired when audio preview ends. */
 
-       void setOnEndPreviewCb(std::function<void()> f);
+       std::function<void()> onPreviewEnd;
 
        Wave* wave;
        int   tracker;         // chan position
+       int   trackerPreview;  // chan position for audio preview
+       int   shift;
        int   mode;            // mode: see const.h
        bool  qWait;           // quantizer wait
-       bool  fadeinOn;
-       float fadeinVol;
-       bool  fadeoutOn;
-       float fadeoutVol;      // fadeout volume
-       int   fadeoutTracker;  // tracker fadeout, xfade only
-       float fadeoutStep;     // fadeout decrease
-  int   fadeoutType;     // xfade or fadeout
-  int          fadeoutEnd;      // what to do when fadeout ends
   bool  inputMonitor;
 
        /* midi stuff */
index 849932406c1dad73c0ec7b0e681b49d7228fa479..5c9519559bc6ab7c3052e9e34a67ef3ea8a5f340 100644 (file)
@@ -40,35 +40,20 @@ using std::string;
 
 
 Wave::Wave()
-: m_data   (nullptr),
-       m_size   (0),
-       m_logical(0),
-       m_edited (0) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-Wave::Wave(float* data, int size, int channels, int rate, int bits, 
-       const std::string& path)
-: m_data    (data),
-  m_size    (size),
-  m_channels(channels),
-  m_rate    (rate),
-  m_bits    (bits),
-  m_logical (false),
-  m_edited  (false),
-  m_path    (path)
+: m_rate   (0),
+  m_bits   (0),
+  m_logical(false),
+  m_edited (false) 
 {
-}      
+}
 
 
 /* -------------------------------------------------------------------------- */
 
 
-Wave::~Wave()
+float* Wave::operator [](int offset) const
 {
-       clear();
+       return buffer[offset];
 }
 
 
@@ -76,40 +61,28 @@ Wave::~Wave()
 
 
 Wave::Wave(const Wave& other)
-: m_data    (nullptr),
-       m_size    (other.m_size),
-       m_channels(other.m_channels),
-  m_rate    (other.m_rate),
-  m_bits    (other.m_bits),    
+:      m_rate    (other.m_rate),
+       m_bits    (other.m_bits),       
        m_logical (true),   // a cloned wave does not exist on disk
        m_edited  (false),
        m_path    (other.m_path)
 {
-       m_data = new float[m_size];
-       memcpy(m_data, other.m_data, m_size * sizeof(float));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Wave::clear()
-{
-       free();
-       m_path = "";
-       m_size = 0;
+       buffer.alloc(other.getSize(), other.getChannels());
+       buffer.copyData(other.getFrame(0), other.getSize(), other.getChannels());
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void Wave::free()
+bool Wave::alloc(int size, int channels, int rate, int bits, const std::string& path)
 {
-       if (m_data == nullptr) 
-               return;
-       delete[] m_data;
-       m_data = nullptr;
+       if (!buffer.alloc(size, channels))
+               return false;
+       m_rate = rate;
+       m_bits = bits;
+       m_path = path;
+       return true;
 }
 
 
@@ -126,10 +99,9 @@ string Wave::getBasename(bool ext) const
 
 
 int Wave::getRate() const { return m_rate; }
-int Wave::getChannels() const { return m_channels; }
+int Wave::getChannels() const { return buffer.countChannels(); }
 std::string Wave::getPath() const { return m_path; }
-float* Wave::getData() const { return m_data; }
-int Wave::getSize() const { return m_size / m_channels; }
+int Wave::getSize() const { return buffer.countFrames(); }
 int Wave::getBits() const { return m_bits; }
 bool Wave::isLogical() const { return m_logical; }
 bool Wave::isEdited() const { return m_edited; }
@@ -140,7 +112,7 @@ bool Wave::isEdited() const { return m_edited; }
 
 int Wave::getDuration() const
 {
-       return m_size / m_channels / m_rate;
+       return buffer.countFrames() / m_rate;
 }
 
 
@@ -158,21 +130,16 @@ std::string Wave::getExtension() const
 
 float* Wave::getFrame(int f) const
 {
-       assert(f >= 0);
-       assert(f < getSize());  
-
-       f *= m_channels;    // convert frame to sample
-       return m_data + f;  // i.e. a pointer to m_data[f]
+       return buffer[f];
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void Wave::setRate(int v) { m_rate = v; }
-void Wave::setChannels(int v) { m_channels = v; }
+void Wave::setRate(int v)     { m_rate = v; }
 void Wave::setLogical(bool l) { m_logical = l; }
-void Wave::setEdited(bool e) { m_edited = e; }
+void Wave::setEdited(bool e)  { m_edited = e; }
 
 
 /* -------------------------------------------------------------------------- */
@@ -184,16 +151,22 @@ void Wave::setPath(const string& p, int id)
                m_path = p; 
        else 
                m_path = gu_stripExt(p) + "-" + gu_iToString(id) + "." + gu_getExt(p);
+}
+
 
+/* -------------------------------------------------------------------------- */
 
+
+void Wave::copyData(float* data, int frames, int offset)
+{
+       buffer.copyData(data, frames, offset);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void Wave::setData(float* d, int size) 
-{ 
-       m_data = d; 
-       m_size = size;
-}
+void Wave::moveData(giada::m::AudioBuffer& b)
+{
+       buffer.moveData(b);
+}
\ No newline at end of file
index 7491a14cbfa24bd4782f071058349f9f4ee19b66..ecdcc4ab8236f057c4e3a2f7429108573c3670a2 100644 (file)
 #include <sndfile.h>
 #include <string>
 #include "const.h"
+#include "audioBuffer.h"
 
 
 class Wave
 {
-private:
-
-       float* m_data;
-       int m_size;                 // Wave size in bytes (size in frames: m_size / m_channels)
-       int m_channels;
-       int m_rate;
-       int m_bits;
-       bool m_logical;   // memory only (a take)
-       bool m_edited;    // edited via editor
-       
-       std::string m_path; // E.g. /path/to/my/sample.wav
-
 public:
 
        Wave();
-       Wave(float* data, int size, int channels, int rate, int bits, const std::string& path);
-       ~Wave();
        Wave(const Wave& other);
 
-       /* setPath
-       Sets new path 'p'. If 'id' != -1 inserts a numeric id next to the file 
-       extension, e.g. : /path/to/sample-[id].wav */
-        
-       void setPath(const std::string& p, int id=-1);
+       float* operator [](int offset) const;
 
+       /* getFrame
+       Works like operator []. See AudioBuffer for reference. */
+       
+       float* getFrame(int f) const;
+       
        std::string getBasename(bool ext=false) const;
        std::string getExtension() const;
        int getRate() const;
        int getChannels() const;
        std::string getPath() const;    
        int getBits() const;
-       float* getData() const;
        int getSize() const;        // in frames
        int getDuration() const;
        bool isLogical() const;
        bool isEdited() const;
 
+       /* setPath
+       Sets new path 'p'. If 'id' != -1 inserts a numeric id next to the file 
+       extension, e.g. : /path/to/sample-[id].wav */
+
+       void setPath(const std::string& p, int id=-1);
+
        void setRate(int v);
-       void setChannels(int v);
-       void setData(float* data, int size);
        void setLogical(bool l);
        void setEdited(bool e);
-       
-       /* clear
-       Resets Wave to init state. */
-
-       void clear();
 
-       /* free
-       Frees memory, leaving everything else untouched. */
+       /* moveData
+       Moves data held by 'b' into this buffer. Then 'b' becomes an empty buffer. */
 
-       void free();
+       void moveData(giada::m::AudioBuffer& b); 
+       
+       /* copyData
+       Copies 'frames' frames from the new 'data' into m_data, starting from frame 
+       'offset'. It takes for granted that the new data contains the same number of 
+       channels than m_channels. */
 
-       /* getFrame
-       Given a frame 'f', returns a pointer to it. This is useful for digging inside
-       a frame, i.e. parsing each channel. How to use it:
+       void copyData(float* data, int frames, int offset=0);
 
-               float* frame = w->getFrame(40);
-               for (int i=0; i<w->getChannels(); i++)
-                       ... frame[i] ...
-       */
+       bool alloc(int size, int channels, int rate, int bits, const std::string& path);
 
-       float* getFrame(int f) const;
+private:
 
+       giada::m::AudioBuffer buffer;
+       int m_rate;
+       int m_bits;
+       bool m_logical;     // memory only (a take)
+       bool m_edited;      // edited via editor
+       std::string m_path; // E.g. /path/to/my/sample.wav
 };
 
 #endif
index e50fe70d23c32216a1a7feda682030d5675bdf57..91549393c19f0a174644b2fb489e3d4a6048ad88 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <cmath>
+#include <cassert>
 #include <algorithm>
 #include "../utils/log.h"
 #include "wave.h"
@@ -38,25 +39,23 @@ namespace wfx
 {
 namespace
 {
-void fadeFrame(Wave* w, int i, float val)
+void fadeFrame(Wave& w, int i, float val)
 {
-       float* frame = w->getFrame(i);
-       for (int j=0; j<w->getChannels(); j++)
-               frame[j] *= val;
+       for (int j=0; j<w.getChannels(); j++)
+               w[i][j] *= val;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-float getPeak(Wave* w, int a, int b)
+float getPeak(const Wave& w, int a, int b)
 {
        float peak = 0.0f;
        float abs  = 0.0f;
        for (int i=a; i<b; i++) {
-               float* frame = w->getFrame(i);
-               for (int j=0; j<w->getChannels(); j++) // Find highest value in any channel
-                       abs = fabs(frame[j]);
+               for (int j=0; j<w.getChannels(); j++) // Find highest value in any channel
+                       abs = fabs(w[i][j]);
                if (abs > peak)
                        peak = abs;
        }
@@ -70,9 +69,9 @@ float getPeak(Wave* w, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-float normalizeSoft(Wave* w)
+float normalizeSoft(const Wave& w)
 {
-       float peak = getPeak(w, 0, w->getSize());
+       float peak = getPeak(w, 0, w.getSize());
 
        /* peak == 0.0f: don't normalize the silence
         * peak > 1.0f: don't reduce the amplitude, just leave it alone */
@@ -87,46 +86,39 @@ float normalizeSoft(Wave* w)
 /* -------------------------------------------------------------------------- */
 
 
-void normalizeHard(Wave* w, int a, int b)
+void normalizeHard(Wave& w, int a, int b)
 {
        float peak = getPeak(w, a, b);
        if (peak == 0.0f || peak > 1.0f)  // as in ::normalizeSoft
                return;
 
        for (int i=a; i<b; i++) {
-               float* frame = w->getFrame(i);
-               for (int j=0; j<w->getChannels(); j++)
-                       frame[j] = frame[j] * (1.0f / peak);
+               for (int j=0; j<w.getChannels(); j++)
+                       w[i][j] = w[i][j] * (1.0f / peak);
        }
-       w->setEdited(true);
+       w.setEdited(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int monoToStereo(Wave* w)
+int monoToStereo(Wave& w)
 {
-       if (w->getChannels() >= G_DEFAULT_AUDIO_CHANS)
+       if (w.getChannels() >= G_MAX_IO_CHANS)
                return G_RES_OK;
 
-       unsigned newSize = w->getSize() * G_DEFAULT_AUDIO_CHANS;
-       
-       float* newData = new (std::nothrow) float[newSize];
-       if (newData == nullptr) {
+       AudioBuffer newData;
+       if (!newData.alloc(w.getSize(), G_MAX_IO_CHANS)) {
                gu_log("[wfx::monoToStereo] unable to allocate memory!\n");
                return G_RES_ERR_MEMORY;
        }
 
-       for (int i=0, k=0; i<w->getSize(); i++, k+=G_DEFAULT_AUDIO_CHANS) {
-               float* frame = w->getFrame(i);
-               for (int j=0; j<G_DEFAULT_AUDIO_CHANS; j++)
-                       newData[k+j] = frame[j];
-       }
+       for (int i=0; i<newData.countFrames(); i++)
+               for (int j=0; j<newData.countChannels(); j++)
+                       newData[i][j] = w[i][0];
 
-       w->free();
-       w->setData(newData, newSize);
-       w->setChannels(G_DEFAULT_AUDIO_CHANS);
+       w.moveData(newData);
 
        return G_RES_OK;
 }
@@ -135,52 +127,50 @@ int monoToStereo(Wave* w)
 /* -------------------------------------------------------------------------- */
 
 
-void silence(Wave* w, int a, int b)
+void silence(Wave& w, int a, int b)
 {
        gu_log("[wfx::silence] silencing from %d to %d\n", a, b);
 
        for (int i=a; i<b; i++) {
-               float* frame = w->getFrame(i);
-               for (int j=0; j<w->getChannels(); j++)  
-                       frame[j] = 0.0f;
+               for (int j=0; j<w.getChannels(); j++)   
+                       w[i][j] = 0.0f;
        }
 
-       w->setEdited(true);
+       w.setEdited(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int cut(Wave* w, int a, int b)
+int cut(Wave& w, int a, int b)
 {
        if (a < 0) a = 0;
-       if (b > w->getSize()) b = w->getSize();
+       if (b > w.getSize()) b = w.getSize();
 
        /* Create a new temp wave and copy there the original one, skipping the a-b 
        range. */
 
-       unsigned newSize = (w->getSize() - (b - a)) * w->getChannels();
-       float* newData = new (std::nothrow) float[newSize];
-       if (newData == nullptr) {
+       int newSize = w.getSize() - (b - a);
+
+       AudioBuffer newData;
+       if (!newData.alloc(newSize, w.getChannels())) {
                gu_log("[wfx::cut] unable to allocate memory!\n");
                return G_RES_ERR_MEMORY;
        }
 
        gu_log("[wfx::cut] cutting from %d to %d\n", a, b);
 
-       for (int i=0, k=0; i<w->getSize(); i++) {
+       for (int i=0, k=0; i<w.getSize(); i++) {
                if (i < a || i >= b) {
-                       float* frame = w->getFrame(i);
-                       for (int j=0; j<w->getChannels(); j++)  
-                               newData[k+j] = frame[j];
-                       k += w->getChannels();
+                       for (int j=0; j<w.getChannels(); j++)   
+                               newData[k][j] = w[i][j];
+                       k++;
                }
        }
 
-       w->free();
-       w->setData(newData, newSize);
-       w->setEdited(true);
+       w.moveData(newData);
+       w.setEdited(true);
 
        return G_RES_OK;
 }
@@ -189,29 +179,27 @@ int cut(Wave* w, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-int trim(Wave* w, int a, int b)
+int trim(Wave& w, int a, int b)
 {
        if (a < 0) a = 0;
-       if (b > w->getSize()) b = w->getSize();
+       if (b > w.getSize()) b = w.getSize();
 
-       int newSize = (b - a) * w->getChannels();
-       float* newData = new (std::nothrow) float[newSize];
-       if (newData == nullptr) {
+       int newSize = b - a;
+
+       AudioBuffer newData;
+       if (!newData.alloc(newSize, w.getChannels())) {
                gu_log("[wfx::trim] unable to allocate memory!\n");
                return G_RES_ERR_MEMORY;
        }
 
        gu_log("[wfx::trim] trimming from %d to %d (area = %d)\n", a, b, b-a);
 
-       for (int i=a, k=0; i<b; i++, k+=w->getChannels()) {
-               float* frame = w->getFrame(i);
-               for (int j=0; j<w->getChannels(); j++)
-                       newData[k+j] = frame[j];
-       }
+       for (int i=0; i<newData.countFrames(); i++)
+               for (int j=0; j<newData.countChannels(); j++)
+                       newData[i][j] = w[i+a][j];
 
-       w->free();
-       w->setData(newData, newSize);
-       w->setEdited(true);
+       w.moveData(newData);
+       w.setEdited(true);
 
        return G_RES_OK;
 }
@@ -220,39 +208,25 @@ int trim(Wave* w, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-int paste(Wave* src, Wave* des, int aFrame)
+int paste(const Wave& src, Wave& des, int a)
 {
-       int srcNumSamples = src->getSize() * src->getChannels();
-       int desNumSamples = des->getSize() * des->getChannels();
-       int aSample = aFrame * des->getChannels();
+       assert(src.getChannels() == des.getChannels());
 
-       int newSize = srcNumSamples + desNumSamples;
-       float* newData = new (std::nothrow) float[newSize];
-       if (newData == nullptr) {
+       AudioBuffer newData;
+       if (!newData.alloc(src.getSize() + des.getSize(), des.getChannels())) {
                gu_log("[wfx::paste] unable to allocate memory!\n");
                return G_RES_ERR_MEMORY;
        }
 
        /* |---original data---|///paste data///|---original data---|
-                 chunk 1            chunk 2          chunk 3
-       */
-
-       float* chunk1a = des->getData();
-       float* chunk1b = des->getData() + aSample;
-
-       float* chunk2a = src->getData();
-       float* chunk2b = src->getData() + srcNumSamples;        
-
-       float* chunk3a = chunk1b;
-       float* chunk3b = des->getData() + desNumSamples;
+                des[0, a)      src[0, src.size)   des[a, des.size)     */
 
-       std::copy(chunk1a, chunk1b, newData);
-       std::copy(chunk2a, chunk2b, newData + aSample); 
-       std::copy(chunk3a, chunk3b, newData + aSample + srcNumSamples);
+       newData.copyData(des[0], a, 0);
+       newData.copyData(src[0], src.getSize(), a);
+       newData.copyData(des[a], des.getSize() - a, src.getSize() + a);
 
-       des->free();
-       des->setData(newData, newSize);
-       des->setEdited(true);
+       des.moveData(newData);
+       des.setEdited(true);
 
        return G_RES_OK;
 }
@@ -261,7 +235,7 @@ int paste(Wave* src, Wave* des, int aFrame)
 /* -------------------------------------------------------------------------- */
 
 
-void fade(Wave* w, int a, int b, int type)
+void fade(Wave& w, int a, int b, int type)
 {
        gu_log("[wfx::fade] fade from %d to %d (range = %d)\n", a, b, b-a);
 
@@ -275,14 +249,14 @@ void fade(Wave* w, int a, int b, int type)
                for (int i=b; i>=a; i--, m+=d)
                        fadeFrame(w, i, m);             
 
-  w->setEdited(true);
+  w.setEdited(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void smooth(Wave* w, int a, int b)
+void smooth(Wave& w, int a, int b)
 {
        /* Do nothing if fade edges (both of SMOOTH_SIZE samples) are > than selected 
        portion of wave. SMOOTH_SIZE*2 to count both edges. */
@@ -295,39 +269,39 @@ void smooth(Wave* w, int a, int b)
        fade(w, a, a+SMOOTH_SIZE, FADE_IN);
        fade(w, b-SMOOTH_SIZE, b, FADE_OUT);
 
-       w->setEdited(true);
+       w.setEdited(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void shift(Wave* w, int offset)
+void shift(Wave& w, int offset)
 {
        if (offset < 0)
-               offset = (w->getSize() + w->getChannels()) + offset;
+               offset = (w.getSize() + w.getChannels()) + offset;
 
-       float* begin = w->getData();
-       float* end   = w->getData() + (w->getSize() * w->getChannels());
+       float* begin = w.getFrame(0);
+       float* end   = w.getFrame(0) + (w.getSize() * w.getChannels());
 
-       std::rotate(begin, end - (offset * w->getChannels()), end);
-       w->setEdited(true);
+       std::rotate(begin, end - (offset * w.getChannels()), end);
+       w.setEdited(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void reverse(Wave* w, int a, int b)
+void reverse(Wave& w, int a, int b)
 {
        /* https://stackoverflow.com/questions/33201528/reversing-an-array-of-structures-in-c */
 
-       float* begin = w->getData() + (a * w->getChannels());
-       float* end   = w->getData() + (b * w->getChannels());
+       float* begin = w.getFrame(0) + (a * w.getChannels());
+       float* end   = w.getFrame(0) + (b * w.getChannels());
 
        std::reverse(begin, end);
 
-       w->setEdited(true);
+       w.setEdited(true);
 }
 
 }}}; // giada::m::wfx::
\ No newline at end of file
index b0ac02ca664200d9014587f2a51f004ee3400f3e..51146ba1c1d496bf60ebef0b11d21ffdf698d8e1 100644 (file)
@@ -43,35 +43,39 @@ static const int SMOOTH_SIZE = 32;
 /* normalizeSoft
 Normalizes the wave by returning the dB value for the boost volume. */
 
-float normalizeSoft(Wave* w);
+float normalizeSoft(const Wave& w);
 
 /* normalizeHard
 Normalizes the wave in range a-b by altering values in memory. */
 
-void normalizeHard(Wave* w, int a, int b);
+void normalizeHard(Wave& w, int a, int b);
 
-int monoToStereo(Wave* w);
-void silence(Wave* w, int a, int b);
-int cut(Wave* w, int a, int b);
-int trim(Wave* w, int a, int b);
-int paste(Wave* src, Wave* dest, int a);
+int monoToStereo(Wave& w);
+void silence(Wave& w, int a, int b);
+int cut(Wave& w, int a, int b);
+int trim(Wave& w, int a, int b);
+
+/* paste
+Pastes Wave 'src' into Wave 'dest', starting from frame 'a'. */
+
+int paste(const Wave& src, Wave& dest, int a);
 
 /* fade
 Fades in or fades out selection. Fade In = type 0, Fade Out = type 1 */
 
-void fade(Wave* w, int a, int b, int type);
+void fade(Wave& w, int a, int b, int type);
 
 /* smooth
 Smooth edges of selection. */
 
-void smooth(Wave* w, int a, int b);
+void smooth(Wave& w, int a, int b);
 
 /* reverse
 Flips Wave's data. */
 
-void reverse(Wave* w, int a, int b);
+void reverse(Wave& w, int a, int b);
 
-void shift(Wave* w, int offset);
+void shift(Wave& w, int offset);
 
 }}}; // giada::m::wfx::
 
index 2b3b3941e6e697ba66555e8aa1ea1d3912772021..b7905e65c8bf9c8ba1593a3067b003d9ec961fa3 100644 (file)
@@ -89,33 +89,24 @@ int create(const string& path, Wave** out)
                return G_RES_ERR_IO;
        }
 
-       if (header.channels > 2) {
+       if (header.channels > G_MAX_IO_CHANS) {
                gu_log("[waveManager::create] unsupported multi-channel sample\n");
                return G_RES_ERR_WRONG_DATA;
        }
 
-       /* Libsndfile's frame structure:
-
-       frame1 = [leftChannel, rightChannel]
-       frame2 = [leftChannel, rightChannel]
-       ... */
-
-       int size = header.frames * header.channels;
-       float* data = new (std::nothrow) float[size];
-       if (data == nullptr) {
+       Wave* wave = new Wave();
+       if (!wave->alloc(header.frames, header.channels, header.samplerate, getBits(header), path)) {
                gu_log("[waveManager::create] unable to allocate memory\n");
+               delete wave;
                return G_RES_ERR_MEMORY;
        }
 
-       if (sf_read_float(fileIn, data, size) != size)
+       if (sf_readf_float(fileIn, wave->getFrame(0), header.frames) != header.frames)
                gu_log("[waveManager::create] warning: incomplete read!\n");
 
        sf_close(fileIn);
 
-       Wave* wave = new Wave(data, size, header.channels, header.samplerate,
-               getBits(header), path);
-
-       if (header.channels == 1 && !wfx::monoToStereo(wave)) {
+       if (header.channels == 1 && !wfx::monoToStereo(*wave)) {
                delete wave;
                return G_RES_ERR_PROCESSING;
        }
@@ -131,21 +122,22 @@ int create(const string& path, Wave** out)
 /* -------------------------------------------------------------------------- */
 
 
-int createEmpty(int size, int samplerate, const string& name, Wave** out)
+int createEmpty(int frames, int channels, int samplerate, const string& name, 
+       Wave** out)
 {
-       float* data = new (std::nothrow) float[size];
-       if (data == nullptr) {
+       Wave* wave = new Wave();
+       if (!wave->alloc(frames, channels, samplerate, G_DEFAULT_BIT_DEPTH, name)) {
                gu_log("[waveManager::createEmpty] unable to allocate memory\n");
+               delete wave;
                return G_RES_ERR_MEMORY;
        }
 
-       Wave* wave = new Wave(data, size, G_DEFAULT_AUDIO_CHANS, samplerate, 
-               G_DEFAULT_BIT_DEPTH, "");
        wave->setLogical(true);
 
        *out = wave;
 
-       gu_log("[waveManager::createEmpty] new empty Wave created, %d frames\n", size);
+       gu_log("[waveManager::createEmpty] new empty Wave created, %d frames\n", 
+               wave->getSize());
 
        return G_RES_OK;
 }
@@ -156,23 +148,22 @@ int createEmpty(int size, int samplerate, const string& name, Wave** out)
 
 int createFromWave(const Wave* src, int a, int b, Wave** out)
 {
-       int numChans = src->getChannels();
-       int size = (b - a) * numChans;
-       float* data = new (std::nothrow) float[size];
-       if (data == nullptr) {
+       int channels = src->getChannels();
+       int frames   = b - a;
+
+       Wave* wave = new Wave();
+       if (!wave->alloc(frames, channels, src->getRate(), src->getBits(), src->getPath())) {
                gu_log("[waveManager::createFromWave] unable to allocate memory\n");
+               delete wave;
                return G_RES_ERR_MEMORY;
        }
 
-       std::copy(src->getData() + (a*numChans), src->getData() + (b*numChans), data);
-
-       Wave* wave = new Wave(data, size, numChans, src->getRate(),
-               src->getBits(), src->getPath());
+       wave->copyData(src->getFrame(a), frames);
        wave->setLogical(true);
 
        *out = wave;
 
-       gu_log("[waveManager::createFromWave] new Wave created, %d frames\n", size);
+       gu_log("[waveManager::createFromWave] new Wave created, %d frames\n", frames);
 
        return G_RES_OK;
 }
@@ -184,34 +175,30 @@ int createFromWave(const Wave* src, int a, int b, Wave** out)
 int resample(Wave* w, int quality, int samplerate)
 {
        float ratio = samplerate / (float) w->getRate();
-       int newSizeFrames  = ceil(w->getSize() * ratio);
-       int newSizeSamples = newSizeFrames * w->getChannels();
+       int newSizeFrames = ceil(w->getSize() * ratio);
 
-       float* newData = new (std::nothrow) float[newSizeSamples];
-       if (newData == nullptr) {
+       AudioBuffer newData;
+       if (!newData.alloc(newSizeFrames, w->getChannels())) {
                gu_log("[waveManager::resample] unable to allocate memory\n");
                return G_RES_ERR_MEMORY;
        }
 
        SRC_DATA src_data;
-       src_data.data_in       = w->getData();
+       src_data.data_in       = w->getFrame(0);
        src_data.input_frames  = w->getSize();
-       src_data.data_out      = newData;
+       src_data.data_out      = newData[0];
        src_data.output_frames = newSizeFrames;
        src_data.src_ratio     = ratio;
 
-       gu_log("[waveManager::resample] resampling: new size=%d (%d frames)\n",
-               newSizeSamples, newSizeFrames);
+       gu_log("[waveManager::resample] resampling: new size=%d frames\n", newSizeFrames);
 
        int ret = src_simple(&src_data, quality, w->getChannels());
        if (ret != 0) {
                gu_log("[waveManager::resample] resampling error: %s\n", src_strerror(ret));
-               delete[] newData;
                return G_RES_ERR_PROCESSING;
        }
 
-       w->free();
-       w->setData(newData, newSizeSamples);
+       w->moveData(newData);
        w->setRate(samplerate);
 
        return G_RES_OK;
@@ -235,7 +222,7 @@ int save(Wave* w, const string& path)
                return G_RES_ERR_IO;
        }
 
-       if (sf_writef_float(file, w->getData(), w->getSize()) != w->getSize())
+       if (sf_writef_float(file, w->getFrame(0), w->getSize()) != w->getSize())
                gu_log("[waveManager::save] warning: incomplete write!\n");
 
        sf_close(file);
index 50da3726d5fa7528ef1c09ffd0838741b7b7dffb..b350695bdea81a3f451bbc5e3c265d4b35b0a480 100644 (file)
@@ -45,10 +45,10 @@ Creates a new Wave object with data read from file 'path'. */
 int create(const std::string& path, Wave** out);
 
 /* createEmpty
-Creates a new silent Wave object. Note: 'size' must take 2 channels into account
-(stereo). */
+Creates a new silent Wave object. */
 
-int createEmpty(int size, int samplerate, const std::string& name, Wave** out);
+int createEmpty(int frames, int channels, int samplerate, const std::string& name, 
+       Wave** out);
 
 /* createFromWave
 Creates a new Wave from an existing one, copying the data in range a - b. */
index 9fbba3e78f53e52a783793f891af651779c19277..4dd0171299f9f078a88419f8643c8f099d4425b5 100644 (file)
@@ -72,17 +72,6 @@ namespace giada {
 namespace c     {
 namespace channel 
 {
-namespace
-{
-bool soloSession__ = false;
-} // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
 int loadChannel(SampleChannel* ch, const string& fname)
 {
        using namespace giada::m;
@@ -187,9 +176,9 @@ void freeChannel(Channel* ch)
 
 void toggleArm(Channel* ch, bool gui)
 {
-       ch->setArmed(!ch->isArmed());
+       ch->armed = !ch->armed;
        if (!gui)
-               ch->guiChannel->arm->value(ch->isArmed());
+               ch->guiChannel->arm->value(ch->armed);
 }
 
 
@@ -227,7 +216,7 @@ int cloneChannel(Channel* src)
 
 void setVolume(Channel* ch, float v, bool gui, bool editor)
 {
-       ch->setVolume(v);
+       ch->volume = v;
 
        /* Changing channel volume? Update wave editor (if it's shown). */
 
@@ -292,7 +281,7 @@ void toggleMute(Channel* ch, bool gui)
                        ch->readActions = false;   // don't read actions while overdubbing
                }
                else
-                recorder::stopOverdub(clock::getCurrentFrame(), clock::getTotalFrames(),
+                recorder::stopOverdub(clock::getCurrentFrame(), clock::getFramesInLoop(),
                        &mixer::mutex_recs);
        }
 
@@ -310,63 +299,15 @@ void toggleMute(Channel* ch, bool gui)
 
 
 void toggleSolo(Channel* ch, bool gui)
-{
-       ch->solo ? setSoloOn(ch, gui) : setSoloOff(ch, gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void kill(Channel* ch)
-{
-       ch->kill(0); // on frame 0: it's a user-generated event
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void setSoloOn(Channel* ch, bool gui)
 {
        using namespace giada::m;
-
-       /* if there's no solo session, store mute configuration of all chans
-        * and start the session */
-
-       if (!soloSession__) {
-               for (unsigned i=0; i<mixer::channels.size(); i++) {
-                       Channel *och = mixer::channels.at(i);
-                       och->mute_s  = och->mute;
-               }
-               soloSession__ = true;
-       }
-
+       
        ch->solo = !ch->solo;
-       ch->sendMidiLsolo();
-
-       /* mute all other channels and unmute this (if muted) */
-
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               Channel *och = mixer::channels.at(i);
-               if (!och->solo && !och->mute) {
-                       och->setMute(false);
-                       Fl::lock();
-                       och->guiChannel->mute->value(true);
-                       Fl::unlock();
-               }
-       }
-
-       if (ch->mute) {
-               ch->unsetMute(false);
-               Fl::lock();
-               ch->guiChannel->mute->value(false);
-               Fl::unlock();
-       }
-
+       mh::updateSoloCount();  
+       
        if (!gui) {
                Fl::lock();
-               ch->guiChannel->solo->value(1);
+               ch->guiChannel->solo->value(ch->solo);
                Fl::unlock();
        }
 }
@@ -375,47 +316,9 @@ void setSoloOn(Channel* ch, bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void setSoloOff(Channel* ch, bool gui)
+void kill(Channel* ch)
 {
-       using namespace giada::m;
-
-       /* if this is uniqueSolo, stop solo session and restore mute status,
-        * else mute this */
-
-       if (mh::uniqueSolo(ch)) {
-               soloSession__ = false;
-               for (unsigned i=0; i<mixer::channels.size(); i++) {
-                       Channel *och = mixer::channels.at(i);
-                       if (och->mute_s) {
-                               och->setMute(false);
-                               Fl::lock();
-                               och->guiChannel->mute->value(true);
-                               Fl::unlock();
-                       }
-                       else {
-                               och->unsetMute(false);
-                               Fl::lock();
-                               och->guiChannel->mute->value(false);
-                               Fl::unlock();
-                       }
-                       och->mute_s = false;
-               }
-       }
-       else {
-               ch->setMute(false);
-               Fl::lock();
-               ch->guiChannel->mute->value(true);
-               Fl::unlock();
-       }
-
-       ch->solo = !ch->solo;
-       ch->sendMidiLsolo();
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->solo->value(0);
-               Fl::unlock();
-       }
+       ch->kill(0); // on frame 0: it's a user-generated event
 }
 
 
@@ -439,7 +342,7 @@ void setBoost(SampleChannel* ch, float val)
 
 void setName(Channel* ch, const string& name)
 {
-       ch->setName(name);
+       ch->name = name;
        ch->guiChannel->update();
 }
 
index 22286223bc83058a5549f38cf06c1cb527d02e41..e5212bb72ef16628b93ddafb66a4c9b46a67f1a2 100644 (file)
@@ -73,8 +73,6 @@ void toggleArm(Channel* ch, bool gui=true);
 void toggleInputMonitor(Channel* ch);
 void kill(Channel* ch);
 void toggleMute(Channel* ch, bool gui=true);
-void setSoloOn(Channel* ch, bool gui=true);
-void setSoloOff(Channel* ch, bool gui=true);
 void toggleSolo(Channel* ch, bool gui=true);
 void setVolume(Channel* ch, float v, bool gui=true, bool editor=false);
 void setName(Channel* ch, const std::string& name);
index 7e85d8033075bcb9eb9df1d06d587d07e6100436..2da007dfa3757637076dead4439dd5bf75b33c4d 100644 (file)
@@ -156,7 +156,7 @@ void cleanPress(SampleChannel* ch, int velocity)
 
 void keyPress(Channel* ch, bool ctrl, bool shift, int velocity)
 {
-       if (ch->type == CHANNEL_SAMPLE)
+       if (ch->type == G_CHANNEL_SAMPLE)
                keyPress(static_cast<SampleChannel*>(ch), ctrl, shift, velocity);
        else
                keyPress(static_cast<MidiChannel*>(ch), ctrl, shift);
@@ -168,7 +168,7 @@ void keyPress(Channel* ch, bool ctrl, bool shift, int velocity)
 
 void keyRelease(Channel* ch, bool ctrl, bool shift)
 {
-       if (ch->type == CHANNEL_SAMPLE)
+       if (ch->type == G_CHANNEL_SAMPLE)
                keyRelease(static_cast<SampleChannel*>(ch), ctrl, shift);
 }
 
@@ -218,7 +218,7 @@ void keyRelease(SampleChannel* ch, bool ctrl, bool shift)
         * other mode the KEY REL is meaningless. */
 
        if (ch->mode == SINGLE_PRESS && recorder::canRec(ch, clock::isRunning(), mixer::recording))
-               recorder::stopOverdub(clock::getCurrentFrame(), clock::getTotalFrames(),
+               recorder::stopOverdub(clock::getCurrentFrame(), clock::getFramesInLoop(),
                        &mixer::mutex_recs);
 
        /* the GUI update is done by gui_refresh() */
@@ -270,7 +270,7 @@ void stopActionRec(bool gui)
 
        for (Channel* ch : m::mixer::channels)
        {
-               if (ch->type == CHANNEL_MIDI)
+               if (ch->type == G_CHANNEL_MIDI)
                        continue;
                SampleChannel* sch = static_cast<SampleChannel*>(ch);
                G_MainWin->keyboard->setChannelWithActions(static_cast<geSampleChannel*>(sch->guiChannel));
@@ -352,10 +352,10 @@ int stopInputRec(bool gui)
        beat. */
 
        for (Channel* ch : mixer::channels) {
-               if (ch->type == CHANNEL_MIDI)
+               if (ch->type == G_CHANNEL_MIDI)
                        continue;
                SampleChannel* sch = static_cast<SampleChannel*>(ch);
-               if (sch->mode & (LOOP_ANY) && sch->status == STATUS_OFF && sch->isArmed())
+               if (sch->mode & (LOOP_ANY) && sch->status == STATUS_OFF && sch->armed)
                        sch->start(clock::getCurrentFrame(), true, clock::getQuantize(),
                                clock::isRunning(), true, true);
        }
index 6de32a7baefe6a43d5e5db18068d95968a9802ec..4fc529d726543736df6ce8a5dbc64dc349bbf3fa 100644 (file)
@@ -77,7 +77,7 @@ void glue_setBpm(const char *v1, const char *v2)
        float oldBpmF = clock::getBpm();
        clock::setBpm(bpmF);
        recorder::updateBpm(oldBpmF, bpmF, clock::getQuanto());
-       mixer::allocVirtualInput(clock::getTotalFrames());
+       mixer::allocVirtualInput(clock::getFramesInLoop());
 
 #ifdef __linux__
        kernelAudio::jackSetBpm(clock::getBpm());
@@ -118,18 +118,18 @@ void glue_setBeats(int beats, int bars, bool expand)
        /* Temp vars to store old data (they are necessary) */
 
        int oldBeats = clock::getBeats();
-       unsigned oldTotalFrames = clock::getTotalFrames();
+       unsigned oldTotalFrames = clock::getFramesInLoop();
 
        clock::setBeats(beats);
        clock::setBars(bars);
        clock::updateFrameBars();
-       mixer::allocVirtualInput(clock::getTotalFrames());
+       mixer::allocVirtualInput(clock::getFramesInLoop());
 
        /* Update recorded actions, if 'expand' required and an expansion is taking
        place. */
 
        if (expand && clock::getBeats() > oldBeats)
-               recorder::expand(oldTotalFrames, clock::getTotalFrames());
+               recorder::expand(oldTotalFrames, clock::getFramesInLoop());
 
        G_MainWin->mainTimer->setMeter(clock::getBeats(), clock::getBars());
        gu_refreshActionEditor();  // in case the action editor is open
@@ -200,9 +200,9 @@ void glue_setInVol(float v, bool gui)
 void glue_clearAllSamples()
 {
        clock::stop();
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               mixer::channels.at(i)->empty();
-               mixer::channels.at(i)->guiChannel->reset();
+       for (Channel* ch : mixer::channels) {
+               ch->empty();
+               ch->guiChannel->reset();
        }
        recorder::init();
        return;
@@ -212,9 +212,11 @@ void glue_clearAllSamples()
 /* -------------------------------------------------------------------------- */
 
 
-void glue_clearAllRecs()
+void glue_clearAllActions()
 {
        recorder::init();
+       for (Channel* ch : mixer::channels)
+               ch->hasActions = false;
        gu_updateControls();
 }
 
@@ -227,7 +229,7 @@ void glue_resetToInitState(bool resetGui, bool createColumns)
        gu_closeAllSubwindows();
        mixer::close();
        clock::init(conf::samplerate, conf::midiTCfps);
-       mixer::init(clock::getTotalFrames(), kernelAudio::getRealBufSize());
+       mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
        recorder::init();
 #ifdef WITH_VST
        pluginHost::freeAllStacks(&mixer::channels, &mixer::mutex_plugins);
index 3644f9383550b0dbb62b61a75313a2eb0bdf4739..c684b2207b802252ed0e987f313f6b1481f30894 100644 (file)
 #define G_GLUE_MAIN_H
 
 
-void glue_setBpm(const char *v1, const char *v2);
+void glue_setBpm(const char* v1, const char* v2);
 void glue_setBpm(float v);
 void glue_setBeats(int beats, int bars, bool expand);
 void glue_quantize(int val);
 void glue_setOutVol(float v, bool gui=true);
 void glue_setInVol(float v, bool gui=true);
 void glue_clearAllSamples();
-void glue_clearAllRecs();
+void glue_clearAllActions();
 
 /* resetToInitState
  * reset Giada to init state. If resetGui also refresh all widgets. If
index 9e0a33323cfd882a4932af4b13f9b8f9e79da14d..53670c3b8684f65fb89c653578ed01f2f334c65f 100644 (file)
@@ -51,7 +51,7 @@ namespace
 void updateChannel(geChannel* gch)
 {
        gch->ch->hasActions = m::recorder::hasActions(gch->ch->index);
-       if (gch->ch->type == CHANNEL_SAMPLE && !gch->ch->hasActions)
+       if (gch->ch->type == G_CHANNEL_SAMPLE && !gch->ch->hasActions)
                static_cast<geSampleChannel*>(gch)->hideActionButton();
        /* TODO - set mute=false */
        gu_refreshActionEditor(); // refresh a.editor window, it could be open
@@ -117,7 +117,7 @@ void recordMidiAction(int chan, int note, int frame_a, int frame_b)
 
        /* Avoid frame overflow. */
 
-       int overflow = frame_b - m::clock::getTotalFrames();
+       int overflow = frame_b - (m::clock::getFramesInLoop());
        if (overflow > 0) {
                frame_b -= overflow;
                frame_a -= overflow;
index 811e002e6f086c8ef76f17da7a9217e19ad1e899..ab417db278d273be87bdef6b0b77abb42730a31f 100644 (file)
@@ -40,10 +40,10 @@ namespace giada {
 namespace c     {
 namespace recorder 
 {
-void clearAllActions(geChannel *gch);
-void clearMuteActions(geChannel *gch);
-void clearVolumeActions(geChannel *gch);
-void clearStartStopActions(geChannel *gch);
+void clearAllActions(geChannelgch);
+void clearMuteActions(geChannelgch);
+void clearVolumeActions(geChannelgch);
+void clearStartStopActions(geChannelgch);
 
 /* recordMidiAction
 Records a new MIDI action at frame_a. If frame_b == 0, uses the default action
index da35360699b66ed9ae73082567d21f9210216fdc..568e508a587fad78bfa95220ef42a52ae264401b 100644 (file)
@@ -102,7 +102,7 @@ void setBeginEnd(SampleChannel* ch, int b, int e)
 void cut(SampleChannel* ch, int a, int b)
 {
        copy(ch, a, b);
-       if (!m::wfx::cut(ch->wave, a, b)) {
+       if (!m::wfx::cut(*ch->wave, a, b)) {
                gdAlert("Unable to cut the sample!");
                return;
        }
@@ -140,7 +140,7 @@ void paste(SampleChannel* ch, int a)
                return;
        }
        
-       m::wfx::paste(m_waveBuffer, ch->wave, a);
+       m::wfx::paste(*m_waveBuffer, *ch->wave, a);
 
        /* Shift begin/end points to keep the previous position. */
 
@@ -162,7 +162,7 @@ void paste(SampleChannel* ch, int a)
 
 void silence(SampleChannel* ch, int a, int b)
 {
-       m::wfx::silence(ch->wave, a, b);
+       m::wfx::silence(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->refresh();
 }
@@ -173,7 +173,7 @@ void silence(SampleChannel* ch, int a, int b)
 
 void fade(SampleChannel* ch, int a, int b, int type)
 {
-       m::wfx::fade(ch->wave, a, b, type);
+       m::wfx::fade(*ch->wave, a, b, type);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->refresh();
 }
@@ -184,7 +184,7 @@ void fade(SampleChannel* ch, int a, int b, int type)
 
 void smoothEdges(SampleChannel* ch, int a, int b)
 {
-       m::wfx::smooth(ch->wave, a, b);
+       m::wfx::smooth(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->refresh();
 }
@@ -195,7 +195,7 @@ void smoothEdges(SampleChannel* ch, int a, int b)
 
 void reverse(SampleChannel* ch, int a, int b)
 {
-       m::wfx::reverse(ch->wave, a, b);
+       m::wfx::reverse(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->refresh();
 }
@@ -206,7 +206,7 @@ void reverse(SampleChannel* ch, int a, int b)
 
 void normalizeHard(SampleChannel* ch, int a, int b)
 {
-       m::wfx::normalizeHard(ch->wave, a, b);
+       m::wfx::normalizeHard(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->refresh();
 }
@@ -217,7 +217,7 @@ void normalizeHard(SampleChannel* ch, int a, int b)
 
 void trim(SampleChannel* ch, int a, int b)
 {
-       if (!m::wfx::trim(ch->wave, a, b)) {
+       if (!m::wfx::trim(*ch->wave, a, b)) {
                gdAlert("Unable to trim the sample!");
                return;
        }
@@ -234,7 +234,7 @@ void trim(SampleChannel* ch, int a, int b)
 
 void setPlayHead(SampleChannel* ch, int f)
 {
-       ch->setTrackerPreview(f);
+       ch->trackerPreview = f;
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->redraw();
 }
@@ -257,7 +257,7 @@ void setPreview(SampleChannel* ch, int mode)
 void rewindPreview(SampleChannel* ch)
 {
        geWaveform* waveform = getSampleEditorWindow()->waveTools->waveform;
-       if (waveform->isSelected() && ch->getTrackerPreview() != waveform->getSelectionA())
+       if (waveform->isSelected() && ch->trackerPreview != waveform->getSelectionA())
                setPlayHead(ch, waveform->getSelectionA());
        else
                setPlayHead(ch, 0);
@@ -270,7 +270,7 @@ void rewindPreview(SampleChannel* ch)
 void toNewChannel(SampleChannel* ch, int a, int b)
 {
        SampleChannel* newCh = static_cast<SampleChannel*>(c::channel::addChannel(
-               ch->guiChannel->getColumnIndex(), CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
+               ch->guiChannel->getColumnIndex(), G_CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
 
        Wave* wave = nullptr;
        int result = m::waveManager::createFromWave(ch->wave, a, b, &wave);
@@ -298,8 +298,8 @@ bool isWaveBufferFull()
 
 void shift(SampleChannel* ch, int offset)
 {
-       m::wfx::shift(ch->wave, offset - ch->getShift());
-       ch->setShift(offset);
+       m::wfx::shift(*ch->wave, offset - ch->shift);
+       ch->shift = offset;
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->shiftTool->refresh();
        gdEditor->waveTools->waveform->refresh();       
index 8fc44d8577c75ddae17572ef0373cef6b1b88949..4f99a0080b5ed7087e490422c730c4753184ca26 100644 (file)
@@ -284,16 +284,16 @@ void glue_loadPatch(void* data)
                for (const patch::channel_t& pch : patch::channels) {
                        if (pch.column == col.index) {
                                Channel* ch = c::channel::addChannel(pch.column, pch.type, pch.size);
-                               ch->readPatch(basePath, k, &mixer::mutex_plugins, conf::samplerate,
-                                       conf::rsmpQuality);
+                               ch->readPatch(basePath, k);
                        }
                        browser->setStatusBar(steps);
                        k++;
                }
        }
 
-       /* Fill Mixer. */
+       /* Prepare Mixer. */
 
+       mh::updateSoloCount();
        mh::readPatch();
 
        /* Let recorder recompute the actions' positions if the current 
@@ -360,7 +360,7 @@ void glue_saveProject(void* data)
 
        for (const Channel* ch : mixer::channels) {
 
-               if (ch->type == CHANNEL_MIDI)
+               if (ch->type == G_CHANNEL_MIDI)
                        continue;
 
                const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
@@ -410,7 +410,7 @@ void glue_loadSample(void* data)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_saveSample(void *data)
+void glue_saveSample(voiddata)
 {
        using namespace giada::m;
 
index f2423a21b4713f8db2d842bd421e75f24f08ab0a..9380852ebf5681a16f97b1ae6de410c065596301 100644 (file)
@@ -54,7 +54,7 @@ gdChannelNameInput::gdChannelNameInput(Channel* ch)
        m_cancel = new geButton(m_ok->x() - 70 - G_GUI_OUTER_MARGIN, m_ok->y(), 70, G_GUI_UNIT, "Cancel");
        end();
 
-       m_name->value(m_ch->getName().c_str());
+       m_name->value(m_ch->name.c_str());
 
        m_ok->shortcut(FL_Enter);
        m_ok->callback(cb_update, (void*)this);
index becac71f1195941ac2ba5a6f19f583805d00ca2e..885f549fbcd02bf1536d57f8e6034c53b29c6686 100644 (file)
@@ -61,7 +61,7 @@ gdActionEditor::gdActionEditor(Channel *chan)
                zoom = conf::actionEditorZoom;
        }
 
-       totalWidth = (int) std::ceil(clock::getFramesInSequencer() / (float) zoom);
+       totalWidth = (int) std::ceil(clock::getFramesInSeq() / (float) zoom);
 
        /* container with zoom buttons and the action type selector. Scheme of
         * the resizable boxes: |[--b1--][actionType][--b2--][+][-]| */
@@ -70,7 +70,7 @@ gdActionEditor::gdActionEditor(Channel *chan)
 
        upperArea->begin();
 
-       if (chan->type == CHANNEL_SAMPLE) {
+       if (chan->type == G_CHANNEL_SAMPLE) {
          actionType = new geChoice(8, 8, 80, 20);
          gridTool   = new geGridTool(actionType->x()+actionType->w()+4, 8, this);
                actionType->add("key press");
@@ -99,7 +99,7 @@ gdActionEditor::gdActionEditor(Channel *chan)
 
        scroller = new geScroll(8, 36, w()-16, h()-44);
 
-       if (chan->type == CHANNEL_SAMPLE) {
+       if (chan->type == G_CHANNEL_SAMPLE) {
 
                SampleChannel *ch = (SampleChannel*) chan;
 
@@ -188,7 +188,7 @@ void gdActionEditor::__cb_zoomIn()
 
        update();
 
-       if (chan->type == CHANNEL_SAMPLE) {
+       if (chan->type == G_CHANNEL_SAMPLE) {
                ac->size(totalWidth, ac->h());
                mc->size(totalWidth, mc->h());
                vc->size(totalWidth, vc->h());
@@ -222,7 +222,7 @@ void gdActionEditor::__cb_zoomOut()
 
        update();
 
-       if (chan->type == CHANNEL_SAMPLE) {
+       if (chan->type == G_CHANNEL_SAMPLE) {
                ac->size(totalWidth, ac->h());
                mc->size(totalWidth, mc->h());
                vc->size(totalWidth, vc->h());
@@ -254,10 +254,10 @@ void gdActionEditor::__cb_zoomOut()
 
 void gdActionEditor::update()
 {
-       totalWidth = (int) ceilf(clock::getFramesInSequencer() / (float) zoom);
+       totalWidth = (int) ceilf(clock::getFramesInSeq() / (float) zoom);
        if (totalWidth < scroller->w()) {
                totalWidth = scroller->w();
-               zoom = (int) ceilf(clock::getFramesInSequencer() / (float) totalWidth);
+               zoom = (int) ceilf(clock::getFramesInSeq() / (float) totalWidth);
                scroller->scroll_to(0, scroller->yposition());
        }
 }
index dffd2989111dab17a600e2332b588c8559fafc16..3fec31779c612080610926df0ac6de7407c55b8f 100644 (file)
@@ -59,7 +59,7 @@ gdMidiInputChannel::gdMidiInputChannel(Channel* ch)
        label(title.c_str());
        size_range(G_DEFAULT_MIDI_INPUT_UI_W, G_DEFAULT_MIDI_INPUT_UI_H);
 
-       int extra = ch->type == CHANNEL_SAMPLE ? 28 : 0;
+       int extra = ch->type == G_CHANNEL_SAMPLE ? 28 : 0;
 
        Fl_Group* groupHeader = new Fl_Group(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w(), 20 + extra);
        groupHeader->begin();
@@ -98,7 +98,7 @@ gdMidiInputChannel::gdMidiInputChannel(Channel* ch)
        enable->value(ch->midiIn);
        enable->callback(cb_enable, (void*)this);
 
-       if (ch->type == CHANNEL_SAMPLE) {
+       if (ch->type == G_CHANNEL_SAMPLE) {
                veloAsVol->value(static_cast<SampleChannel*>(ch)->midiInVeloAsVol);
                veloAsVol->callback(cb_veloAsVol, (void*)this); 
        }
@@ -122,7 +122,7 @@ gdMidiInputChannel::gdMidiInputChannel(Channel* ch)
        channel->add("Channel 14");
        channel->add("Channel 15");
        channel->add("Channel 16");
-       channel->value(ch->getMidiInFilter() == -1 ? 0 : ch->getMidiInFilter() + 1);
+       channel->value(ch->midiInFilter == -1 ? 0 : ch->midiInFilter + 1);
        channel->callback(cb_setChannel, (void*)this);
 
        resizable(container);
@@ -165,7 +165,7 @@ void gdMidiInputChannel::addChannelLearners()
                new geMidiLearner(0, 0, LEARNER_WIDTH, "mute",        cb_learn, &ch->midiInMute, ch);
                new geMidiLearner(0, 0, LEARNER_WIDTH, "solo",        cb_learn, &ch->midiInSolo, ch);
                new geMidiLearner(0, 0, LEARNER_WIDTH, "volume",      cb_learn, &ch->midiInVolume, ch);
-               if (ch->type == CHANNEL_SAMPLE) {
+               if (ch->type == G_CHANNEL_SAMPLE) {
                        new geMidiLearner(0, 0, LEARNER_WIDTH, "pitch", cb_learn, 
                                &(static_cast<SampleChannel*>(ch))->midiInPitch, ch);
                        new geMidiLearner(0, 0, LEARNER_WIDTH, "read actions", cb_learn, 
@@ -239,8 +239,7 @@ void gdMidiInputChannel::cb_veloAsVol()
 
 void gdMidiInputChannel::cb_setChannel()
 {
-       ch->setMidiInFilter(channel->value() == 0 ? -1 : channel->value() - 1);
-       gu_log("[gdMidiInputChannel] Set MIDI channel to %d\n", 
-               ch->getMidiInFilter());
+       ch->midiInFilter = channel->value() == 0 ? -1 : channel->value() - 1;
+       gu_log("[gdMidiInputChannel] Set MIDI channel to %d\n", ch->midiInFilter);
 }
 
index 275f5d7ae2409f29481924b5ac97308ac6b30830..ee000d3e76f6ee74925009d41d82d90f9e150bd3 100644 (file)
@@ -85,7 +85,7 @@ gdSampleEditor::gdSampleEditor(SampleChannel* ch)
 
   gu_setFavicon(this);
   set_non_modal();
-  copy_label(ch->getName().c_str());
+  copy_label(ch->name.c_str());
 
   size_range(720, 480);
   if (conf::sampleEditorX)
@@ -199,9 +199,9 @@ Fl_Group* gdSampleEditor::createPreviewBox(int x, int y, int h)
   play->callback(cb_togglePreview, (void*)this);
   rewind->callback(cb_rewindPreview, (void*)this);
 
-  ch->setOnEndPreviewCb([this] { 
+  ch->onPreviewEnd = [this] { 
        play->value(0);
-  });
+  };
 
   return g;
 }
index 85169707f2072e71065e6c776db89fc9d7723061..ee8c954306a933229215244f04fcfba9c7186d53 100644 (file)
@@ -173,11 +173,6 @@ int geAction::handle(int e)
 
 void geAction::addAction()
 {
-       /* always check frame parity */
-
-       if (frame_a % 2 != 0)
-               frame_a++;
-
        /* anatomy of an action
         * ____[#######]_____ (a) is the left margin, G_ACTION_KEYPRESS. (b) is
         *     a       b      the right margin, the G_ACTION_KEYREL. This is the
index db60c350baa038a20fc20cc5e3506d6ffb48bc90..5adfc13ab52c42743f6910c9c1006ba4be136a5e 100644 (file)
@@ -67,10 +67,10 @@ geActionEditor::geActionEditor(int x, int y, gdActionEditor *pParent, SampleChan
         find the other piece (namely frame_b)
       - not of types G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL */
 
-      if ((action->chan != pParent->chan->index)                            ||
-          (recorder::frames.at(i) > clock::getTotalFrames())              ||
+      if ((action->chan != pParent->chan->index)                          ||
+          (recorder::frames.at(i) > clock::getFramesInLoop())             ||
           (action->type == G_ACTION_KILL && ch->mode == SINGLE_PRESS)     ||
-          (action->type == G_ACTION_KEYREL && ch->mode == SINGLE_PRESS)       ||
+          (action->type == G_ACTION_KEYREL && ch->mode == SINGLE_PRESS)   ||
           (action->type & ~(G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL))
       )
         continue;
index 0615b7f49100a6c6475f4e67123a253b178d36a1..22b97d5ab0db08c0796f88e68ac0a45ca1ef9aa5 100644 (file)
@@ -195,8 +195,8 @@ int geEnvelopeEditor::handle(int e) {
                                                if (points.size() == 0) {
                                                        addPoint(0, 0, 1.0f, 0, 1);
                                                        recorder::rec(pParent->chan->index, type, 0, 0, 1.0f);
-                                                       addPoint(clock::getTotalFrames(), 0, 1.0f, pParent->coverX, 1);
-                                                       recorder::rec(pParent->chan->index, type, clock::getTotalFrames(), 0, 1.0f);
+                                                       addPoint(clock::getFramesInLoop(), 0, 1.0f, pParent->coverX, 1);
+                                                       recorder::rec(pParent->chan->index, type, clock::getFramesInLoop(), 0, 1.0f);
               pParent->chan->hasActions = true;
                                                }
 
@@ -256,8 +256,8 @@ int geEnvelopeEditor::handle(int e) {
 
                                        if (newFrame < 0)
                                                newFrame = 0;
-                                       else if (newFrame > clock::getTotalFrames())
-                                               newFrame = clock::getTotalFrames();
+                                       else if (newFrame > clock::getFramesInLoop())
+                                               newFrame = clock::getFramesInLoop();
 
                                        /* vertical line check */
 
index a481fb333439010e821fe39bb117d54ecaaa988b..4f17dbb12d1cda553fb52a3dcc971c1d44dca848 100644 (file)
@@ -133,20 +133,20 @@ void geGridTool::calc()
         * put a concentrate of each block (which is totalFrames / zoom) */
 
        int  j   = 0;
-       int fpgc = floor(clock::getFramesPerBeat() / getValue());  // frames per grid cell
+       int fpgc = floor(clock::getFramesInBeat() / getValue());  // frames per grid cell
 
        for (int i=1; i<parent->totalWidth; i++) {   // if i=0, step=0 -> useless cycle
                int step = parent->zoom*i;
-               while (j < step && j < clock::getTotalFrames()) {
+               while (j < step && j < clock::getFramesInLoop()) {
                        if (j % fpgc == 0) {
                                points.push_back(i);
                                frames.push_back(j);
                        }
-                       if (j % clock::getFramesPerBeat() == 0)
+                       if (j % clock::getFramesInBeat() == 0)
                                beats.push_back(i);
-                       if (j % clock::getFramesPerBar() == 0 && i != 1)
+                       if (j % clock::getFramesInBar() == 0 && i != 1)
                                bars.push_back(i);
-                       if (j == clock::getTotalFrames() - 1)
+                       if (j == clock::getFramesInLoop() - 1)
                                parent->coverX = i;
                        j++;
                }
index cba778f82943beb2c2b1ffab2c3c0f457566dcb9..9ad12840dcc72063fd6687ddf8e1d844b5ca22b9 100644 (file)
@@ -244,8 +244,8 @@ int geMuteEditor::handle(int e) {
                                        /* avoid overflow: frame_b must be within the sequencer range. In that
                                         * case shift the ON-OFF block */
 
-                                       if (frame_b >= clock::getTotalFrames()) {
-                                               frame_b = clock::getTotalFrames();
+                                       if (frame_b >= clock::getFramesInLoop()) {
+                                               frame_b = clock::getFramesInLoop();
                                                frame_a = frame_b-2048;
                                        }
 
index e28656b0f15249ea777dc6f3d1c7c17394732480..346685261f894086b97e55b151a2ac0de91e1689 100644 (file)
@@ -75,10 +75,10 @@ void gePianoRoll::build()
        
        clear();
 
-       int channel  = pParent->chan->index;
-       int maxFrame = m::clock::getTotalFrames();
+       int channel   = pParent->chan->index;
+       int maxSample = m::clock::getFramesInLoop();
 
-       vector<Composite> actions = c::recorder::getMidiActions(channel, maxFrame); 
+       vector<Composite> actions = c::recorder::getMidiActions(channel, maxSample); 
        for (Composite composite : actions)
        {
                m::MidiEvent e1 = composite.a1.iValue;
index a222174c105b83b9aa30e39ca82eb27dbd452039..48db620e6b782b4bf0fe0a34eb545013fb03aa0d 100644 (file)
@@ -92,7 +92,7 @@ void geChannel::cb_mute()
 
 void geChannel::cb_solo()
 {
-       solo->value() ? c::channel::setSoloOn(ch) : c::channel::setSoloOff(ch);
+       c::channel::toggleSolo(ch);
 }
 
 
index 509df9261a2bf594b3d5e2fa44611581ac340268..6d95b4699da55178482e87220636fcd82edb9426 100644 (file)
@@ -63,7 +63,7 @@ void geChannelStatus::draw()
       fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);     // status empty
 
 
-    if (mixer::recording && ch->isArmed())
+    if (mixer::recording && ch->armed)
       fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_RED);     // take in progress
     else
     if (recorder::active && recorder::canRec(ch, clock::isRunning(), mixer::recording))
index 74861afef1c2879a1f109ce0c13ab1bc6924b232..0f39ec5ebb404e7ab833a8dc6928b1219d719ad6 100644 (file)
@@ -112,7 +112,7 @@ int geColumn::handle(int e)
                        for (string& path : paths) {
                                gu_log("[geColumn::handle] loading %s...\n", path.c_str());
                                SampleChannel* c = static_cast<SampleChannel*>(c::channel::addChannel(
-                                       m_index, CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
+                                       m_index, G_CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
                                result = c::channel::loadChannel(c, gu_stripFileUrl(path));
                                if (result != G_RES_OK) {
                                        deleteChannel(c->guiChannel);
@@ -217,7 +217,7 @@ geChannel* geColumn::addChannel(Channel* ch, int size)
        /* All geChannels are added with y=0. That's not a problem, they will be 
        repositioned later on during geColumn::resize(). */
 
-       if (ch->type == CHANNEL_SAMPLE)
+       if (ch->type == G_CHANNEL_SAMPLE)
                gch = new geSampleChannel(x(), 0, w(), size, static_cast<SampleChannel*>(ch));
        else
                gch = new geMidiChannel(x(), 0, w(), size, static_cast<MidiChannel*>(ch));
@@ -281,9 +281,9 @@ int geColumn::openTypeMenu()
        if (!m) return 0;
 
        if (strcmp(m->label(), "Sample channel") == 0)
-               return CHANNEL_SAMPLE;
+               return G_CHANNEL_SAMPLE;
        if (strcmp(m->label(), "MIDI channel") == 0)
-               return CHANNEL_MIDI;
+               return G_CHANNEL_MIDI;
        return 0;
 }
 
index 8e1957cd36341e8449427d9ab4c7a5ff790da61a..9f913e77a7cb179de88115064cfe06c5ba4ad925 100644 (file)
@@ -148,7 +148,7 @@ void menuCallback(Fl_Widget* w, void* v)
 
 
 geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel* ch)
-       : geChannel(X, Y, W, H, CHANNEL_MIDI, ch)
+       : geChannel(X, Y, W, H, G_CHANNEL_MIDI, ch)
 {
        begin();
 
@@ -292,23 +292,23 @@ void geMidiChannel::update()
        const MidiChannel* mch = static_cast<const MidiChannel*>(ch);
 
        string label; 
-       if (mch->getName().empty())
+       if (mch->name.empty())
                label = "-- MIDI --";
        else
-               label = mch->getName().c_str();
+               label = mch->name.c_str();
 
        if (mch->midiOut) 
                label += " (ch " + gu_iToString(mch->midiOutChan + 1) + " out)";
 
        mainButton->label(label.c_str());
 
-       vol->value(mch->getVolume());
+       vol->value(mch->volume);
        mute->value(mch->mute);
        solo->value(mch->solo);
 
        mainButton->setKey(mch->key);
 
-       arm->value(mch->isArmed());
+       arm->value(mch->armed);
 
 #ifdef WITH_VST
        fx->status = mch->plugins.size() > 0;
index 08b582bc82d234b22cd77b47381711098f95818e..d477915c40394ce957c5b0821668304e9a414fb3 100644 (file)
@@ -208,7 +208,7 @@ void menuCallback(Fl_Widget* w, void* v)
 
 
 geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel* ch)
-       : geChannel(X, Y, W, H, CHANNEL_SAMPLE, ch)
+       : geChannel(X, Y, W, H, G_CHANNEL_SAMPLE, ch)
 {
        begin();
 
@@ -380,7 +380,7 @@ void geSampleChannel::refresh()
        setColorsByStatus(ch->status, ch->recStatus);
 
        if (static_cast<SampleChannel*>(ch)->wave != nullptr) {
-               if (m::mixer::recording && ch->isArmed())
+               if (m::mixer::recording && ch->armed)
                        mainButton->setInputRecordMode();
                if (m::recorder::active) {
                        if (m::recorder::canRec(ch, m::clock::isRunning(), m::mixer::recording))
@@ -420,10 +420,10 @@ void geSampleChannel::update()
                        mainButton->label("* file not found! *");
                        break;
                default:
-                       if (sch->getName().empty())
+                       if (sch->name.empty())
                                mainButton->label(sch->wave->getBasename(false).c_str());
                        else
-                               mainButton->label(sch->getName().c_str());
+                               mainButton->label(sch->name.c_str());
                        break;
        }
 
@@ -439,13 +439,13 @@ void geSampleChannel::update()
        modeBox->value(sch->mode);
        modeBox->redraw();
 
-       vol->value(sch->getVolume());
+       vol->value(sch->volume);
        mute->value(sch->mute);
        solo->value(sch->solo);
 
        mainButton->setKey(sch->key);
 
-       arm->value(sch->isArmed());
+       arm->value(sch->armed);
 
 #ifdef WITH_VST
        fx->status = sch->plugins.size() > 0;
index 572842a0918be419f5bd99c962d4568b861ac29b..ced6cb81786601d165b0e36bac210532b27ffc0d 100644 (file)
@@ -183,7 +183,7 @@ void geMainMenu::__cb_edit()
                        break;
                }
        for (unsigned i=0; i<mixer::channels.size(); i++)
-               if (mixer::channels.at(i)->type == CHANNEL_SAMPLE)
+               if (mixer::channels.at(i)->type == G_CHANNEL_SAMPLE)
                        if (((SampleChannel*)mixer::channels.at(i))->wave != nullptr) {
                                menu[0].activate();
                                break;
@@ -209,7 +209,7 @@ void geMainMenu::__cb_edit()
                if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
                        return;
                G_MainWin->delSubWindow(WID_ACTION_EDITOR);
-               glue_clearAllRecs();
+               glue_clearAllActions();
                return;
        }
        if (strcmp(m->label(), "Reset to init state") == 0) {
index a0e1eaca563bf5771e32b6bd59317c0034deece2..624658d601c9c701c3d7597dffb088bbf4a8517b 100644 (file)
@@ -122,7 +122,7 @@ void geBoostTool::cb_normalize()
 {
   using namespace giada;
 
-  float val = m::wfx::normalizeSoft(ch->wave);
+  float val = m::wfx::normalizeSoft(*ch->wave);
   c::channel::setBoost(ch, val); // it's like a fake user moving the dial 
   static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
 }
index 33173ca4aca8901217e1cff7a3edae90626a3ed9..0cc1e47174a799ba289f3a5ce453bb2f1460df8c 100644 (file)
@@ -141,7 +141,7 @@ void gePitchTool::__cb_setPitchDouble()
 void gePitchTool::__cb_setPitchToBar()
 {
   // TODO - opaque channel's count
-  c::channel::setPitch(ch, (ch->getEnd()*2) / (float) m::clock::getFramesPerBar());
+  c::channel::setPitch(ch, (ch->getEnd()) / (float) m::clock::getFramesInBar());
 }
 
 
@@ -151,7 +151,7 @@ void gePitchTool::__cb_setPitchToBar()
 void gePitchTool::__cb_setPitchToSong()
 {
   // TODO - opaque channel's count
-  c::channel::setPitch(ch, (ch->getEnd()*2) / (float) m::clock::getTotalFrames());
+  c::channel::setPitch(ch, ch->getEnd() / (float) m::clock::getFramesInLoop());
 }
 
 
index bbcf127a2dadbd1c5dca8e221516d26fe14c7997..5f0a2f8d3cf8defedf3f0de0b12f5323e8311a2b 100644 (file)
@@ -53,7 +53,7 @@ geShiftTool::geShiftTool(int x, int y, SampleChannel* ch)
 
        m_shift->type(FL_INT_INPUT);
        m_shift->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
-       m_shift->value(gu_iToString(ch->getShift()).c_str());
+       m_shift->value(gu_iToString(ch->shift).c_str());
        m_shift->callback(cb_setShift, (void*)this);
 
        m_reset->callback(cb_reset, (void*)this);
@@ -92,7 +92,7 @@ void geShiftTool::cb_reset()
 
 void geShiftTool::refresh()
 {
-       m_shift->value(gu_iToString(m_ch->getShift()).c_str());
+       m_shift->value(gu_iToString(m_ch->shift).c_str());
 }
 
 
index ddcdfb3e16487eee09016c01c6eb0692abb09db6..4176150ab1cbe3f1739649d07eab122948bafaa9 100644 (file)
@@ -71,7 +71,7 @@ void geVolumeTool::refresh()
   using namespace giada::u;
 
   string tmp;
-  float dB = math::linearToDB(ch->getVolume());
+  float dB = math::linearToDB(ch->volume);
   if (dB > -INFINITY) tmp = gu_fToString(dB, 2);  // 2 digits
   else                tmp = "-inf";
   input->value(tmp.c_str());
index 806356f8d9966ffa669dff9f0b798a53801ad192..7e3c4470b6571aa5657a19f37fc8ea3fed4b4243 100644 (file)
@@ -302,7 +302,7 @@ void geWaveform::drawStartEndPoints()
 
 void geWaveform::drawPlayHead()
 {
-       int p = frameToPixel(m_ch->getTrackerPreview()) + x();
+       int p = frameToPixel(m_ch->trackerPreview) + x();
        fl_color(G_COLOR_LIGHT_2);
        fl_line(p, y() + 1, p, y() + h() - 2);
 }
@@ -621,7 +621,7 @@ void geWaveform::clearSel()
 
 void geWaveform::setZoom(int type)
 {
-       if (!alloc(type == ZOOM_IN ? m_data.size * 2 : m_data.size / 2)) 
+       if (!alloc(type == ZOOM_IN ? m_data.size * G_GUI_ZOOM_FACTOR : m_data.size / G_GUI_ZOOM_FACTOR)) 
                return;
 
        size(m_data.size, h());
index 8af7901f73fd74321b2e073dd451714a525656af..ec4de69e245f1035063e62033ddddc18fbac9895 100644 (file)
@@ -111,8 +111,8 @@ int gu_getBlinker()
 
 void gu_updateControls()
 {
-       for (unsigned i=0; i<mixer::channels.size(); i++)
-               mixer::channels.at(i)->guiChannel->update();
+       for (const Channel* ch : mixer::channels)
+               ch->guiChannel->update();
 
        G_MainWin->mainIO->setOutVol(mixer::outVol);
        G_MainWin->mainIO->setInVol(mixer::inVol);
@@ -132,7 +132,7 @@ void gu_updateControls()
 /* -------------------------------------------------------------------------- */
 
 
-void gu_updateMainWinLabel(const string &s)
+void gu_updateMainWinLabel(const strings)
 {
        std::string out = std::string(G_APP_NAME) + " - " + s;
        G_MainWin->copy_label(out.c_str());
@@ -142,7 +142,7 @@ void gu_updateMainWinLabel(const string &s)
 /* -------------------------------------------------------------------------- */
 
 
-void gu_setFavicon(Fl_Window *w)
+void gu_setFavicon(Fl_Windoww)
 {
 #if defined(__linux__)
 
@@ -163,7 +163,7 @@ void gu_setFavicon(Fl_Window *w)
 /* -------------------------------------------------------------------------- */
 
 
-void gu_openSubWindow(gdWindow *parent, gdWindow *child, int id)
+void gu_openSubWindow(gdWindow* parent, gdWindow* child, int id)
 {
        if (parent->hasWindow(id)) {
                gu_log("[GU] parent has subwindow with id=%d, deleting\n", id);
@@ -181,7 +181,7 @@ void gu_refreshActionEditor()
 {
        /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */
 
-       gdActionEditor *aeditor = (gdActionEditor*) G_MainWin->getChild(WID_ACTION_EDITOR);
+       gdActionEditoraeditor = (gdActionEditor*) G_MainWin->getChild(WID_ACTION_EDITOR);
        if (aeditor) {
                Channel *chan = aeditor->chan;
                G_MainWin->delSubWindow(WID_ACTION_EDITOR);
diff --git a/tests/audioBuffer.cpp b/tests/audioBuffer.cpp
new file mode 100644 (file)
index 0000000..254941b
--- /dev/null
@@ -0,0 +1,100 @@
+#include <memory>
+#include "../src/core/audioBuffer.h"
+#include <catch.hpp>
+
+
+TEST_CASE("Test AudioBuffer class")
+{
+       using namespace giada::m;
+
+       static const int BUFFER_SIZE = 4096;
+
+       /* Each SECTION the TEST_CASE is executed from the start. Any code between 
+       this comment and the first SECTION macro is exectuted before each SECTION. */
+
+       AudioBuffer buffer;
+       buffer.alloc(BUFFER_SIZE, 2);
+       
+       SECTION("test allocation")
+       {
+               SECTION("test mono")
+               {
+                       REQUIRE(buffer.alloc(BUFFER_SIZE, 1) == 1);
+                       REQUIRE(buffer.countFrames() == BUFFER_SIZE);
+                       REQUIRE(buffer.countSamples() == BUFFER_SIZE);
+                       REQUIRE(buffer.countChannels() == 1);
+               }               
+
+               SECTION("test stereo")
+               {
+                       REQUIRE(buffer.countFrames() == BUFFER_SIZE);
+                       REQUIRE(buffer.countSamples() == BUFFER_SIZE * 2);
+                       REQUIRE(buffer.countChannels() == 2);
+               }               
+
+               SECTION("test odd channels count")
+               {
+                       REQUIRE(buffer.alloc(BUFFER_SIZE, 7) == 1);
+                       REQUIRE(buffer.countFrames() == BUFFER_SIZE);
+                       REQUIRE(buffer.countSamples() == BUFFER_SIZE * 7);
+                       REQUIRE(buffer.countChannels() == 7);
+               }
+
+               buffer.free();
+
+               REQUIRE(buffer[0] == nullptr);
+               REQUIRE(buffer.countFrames() == 0);
+               REQUIRE(buffer.countSamples() == 0);
+               REQUIRE(buffer.countChannels() == 0);
+       }
+
+       SECTION("test clear all")
+       {       
+               buffer.clear();
+               for (int i=0; i<buffer.countFrames(); i++)
+                       for (int k=0; k<buffer.countChannels(); k++)
+                               REQUIRE(buffer[i][k] == 0.0f);
+               buffer.free();
+       }
+
+       SECTION("test clear range")
+       {       
+               for (int i=0; i<buffer.countFrames(); i++)
+                       for (int k=0; k<buffer.countChannels(); k++)
+                                       buffer[i][k] = 1.0f;
+
+               buffer.clear(5, 6);
+
+               for (int k=0; k<buffer.countChannels(); k++)
+                       REQUIRE(buffer[5][k] == 0.0f);
+
+               buffer.free();
+       }
+
+       SECTION("test copy")
+       {       
+               int size = BUFFER_SIZE * 2;
+               float* data = new float[size];
+               for (int i=0; i<size; i++)
+                       data[i] = (float) i;
+
+               SECTION("test full copy")
+               {       
+                       buffer.copyData(data, BUFFER_SIZE);
+
+                       REQUIRE(buffer[0][0]    == 0.0f);
+                       REQUIRE(buffer[16][0]   == 32.0f);
+                       REQUIRE(buffer[32][0]   == 64.0f);
+                       REQUIRE(buffer[1024][0] == 2048.0f);
+               }
+
+               SECTION("test copy frame")
+               {       
+                       buffer.copyFrame(16, &data[32]);
+                       REQUIRE(buffer[16][0] == 32.0f);
+                       REQUIRE(buffer[16][1] == 33.0f);
+               }
+
+               delete[] data;
+       }
+}
index b7a0808c6014c8a194316c3e1807f8462380169a..8e302bd1c1637d82cb504c48b69b0e769e171055 100644 (file)
@@ -55,7 +55,7 @@ TEST_CASE("Test Patch class")
                channel1.plugins.push_back(plugin2);
 #endif
 
-               channel1.type              = CHANNEL_SAMPLE;
+               channel1.type              = G_CHANNEL_SAMPLE;
                channel1.index             = 666;
                channel1.size              = G_GUI_CHANNEL_H_1;
                channel1.column            = 0;
@@ -144,7 +144,7 @@ TEST_CASE("Test Patch class")
                REQUIRE(column0.width == 500);
 
                patch::channel_t channel0 = patch::channels.at(0);
-               REQUIRE(channel0.type == CHANNEL_SAMPLE);
+               REQUIRE(channel0.type == G_CHANNEL_SAMPLE);
                REQUIRE(channel0.index == 666);
                REQUIRE(channel0.size == G_GUI_CHANNEL_H_1);
                REQUIRE(channel0.column == 0);
index 72cffa326a7b0cc57d8fd27afa4595c345b2abab..00977202e59c72f48db23f1a042b971b6bf3bff8 100644 (file)
@@ -16,52 +16,36 @@ TEST_CASE("Test Wave class")
        /* Each SECTION the TEST_CASE is executed from the start. Any code between 
        this comment and the first SECTION macro is exectuted before each SECTION. */
 
-       std::unique_ptr<Wave> wave;
-       
-       SECTION("test basename")
-       {
-               wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS, 
-                       SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
-
-               REQUIRE(wave->getPath() == "path/to/sample.wav");
-               REQUIRE(wave->getBasename() == "sample");
-               REQUIRE(wave->getBasename(true) == "sample.wav");
-       }
 
-       SECTION("test path")
+       SECTION("test allocation")
        {
-               wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS, 
-                       SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
-
-               wave->setPath("path/is/now/different.mp3");
+               Wave wave;
 
-               REQUIRE(wave->getPath() == "path/is/now/different.mp3");
+               REQUIRE(wave.alloc(BUFFER_SIZE, CHANNELS, SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav") == true);
 
-               wave->setPath("path/is/now/different.mp3", 5);
+               SECTION("test basename")
+               {
+                       REQUIRE(wave.getPath() == "path/to/sample.wav");
+                       REQUIRE(wave.getBasename() == "sample");
+                       REQUIRE(wave.getBasename(true) == "sample.wav");
+               }
 
-               REQUIRE(wave->getPath() == "path/is/now/different-5.mp3");
-       }  
+               SECTION("test path")
+               {
+                       wave.setPath("path/is/now/different.mp3");
 
-       SECTION("test change name")
-       {
-               wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS, 
-                       SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
-
-               REQUIRE(wave->getPath() == "path/to/sample.wav");
-               REQUIRE(wave->getBasename() == "sample");
-               REQUIRE(wave->getBasename(true) == "sample.wav");
-       }
+                       REQUIRE(wave.getPath() == "path/is/now/different.mp3");
 
-       SECTION("test memory cleanup")
-       {
-               float* data = new float[BUFFER_SIZE];
+                       wave.setPath("path/is/now/different.mp3", 5);
 
-               wave = std::unique_ptr<Wave>(new Wave(data, BUFFER_SIZE, CHANNELS, 
-                       SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
-               wave->clear();
+                       REQUIRE(wave.getPath() == "path/is/now/different-5.mp3");
+               }  
 
-               REQUIRE(wave->getData() == nullptr);
-               REQUIRE(wave->getPath() == "");
-               REQUIRE(wave->getSize() == 0);
+               SECTION("test change name")
+               {
+                       REQUIRE(wave.getPath() == "path/to/sample.wav");
+                       REQUIRE(wave.getBasename() == "sample");
+                       REQUIRE(wave.getBasename(true) == "sample.wav");
+               }
        }
 }
index 9c16d280f994e7a823234fe04ca8ac947969af2d..e12c8cbca1230b6922c28ea8a6a87d0524856606 100644 (file)
@@ -15,28 +15,27 @@ TEST_CASE("Test waveFx")
        static const int BUFFER_SIZE = 4000;
        static const int BIT_DEPTH = 32;
 
-       std::unique_ptr<Wave> waveMono = std::unique_ptr<Wave>(new Wave(new float[BUFFER_SIZE], 
-               BUFFER_SIZE, 1, SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
-
-       std::unique_ptr<Wave> waveStereo = std::unique_ptr<Wave>(new Wave(new float[BUFFER_SIZE * 2], 
-               BUFFER_SIZE, 2, SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
+       Wave waveMono;
+       Wave waveStereo;
+       waveMono.alloc(BUFFER_SIZE, 1, SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav");
+       waveStereo.alloc(BUFFER_SIZE, 2, SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav");
 
        SECTION("test mono->stereo conversion")
        {
-               int prevSize = waveMono->getSize();
+               int prevSize = waveMono.getSize();
 
-               REQUIRE(wfx::monoToStereo(waveMono.get()) == G_RES_OK);
-               REQUIRE(waveMono->getSize() == prevSize);  // size does not change, channels do
-               REQUIRE(waveMono->getChannels() == 2);
+               REQUIRE(wfx::monoToStereo(waveMono) == G_RES_OK);
+               REQUIRE(waveMono.getSize() == prevSize);  // size does not change, channels do
+               REQUIRE(waveMono.getChannels() == 2);
 
                SECTION("test mono->stereo conversion for already stereo wave")
                {
                        /* Should do nothing. */
-                       int prevSize = waveStereo->getSize();
+                       int prevSize = waveStereo.getSize();
 
-                       REQUIRE(wfx::monoToStereo(waveStereo.get()) == G_RES_OK);
-                       REQUIRE(waveStereo->getSize() == prevSize);
-                       REQUIRE(waveStereo->getChannels() == 2);
+                       REQUIRE(wfx::monoToStereo(waveStereo) == G_RES_OK);
+                       REQUIRE(waveStereo.getSize() == prevSize);
+                       REQUIRE(waveStereo.getChannels() == 2);
                }
        }
 
@@ -44,23 +43,19 @@ TEST_CASE("Test waveFx")
        {
                int a = 20;
                int b = 57;
-               wfx::silence(waveStereo.get(), a, b);
+               wfx::silence(waveStereo, a, b);
 
-               for (int i=a; i<b; i++) {
-                       float* frame = waveStereo->getFrame(i);
-                       for (int k=0; k<waveStereo->getChannels(); k++)
-                               REQUIRE(frame[k] == 0.0f);
-               }
+               for (int i=a; i<b; i++)
+                       for (int k=0; k<waveStereo.getChannels(); k++)
+                               REQUIRE(waveStereo[i][k] == 0.0f);
 
                SECTION("test silence (mono)")
                {
-                       wfx::silence(waveMono.get(), a, b);
+                       wfx::silence(waveMono, a, b);
 
-                       for (int i=a; i<b; i++) {
-                               float* frame = waveMono->getFrame(i);
-                               for (int k=0; k<waveMono->getChannels(); k++)
-                                       REQUIRE(frame[k] == 0.0f);
-                       }
+                       for (int i=a; i<b; i++)
+                               for (int k=0; k<waveMono.getChannels(); k++)
+                                       REQUIRE(waveMono[i][k] == 0.0f);
                }
        }
 
@@ -69,16 +64,16 @@ TEST_CASE("Test waveFx")
                int a = 47;
                int b = 210;
                int range = b - a;
-               int prevSize = waveStereo->getSize();
+               int prevSize = waveStereo.getSize();
 
-               REQUIRE(wfx::cut(waveStereo.get(), a, b) == G_RES_OK);
-               REQUIRE(waveStereo->getSize() == prevSize - range);
+               REQUIRE(wfx::cut(waveStereo, a, b) == G_RES_OK);
+               REQUIRE(waveStereo.getSize() == prevSize - range);
 
                SECTION("test cut (mono)")
                {
-                       prevSize = waveMono->getSize();
-                       REQUIRE(wfx::cut(waveMono.get(), a, b) == G_RES_OK);
-                       REQUIRE(waveMono->getSize() == prevSize - range);
+                       prevSize = waveMono.getSize();
+                       REQUIRE(wfx::cut(waveMono, a, b) == G_RES_OK);
+                       REQUIRE(waveMono.getSize() == prevSize - range);
                }
        }
 
@@ -88,13 +83,13 @@ TEST_CASE("Test waveFx")
                int b = 210;
                int area = b - a;
 
-               REQUIRE(wfx::trim(waveStereo.get(), a, b) == G_RES_OK);
-               REQUIRE(waveStereo->getSize() == area);
+               REQUIRE(wfx::trim(waveStereo, a, b) == G_RES_OK);
+               REQUIRE(waveStereo.getSize() == area);
 
                SECTION("test trim (mono)")
                {
-                       REQUIRE(wfx::trim(waveMono.get(), a, b) == G_RES_OK);
-                       REQUIRE(waveMono->getSize() == area);
+                       REQUIRE(wfx::trim(waveMono, a, b) == G_RES_OK);
+                       REQUIRE(waveMono.getSize() == area);
                }
        }
 
@@ -103,21 +98,21 @@ TEST_CASE("Test waveFx")
                int a = 47;
                int b = 500;
 
-               wfx::fade(waveStereo.get(), a, b, wfx::FADE_IN);
-               wfx::fade(waveStereo.get(), a, b, wfx::FADE_OUT);
+               wfx::fade(waveStereo, a, b, wfx::FADE_IN);
+               wfx::fade(waveStereo, a, b, wfx::FADE_OUT);
 
-               REQUIRE(waveStereo->getFrame(a)[0] == 0.0f);
-               REQUIRE(waveStereo->getFrame(a)[1] == 0.0f);
-               REQUIRE(waveStereo->getFrame(b)[0] == 0.0f);
-               REQUIRE(waveStereo->getFrame(b)[1] == 0.0f);
+               REQUIRE(waveStereo.getFrame(a)[0] == 0.0f);
+               REQUIRE(waveStereo.getFrame(a)[1] == 0.0f);
+               REQUIRE(waveStereo.getFrame(b)[0] == 0.0f);
+               REQUIRE(waveStereo.getFrame(b)[1] == 0.0f);
 
                SECTION("test fade (mono)")
                {
-                       wfx::fade(waveMono.get(), a, b, wfx::FADE_IN);
-                       wfx::fade(waveMono.get(), a, b, wfx::FADE_OUT);
+                       wfx::fade(waveMono, a, b, wfx::FADE_IN);
+                       wfx::fade(waveMono, a, b, wfx::FADE_OUT);
 
-                       REQUIRE(waveMono->getFrame(a)[0] == 0.0f);
-                       REQUIRE(waveMono->getFrame(b)[0] == 0.0f);              
+                       REQUIRE(waveMono.getFrame(a)[0] == 0.0f);
+                       REQUIRE(waveMono.getFrame(b)[0] == 0.0f);               
                }
        }
 
@@ -126,18 +121,18 @@ TEST_CASE("Test waveFx")
                int a = 11;
                int b = 79;
 
-               wfx::smooth(waveStereo.get(), a, b);
+               wfx::smooth(waveStereo, a, b);
 
-               REQUIRE(waveStereo->getFrame(a)[0] == 0.0f);
-               REQUIRE(waveStereo->getFrame(a)[1] == 0.0f);
-               REQUIRE(waveStereo->getFrame(b)[0] == 0.0f);
-               REQUIRE(waveStereo->getFrame(b)[1] == 0.0f);
+               REQUIRE(waveStereo.getFrame(a)[0] == 0.0f);
+               REQUIRE(waveStereo.getFrame(a)[1] == 0.0f);
+               REQUIRE(waveStereo.getFrame(b)[0] == 0.0f);
+               REQUIRE(waveStereo.getFrame(b)[1] == 0.0f);
                
                SECTION("test smooth (mono)")
                {
-                       wfx::smooth(waveMono.get(), a, b);
-                       REQUIRE(waveMono->getFrame(a)[0] == 0.0f);
-                       REQUIRE(waveMono->getFrame(b)[0] == 0.0f);              
+                       wfx::smooth(waveMono, a, b);
+                       REQUIRE(waveMono.getFrame(a)[0] == 0.0f);
+                       REQUIRE(waveMono.getFrame(b)[0] == 0.0f);               
                }
        }
 }
index f9b2eb85420f1007d6c0f559459507821130744a..d32be1b7efd0b166b66818db72167c2cc6644d1e 100644 (file)
@@ -35,13 +35,13 @@ TEST_CASE("Test waveManager")
 
   SECTION("test recording")
   {
-    int res = waveManager::createEmpty(G_BUFFER_SIZE, G_SAMPLE_RATE, 
+    int res = waveManager::createEmpty(G_BUFFER_SIZE, G_MAX_IO_CHANS, G_SAMPLE_RATE, 
       "test.wav", &w);
     std::unique_ptr<Wave> wave(w);
 
     REQUIRE(res == G_RES_OK);
     REQUIRE(wave->getRate() == G_SAMPLE_RATE);
-    REQUIRE(wave->getSize() == G_BUFFER_SIZE / wave->getChannels());
+    REQUIRE(wave->getSize() == G_BUFFER_SIZE);
     REQUIRE(wave->getChannels() == G_CHANNELS);
     REQUIRE(wave->isLogical() == true);
     REQUIRE(wave->isEdited() == false);