Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microtuner core #6036

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/ComboBoxModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef COMBOBOX_MODEL_H
#define COMBOBOX_MODEL_H

#include <cassert>
#include <memory>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -52,6 +53,8 @@ class LMMS_EXPORT ComboBoxModel : public IntModel

void addItem( QString item, std::unique_ptr<PixmapLoader> loader = nullptr );

void replaceItem(std::size_t index, QString item, std::unique_ptr<PixmapLoader> loader = nullptr);

void clear();

int findText( const QString& txt ) const;
Expand Down
8 changes: 8 additions & 0 deletions include/InstrumentTrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "GroupBox.h"
#include "InstrumentFunctions.h"
#include "InstrumentSoundShaping.h"
#include "Microtuner.h"
#include "Midi.h"
#include "MidiCCRackView.h"
#include "MidiEventProcessor.h"
Expand Down Expand Up @@ -193,6 +194,11 @@ class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor
return &m_piano;
}

Microtuner *microtuner()
{
return &m_microtuner;
}

bool isArpeggioEnabled() const
{
return m_arpeggio.m_arpEnabledModel.value();
Expand Down Expand Up @@ -303,6 +309,8 @@ protected slots:

Piano m_piano;

Microtuner m_microtuner;

std::unique_ptr<BoolModel> m_midiCCEnable;
std::unique_ptr<FloatModel> m_midiCCModel[MidiControllerCount];

Expand Down
79 changes: 79 additions & 0 deletions include/Keymap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Keymap.h - holds information about a key mapping
*
* Copyright (c) 2020 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program 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 2 of the License, or (at your option) any later version.
*
* This program 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 this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef KEYMAP_H
#define KEYMAP_H

#include <vector>
#include <QObject>
#include <QString>

#include "Note.h"
#include "SerializingObject.h"

class Keymap : public QObject, public SerializingObject
{
Q_OBJECT
public:
Keymap();
Keymap(
const QString &description,
const std::vector<int> &newMap,
int newFirst,
int newLast,
int newMiddle,
int newBaseKey,
float newBaseFreq
);

QString getDescription() const;
void setDescription(const QString &description);

int getMiddleKey() const {return m_middleKey;}
int getFirstKey() const {return m_firstKey;}
int getLastKey() const {return m_lastKey;}
int getBaseKey() const {return m_baseKey;}
float getBaseFreq() const {return m_baseFreq;}

std::size_t getSize() const {return m_map.size();}
int getDegree(int key) const;
int getOctave(int key) const;
const std::vector<int> &getMap() const {return m_map;}

void saveSettings(QDomDocument &doc, QDomElement &element) override;
void loadSettings(const QDomElement &element) override;
inline QString nodeName() const override {return "keymap";}

private:
QString m_description; //!< name or description of the keymap

std::vector<int> m_map; //!< key to scale degree mapping
int m_firstKey; //!< first key that will be mapped
int m_lastKey; //!< last key that will be mapped
int m_middleKey; //!< first line of the map refers to this key
int m_baseKey; //!< key which is assigned the reference "base note"
float m_baseFreq; //!< frequency of the base note (usually A4 @440 Hz)
};

#endif
77 changes: 77 additions & 0 deletions include/Microtuner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Microtuner.h - manage tuning and scale information of an instrument
*
* Copyright (c) 2020 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program 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 2 of the License, or (at your option) any later version.
*
* This program 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 this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef MICROTUNER_H
#define MICROTUNER_H

#include "AutomatableModel.h"
#include "ComboBoxModel.h"
#include "JournallingObject.h"
#include "lmms_constants.h"
#include "Note.h"

class InstrumentTrack;

class LMMS_EXPORT Microtuner : public Model, public JournallingObject
{
Q_OBJECT
public:
explicit Microtuner(InstrumentTrack *parent);

bool enabled() const {return m_enabledModel.value();}
bool keyRangeImport() const {return enabled() && m_keyRangeImportModel.value();}

BoolModel *enabledModel() {return &m_enabledModel;}
ComboBoxModel *scaleModel() {return &m_scaleModel;}
ComboBoxModel *keymapModel() {return &m_keymapModel;}
BoolModel *keyRangeImportModel() {return &m_keyRangeImportModel;}

int firstKey() const;
int lastKey() const;
int middleKey() const;
int baseKey() const;
float baseFreq() const;

float keyToFreq(int key) const;
bool isKeyMapped(int key) const;

QString nodeName() const override {return "microtuner";}
void saveSettings(QDomDocument & document, QDomElement &element) override;
void loadSettings(const QDomElement &element) override;

protected slots:
void updateScaleList(int index);
void updateKeymapList(int index);

private:
InstrumentTrack *m_instrumentTrack; // Required to access base note etc. when range import is disabled

BoolModel m_enabledModel; //!< Enable microtuner (otherwise using 12-TET @440 Hz)
ComboBoxModel m_scaleModel;
ComboBoxModel m_keymapModel;
BoolModel m_keyRangeImportModel;

};

#endif
5 changes: 0 additions & 5 deletions include/Mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ const int BYTES_PER_SURROUND_FRAME = sizeof( surroundSampleFrame );
const float OUTPUT_SAMPLE_MULTIPLIER = 32767.0f;


const float BaseFreq = 440.0f;
const Keys BaseKey = Key_A;
const Octaves BaseOctave = DefaultOctave;


#include "PlayHandle.h"


Expand Down
87 changes: 87 additions & 0 deletions include/Scale.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Scale.h - holds information about a scale and its intervals
*
* Copyright (c) 2020 Martin Pavelek <he29.HS/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program 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 2 of the License, or (at your option) any later version.
*
* This program 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 this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef SCALE_H
#define SCALE_H

#include <cmath>
#include <cstdint>
#include <vector>
#include <QObject>
#include <QString>

#include "SerializingObject.h"

class Interval : public SerializingObject
{
public:
Interval() : m_numerator(1), m_denominator(1), m_cents(0), m_ratio(1) {};
explicit Interval(float cents);
Interval(uint32_t numerator, uint32_t denominator);

float getRatio() const {return m_ratio;}

QString getString() const
{
if (m_denominator) {return QString::number(m_numerator) + "/" + QString::number(m_denominator);}
else {return QString().sprintf("%.4f", m_cents);}
}

void saveSettings(QDomDocument &doc, QDomElement &element) override;
void loadSettings(const QDomElement &element) override;
inline QString nodeName() const override {return "interval";}

private:
// Scala specifies that numerators and denominators should go at least up to 2147483647 → use uint32_t.
uint32_t m_numerator; //!< numerator of the interval fraction
uint32_t m_denominator; //!< denominator of the interval fraction
float m_cents; //!< interval defined in cents (used when denominator is set to zero)
float m_ratio; //!< precomputed output value for better performance
};


class Scale : public QObject, public SerializingObject
{
Q_OBJECT
public:
Scale();
Scale(const QString &description, const std::vector<Interval> &intervals);

QString getDescription() const;
void setDescription(const QString &description);

const std::vector<Interval> &getIntervals() const {return m_intervals;}
void setIntervals(std::vector<Interval> input) {m_intervals = std::move(input);}

void saveSettings(QDomDocument &doc, QDomElement &element) override;
void loadSettings(const QDomElement &element) override;
inline QString nodeName() const override {return "scale";}

private:
QString m_description; //!< name or description of the scale
std::vector<Interval> m_intervals; //!< a series of ratios that define the scale

};

#endif
20 changes: 20 additions & 0 deletions include/Song.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef SONG_H
#define SONG_H

#include <memory>
#include <utility>

#include <QtCore/QSharedMemory>
Expand All @@ -34,8 +35,11 @@

#include "TrackContainer.h"
#include "Controller.h"
#include "Keymap.h"
#include "lmms_constants.h"
#include "MeterModel.h"
#include "Mixer.h"
#include "Scale.h"
#include "VstSyncController.h"


Expand Down Expand Up @@ -350,6 +354,11 @@ class LMMS_EXPORT Song : public TrackContainer

bool isSavingProject() const;

std::shared_ptr<const Scale> getScale(unsigned int index) const;
std::shared_ptr<const Keymap> getKeymap(unsigned int index) const;
void setScale(unsigned int index, std::shared_ptr<Scale> newScale);
void setKeymap(unsigned int index, std::shared_ptr<Keymap> newMap);

public slots:
void playSong();
void record();
Expand Down Expand Up @@ -416,6 +425,12 @@ private slots:

void removeAllControllers();

void saveScaleStates(QDomDocument &doc, QDomElement &element);
void restoreScaleStates(const QDomElement &element);

void saveKeymapStates(QDomDocument &doc, QDomElement &element);
void restoreKeymapStates(const QDomElement &element);

void processAutomations(const TrackList& tracks, TimePos timeStart, fpp_t frames);

void setModified(bool value);
Expand Down Expand Up @@ -475,6 +490,9 @@ private slots:
TimePos m_exportSongEnd;
TimePos m_exportEffectiveLength;

std::shared_ptr<Scale> m_scales[MaxScaleCount];
std::shared_ptr<Keymap> m_keymaps[MaxKeymapCount];

AutomatedValueMap m_oldAutomatedValues;

friend class LmmsCore;
Expand All @@ -495,6 +513,8 @@ private slots:
void stopped();
void modified();
void projectFileNameChanged();
void scaleListChanged(int index);
void keymapListChanged(int index);
} ;


Expand Down
6 changes: 5 additions & 1 deletion include/lmms_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ const float F_PI_SQR = (float) LD_PI_SQR;
const float F_E = (float) LD_E;
const float F_E_R = (float) LD_E_R;

// Microtuner
const unsigned int MaxScaleCount = 10; //!< number of scales per project
const unsigned int MaxKeymapCount = 10; //!< number of keyboard mappings per project

// Frequency ranges (in Hz).
// Arbitrary low limit for logarithmic frequency scale; >1 Hz.
const int LOWEST_LOG_FREQ = 10;
const int LOWEST_LOG_FREQ = 5;

// Full range is defined by LOWEST_LOG_FREQ and current sample rate.
enum FREQUENCY_RANGES
Expand Down
3 changes: 2 additions & 1 deletion plugins/audio_file_processor/audio_file_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ QString audioFileProcessor::nodeName( void ) const

int audioFileProcessor::getBeatLen( NotePlayHandle * _n ) const
{
const float freq_factor = BaseFreq / _n->frequency() *
const auto baseFreq = instrumentTrack()->microtuner()->baseFreq();
const float freq_factor = baseFreq / _n->frequency() *
Engine::mixer()->processingSampleRate() / Engine::mixer()->baseSampleRate();

return static_cast<int>( floorf( ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() ) * freq_factor ) );
Expand Down
Loading