Merge pull request #6335 from igorkorsukov/mu4/audio_midi
[MU4] Audio midi
This commit is contained in:
commit
0231e81024
87 changed files with 23294 additions and 63 deletions
|
@ -26,6 +26,7 @@
|
|||
# set(MODULE_QRC somename.qrc) - set resource (qrc) file
|
||||
# set(MODULE_UI ...) - set ui headers
|
||||
# set(MODULE_QML_IMPORT ...) - set Qml import for QtCreator (so that there is code highlighting, jump, etc.)
|
||||
# set(MODULE_HAS_C_CODE, 1) - set if source contains C code
|
||||
|
||||
# After all the settings you need to do:
|
||||
# include(${PROJECT_SOURCE_DIR}/build/module.cmake)
|
||||
|
@ -77,19 +78,28 @@ target_link_libraries(${MODULE}
|
|||
${MODULE_LINK}
|
||||
)
|
||||
|
||||
if (NOT MSVC)
|
||||
set_target_properties (${MODULE} PROPERTIES COMPILE_FLAGS "${PCH_INCLUDE} -g -Wall -Wextra -Winvalid-pch")
|
||||
else (NOT MSVC)
|
||||
set_target_properties (${MODULE} PROPERTIES COMPILE_FLAGS "${PCH_INCLUDE}" )
|
||||
endif (NOT MSVC)
|
||||
if (MODULE_HAS_C_CODE)
|
||||
|
||||
xcode_pch(${MODULE} all)
|
||||
set_target_properties( ${MODULE} PROPERTIES COMPILE_FLAGS "-fPIC")
|
||||
|
||||
# Use MSVC pre-compiled headers
|
||||
vstudio_pch( ${MODULE} )
|
||||
else(MODULE_HAS_C_CODE)
|
||||
|
||||
if (NOT MSVC)
|
||||
set_target_properties (${MODULE} PROPERTIES COMPILE_FLAGS "${PCH_INCLUDE} -g -Wall -Wextra -Winvalid-pch")
|
||||
else (NOT MSVC)
|
||||
set_target_properties (${MODULE} PROPERTIES COMPILE_FLAGS "${PCH_INCLUDE}" )
|
||||
endif (NOT MSVC)
|
||||
|
||||
xcode_pch(${MODULE} all)
|
||||
|
||||
# Use MSVC pre-compiled headers
|
||||
vstudio_pch( ${MODULE} )
|
||||
|
||||
# MSVC does not depend on mops1 & mops2 for PCH
|
||||
if (NOT MSVC)
|
||||
ADD_DEPENDENCIES(${MODULE} mops1)
|
||||
ADD_DEPENDENCIES(${MODULE} mops2)
|
||||
endif (NOT MSVC)
|
||||
|
||||
endif()
|
||||
|
||||
# MSVC does not depend on mops1 & mops2 for PCH
|
||||
if (NOT MSVC)
|
||||
ADD_DEPENDENCIES(${MODULE} mops1)
|
||||
ADD_DEPENDENCIES(${MODULE} mops2)
|
||||
endif (NOT MSVC)
|
||||
|
|
|
@ -7,6 +7,7 @@ add_subdirectory(shortcuts)
|
|||
add_subdirectory(workspace)
|
||||
|
||||
add_subdirectory(audio/engine)
|
||||
add_subdirectory(audio/midi)
|
||||
|
||||
if (BUILD_TELEMETRY_MODULE)
|
||||
add_subdirectory(telemetry)
|
||||
|
|
|
@ -47,12 +47,17 @@ set(MODULE_SRC
|
|||
${CMAKE_CURRENT_LIST_DIR}/iaudioengine.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/iaudiosource.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/audioerrors.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/iaudioplayer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/sinesource.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/sinesource.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/midisource.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/midisource.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/audioengine.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/audioengine.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/audioplayer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/audioplayer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/devtools/audioenginedevtools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/devtools/audioenginedevtools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/devtools/sinestream.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/devtools/sinestream.h
|
||||
)
|
||||
|
||||
set(MODULE_DEF
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "modularity/ioc.h"
|
||||
#include "internal/audioengine.h"
|
||||
#include "internal/audioplayer.h"
|
||||
|
||||
#include "devtools/audioenginedevtools.h"
|
||||
|
||||
|
@ -45,6 +46,7 @@ std::string AudioEngineModule::moduleName() const
|
|||
void AudioEngineModule::registerExports()
|
||||
{
|
||||
framework::ioc()->registerExport<IAudioEngine>(moduleName(), audioEngine);
|
||||
framework::ioc()->registerExport<IAudioPlayer>(moduleName(), new AudioPlayer());
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
framework::ioc()->registerExport<IAudioDriver>(moduleName(), new LinuxAudioDriver());
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "audioenginedevtools.h"
|
||||
|
||||
using namespace mu::audio::engine;
|
||||
using namespace mu::audio::midi;
|
||||
|
||||
AudioEngineDevTools::AudioEngineDevTools(QObject* parent)
|
||||
: QObject(parent)
|
||||
|
@ -27,10 +28,73 @@ AudioEngineDevTools::AudioEngineDevTools(QObject* parent)
|
|||
|
||||
void AudioEngineDevTools::playSine()
|
||||
{
|
||||
m_sineHandle = engine()->play(&m_sineStream);
|
||||
if (!m_sineSource) {
|
||||
m_sineSource = std::make_shared<SineSource>();
|
||||
}
|
||||
m_sineHandle = audioEngine()->play(m_sineSource);
|
||||
}
|
||||
|
||||
void AudioEngineDevTools::stopSine()
|
||||
{
|
||||
engine()->stop(m_sineHandle);
|
||||
audioEngine()->stop(m_sineHandle);
|
||||
}
|
||||
|
||||
void AudioEngineDevTools::playSourceMidi()
|
||||
{
|
||||
if (!m_midiSource) {
|
||||
m_midiSource = std::make_shared<MidiSource>();
|
||||
}
|
||||
|
||||
if (!m_midiData) {
|
||||
m_midiData = makeArpeggio();
|
||||
m_midiSource->init(audioEngine()->sampleRate());
|
||||
m_midiSource->loadMIDI(m_midiData);
|
||||
}
|
||||
|
||||
m_midiHandel = audioEngine()->play(m_midiSource);
|
||||
}
|
||||
|
||||
void AudioEngineDevTools::stopSourceMidi()
|
||||
{
|
||||
audioEngine()->stop(m_midiHandel);
|
||||
}
|
||||
|
||||
void AudioEngineDevTools::playPlayerMidi()
|
||||
{
|
||||
if (!m_midiData) {
|
||||
m_midiData = makeArpeggio();
|
||||
}
|
||||
|
||||
player()->setMidiData(m_midiData);
|
||||
player()->play();
|
||||
}
|
||||
|
||||
void AudioEngineDevTools::stopPlayerMidi()
|
||||
{
|
||||
player()->stop();
|
||||
}
|
||||
|
||||
std::shared_ptr<MidiData> AudioEngineDevTools::makeArpeggio() const
|
||||
{
|
||||
/* notes of the arpeggio */
|
||||
static std::vector<int> notes = { 60, 64, 67, 72, 76, 79, 84, 79, 76, 72, 67, 64 };
|
||||
static uint64_t duration = 4440;
|
||||
|
||||
uint64_t note_duration = duration / notes.size();
|
||||
uint64_t note_time = 0;
|
||||
|
||||
Channel ch;
|
||||
for (int n : notes) {
|
||||
ch.events.push_back(Event(note_time, ME_NOTEON, n, 100));
|
||||
note_time += note_duration;
|
||||
ch.events.push_back(Event(note_time, ME_NOTEOFF, n, 100));
|
||||
}
|
||||
|
||||
Track t;
|
||||
t.channels.push_back(ch);
|
||||
|
||||
std::shared_ptr<MidiData> data = std::make_shared<MidiData>();
|
||||
data->tracks.push_back(t);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
#include "modularity/ioc.h"
|
||||
#include "audio/engine/iaudioengine.h"
|
||||
#include "sinestream.h"
|
||||
#include "audio/engine/iaudioplayer.h"
|
||||
#include "sinesource.h"
|
||||
#include "midisource.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
|
@ -31,7 +33,8 @@ namespace engine {
|
|||
class AudioEngineDevTools : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
INJECT(audio, IAudioEngine, engine)
|
||||
INJECT(audio, IAudioEngine, audioEngine)
|
||||
INJECT(audio, IAudioPlayer, player)
|
||||
|
||||
public:
|
||||
explicit AudioEngineDevTools(QObject* parent = nullptr);
|
||||
|
@ -39,10 +42,22 @@ public:
|
|||
Q_INVOKABLE void playSine();
|
||||
Q_INVOKABLE void stopSine();
|
||||
|
||||
Q_INVOKABLE void playSourceMidi();
|
||||
Q_INVOKABLE void stopSourceMidi();
|
||||
|
||||
Q_INVOKABLE void playPlayerMidi();
|
||||
Q_INVOKABLE void stopPlayerMidi();
|
||||
|
||||
private:
|
||||
|
||||
SineStream m_sineStream;
|
||||
std::shared_ptr<midi::MidiData> makeArpeggio() const;
|
||||
|
||||
std::shared_ptr<SineSource> m_sineSource;
|
||||
IAudioEngine::handle m_sineHandle = 0;
|
||||
|
||||
std::shared_ptr<midi::MidiData> m_midiData;
|
||||
std::shared_ptr<MidiSource> m_midiSource;
|
||||
IAudioEngine::handle m_midiHandel = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "modularity/imoduleexport.h"
|
||||
|
||||
#include "ret.h"
|
||||
#include "iaudiosource.h"
|
||||
|
||||
namespace mu {
|
||||
|
@ -38,12 +39,16 @@ public:
|
|||
using handle = unsigned int;
|
||||
using time = float;
|
||||
|
||||
virtual Ret init() = 0;
|
||||
virtual void deinit() = 0;
|
||||
virtual bool isInited() const = 0;
|
||||
|
||||
virtual float sampleRate() const = 0;
|
||||
|
||||
virtual handle play(IAudioSource* s, float volume = -1, float pan = 0, bool paused = false) = 0;
|
||||
virtual handle play(std::shared_ptr<IAudioSource> src, float volume = -1, float pan = 0, bool paused = false) = 0;
|
||||
virtual void seek(time sec) = 0;
|
||||
virtual void stop(handle h) = 0;
|
||||
virtual void pause(handle h, bool paused) = 0;
|
||||
virtual void setPause(handle h, bool paused) = 0;
|
||||
|
||||
virtual time position(handle h) const = 0;
|
||||
virtual bool isEnded(handle h) const = 0;
|
||||
|
|
69
framework/audio/engine/iaudioplayer.h
Normal file
69
framework/audio/engine/iaudioplayer.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#ifndef MU_AUDIO_IAUDIOPLAYER_H
|
||||
#define MU_AUDIO_IAUDIOPLAYER_H
|
||||
|
||||
#include "modularity/imoduleexport.h"
|
||||
|
||||
#include "retval.h"
|
||||
#include "audio/midi/miditypes.h"
|
||||
|
||||
//! NOTE This is the main public playback control interface for consumers,
|
||||
//! so namespace is just mu::audio
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
enum class PlayStatus {
|
||||
UNDEFINED = 0,
|
||||
STOPED,
|
||||
PLAYING,
|
||||
PAUSED
|
||||
};
|
||||
|
||||
class IAudioPlayer : MODULE_EXPORT_INTERFACE
|
||||
{
|
||||
INTERFACE_ID(IAudioPlayer)
|
||||
|
||||
public:
|
||||
virtual ~IAudioPlayer() = default;
|
||||
|
||||
virtual ValCh<PlayStatus> status() const = 0;
|
||||
|
||||
// data
|
||||
virtual void setMidiData(std::shared_ptr<midi::MidiData> midi) = 0;
|
||||
|
||||
// Action
|
||||
virtual bool play() = 0;
|
||||
virtual void pause() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void rewind() = 0;
|
||||
|
||||
virtual float playbackPosition() const = 0; // sec
|
||||
virtual void setPlaybackPosition(float sec) = 0; // sec
|
||||
|
||||
// General
|
||||
virtual float generalVolume() const = 0; // 0.0 to 1.0.
|
||||
virtual void setGeneralVolume(float v) = 0; // 0.0 to 1.0.
|
||||
virtual float generalBalance() const = 0;
|
||||
virtual void setGeneralBalance(float b) = 0; // -1.0 only left, 0.0 center, 1.0 only right
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_IAUDIOPLAYER_H
|
|
@ -105,7 +105,7 @@ float AudioEngine::sampleRate() const
|
|||
return m_sl->engine.getBackendSamplerate();
|
||||
}
|
||||
|
||||
IAudioEngine::handle AudioEngine::play(IAudioSource* s, float volume, float pan, bool paused)
|
||||
IAudioEngine::handle AudioEngine::play(std::shared_ptr<IAudioSource> s, float volume, float pan, bool paused)
|
||||
{
|
||||
IF_ASSERT_FAILED(s) {
|
||||
return 0;
|
||||
|
@ -146,7 +146,7 @@ void AudioEngine::stop(handle h)
|
|||
m_sources.erase(h);
|
||||
}
|
||||
|
||||
void AudioEngine::pause(handle h, bool paused)
|
||||
void AudioEngine::setPause(handle h, bool paused)
|
||||
{
|
||||
LOGI() << (paused ? "pause" : "resume");
|
||||
|
||||
|
|
|
@ -39,16 +39,16 @@ class AudioEngine : public IAudioEngine
|
|||
public:
|
||||
AudioEngine();
|
||||
|
||||
Ret init();
|
||||
void deinit();
|
||||
bool isInited() const;
|
||||
Ret init() override;
|
||||
void deinit() override;
|
||||
bool isInited() const override;
|
||||
|
||||
float sampleRate() const override;
|
||||
|
||||
handle play(IAudioSource* s, float volume = -1, float pan = 0, bool paused = false) override;
|
||||
handle play(std::shared_ptr<IAudioSource> s, float volume = -1, float pan = 0, bool paused = false) override;
|
||||
void seek(time sec) override;
|
||||
void stop(handle h) override;
|
||||
void pause(handle h, bool paused) override;
|
||||
void setPause(handle h, bool paused) override;
|
||||
|
||||
void syncAll(time sec);
|
||||
void stopAll();
|
||||
|
@ -64,12 +64,12 @@ private:
|
|||
|
||||
struct SL;
|
||||
std::shared_ptr<SL> m_sl;
|
||||
bool m_inited{ false };
|
||||
bool m_inited = false;
|
||||
|
||||
struct Source {
|
||||
handle handel;
|
||||
IAudioSource* source{ nullptr };
|
||||
bool playing{ false };
|
||||
handle handel = 0;
|
||||
std::shared_ptr<IAudioSource> source;
|
||||
bool playing = false;
|
||||
};
|
||||
|
||||
std::map<handle, Source> m_sources;
|
||||
|
|
238
framework/audio/engine/internal/audioplayer.cpp
Normal file
238
framework/audio/engine/internal/audioplayer.cpp
Normal file
|
@ -0,0 +1,238 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#include "audioplayer.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
using namespace mu;
|
||||
using namespace mu::audio;
|
||||
using namespace mu::audio::engine;
|
||||
|
||||
template<class T>
|
||||
static const T& clamp(const T& v, const T& lo, const T& hi)
|
||||
{
|
||||
return (v < lo) ? lo : (hi < v) ? hi : v;
|
||||
}
|
||||
|
||||
AudioPlayer::AudioPlayer()
|
||||
{
|
||||
m_status.val = PlayStatus::UNDEFINED;
|
||||
}
|
||||
|
||||
void AudioPlayer::setMidiData(std::shared_ptr<midi::MidiData> midi)
|
||||
{
|
||||
if (midi) {
|
||||
m_midiSource = std::make_shared<MidiSource>();
|
||||
m_midiSource->loadMIDI(midi);
|
||||
|
||||
m_tracks.clear();
|
||||
for (size_t num = 0; num < midi->tracks.size(); ++num) {
|
||||
m_tracks[num] = std::make_shared<Track>();
|
||||
}
|
||||
|
||||
m_status.set(PlayStatus::STOPED);
|
||||
} else {
|
||||
m_tracks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioPlayer::play()
|
||||
{
|
||||
LOGD() << "try play \n";
|
||||
if (m_status.val == PlayStatus::PLAYING) {
|
||||
LOGW() << "already playing \n";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!doPlay()) {
|
||||
LOGE() << "failed do play \n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_status.set(PlayStatus::PLAYING);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioPlayer::pause()
|
||||
{
|
||||
doPause();
|
||||
m_status.set(PlayStatus::PAUSED);
|
||||
}
|
||||
|
||||
void AudioPlayer::stop()
|
||||
{
|
||||
doStop();
|
||||
m_status.set(PlayStatus::STOPED);
|
||||
}
|
||||
|
||||
void AudioPlayer::rewind()
|
||||
{
|
||||
doStop();
|
||||
m_status.set(PlayStatus::STOPED);
|
||||
}
|
||||
|
||||
bool AudioPlayer::init()
|
||||
{
|
||||
if (m_inited && audioEngine()->isInited()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_inited = audioEngine()->init();
|
||||
if (m_inited) {
|
||||
if (m_midiSource) {
|
||||
float samplerate = audioEngine()->sampleRate();
|
||||
m_midiSource->init(samplerate);
|
||||
}
|
||||
|
||||
m_inited = true;
|
||||
}
|
||||
return m_inited;
|
||||
}
|
||||
|
||||
bool AudioPlayer::isInited() const
|
||||
{
|
||||
return m_inited;
|
||||
}
|
||||
|
||||
bool AudioPlayer::doPlay()
|
||||
{
|
||||
if (!init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasTracks()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IF_ASSERT_FAILED(m_midiSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_midiHandle) {
|
||||
m_midiHandle = audioEngine()->play(m_midiSource, -1, 0, true); // paused
|
||||
}
|
||||
|
||||
audioEngine()->seek(m_beginPlayPosition);
|
||||
audioEngine()->setPause(m_midiHandle, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioPlayer::doPause()
|
||||
{
|
||||
m_beginPlayPosition = m_currentPlayPosition;
|
||||
if (m_midiHandle) {
|
||||
audioEngine()->setPause(m_midiHandle, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::doStop()
|
||||
{
|
||||
m_beginPlayPosition = 0;
|
||||
m_currentPlayPosition = 0;
|
||||
audioEngine()->stop(m_midiHandle);
|
||||
m_midiHandle = 0;
|
||||
}
|
||||
|
||||
float AudioPlayer::playbackPosition() const
|
||||
{
|
||||
if (m_status.val == PlayStatus::PLAYING) {
|
||||
return m_currentPlayPosition;
|
||||
}
|
||||
return m_beginPlayPosition;
|
||||
}
|
||||
|
||||
void AudioPlayer::setPlaybackPosition(float sec)
|
||||
{
|
||||
sec = std::max(sec, 0.f);
|
||||
|
||||
m_beginPlayPosition = sec;
|
||||
m_currentPlayPosition = sec;
|
||||
|
||||
if (m_status.val == PlayStatus::PLAYING) {
|
||||
audioEngine()->seek(sec);
|
||||
}
|
||||
}
|
||||
|
||||
float AudioPlayer::generalVolume() const
|
||||
{
|
||||
return m_generalVolume;
|
||||
}
|
||||
|
||||
void AudioPlayer::setGeneralVolume(float v)
|
||||
{
|
||||
m_generalVolume = clamp(v, 0.f, 1.27f); //! NOTE 127 - midi limitation
|
||||
|
||||
if (!isInited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyCurrentVolume();
|
||||
}
|
||||
|
||||
float AudioPlayer::generalBalance() const
|
||||
{
|
||||
return m_generalBalance;
|
||||
}
|
||||
|
||||
void AudioPlayer::setGeneralBalance(float b)
|
||||
{
|
||||
m_generalBalance = clamp(b, -1.f, 1.f);
|
||||
|
||||
if (!isInited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyCurrentBalance();
|
||||
}
|
||||
|
||||
float AudioPlayer::normalizedVolume(float volume) const
|
||||
{
|
||||
return clamp(m_generalVolume * volume, 0.f, 1.27f); //! NOTE 127 - midi limitation
|
||||
}
|
||||
|
||||
float AudioPlayer::normalizedBalance(float balance) const
|
||||
{
|
||||
return clamp(m_generalBalance + balance, -1.f, 1.f);
|
||||
}
|
||||
|
||||
void AudioPlayer::applyCurrentVolume()
|
||||
{
|
||||
for (const auto& p : m_tracks) {
|
||||
m_midiSource->setTrackVolume(p.first, normalizedVolume(p.second->volume));
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::applyCurrentBalance()
|
||||
{
|
||||
for (const auto& p : m_tracks) {
|
||||
m_midiSource->setTrackBalance(p.first, normalizedBalance(p.second->balance));
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioPlayer::hasTracks() const
|
||||
{
|
||||
return m_tracks.size() > 0;
|
||||
}
|
||||
|
||||
ValCh<PlayStatus> AudioPlayer::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
98
framework/audio/engine/internal/audioplayer.h
Normal file
98
framework/audio/engine/internal/audioplayer.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#ifndef MU_AUDIO_AUDIOPLAYER_H
|
||||
#define MU_AUDIO_AUDIOPLAYER_H
|
||||
|
||||
#include "../iaudioplayer.h"
|
||||
|
||||
#include "modularity/ioc.h"
|
||||
#include "../iaudioengine.h"
|
||||
|
||||
#include "midisource.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
class AudioPlayer : public IAudioPlayer
|
||||
{
|
||||
INJECT(audio, engine::IAudioEngine, audioEngine)
|
||||
|
||||
public:
|
||||
AudioPlayer();
|
||||
|
||||
ValCh<PlayStatus> status() const override;
|
||||
|
||||
// data
|
||||
void setMidiData(std::shared_ptr<midi::MidiData> midi) override;
|
||||
|
||||
// Action
|
||||
bool play() override;
|
||||
void pause() override;
|
||||
void stop() override;
|
||||
void rewind() override;
|
||||
|
||||
float playbackPosition() const override;
|
||||
void setPlaybackPosition(float sec) override;
|
||||
|
||||
// General
|
||||
float generalVolume() const override;
|
||||
void setGeneralVolume(float v) override;
|
||||
float generalBalance() const override;
|
||||
void setGeneralBalance(float b) override;
|
||||
|
||||
private:
|
||||
|
||||
struct Track {
|
||||
bool muted = false;
|
||||
float volume = 1.0f;
|
||||
float balance = 0.0f;
|
||||
};
|
||||
|
||||
bool init();
|
||||
bool isInited() const;
|
||||
bool doPlay();
|
||||
void doPause();
|
||||
void doStop();
|
||||
|
||||
bool hasTracks() const;
|
||||
|
||||
float normalizedVolume(float volume) const;
|
||||
float normalizedBalance(float balance) const;
|
||||
|
||||
void applyCurrentVolume();
|
||||
void applyCurrentBalance();
|
||||
|
||||
bool m_inited = false;
|
||||
ValCh<PlayStatus> m_status;
|
||||
|
||||
std::shared_ptr<midi::MidiData> m_midi;
|
||||
std::shared_ptr<engine::MidiSource> m_midiSource;
|
||||
engine::IAudioEngine::handle m_midiHandle = 0;
|
||||
|
||||
float m_beginPlayPosition = 0.0f;
|
||||
float m_currentPlayPosition = 0.0f;
|
||||
|
||||
float m_generalVolume = 1.0f;
|
||||
float m_generalBalance = 0.0f;
|
||||
|
||||
std::map<int, std::shared_ptr<Track> > m_tracks;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_AUDIOPLAYER_H
|
129
framework/audio/engine/midisource.cpp
Normal file
129
framework/audio/engine/midisource.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#include "midisource.h"
|
||||
|
||||
#include <soloud.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
using namespace mu::audio::engine;
|
||||
using namespace mu::audio::midi;
|
||||
|
||||
struct MidiSource::SLInstance : public SoLoud::AudioSourceInstance {
|
||||
std::shared_ptr<ISequencer> seq;
|
||||
|
||||
SLInstance(std::shared_ptr<ISequencer> s)
|
||||
: seq(s)
|
||||
{
|
||||
seq->run(mStreamTime);
|
||||
}
|
||||
|
||||
~SLInstance() override
|
||||
{
|
||||
seq->stop();
|
||||
}
|
||||
|
||||
SoLoud::result seek_frame(double sec) override
|
||||
{
|
||||
seq->seek(sec);
|
||||
return SoLoud::SO_NO_ERROR;
|
||||
}
|
||||
|
||||
unsigned int getAudio(float* aBuffer, unsigned int aSamplesToRead, unsigned int /*aBufferSize*/) override
|
||||
{
|
||||
seq->getAudio(mStreamTime, aBuffer, aSamplesToRead);
|
||||
return aSamplesToRead;
|
||||
}
|
||||
|
||||
bool hasEnded() override
|
||||
{
|
||||
return seq->hasEnded();
|
||||
}
|
||||
};
|
||||
|
||||
struct MidiSource::SL : public SoLoud::AudioSource {
|
||||
std::shared_ptr<ISequencer> seq;
|
||||
~SL() override {}
|
||||
|
||||
SoLoud::AudioSourceInstance* createInstance() override
|
||||
{
|
||||
return new SLInstance(seq);
|
||||
}
|
||||
};
|
||||
|
||||
MidiSource::MidiSource()
|
||||
{
|
||||
m_seq = sequencer();
|
||||
|
||||
m_sl = std::make_shared<MidiSource::SL>();
|
||||
m_sl->mChannels = 2;
|
||||
m_sl->seq = m_seq;
|
||||
}
|
||||
|
||||
void MidiSource::setSampleRate(float samplerate)
|
||||
{
|
||||
m_sl->mBaseSamplerate = samplerate;
|
||||
}
|
||||
|
||||
void MidiSource::sync(float sec)
|
||||
{
|
||||
m_seq->seek(sec);
|
||||
}
|
||||
|
||||
SoLoud::AudioSource* MidiSource::source()
|
||||
{
|
||||
return m_sl.get();
|
||||
}
|
||||
|
||||
void MidiSource::loadMIDI(const std::shared_ptr<midi::MidiData>& midi)
|
||||
{
|
||||
m_seq->loadMIDI(midi);
|
||||
}
|
||||
|
||||
void MidiSource::init(float samplerate)
|
||||
{
|
||||
m_seq->init(samplerate);
|
||||
setSampleRate(samplerate);
|
||||
}
|
||||
|
||||
float MidiSource::playbackSpeed() const
|
||||
{
|
||||
return m_seq->playbackSpeed();
|
||||
}
|
||||
|
||||
void MidiSource::setPlaybackSpeed(float speed)
|
||||
{
|
||||
m_seq->setPlaybackSpeed(speed);
|
||||
}
|
||||
|
||||
void MidiSource::setIsTrackMuted(int ti, bool mute)
|
||||
{
|
||||
m_seq->setIsTrackMuted(ti, mute);
|
||||
}
|
||||
|
||||
void MidiSource::setTrackVolume(int ti, float volume)
|
||||
{
|
||||
m_seq->setTrackVolume(ti, volume);
|
||||
}
|
||||
|
||||
void MidiSource::setTrackBalance(int ti, float balance)
|
||||
{
|
||||
m_seq->setTrackBalance(ti, balance);
|
||||
}
|
67
framework/audio/engine/midisource.h
Normal file
67
framework/audio/engine/midisource.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_MIDISOURCE_H
|
||||
#define MU_AUDIO_MIDISOURCE_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "iaudiosource.h"
|
||||
|
||||
#include "modularity/ioc.h"
|
||||
#include "audio/midi/isequencer.h"
|
||||
#include "audio/midi/miditypes.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace engine {
|
||||
class MidiSource : public IAudioSource
|
||||
{
|
||||
INJECT(audio_engine, midi::ISequencer, sequencer)
|
||||
|
||||
public:
|
||||
MidiSource();
|
||||
|
||||
void setSampleRate(float samplerate) override;
|
||||
void sync(float sec) override;
|
||||
SoLoud::AudioSource* source() override;
|
||||
|
||||
void loadMIDI(const std::shared_ptr<midi::MidiData>& midi);
|
||||
void init(float samplerate);
|
||||
|
||||
float playbackSpeed() const;
|
||||
void setPlaybackSpeed(float speed);
|
||||
|
||||
void setIsTrackMuted(int ti, bool mute);
|
||||
void setTrackVolume(int ti, float volume);
|
||||
void setTrackBalance(int ti, float balance);
|
||||
|
||||
private:
|
||||
|
||||
struct SL;
|
||||
struct SLInstance;
|
||||
std::shared_ptr<SL> m_sl;
|
||||
std::shared_ptr<midi::ISequencer> m_seq;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_MIDISOURCE_H
|
|
@ -16,7 +16,7 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#include "sinestream.h"
|
||||
#include "sinesource.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
@ -27,11 +27,11 @@
|
|||
|
||||
using namespace mu::audio::engine;
|
||||
|
||||
struct SineStream::SLInstance : public SoLoud::AudioSourceInstance {
|
||||
std::shared_ptr<SineStream::Samples> samples;
|
||||
struct SineSource::SLInstance : public SoLoud::AudioSourceInstance {
|
||||
std::shared_ptr<SineSource::Samples> samples;
|
||||
size_t position = 0;
|
||||
|
||||
SLInstance(std::shared_ptr<SineStream::Samples> s)
|
||||
SLInstance(std::shared_ptr<SineSource::Samples> s)
|
||||
: samples(s) {}
|
||||
~SLInstance() override = default;
|
||||
|
||||
|
@ -60,8 +60,8 @@ struct SineStream::SLInstance : public SoLoud::AudioSourceInstance {
|
|||
}
|
||||
};
|
||||
|
||||
struct SineStream::SL : public SoLoud::AudioSource {
|
||||
std::shared_ptr<SineStream::Samples> samples;
|
||||
struct SineSource::SL : public SoLoud::AudioSource {
|
||||
std::shared_ptr<SineSource::Samples> samples;
|
||||
~SL() override = default;
|
||||
|
||||
SoLoud::AudioSourceInstance* createInstance() override
|
||||
|
@ -70,7 +70,7 @@ struct SineStream::SL : public SoLoud::AudioSource {
|
|||
}
|
||||
};
|
||||
|
||||
SineStream::SineStream()
|
||||
SineSource::SineSource()
|
||||
{
|
||||
m_samples = std::make_shared<Samples>();
|
||||
|
||||
|
@ -79,7 +79,7 @@ SineStream::SineStream()
|
|||
m_sl->samples = m_samples;
|
||||
}
|
||||
|
||||
void SineStream::generateSine(Samples& samples, float samplerate, float freq, int seconds) const
|
||||
void SineSource::generateSine(Samples& samples, float samplerate, float freq, int seconds) const
|
||||
{
|
||||
size_t buf_size = seconds * samplerate;
|
||||
samples.clear();
|
||||
|
@ -90,18 +90,18 @@ void SineStream::generateSine(Samples& samples, float samplerate, float freq, in
|
|||
}
|
||||
}
|
||||
|
||||
void SineStream::setSampleRate(float samplerate)
|
||||
void SineSource::setSampleRate(float samplerate)
|
||||
{
|
||||
m_sl->mBaseSamplerate = samplerate;
|
||||
generateSine(*m_samples.get(), samplerate, 340.0, 10);
|
||||
}
|
||||
|
||||
void SineStream::sync(float sec)
|
||||
void SineSource::sync(float sec)
|
||||
{
|
||||
UNUSED(sec);
|
||||
}
|
||||
|
||||
SoLoud::AudioSource* SineStream::source()
|
||||
SoLoud::AudioSource* SineSource::source()
|
||||
{
|
||||
return m_sl.get();
|
||||
}
|
|
@ -16,22 +16,22 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#ifndef MU_AUDIO_SINETREAM_H
|
||||
#define MU_AUDIO_SINETREAM_H
|
||||
#ifndef MU_AUDIO_SINESOURCE_H
|
||||
#define MU_AUDIO_SINESOURCE_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../iaudiosource.h"
|
||||
#include "iaudiosource.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace engine {
|
||||
class SineStream : public IAudioSource
|
||||
class SineSource : public IAudioSource
|
||||
{
|
||||
public:
|
||||
SineStream();
|
||||
~SineStream() = default;
|
||||
SineSource();
|
||||
~SineSource() = default;
|
||||
|
||||
void setSampleRate(float samplerate) override;
|
||||
void sync(float sec) override;
|
||||
|
@ -54,4 +54,4 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_SINETREAM_H
|
||||
#endif // MU_AUDIO_SINESOURCE_H
|
23
framework/audio/midi/3rdparty/fluidlite.cmake
vendored
Normal file
23
framework/audio/midi/3rdparty/fluidlite.cmake
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
set(FLUIDSYNTH_DIR ${CMAKE_CURRENT_LIST_DIR}//fluidlite)
|
||||
|
||||
set(FLUIDSYNTH_INC ${FLUIDSYNTH_DIR}/include)
|
||||
|
||||
set(FLUIDSYNTH_SRC
|
||||
${FLUIDSYNTH_DIR}/src/fluid_chan.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_chorus.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_conv.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_defsfont.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_dsp_float.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_gen.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_hash.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_list.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_mod.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_ramsfont.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_rev.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_settings.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_synth.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_sys.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_tuning.c
|
||||
${FLUIDSYNTH_DIR}/src/fluid_voice.c
|
||||
)
|
135
framework/audio/midi/3rdparty/fluidlite/CMakeLists.txt
vendored
Normal file
135
framework/audio/midi/3rdparty/fluidlite/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
include(FindPkgConfig)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
project(fluidlite)
|
||||
|
||||
list(APPEND HEADERS
|
||||
include/fluidlite.h
|
||||
)
|
||||
|
||||
list(APPEND SCOPED_HEADERS
|
||||
include/fluidsynth/types.h
|
||||
include/fluidsynth/settings.h
|
||||
include/fluidsynth/synth.h
|
||||
include/fluidsynth/sfont.h
|
||||
include/fluidsynth/ramsfont.h
|
||||
include/fluidsynth/log.h
|
||||
include/fluidsynth/misc.h
|
||||
include/fluidsynth/mod.h
|
||||
include/fluidsynth/gen.h
|
||||
include/fluidsynth/voice.h
|
||||
include/fluidsynth/version.h
|
||||
)
|
||||
|
||||
list(APPEND SOURCES
|
||||
src/fluid_chan.c
|
||||
src/fluid_chorus.c
|
||||
src/fluid_conv.c
|
||||
src/fluid_defsfont.c
|
||||
src/fluid_dsp_float.c
|
||||
src/fluid_gen.c
|
||||
src/fluid_hash.c
|
||||
src/fluid_list.c
|
||||
src/fluid_mod.c
|
||||
src/fluid_ramsfont.c
|
||||
src/fluid_rev.c
|
||||
src/fluid_settings.c
|
||||
src/fluid_synth.c
|
||||
src/fluid_sys.c
|
||||
src/fluid_tuning.c
|
||||
src/fluid_voice.c
|
||||
)
|
||||
|
||||
# Dependencies:
|
||||
pkg_check_modules(LIBVORBIS vorbis>=1.3.5)
|
||||
pkg_check_modules(LIBVORBISFILE vorbisfile>=1.3.5)
|
||||
if (NOT LIBVORBIS_FOUND OR NOT LIBVORBISFILE_FOUND)
|
||||
list(APPEND SOURCES
|
||||
libvorbis-1.3.5/lib/vorbisenc.c
|
||||
libvorbis-1.3.5/lib/info.c
|
||||
libvorbis-1.3.5/lib/analysis.c
|
||||
libvorbis-1.3.5/lib/bitrate.c
|
||||
libvorbis-1.3.5/lib/block.c
|
||||
libvorbis-1.3.5/lib/codebook.c
|
||||
libvorbis-1.3.5/lib/envelope.c
|
||||
libvorbis-1.3.5/lib/floor0.c
|
||||
libvorbis-1.3.5/lib/floor1.c
|
||||
libvorbis-1.3.5/lib/lookup.c
|
||||
libvorbis-1.3.5/lib/lpc.c
|
||||
libvorbis-1.3.5/lib/lsp.c
|
||||
libvorbis-1.3.5/lib/mapping0.c
|
||||
libvorbis-1.3.5/lib/mdct.c
|
||||
libvorbis-1.3.5/lib/psy.c
|
||||
libvorbis-1.3.5/lib/registry.c
|
||||
libvorbis-1.3.5/lib/res0.c
|
||||
libvorbis-1.3.5/lib/sharedbook.c
|
||||
libvorbis-1.3.5/lib/smallft.c
|
||||
libvorbis-1.3.5/lib/vorbisfile.c
|
||||
libvorbis-1.3.5/lib/window.c
|
||||
libvorbis-1.3.5/lib/synthesis.c
|
||||
)
|
||||
list(APPEND LIBVORBIS_INCLUDE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/libvorbis-1.3.5/include
|
||||
${CMAKE_SOURCE_DIR}/libvorbis-1.3.5/lib
|
||||
)
|
||||
message(WARNING "Using libvorbis shipped sources.")
|
||||
else()
|
||||
message(STATUS "Using pkg-config provided libvorbis")
|
||||
set(ADDITIONAL_LIBS "${LIBVORBIS_LDFLAGS} ${LIBVORBISFILE_LDFLAGS}")
|
||||
endif()
|
||||
|
||||
pkg_check_modules(LIBOGG ogg>=1.3.2)
|
||||
if (NOT LIBOGG_FOUND)
|
||||
list(APPEND SOURCES
|
||||
libogg-1.3.2/src/bitwise.c
|
||||
libogg-1.3.2/src/framing.c
|
||||
)
|
||||
set(LIBOGG_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libogg-1.3.2/include)
|
||||
message(WARNING "Using libogg shipped sources.")
|
||||
else()
|
||||
message(STATUS "Using pkg-config provided libogg")
|
||||
string(CONCAT ADDITIONAL_LIBS "${ADDITIONAL_LIBS} ${LIBOGG_LDFLAGS}")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories(${LIBOGG_INCLUDE_DIRS})
|
||||
include_directories(${LIBVORBIS_INCLUDE_DIRS})
|
||||
|
||||
option(FLUIDLITE_BUILD_STATIC "Build static library" TRUE)
|
||||
if(FLUIDLITE_BUILD_STATIC)
|
||||
add_library(${PROJECT_NAME}-static STATIC ${SOURCES})
|
||||
set_target_properties(${PROJECT_NAME}-static PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
set(FLUIDLITE_LIB_TARGET ${PROJECT_NAME}-static)
|
||||
set(FLUIDLITE_INSTALL_TARGETS ${FLUIDLITE_INSTALL_TARGETS} ";fluidlite-static")
|
||||
endif()
|
||||
|
||||
option(FLUIDLITE_BUILD_SHARED "Build shared library" TRUE)
|
||||
if(FLUIDLITE_BUILD_SHARED)
|
||||
add_library(${PROJECT_NAME} SHARED ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
${LIBVORBIS_LIBRARIES}
|
||||
${LIBVORBISFILE_LIBRARIES}
|
||||
${LIBOGG_LIBRARIES}
|
||||
)
|
||||
set(FLUIDLITE_LIB_TARGET ${PROJECT_NAME})
|
||||
set(FLUIDLITE_INSTALL_TARGETS ${FLUIDLITE_INSTALL_TARGETS} ";fluidlite")
|
||||
endif()
|
||||
|
||||
if(FLUIDLITE_BUILD_SHARED AND FLUIDLITE_BUILD_STATIC)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
set_target_properties(${PROJECT_NAME}-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
endif()
|
||||
|
||||
configure_file(fluidlite.pc.in ${CMAKE_BINARY_DIR}/fluidlite.pc @ONLY)
|
||||
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
|
||||
install(TARGETS ${FLUIDLITE_INSTALL_TARGETS}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${SCOPED_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fluidsynth)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fluidlite.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
15
framework/audio/midi/3rdparty/fluidlite/LICENSE
vendored
Normal file
15
framework/audio/midi/3rdparty/fluidlite/LICENSE
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
FluidLite (c) 2016 Robin Lobel
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
41
framework/audio/midi/3rdparty/fluidlite/README.md
vendored
Normal file
41
framework/audio/midi/3rdparty/fluidlite/README.md
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
FLUIDLITE 1.0 (c) 2016 Robin Lobel
|
||||
=========
|
||||
|
||||
FluidLite is a very light version of FluidSynth
|
||||
designed to be hardware, platform and external dependency independant.
|
||||
It only uses standard C libraries.
|
||||
|
||||
It also adds support for SF3 files (SF2 files compressed with ogg vorbis)
|
||||
and an additional setting to remove the constraint of channel 9 (drums):
|
||||
fluid_settings_setstr(settings, "synth.drums-channel.active", "no");
|
||||
you can still select bank 128 on any channel to use drum kits.
|
||||
|
||||
FluidLite keeps very minimal functionnalities (settings and synth),
|
||||
therefore MIDI file reading, realtime MIDI events and audio output must be
|
||||
implemented externally.
|
||||
|
||||
Usage:
|
||||
=====
|
||||
|
||||
include "fluidlite.h"
|
||||
|
||||
fluid_settings_t* settings=new_fluid_settings();
|
||||
fluid_synth_t* synth=new_fluid_synth(settings);
|
||||
fluid_synth_sfload(synth, "soundfont.sf3",1);
|
||||
|
||||
float* buffer=new float[44100*2];
|
||||
|
||||
FILE* file=fopen("float32output.pcm","wb");
|
||||
|
||||
fluid_synth_noteon(synth,0,60,127);
|
||||
fluid_synth_write_float(synth, 44100,buffer, 0, 2, buffer, 1, 2);
|
||||
fwrite(buffer,sizeof(float),44100*2,file);
|
||||
|
||||
fluid_synth_noteoff(synth,0,60);
|
||||
fluid_synth_write_float(synth, 44100,buffer, 0, 2, buffer, 1, 2);
|
||||
fwrite(buffer,sizeof(float),44100*2,file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
delete_fluid_synth(synth);
|
||||
delete_fluid_settings(settings);
|
10
framework/audio/midi/3rdparty/fluidlite/fluidlite.pc.in
vendored
Normal file
10
framework/audio/midi/3rdparty/fluidlite/fluidlite.pc.in
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: fluidlite
|
||||
Description: Software SoundFont synth
|
||||
Version: 0.0.1
|
||||
Libs: -L${libdir} -lfluidlite @ADDITIONAL_LIBS@
|
||||
Cflags: -I${includedir}
|
97
framework/audio/midi/3rdparty/fluidlite/include/fluidlite.h
vendored
Normal file
97
framework/audio/midi/3rdparty/fluidlite/include/fluidlite.h
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_H
|
||||
#define _FLUIDSYNTH_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//#if defined(WIN32)
|
||||
//#if defined(FLUIDSYNTH_DLL_EXPORTS)
|
||||
//#define FLUIDSYNTH_API __declspec(dllexport)
|
||||
//#elif defined(FLUIDSYNTH_NOT_A_DLL)
|
||||
//#define FLUIDSYNTH_API
|
||||
//#else
|
||||
//#define FLUIDSYNTH_API __declspec(dllimport)
|
||||
//#endif
|
||||
|
||||
//#elif defined(MACOS9)
|
||||
//#define FLUIDSYNTH_API __declspec(export)
|
||||
|
||||
//#else
|
||||
//#define FLUIDSYNTH_API
|
||||
//#endif
|
||||
|
||||
#define FLUIDSYNTH_API
|
||||
|
||||
/**
|
||||
* @file fluidsynth.h
|
||||
* @brief FluidSynth is a real-time synthesizer designed for SoundFont(R) files.
|
||||
*
|
||||
* This is the header of the fluidsynth library and contains the
|
||||
* synthesizer's public API.
|
||||
*
|
||||
* Depending on how you want to use or extend the synthesizer you
|
||||
* will need different API functions. You probably do not need all
|
||||
* of them. Here is what you might want to do:
|
||||
*
|
||||
* o Embedded synthesizer: create a new synthesizer and send MIDI
|
||||
* events to it. The sound goes directly to the audio output of
|
||||
* your system.
|
||||
*
|
||||
* o Plugin synthesizer: create a synthesizer and send MIDI events
|
||||
* but pull the audio back into your application.
|
||||
*
|
||||
* o SoundFont plugin: create a new type of "SoundFont" and allow
|
||||
* the synthesizer to load your type of SoundFonts.
|
||||
*
|
||||
* o MIDI input: Create a MIDI handler to read the MIDI input on your
|
||||
* machine and send the MIDI events directly to the synthesizer.
|
||||
*
|
||||
* o MIDI files: Open MIDI files and send the MIDI events to the
|
||||
* synthesizer.
|
||||
*
|
||||
* o Command lines: You can send textual commands to the synthesizer.
|
||||
*
|
||||
* SoundFont(R) is a registered trademark of E-mu Systems, Inc.
|
||||
*/
|
||||
|
||||
#include "fluidsynth/types.h"
|
||||
#include "fluidsynth/settings.h"
|
||||
#include "fluidsynth/synth.h"
|
||||
#include "fluidsynth/sfont.h"
|
||||
#include "fluidsynth/ramsfont.h"
|
||||
#include "fluidsynth/log.h"
|
||||
#include "fluidsynth/misc.h"
|
||||
#include "fluidsynth/mod.h"
|
||||
#include "fluidsynth/gen.h"
|
||||
#include "fluidsynth/voice.h"
|
||||
#include "fluidsynth/version.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_H */
|
135
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/gen.h
vendored
Normal file
135
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/gen.h
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_GEN_H
|
||||
#define _FLUIDSYNTH_GEN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file gen.h
|
||||
* @brief Functions and defines for SoundFont generator effects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3)
|
||||
*/
|
||||
enum fluid_gen_type {
|
||||
GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
|
||||
GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
|
||||
GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
|
||||
GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
|
||||
GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
|
||||
GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
|
||||
GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
|
||||
GEN_FILTERFC, /**< Filter cutoff */
|
||||
GEN_FILTERQ, /**< Filter Q */
|
||||
GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
|
||||
GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
|
||||
GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
|
||||
GEN_UNUSED1, /**< Unused */
|
||||
GEN_CHORUSSEND, /**< Chorus send amount */
|
||||
GEN_REVERBSEND, /**< Reverb send amount */
|
||||
GEN_PAN, /**< Stereo panning */
|
||||
GEN_UNUSED2, /**< Unused */
|
||||
GEN_UNUSED3, /**< Unused */
|
||||
GEN_UNUSED4, /**< Unused */
|
||||
GEN_MODLFODELAY, /**< Modulation LFO delay */
|
||||
GEN_MODLFOFREQ, /**< Modulation LFO frequency */
|
||||
GEN_VIBLFODELAY, /**< Vibrato LFO delay */
|
||||
GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
|
||||
GEN_MODENVDELAY, /**< Modulation envelope delay */
|
||||
GEN_MODENVATTACK, /**< Modulation envelope attack */
|
||||
GEN_MODENVHOLD, /**< Modulation envelope hold */
|
||||
GEN_MODENVDECAY, /**< Modulation envelope decay */
|
||||
GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
|
||||
GEN_MODENVRELEASE, /**< Modulation envelope release */
|
||||
GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
|
||||
GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
|
||||
GEN_VOLENVDELAY, /**< Volume envelope delay */
|
||||
GEN_VOLENVATTACK, /**< Volume envelope attack */
|
||||
GEN_VOLENVHOLD, /**< Volume envelope hold */
|
||||
GEN_VOLENVDECAY, /**< Volume envelope decay */
|
||||
GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
|
||||
GEN_VOLENVRELEASE, /**< Volume envelope release */
|
||||
GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
|
||||
GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
|
||||
GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
|
||||
GEN_RESERVED1, /**< Reserved */
|
||||
GEN_KEYRANGE, /**< MIDI note range */
|
||||
GEN_VELRANGE, /**< MIDI velocity range */
|
||||
GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
|
||||
GEN_KEYNUM, /**< Fixed MIDI note number */
|
||||
GEN_VELOCITY, /**< Fixed MIDI velocity value */
|
||||
GEN_ATTENUATION, /**< Initial volume attenuation */
|
||||
GEN_RESERVED2, /**< Reserved */
|
||||
GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
|
||||
GEN_COARSETUNE, /**< Coarse tuning */
|
||||
GEN_FINETUNE, /**< Fine tuning */
|
||||
GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
|
||||
GEN_SAMPLEMODE, /**< Sample mode flags */
|
||||
GEN_RESERVED3, /**< Reserved */
|
||||
GEN_SCALETUNE, /**< Scale tuning */
|
||||
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
|
||||
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
||||
|
||||
/* the initial pitch is not a "standard" generator. It is not
|
||||
* mentioned in the list of generator in the SF2 specifications. It
|
||||
* is used, however, as the destination for the default pitch wheel
|
||||
* modulator. */
|
||||
GEN_PITCH, /**< Pitch (NOTE: Not a real SoundFont generator) */
|
||||
GEN_LAST /**< Value defines the count of generators (#fluid_gen_type) */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* SoundFont generator structure.
|
||||
*/
|
||||
typedef struct _fluid_gen_t
|
||||
{
|
||||
unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
|
||||
double val; /**< The nominal value */
|
||||
double mod; /**< Change by modulators */
|
||||
double nrpn; /**< Change by NRPN messages */
|
||||
} fluid_gen_t;
|
||||
|
||||
/**
|
||||
* Enum value for 'flags' field of #_fluid_gen_t (not really flags).
|
||||
*/
|
||||
enum fluid_gen_flags
|
||||
{
|
||||
GEN_UNUSED, /**< Generator value is not set */
|
||||
GEN_SET, /**< Generator value is set */
|
||||
GEN_ABS_NRPN /**< DOCME */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _FLUIDSYNTH_GEN_H */
|
||||
|
83
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/log.h
vendored
Normal file
83
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/log.h
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_LOG_H
|
||||
#define _FLUIDSYNTH_LOG_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @file log.h
|
||||
* @brief Logging interface
|
||||
*
|
||||
* The default logging function of the fluidsynth prints its messages
|
||||
* to the stderr. The synthesizer uses five level of messages: #FLUID_PANIC,
|
||||
* #FLUID_ERR, #FLUID_WARN, #FLUID_INFO, and #FLUID_DBG.
|
||||
*
|
||||
* A client application can install a new log function to handle the
|
||||
* messages differently. In the following example, the application
|
||||
* sets a callback function to display #FLUID_PANIC messages in a dialog,
|
||||
* and ignores all other messages by setting the log function to
|
||||
* NULL:
|
||||
*
|
||||
* DOCME (formatting)
|
||||
* fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window);
|
||||
* fluid_set_log_function(FLUID_ERR, NULL, NULL);
|
||||
* fluid_set_log_function(FLUID_WARN, NULL, NULL);
|
||||
* fluid_set_log_function(FLUID_DBG, NULL, NULL);
|
||||
*/
|
||||
|
||||
/**
|
||||
* FluidSynth log levels.
|
||||
*/
|
||||
enum fluid_log_level {
|
||||
FLUID_PANIC, /**< The synth can't function correctly any more */
|
||||
FLUID_ERR, /**< Serious error occurred */
|
||||
FLUID_WARN, /**< Warning */
|
||||
FLUID_INFO, /**< Verbose informational messages */
|
||||
FLUID_DBG, /**< Debugging messages */
|
||||
LAST_LOG_LEVEL
|
||||
};
|
||||
|
||||
/**
|
||||
* Log function handler callback type used by fluid_set_log_function().
|
||||
* @param level Log level (#fluid_log_level)
|
||||
* @param message Log message text
|
||||
* @param data User data pointer supplied to fluid_set_log_function().
|
||||
*/
|
||||
typedef void (*fluid_log_function_t)(int level, char* message, void* data);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void* data);
|
||||
|
||||
FLUIDSYNTH_API void fluid_default_log_function(int level, char* message, void* data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_log(int level, char * fmt, ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_LOG_H */
|
65
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/misc.h
vendored
Normal file
65
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/misc.h
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_MISC_H
|
||||
#define _FLUIDSYNTH_MISC_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* fluid_is_soundfont returns 1 if the specified filename is a
|
||||
* soundfont. It retuns 0 otherwise. The current implementation only
|
||||
* checks for the "RIFF" header in the file. It is useful only to
|
||||
* distinguish between SoundFonts and MIDI files.
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_is_soundfont(char* filename);
|
||||
|
||||
/**
|
||||
* fluid_is_midifile returns 1 if the specified filename is a MIDI
|
||||
* file. It retuns 0 otherwise. The current implementation only checks
|
||||
* for the "MThd" header in the file.
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_is_midifile(char* filename);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
/** Set the handle to the instance of the application on the Windows
|
||||
platform. The handle is needed to open DirectSound. */
|
||||
FLUIDSYNTH_API void* fluid_get_hinstance(void);
|
||||
FLUIDSYNTH_API void fluid_set_hinstance(void* hinstance);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_MISC_H */
|
112
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/mod.h
vendored
Normal file
112
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/mod.h
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_MOD_H
|
||||
#define _FLUIDSYNTH_MOD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Modulator-related definitions */
|
||||
|
||||
/* Maximum number of modulators in a voice */
|
||||
#define FLUID_NUM_MOD 64
|
||||
|
||||
/*
|
||||
* fluid_mod_t
|
||||
*/
|
||||
struct _fluid_mod_t
|
||||
{
|
||||
unsigned char dest;
|
||||
unsigned char src1;
|
||||
unsigned char flags1;
|
||||
unsigned char src2;
|
||||
unsigned char flags2;
|
||||
double amount;
|
||||
/* The 'next' field allows to link modulators into a list. It is
|
||||
* not used in fluid_voice.c, there each voice allocates memory for a
|
||||
* fixed number of modulators. Since there may be a huge number of
|
||||
* different zones, this is more efficient.
|
||||
*/
|
||||
fluid_mod_t * next;
|
||||
};
|
||||
|
||||
/* Flags telling the polarity of a modulator. Compare with SF2.01
|
||||
section 8.2. Note: The numbers of the bits are different! (for
|
||||
example: in the flags of a SF modulator, the polarity bit is bit
|
||||
nr. 9) */
|
||||
enum fluid_mod_flags
|
||||
{
|
||||
FLUID_MOD_POSITIVE = 0,
|
||||
FLUID_MOD_NEGATIVE = 1,
|
||||
FLUID_MOD_UNIPOLAR = 0,
|
||||
FLUID_MOD_BIPOLAR = 2,
|
||||
FLUID_MOD_LINEAR = 0,
|
||||
FLUID_MOD_CONCAVE = 4,
|
||||
FLUID_MOD_CONVEX = 8,
|
||||
FLUID_MOD_SWITCH = 12,
|
||||
FLUID_MOD_GC = 0,
|
||||
FLUID_MOD_CC = 16
|
||||
};
|
||||
|
||||
/* Flags telling the source of a modulator. This corresponds to
|
||||
* SF2.01 section 8.2.1 */
|
||||
enum fluid_mod_src
|
||||
{
|
||||
FLUID_MOD_NONE = 0,
|
||||
FLUID_MOD_VELOCITY = 2,
|
||||
FLUID_MOD_KEY = 3,
|
||||
FLUID_MOD_KEYPRESSURE = 10,
|
||||
FLUID_MOD_CHANNELPRESSURE = 13,
|
||||
FLUID_MOD_PITCHWHEEL = 14,
|
||||
FLUID_MOD_PITCHWHEELSENS = 16
|
||||
};
|
||||
|
||||
/* Allocates memory for a new modulator */
|
||||
FLUIDSYNTH_API fluid_mod_t * fluid_mod_new(void);
|
||||
|
||||
/* Frees the modulator */
|
||||
FLUIDSYNTH_API void fluid_mod_delete(fluid_mod_t * mod);
|
||||
|
||||
|
||||
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t* mod, int dst);
|
||||
FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t* mod, double amount);
|
||||
|
||||
FLUIDSYNTH_API int fluid_mod_get_source1(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_flags1(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_source2(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_flags2(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_dest(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API double fluid_mod_get_amount(fluid_mod_t* mod);
|
||||
|
||||
|
||||
/* Determines, if two modulators are 'identical' (all parameters
|
||||
except the amount match) */
|
||||
FLUIDSYNTH_API int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _FLUIDSYNTH_MOD_H */
|
||||
|
113
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/ramsfont.h
vendored
Normal file
113
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/ramsfont.h
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_RAMSFONT_H
|
||||
#define _FLUIDSYNTH_RAMSFONT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/* ram soundfonts:
|
||||
October 2002 - Antoine Schmitt
|
||||
|
||||
ram soundfonts live in ram. The samples are loaded from files
|
||||
or from RAM. A minimal API manages a soundFont structure,
|
||||
with presets, each preset having only one preset-zone, which
|
||||
instrument has potentially many instrument-zones. No global
|
||||
zones, and nor generator nor modulator other than the default
|
||||
ones are permitted. This may be extensible in the future.
|
||||
*/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/*
|
||||
We are not using the sfloader protocol, as we need more arguments
|
||||
than what it provides.
|
||||
*/
|
||||
|
||||
/** Creates a fluid_sfont_t wrapping an fluid_ramsfont_t */
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_ramsfont_create_sfont(void);
|
||||
|
||||
/***********************
|
||||
* ramsfont specific API
|
||||
***********************/
|
||||
FLUIDSYNTH_API int fluid_ramsfont_set_name(fluid_ramsfont_t* sfont, char * name);
|
||||
|
||||
/* Creates one instrument zone for the sample inside the preset defined
|
||||
* by bank/num
|
||||
* \returns 0 if success
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_ramsfont_add_izone(fluid_ramsfont_t* sfont,
|
||||
unsigned int bank, unsigned int num, fluid_sample_t* sample,
|
||||
int lokey, int hikey);
|
||||
|
||||
/* Removes the instrument zone corresponding to bank/num and to the sample
|
||||
* \returns 0 if success
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_ramsfont_remove_izone(fluid_ramsfont_t* sfont,
|
||||
unsigned int bank, unsigned int num, fluid_sample_t* sample);
|
||||
|
||||
/* Sets a generator on an instrument zone
|
||||
* \returns 0 if success
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_ramsfont_izone_set_gen(fluid_ramsfont_t* sfont,
|
||||
unsigned int bank, unsigned int num, fluid_sample_t* sample,
|
||||
int gen_type, float value);
|
||||
|
||||
/* Utility : sets the loop start/end values
|
||||
* \on = 0 or 1; if 0, loopstart and loopend are not used
|
||||
* \loopstart and loopend are floats, in frames
|
||||
* \loopstart is counted from frame 0
|
||||
* \loopend is counted from the last frame, thus is < 0
|
||||
* \returns 0 if success
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_ramsfont_izone_set_loop(fluid_ramsfont_t* sfont,
|
||||
unsigned int bank, unsigned int num, fluid_sample_t* sample,
|
||||
int on, float loopstart, float loopend);
|
||||
|
||||
/***************************************
|
||||
* sample_t specific API for ramsfont
|
||||
***************************************/
|
||||
FLUIDSYNTH_API fluid_sample_t* new_fluid_ramsample(void);
|
||||
FLUIDSYNTH_API int delete_fluid_ramsample(fluid_sample_t* sample);
|
||||
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t* sample, char * name);
|
||||
|
||||
/* Sets the sound data of the sample
|
||||
* Warning : if copy_data is FALSE, data should have 8 unused frames at start
|
||||
* and 8 unused frames at the end.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_sample_set_sound_data(fluid_sample_t* sample, short *data,
|
||||
unsigned int nbframes, short copy_data, int rootkey);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_RAMSFONT_H */
|
202
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/settings.h
vendored
Normal file
202
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/settings.h
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_SETTINGS_H
|
||||
#define _FLUIDSYNTH_SETTINGS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* Synthesizer settings
|
||||
*
|
||||
*
|
||||
* The create a synthesizer object you will have to specify its
|
||||
* settings. These settings are stored in the structure below.
|
||||
|
||||
* void my_synthesizer()
|
||||
* {
|
||||
* fluid_settings_t* settings;
|
||||
* fluid_synth_t* synth;
|
||||
* fluid_audio_driver_t* adriver;
|
||||
*
|
||||
*
|
||||
* settings = new_fluid_settings();
|
||||
* fluid_settings_setstr(settings, "audio.driver", "alsa");
|
||||
* // ... change settings ...
|
||||
* synth = new_fluid_synth(settings);
|
||||
* adriver = new_fluid_audio_driver(settings, synth);
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* Hint FLUID_HINT_BOUNDED_BELOW indicates that the LowerBound field
|
||||
of the FLUID_PortRangeHint should be considered meaningful. The
|
||||
value in this field should be considered the (inclusive) lower
|
||||
bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also
|
||||
specified then the value of LowerBound should be multiplied by the
|
||||
sample rate. */
|
||||
#define FLUID_HINT_BOUNDED_BELOW 0x1
|
||||
|
||||
/* Hint FLUID_HINT_BOUNDED_ABOVE indicates that the UpperBound field
|
||||
of the FLUID_PortRangeHint should be considered meaningful. The
|
||||
value in this field should be considered the (inclusive) upper
|
||||
bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also
|
||||
specified then the value of UpperBound should be multiplied by the
|
||||
sample rate. */
|
||||
#define FLUID_HINT_BOUNDED_ABOVE 0x2
|
||||
|
||||
/* Hint FLUID_HINT_TOGGLED indicates that the data item should be
|
||||
considered a Boolean toggle. Data less than or equal to zero should
|
||||
be considered `off' or `false,' and data above zero should be
|
||||
considered `on' or `true.' FLUID_HINT_TOGGLED may not be used in
|
||||
conjunction with any other hint except FLUID_HINT_DEFAULT_0 or
|
||||
FLUID_HINT_DEFAULT_1. */
|
||||
#define FLUID_HINT_TOGGLED 0x4
|
||||
|
||||
/* Hint FLUID_HINT_SAMPLE_RATE indicates that any bounds specified
|
||||
should be interpreted as multiples of the sample rate. For
|
||||
instance, a frequency range from 0Hz to the Nyquist frequency (half
|
||||
the sample rate) could be requested by this hint in conjunction
|
||||
with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
|
||||
at all must support this hint to retain meaning. */
|
||||
#define FLUID_HINT_SAMPLE_RATE 0x8
|
||||
|
||||
/* Hint FLUID_HINT_LOGARITHMIC indicates that it is likely that the
|
||||
user will find it more intuitive to view values using a logarithmic
|
||||
scale. This is particularly useful for frequencies and gains. */
|
||||
#define FLUID_HINT_LOGARITHMIC 0x10
|
||||
|
||||
/* Hint FLUID_HINT_INTEGER indicates that a user interface would
|
||||
probably wish to provide a stepped control taking only integer
|
||||
values. Any bounds set should be slightly wider than the actual
|
||||
integer range required to avoid floating point rounding errors. For
|
||||
instance, the integer set {0,1,2,3} might be described as [-0.1,
|
||||
3.1]. */
|
||||
#define FLUID_HINT_INTEGER 0x20
|
||||
|
||||
|
||||
#define FLUID_HINT_FILENAME 0x01
|
||||
#define FLUID_HINT_OPTIONLIST 0x02
|
||||
|
||||
|
||||
|
||||
enum fluid_types_enum {
|
||||
FLUID_NO_TYPE = -1,
|
||||
FLUID_NUM_TYPE,
|
||||
FLUID_INT_TYPE,
|
||||
FLUID_STR_TYPE,
|
||||
FLUID_SET_TYPE
|
||||
};
|
||||
|
||||
|
||||
FLUIDSYNTH_API fluid_settings_t* new_fluid_settings(void);
|
||||
FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t* settings);
|
||||
|
||||
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_get_type(fluid_settings_t* settings, const char* name);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_get_hints(fluid_settings_t* settings, const char* name);
|
||||
|
||||
/** Returns whether the setting is changeable in real-time. */
|
||||
FLUIDSYNTH_API int fluid_settings_is_realtime(fluid_settings_t* settings, const char* name);
|
||||
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_setstr(fluid_settings_t* settings, const char* name, const char* str);
|
||||
|
||||
/**
|
||||
Get the value of a string setting. If the value does not exists,
|
||||
'str' is set to NULL. Otherwise, 'str' will point to the
|
||||
value. The application does not own the returned value. Instead,
|
||||
the application should make a copy of the value if it needs it
|
||||
later.
|
||||
|
||||
\returns 1 if the value exists, 0 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getstr(fluid_settings_t* settings, const char* name, char** str);
|
||||
|
||||
/** Get the default value of a string setting. */
|
||||
FLUIDSYNTH_API
|
||||
char* fluid_settings_getstr_default(fluid_settings_t* settings, const char* name);
|
||||
|
||||
/** Get the value of a numeric setting.
|
||||
|
||||
\returns 1 if the value exists and is equal to 'value', 0
|
||||
otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_str_equal(fluid_settings_t* settings, const char* name, char* value);
|
||||
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_setnum(fluid_settings_t* settings, const char* name, double val);
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getnum(fluid_settings_t* settings, const char* name, double* val);
|
||||
|
||||
/** Get the default value of a string setting. */
|
||||
FLUIDSYNTH_API
|
||||
double fluid_settings_getnum_default(fluid_settings_t* settings, const char* name);
|
||||
|
||||
/** Get the range of values of a numeric settings. */
|
||||
FLUIDSYNTH_API
|
||||
void fluid_settings_getnum_range(fluid_settings_t* settings, const char* name,
|
||||
double* min, double* max);
|
||||
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_setint(fluid_settings_t* settings, const char* name, int val);
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getint(fluid_settings_t* settings, const char* name, int* val);
|
||||
|
||||
/** Get the default value of a string setting. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getint_default(fluid_settings_t* settings, const char* name);
|
||||
|
||||
/** Get the range of values of a numeric settings. */
|
||||
FLUIDSYNTH_API
|
||||
void fluid_settings_getint_range(fluid_settings_t* settings, const char* name,
|
||||
int* min, int* max);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_SETTINGS_H */
|
195
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/sfont.h
vendored
Normal file
195
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/sfont.h
vendored
Normal file
|
@ -0,0 +1,195 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_SFONT_H
|
||||
#define _FLUIDSYNTH_SFONT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* SoundFont plugins
|
||||
*
|
||||
* It is possible to add new SoundFont loaders to the
|
||||
* synthesizer. The API uses a couple of "interfaces" (structures
|
||||
* with callback functions): fluid_sfloader_t, fluid_sfont_t, and
|
||||
* fluid_preset_t.
|
||||
*
|
||||
* To add a new SoundFont loader to the synthesizer, call
|
||||
* fluid_synth_add_sfloader() and pass a pointer to an
|
||||
* fluid_sfloader_t structure. The important callback function in
|
||||
* this structure is "load", which should try to load a file and
|
||||
* returns a fluid_sfont_t structure, or NULL if it fails.
|
||||
*
|
||||
* The fluid_sfont_t structure contains a callback to obtain the
|
||||
* name of the soundfont. It contains two functions to iterate
|
||||
* though the contained presets, and one function to obtain a
|
||||
* preset corresponding to a bank and preset number. This
|
||||
* function should return an fluid_preset_t structure.
|
||||
*
|
||||
* The fluid_preset_t structure contains some functions to obtain
|
||||
* information from the preset (name, bank, number). The most
|
||||
* important callback is the noteon function. The noteon function
|
||||
* should call fluid_synth_alloc_voice() for every sample that has
|
||||
* to be played. fluid_synth_alloc_voice() expects a pointer to a
|
||||
* fluid_sample_t structure and returns a pointer to the opaque
|
||||
* fluid_voice_t structure. To set or increments the values of a
|
||||
* generator, use fluid_voice_gen_{set,incr}. When you are
|
||||
* finished initializing the voice call fluid_voice_start() to
|
||||
* start playing the synthesis voice.
|
||||
* */
|
||||
|
||||
enum {
|
||||
FLUID_PRESET_SELECTED,
|
||||
FLUID_PRESET_UNSELECTED,
|
||||
FLUID_SAMPLE_DONE
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fluid_sfloader_t
|
||||
*/
|
||||
|
||||
struct _fluid_sfloader_t {
|
||||
/** Private data */
|
||||
void* data;
|
||||
|
||||
/** The free must free the memory allocated for the loader in
|
||||
* addition to any private data. It should return 0 if no error
|
||||
* occured, non-zero otherwise.*/
|
||||
int (*free)(fluid_sfloader_t* loader);
|
||||
|
||||
/** Load a file. Returns NULL if an error occured. */
|
||||
fluid_sfont_t* (*load)(fluid_sfloader_t* loader, const char* filename);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fluid_sfont_t
|
||||
*/
|
||||
|
||||
struct _fluid_sfont_t {
|
||||
void* data;
|
||||
unsigned int id;
|
||||
|
||||
/** The 'free' callback function should return 0 when it was able to
|
||||
free all resources. It should return a non-zero value if some of
|
||||
the samples could not be freed because they are still in use. */
|
||||
int (*free)(fluid_sfont_t* sfont);
|
||||
|
||||
/** Return the name of the sfont */
|
||||
char* (*get_name)(fluid_sfont_t* sfont);
|
||||
|
||||
/** Return the preset with the specified bank and preset number. All
|
||||
* the fields, including the 'sfont' field, should * be filled
|
||||
* in. If the preset cannot be found, the function returns NULL. */
|
||||
fluid_preset_t* (*get_preset)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
|
||||
void (*iteration_start)(fluid_sfont_t* sfont);
|
||||
|
||||
/* return 0 when no more presets are available, 1 otherwise */
|
||||
int (*iteration_next)(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
};
|
||||
|
||||
#define fluid_sfont_get_id(_sf) ((_sf)->id)
|
||||
|
||||
|
||||
/*
|
||||
* fluid_preset_t
|
||||
*/
|
||||
|
||||
struct _fluid_preset_t {
|
||||
void* data;
|
||||
fluid_sfont_t* sfont;
|
||||
int (*free)(fluid_preset_t* preset);
|
||||
char* (*get_name)(fluid_preset_t* preset);
|
||||
int (*get_banknum)(fluid_preset_t* preset);
|
||||
int (*get_num)(fluid_preset_t* preset);
|
||||
|
||||
/** handle a noteon event. Returns 0 if no error occured. */
|
||||
int (*noteon)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/** Implement this function if the preset needs to be notified about
|
||||
preset select and unselect events. */
|
||||
int (*notify)(fluid_preset_t* preset, int reason, int chan);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fluid_sample_t
|
||||
*/
|
||||
|
||||
struct _fluid_sample_t
|
||||
{
|
||||
char name[21];
|
||||
unsigned int start;
|
||||
unsigned int end; /* Note: Index of last valid sample point (contrary to SF spec) */
|
||||
unsigned int loopstart;
|
||||
unsigned int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
unsigned int samplerate;
|
||||
int origpitch;
|
||||
int pitchadj;
|
||||
int sampletype;
|
||||
int valid;
|
||||
short* data;
|
||||
|
||||
/** The amplitude, that will lower the level of the sample's loop to
|
||||
the noise floor. Needed for note turnoff optimization, will be
|
||||
filled out automatically */
|
||||
/* Set this to zero, when submitting a new sample. */
|
||||
int amplitude_that_reaches_noise_floor_is_valid;
|
||||
double amplitude_that_reaches_noise_floor;
|
||||
|
||||
/** Count the number of playing voices that use this sample. */
|
||||
unsigned int refcount;
|
||||
|
||||
/** Implement this function if the sample or SoundFont needs to be
|
||||
notified when the sample is no longer used. */
|
||||
int (*notify)(fluid_sample_t* sample, int reason);
|
||||
|
||||
/** Pointer to SoundFont specific data */
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
|
||||
#define fluid_sample_refcount(_sample) ((_sample)->refcount)
|
||||
|
||||
|
||||
/** Sample types */
|
||||
|
||||
#define FLUID_SAMPLETYPE_MONO 1
|
||||
#define FLUID_SAMPLETYPE_RIGHT 2
|
||||
#define FLUID_SAMPLETYPE_LEFT 4
|
||||
#define FLUID_SAMPLETYPE_LINKED 8
|
||||
#define FLUID_SAMPLETYPE_OGG_VORBIS 0x10 /**< Flag for #fluid_sample_t \a sampletype field for Ogg Vorbis compressed samples */
|
||||
#define FLUID_SAMPLETYPE_OGG_VORBIS_UNPACKED 0x20
|
||||
#define FLUID_SAMPLETYPE_ROM 0x8000
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_SFONT_H */
|
728
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/synth.h
vendored
Normal file
728
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/synth.h
vendored
Normal file
|
@ -0,0 +1,728 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_SYNTH_H
|
||||
#define _FLUIDSYNTH_SYNTH_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Embedded synthesizer
|
||||
*
|
||||
* You create a new synthesizer with new_fluid_synth() and you destroy
|
||||
* if with delete_fluid_synth(). Use the settings structure to specify
|
||||
* the synthesizer characteristics.
|
||||
*
|
||||
* You have to load a SoundFont in order to hear any sound. For that
|
||||
* you use the fluid_synth_sfload() function.
|
||||
*
|
||||
* You can use the audio driver functions described below to open
|
||||
* the audio device and create a background audio thread.
|
||||
*
|
||||
* The API for sending MIDI events is probably what you expect:
|
||||
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/** Creates a new synthesizer object.
|
||||
*
|
||||
* Creates a new synthesizer object. As soon as the synthesizer is
|
||||
* created, it will start playing.
|
||||
*
|
||||
* \param settings a pointer to a settings structure
|
||||
* \return a newly allocated synthesizer or NULL in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t* synth, float sample_rate);
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the synthesizer previously created with new_fluid_synth.
|
||||
*
|
||||
* \param synth the synthesizer object
|
||||
* \return 0 if no error occured, -1 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/** Get a reference to the settings of the synthesizer.
|
||||
*
|
||||
* \param synth the synthesizer object
|
||||
* \return pointer to the settings
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_settings_t* fluid_synth_get_settings(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* MIDI channel messages
|
||||
*
|
||||
*/
|
||||
|
||||
/** Send a noteon message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/** Send a noteoff message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
|
||||
|
||||
/** Send a control change message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
|
||||
|
||||
/** Get a control value. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
|
||||
|
||||
/** Send a pitch bend message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
|
||||
|
||||
/** Get the pitch bend value. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
|
||||
|
||||
/** Set the pitch wheel sensitivity. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val);
|
||||
|
||||
/** Get the pitch wheel sensitivity. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
|
||||
|
||||
/** Send a program change message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
|
||||
char *response, int *response_len, int *handled, int dryrun);
|
||||
|
||||
/** Select a bank. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
|
||||
|
||||
/** Select a sfont. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
|
||||
|
||||
/** Select a preset for a channel. The preset is specified by the
|
||||
SoundFont ID, the bank number, and the preset number. This
|
||||
allows any preset to be selected and circumvents preset masking
|
||||
due to previously loaded SoundFonts on the SoundFont stack.
|
||||
|
||||
\param synth The synthesizer
|
||||
\param chan The channel on which to set the preset
|
||||
\param sfont_id The ID of the SoundFont
|
||||
\param bank_num The bank number
|
||||
\param preset_num The preset number
|
||||
\return 0 if no errors occured, -1 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_program_select(fluid_synth_t* synth, int chan,
|
||||
unsigned int sfont_id,
|
||||
unsigned int bank_num,
|
||||
unsigned int preset_num);
|
||||
|
||||
/** Returns the program, bank, and SoundFont number of the preset on
|
||||
a given channel. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_get_program(fluid_synth_t* synth, int chan,
|
||||
unsigned int* sfont_id,
|
||||
unsigned int* bank_num,
|
||||
unsigned int* preset_num);
|
||||
|
||||
/** Send a bank select and a program change to every channel to
|
||||
* reinitialize the preset of the channel. This function is useful
|
||||
* mainly after a SoundFont has been loaded, unloaded or
|
||||
* reloaded. . Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
|
||||
|
||||
/** Send a reset. A reset turns all the notes off and resets the
|
||||
controller values. */
|
||||
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t *synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Low level access
|
||||
*
|
||||
*/
|
||||
|
||||
/** Create and start voices using a preset. The id passed as
|
||||
* argument will be used as the voice group id. */
|
||||
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t* synth, unsigned int id,
|
||||
fluid_preset_t* preset, int audio_chan,
|
||||
int midi_chan, int key, int vel);
|
||||
|
||||
/** Stop the voices in the voice group defined by id. */
|
||||
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
|
||||
|
||||
/** Change the value of a generator of the voices in the voice group
|
||||
* defined by id. */
|
||||
/* FLUIDSYNTH_API int fluid_synth_ctrl(fluid_synth_t* synth, int id, */
|
||||
/* int gen, float value, */
|
||||
/* int absolute, int normalized); */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* SoundFont management
|
||||
*
|
||||
*/
|
||||
|
||||
/** Set an optional function callback each time a preset has finished loading.
|
||||
This can be useful when calling fluid_synth_sfload asynchronously.
|
||||
The function must be formatted like this:
|
||||
void my_callback_function(int bank, int num, char* name)
|
||||
|
||||
\param callback Pointer to the function
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
void fluid_synth_set_preset_callback(void* callback);
|
||||
|
||||
/** Loads a SoundFont file and creates a new SoundFont. The newly
|
||||
loaded SoundFont will be put on top of the SoundFont
|
||||
stack. Presets are searched starting from the SoundFont on the
|
||||
top of the stack, working the way down the stack until a preset
|
||||
is found.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param filename The file name
|
||||
\param reset_presets If non-zero, the presets on the channels will be reset
|
||||
\returns The ID of the loaded SoundFont, or -1 in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets);
|
||||
|
||||
/** Reload a SoundFont. The reloaded SoundFont retains its ID and
|
||||
index on the stack.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param id The id of the SoundFont
|
||||
\returns The ID of the loaded SoundFont, or -1 in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
|
||||
|
||||
/** Removes a SoundFont from the stack and deallocates it.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param id The id of the SoundFont
|
||||
\param reset_presets If TRUE then presets will be reset for all channels
|
||||
\returns 0 if no error, -1 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets);
|
||||
|
||||
/** Add a SoundFont. The SoundFont will be put on top of
|
||||
the SoundFont stack.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param sfont The SoundFont
|
||||
\returns The ID of the loaded SoundFont, or -1 in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
|
||||
|
||||
/** Remove a SoundFont that was previously added using
|
||||
* fluid_synth_add_sfont(). The synthesizer does not delete the
|
||||
* SoundFont; this is responsability of the caller.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param sfont The SoundFont
|
||||
*/
|
||||
FLUIDSYNTH_API void fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
|
||||
|
||||
/** Count the number of loaded SoundFonts.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\returns The number of loaded SoundFonts
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t* synth);
|
||||
|
||||
/** Get a SoundFont. The SoundFont is specified by its index on the
|
||||
stack. The top of the stack has index zero.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param num The number of the SoundFont (0 <= num < sfcount)
|
||||
\returns A pointer to the SoundFont
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num);
|
||||
|
||||
/** Get a SoundFont. The SoundFont is specified by its ID.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param id The id of the sfont
|
||||
\returns A pointer to the SoundFont
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id);
|
||||
|
||||
|
||||
/** Get the preset of a channel */
|
||||
FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
|
||||
|
||||
/** Offset the bank numbers in a SoundFont. Returns -1 if an error
|
||||
* occured (out of memory or negative offset) */
|
||||
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset);
|
||||
|
||||
/** Get the offset of the bank numbers in a SoundFont. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Reverb
|
||||
*
|
||||
*/
|
||||
|
||||
/** Set the parameters for the built-in reverb unit */
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize,
|
||||
double damping, double width, double level);
|
||||
|
||||
/** Turn on (1) / off (0) the built-in reverb unit */
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t* synth, int on);
|
||||
|
||||
|
||||
/** Query the current state of the reverb. */
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
|
||||
|
||||
/* Those are the default settings for the reverb */
|
||||
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f
|
||||
#define FLUID_REVERB_DEFAULT_DAMP 0.0f
|
||||
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f
|
||||
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Chorus
|
||||
*
|
||||
*/
|
||||
|
||||
enum fluid_chorus_mod {
|
||||
FLUID_CHORUS_MOD_SINE = 0,
|
||||
FLUID_CHORUS_MOD_TRIANGLE = 1
|
||||
};
|
||||
|
||||
/** Set up the chorus. It should be turned on with fluid_synth_set_chorus_on.
|
||||
* If faulty parameters are given, all new settings are discarded.
|
||||
* Keep in mind, that the needed CPU time is proportional to 'nr'.
|
||||
*/
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
|
||||
/** Turn on (1) / off (0) the built-in chorus unit */
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t* synth, int on);
|
||||
|
||||
/** Query the current state of the chorus. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t* synth); /* see fluid_chorus_mod */
|
||||
|
||||
/* Those are the default settings for the chorus. */
|
||||
#define FLUID_CHORUS_DEFAULT_N 3
|
||||
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f
|
||||
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f
|
||||
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f
|
||||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Audio and MIDI channels
|
||||
*
|
||||
*/
|
||||
|
||||
/** Returns the number of MIDI channels that the synthesizer uses
|
||||
internally */
|
||||
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t* synth);
|
||||
|
||||
/** Returns the number of audio channels that the synthesizer uses
|
||||
internally */
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t* synth);
|
||||
|
||||
/** Returns the number of audio groups that the synthesizer uses
|
||||
internally. This is usually identical to audio_channels. */
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t* synth);
|
||||
|
||||
/** Returns the number of effects channels that the synthesizer uses
|
||||
internally */
|
||||
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t* synth);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Synthesis parameters
|
||||
*
|
||||
*/
|
||||
|
||||
/** Set the master gain */
|
||||
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
|
||||
|
||||
/** Get the master gain */
|
||||
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
|
||||
|
||||
/** Set the polyphony limit (FluidSynth >= 1.0.6) */
|
||||
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
|
||||
|
||||
/** Get the polyphony limit (FluidSynth >= 1.0.6) */
|
||||
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
|
||||
|
||||
/** Get the internal buffer size. The internal buffer size if not the
|
||||
same thing as the buffer size specified in the
|
||||
settings. Internally, the synth *always* uses a specific buffer
|
||||
size independent of the buffer size used by the audio driver. The
|
||||
internal buffer size is normally 64 samples. The reason why it
|
||||
uses an internal buffer size is to allow audio drivers to call the
|
||||
synthesizer with a variable buffer length. The internal buffer
|
||||
size is useful for client who want to optimize their buffer sizes.
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t* synth);
|
||||
|
||||
/** Set the interpolation method for one channel or all channels (chan = -1) */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method);
|
||||
|
||||
/* Flags to choose the interpolation method */
|
||||
enum fluid_interp {
|
||||
/* no interpolation: Fastest, but questionable audio quality */
|
||||
FLUID_INTERP_NONE = 0,
|
||||
/* Straight-line interpolation: A bit slower, reasonable audio quality */
|
||||
FLUID_INTERP_LINEAR = 1,
|
||||
/* Fourth-order interpolation: Requires 50 % of the whole DSP processing time, good quality
|
||||
* Default. */
|
||||
FLUID_INTERP_DEFAULT = 4,
|
||||
FLUID_INTERP_4THORDER = 4,
|
||||
FLUID_INTERP_7THORDER = 7,
|
||||
FLUID_INTERP_HIGHEST=7
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Generator interface
|
||||
*
|
||||
*/
|
||||
|
||||
/** Change the value of a generator. This function allows to control
|
||||
all synthesis parameters in real-time. The changes are additive,
|
||||
i.e. they add up to the existing parameter value. This function is
|
||||
similar to sending an NRPN message to the synthesizer. The
|
||||
function accepts a float as the value of the parameter. The
|
||||
parameter numbers and ranges are described in the SoundFont 2.01
|
||||
specification, paragraph 8.1.3, page 48. See also 'fluid_gen_type'.
|
||||
|
||||
\param synth The synthesizer object.
|
||||
\param chan The MIDI channel number.
|
||||
\param param The parameter number.
|
||||
\param value The parameter value.
|
||||
\returns Your favorite dish.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value);
|
||||
|
||||
|
||||
/** Retreive the value of a generator. This function returns the value
|
||||
set by a previous call 'fluid_synth_set_gen' or by an NRPN message.
|
||||
|
||||
\param synth The synthesizer object.
|
||||
\param chan The MIDI channel number.
|
||||
\param param The generator number.
|
||||
\returns The value of the generator.
|
||||
*/
|
||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Tuning
|
||||
*
|
||||
*/
|
||||
|
||||
/** Create a new key-based tuning with given name, number, and
|
||||
pitches. The array 'pitches' should have length 128 and contains
|
||||
the pitch in cents of every key in cents. However, if 'pitches' is
|
||||
NULL, a new tuning is created with the well-tempered scale.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
\param name The name of the tuning
|
||||
\param pitch The array of pitch values. The array length has to be 128.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
|
||||
const char* name, double* pitch);
|
||||
|
||||
/** Create a new octave-based tuning with given name, number, and
|
||||
pitches. The array 'pitches' should have length 12 and contains
|
||||
derivation in cents from the well-tempered scale. For example, if
|
||||
pitches[0] equals -33, then the C-keys will be tuned 33 cents
|
||||
below the well-tempered C.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
\param name The name of the tuning
|
||||
\param pitch The array of pitch derivations. The array length has to be 12.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
|
||||
const char* name, const double* pitch);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
const char* name, const double* pitch, int apply);
|
||||
|
||||
/** Request a note tuning changes. Both they 'keys' and 'pitches'
|
||||
arrays should be of length 'num_pitches'. If 'apply' is non-zero,
|
||||
the changes should be applied in real-time, i.e. sounding notes
|
||||
will have their pitch updated. 'APPLY' IS CURRENTLY IGNORED. The
|
||||
changes will be available for newly triggered notes only.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
\param len The length of the keys and pitch arrays
|
||||
\param keys The array of keys values.
|
||||
\param pitch The array of pitch values.
|
||||
\param apply Flag to indicate whether to changes should be applied in real-time.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tune_notes(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
|
||||
int len, int *keys, double* pitch, int apply);
|
||||
|
||||
/** Select a tuning for a channel.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param chan The channel number [0-max channels]
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int tuning_bank, int tuning_prog);
|
||||
|
||||
int fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog, int apply);
|
||||
|
||||
/** Set the tuning to the default well-tempered tuning on a channel.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param chan The channel number [0-max channels]
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
|
||||
|
||||
/** Start the iteration throught the list of available tunings.
|
||||
|
||||
\param synth The synthesizer object
|
||||
*/
|
||||
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/** Get the next tuning in the iteration. This functions stores the
|
||||
bank and program number of the next tuning in the pointers given as
|
||||
arguments.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param bank Pointer to an int to store the bank number
|
||||
\param prog Pointer to an int to store the program number
|
||||
\returns 1 if there is a next tuning, 0 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
|
||||
|
||||
|
||||
/** Dump the data of a tuning. This functions stores the name and
|
||||
pitch values of a tuning in the pointers given as arguments. Both
|
||||
name and pitch can be NULL is the data is not needed.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param bank The tuning bank number [0-127]
|
||||
\param prog The tuning program number [0-127]
|
||||
\param name Pointer to a buffer to store the name
|
||||
\param len The length of the name buffer
|
||||
\param pitch Pointer to buffer to store the pitch values
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, int len, double* pitch);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Misc
|
||||
*
|
||||
*/
|
||||
|
||||
/** Get a textual representation of the last error */
|
||||
FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Synthesizer plugin
|
||||
*
|
||||
*
|
||||
* To create a synthesizer plugin, create the synthesizer as
|
||||
* explained above. Once the synthesizer is created you can call
|
||||
* any of the functions below to get the audio.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Generate a number of samples. This function expects two signed
|
||||
* 16bits buffers (left and right channel) that will be filled with
|
||||
* samples.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param lout The sample buffer for the left channel
|
||||
* \param loff The offset, in samples, in the left buffer where the writing pointer starts
|
||||
* \param lincr The increment, in samples, of the writing pointer in the left buffer
|
||||
* \param rout The sample buffer for the right channel
|
||||
* \param roff The offset, in samples, in the right buffer where the writing pointer starts
|
||||
* \param rincr The increment, in samples, of the writing pointer in the right buffer
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
|
||||
|
||||
/** Generate a number of samples. This function expects two floating
|
||||
* point buffers (left and right channel) that will be filled with
|
||||
* samples.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param lout The sample buffer for the left channel
|
||||
* \param loff The offset, in samples, in the left buffer where the writing pointer starts
|
||||
* \param lincr The increment, in samples, of the writing pointer in the left buffer
|
||||
* \param rout The sample buffer for the right channel
|
||||
* \param roff The offset, in samples, in the right buffer where the writing pointer starts
|
||||
* \param rincr The increment, in samples, of the writing pointer in the right buffer
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t* synth, int len,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
||||
float** left, float** right,
|
||||
float** fx_left, float** fx_right);
|
||||
|
||||
|
||||
/** Generate a number of samples. This function expects planar floating
|
||||
* point buffers (first half of the buffer is filled by the left channel, second half is filled by the right channel) that will be filled with
|
||||
* samples.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param out The sample buffer for the left channel
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_pnwrite_float(fluid_synth_t* synth, int len, void* lout, void* rout);
|
||||
|
||||
/** Generate a number of samples. This function implements the
|
||||
* default interface defined in fluidsynth/audio.h. This function
|
||||
* ignores the input buffers and expects at least two output
|
||||
* buffer.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param nin The number of input buffers
|
||||
* \param in The array of input buffers
|
||||
* \param nout The number of output buffers
|
||||
* \param out The array of output buffers
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
|
||||
int nin, float** in,
|
||||
int nout, float** out);
|
||||
|
||||
|
||||
|
||||
/* Type definition of the synthesizer's audio callback function. */
|
||||
typedef int (*fluid_audio_callback_t)(fluid_synth_t* synth, int len,
|
||||
void* out1, int loff, int lincr,
|
||||
void* out2, int roff, int rincr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Synthesizer's interface to handle SoundFont loaders
|
||||
*/
|
||||
|
||||
|
||||
/** Add a SoundFont loader to the synthesizer. Note that SoundFont
|
||||
loader don't necessarily load SoundFonts. They can load any type
|
||||
of wavetable data but export a SoundFont interface. */
|
||||
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader);
|
||||
|
||||
/** Allocate a synthesis voice. This function is called by a
|
||||
soundfont's preset in response to a noteon event.
|
||||
The returned voice comes with default modulators installed (velocity-to-attenuation,
|
||||
velocity to filter, ...)
|
||||
Note: A single noteon event may create any number of voices, when the preset is layered.
|
||||
Typically 1 (mono) or 2 (stereo).*/
|
||||
FLUIDSYNTH_API fluid_voice_t* fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample,
|
||||
int channum, int key, int vel);
|
||||
|
||||
/** Start a synthesis voice. This function is called by a
|
||||
soundfont's preset in response to a noteon event after the voice
|
||||
has been allocated with fluid_synth_alloc_voice() and
|
||||
initialized.
|
||||
Exclusive classes are processed here.*/
|
||||
FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice);
|
||||
|
||||
|
||||
/** Write a list of all voices matching ID into buf, but not more than bufsize voices.
|
||||
* If ID <0, return all voices. */
|
||||
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
|
||||
fluid_voice_t* buf[], int bufsize, int ID);
|
||||
|
||||
|
||||
//midi router disabled
|
||||
// /** This is a hack to get command handlers working */
|
||||
//FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
|
||||
// fluid_midi_router_t* router);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_SYNTH_H */
|
66
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/types.h
vendored
Normal file
66
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/types.h
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_TYPES_H
|
||||
#define _FLUIDSYNTH_TYPES_H
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Forward declarations
|
||||
|
||||
*/
|
||||
typedef struct _fluid_hashtable_t fluid_settings_t;
|
||||
typedef struct _fluid_synth_t fluid_synth_t;
|
||||
typedef struct _fluid_voice_t fluid_voice_t;
|
||||
typedef struct _fluid_sfloader_t fluid_sfloader_t;
|
||||
typedef struct _fluid_sfont_t fluid_sfont_t;
|
||||
typedef struct _fluid_preset_t fluid_preset_t;
|
||||
typedef struct _fluid_sample_t fluid_sample_t;
|
||||
typedef struct _fluid_mod_t fluid_mod_t;
|
||||
typedef struct _fluid_audio_driver_t fluid_audio_driver_t;
|
||||
typedef struct _fluid_player_t fluid_player_t;
|
||||
typedef struct _fluid_midi_event_t fluid_midi_event_t;
|
||||
typedef struct _fluid_midi_driver_t fluid_midi_driver_t;
|
||||
typedef struct _fluid_midi_router_t fluid_midi_router_t;
|
||||
typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t;
|
||||
typedef struct _fluid_hashtable_t fluid_cmd_handler_t;
|
||||
typedef struct _fluid_shell_t fluid_shell_t;
|
||||
typedef struct _fluid_server_t fluid_server_t;
|
||||
typedef struct _fluid_event_t fluid_event_t;
|
||||
typedef struct _fluid_sequencer_t fluid_sequencer_t;
|
||||
typedef struct _fluid_ramsfont_t fluid_ramsfont_t;
|
||||
typedef struct _fluid_rampreset_t fluid_rampreset_t;
|
||||
|
||||
typedef int fluid_istream_t;
|
||||
typedef int fluid_ostream_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_TYPES_H */
|
44
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/version.h
vendored
Normal file
44
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/version.h
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_VERSION_H
|
||||
#define _FLUIDSYNTH_VERSION_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FLUIDSYNTH_VERSION "1.1.0"
|
||||
#define FLUIDSYNTH_VERSION_MAJOR 1
|
||||
#define FLUIDSYNTH_VERSION_MINOR 1
|
||||
#define FLUIDSYNTH_VERSION_MICRO 0
|
||||
|
||||
|
||||
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
|
||||
|
||||
FLUIDSYNTH_API char* fluid_version_str(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUIDSYNTH_VERSION_H */
|
97
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/voice.h
vendored
Normal file
97
framework/audio/midi/3rdparty/fluidlite/include/fluidsynth/voice.h
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUIDSYNTH_VOICE_H
|
||||
#define _FLUIDSYNTH_VOICE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The interface to the synthesizer's voices
|
||||
* Examples on using them can be found in fluid_defsfont.c
|
||||
*/
|
||||
|
||||
/** Update all the synthesis parameters, which depend on generator gen.
|
||||
This is only necessary after changing a generator of an already operating voice.
|
||||
Most applications will not need this function.*/
|
||||
|
||||
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t* voice, int gen);
|
||||
|
||||
|
||||
/* for fluid_voice_add_mod */
|
||||
enum fluid_voice_add_mod{
|
||||
FLUID_VOICE_OVERWRITE,
|
||||
FLUID_VOICE_ADD,
|
||||
FLUID_VOICE_DEFAULT
|
||||
};
|
||||
|
||||
/* Add a modulator to a voice (SF2.1 only). */
|
||||
FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode);
|
||||
|
||||
/** Set the value of a generator */
|
||||
FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t* voice, int gen, float val);
|
||||
|
||||
/** Get the value of a generator */
|
||||
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
|
||||
|
||||
/** Modify the value of a generator by val */
|
||||
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
|
||||
|
||||
|
||||
/** Return the unique ID of the noteon-event. A sound font loader
|
||||
* may store the voice processes it has created for * real-time
|
||||
* control during the operation of a voice (for example: parameter
|
||||
* changes in sound font editor). The synth uses a pool of
|
||||
* voices, which are 'recycled' and never deallocated.
|
||||
*
|
||||
* Before modifying an existing voice, check
|
||||
* - that its state is still 'playing'
|
||||
* - that the ID is still the same
|
||||
* Otherwise the voice has finished playing.
|
||||
*/
|
||||
FLUIDSYNTH_API unsigned int fluid_voice_get_id(fluid_voice_t* voice);
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
|
||||
|
||||
/** If the peak volume during the loop is known, then the voice can
|
||||
* be released earlier during the release phase. Otherwise, the
|
||||
* voice will operate (inaudibly), until the envelope is at the
|
||||
* nominal turnoff point. In many cases the loop volume is many dB
|
||||
* below the maximum volume. For example, the loop volume for a
|
||||
* typical acoustic piano is 20 dB below max. Taking that into
|
||||
* account in the turn-off algorithm we can save 20 dB / 100 dB =>
|
||||
* 1/5 of the total release time.
|
||||
* So it's a good idea to call fluid_voice_optimize_sample
|
||||
* on each sample once.
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t* s);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _FLUIDSYNTH_VOICE_H */
|
||||
|
444
framework/audio/midi/3rdparty/fluidlite/src/fluid_chan.c
vendored
Normal file
444
framework/audio/midi/3rdparty/fluidlite/src/fluid_chan.c
vendored
Normal file
|
@ -0,0 +1,444 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluid_chan.h"
|
||||
#include "fluid_mod.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_sfont.h"
|
||||
|
||||
#define SETCC(_c,_n,_v) _c->cc[_n] = _v
|
||||
|
||||
/*
|
||||
* new_fluid_channel
|
||||
*/
|
||||
fluid_channel_t*
|
||||
new_fluid_channel(fluid_synth_t* synth, int num)
|
||||
{
|
||||
fluid_channel_t* chan;
|
||||
|
||||
chan = FLUID_NEW(fluid_channel_t);
|
||||
if (chan == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chan->synth = synth;
|
||||
chan->channum = num;
|
||||
chan->preset = NULL;
|
||||
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan,0);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_channel_init(fluid_channel_t* chan)
|
||||
{
|
||||
chan->prognum = 0;
|
||||
chan->banknum = 0;
|
||||
chan->sfontnum = 0;
|
||||
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
chan->preset = fluid_synth_find_preset(chan->synth, chan->banknum, chan->prognum);
|
||||
|
||||
chan->interp_method = FLUID_INTERP_DEFAULT;
|
||||
chan->tuning = NULL;
|
||||
chan->nrpn_select = 0;
|
||||
chan->nrpn_active = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@param is_all_ctrl_off if nonzero, only resets some controllers, according to
|
||||
http://www.midi.org/techspecs/rp15.php
|
||||
*/
|
||||
void
|
||||
fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
|
||||
{
|
||||
int i;
|
||||
|
||||
chan->key_pressure = 0;
|
||||
chan->channel_pressure = 0;
|
||||
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
|
||||
|
||||
for (i = 0; i < GEN_LAST; i++) {
|
||||
chan->gen[i] = 0.0f;
|
||||
chan->gen_abs[i] = 0;
|
||||
}
|
||||
|
||||
if (is_all_ctrl_off) {
|
||||
for (i = 0; i < ALL_SOUND_OFF; i++) {
|
||||
if (i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5) {
|
||||
continue;
|
||||
}
|
||||
if (i >= SOUND_CTRL1 && i <= SOUND_CTRL10) {
|
||||
continue;
|
||||
}
|
||||
if (i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
|
||||
i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SETCC(chan, i, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < 128; i++) {
|
||||
SETCC(chan, i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set RPN controllers to NULL state */
|
||||
SETCC(chan, RPN_LSB, 127);
|
||||
SETCC(chan, RPN_MSB, 127);
|
||||
|
||||
/* Set NRPN controllers to NULL state */
|
||||
SETCC(chan, NRPN_LSB, 127);
|
||||
SETCC(chan, NRPN_MSB, 127);
|
||||
|
||||
/* Expression (MSB & LSB) */
|
||||
SETCC(chan, EXPRESSION_MSB, 127);
|
||||
SETCC(chan, EXPRESSION_LSB, 127);
|
||||
|
||||
if (!is_all_ctrl_off) {
|
||||
|
||||
chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
|
||||
|
||||
/* Just like panning, a value of 64 indicates no change for sound ctrls */
|
||||
for (i = SOUND_CTRL1; i <= SOUND_CTRL10; i++) {
|
||||
SETCC(chan, i, 64);
|
||||
}
|
||||
|
||||
/* Volume / initial attenuation (MSB & LSB) */
|
||||
SETCC(chan, VOLUME_MSB, 100);
|
||||
SETCC(chan, VOLUME_LSB, 0);
|
||||
|
||||
/* Pan (MSB & LSB) */
|
||||
SETCC(chan, PAN_MSB, 64);
|
||||
SETCC(chan, PAN_LSB, 0);
|
||||
|
||||
/* Reverb */
|
||||
/* SETCC(chan, EFFECTS_DEPTH1, 40); */
|
||||
/* Note: although XG standard specifies the default amount of reverb to
|
||||
be 40, most people preferred having it at zero.
|
||||
See http://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_channel_reset(fluid_channel_t* chan)
|
||||
{
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan,0);
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_channel
|
||||
*/
|
||||
int
|
||||
delete_fluid_channel(fluid_channel_t* chan)
|
||||
{
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
FLUID_FREE(chan);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_set_preset
|
||||
*/
|
||||
int
|
||||
fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
|
||||
{
|
||||
fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
|
||||
fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
|
||||
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
chan->preset = preset;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_preset
|
||||
*/
|
||||
fluid_preset_t*
|
||||
fluid_channel_get_preset(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->preset;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_banknum
|
||||
*/
|
||||
unsigned int
|
||||
fluid_channel_get_banknum(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->banknum;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_set_prognum
|
||||
*/
|
||||
int
|
||||
fluid_channel_set_prognum(fluid_channel_t* chan, int prognum)
|
||||
{
|
||||
chan->prognum = prognum;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_prognum
|
||||
*/
|
||||
int
|
||||
fluid_channel_get_prognum(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->prognum;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_set_banknum
|
||||
*/
|
||||
int
|
||||
fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int banknum)
|
||||
{
|
||||
chan->banknum = banknum;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_cc
|
||||
*/
|
||||
int
|
||||
fluid_channel_cc(fluid_channel_t* chan, int num, int value)
|
||||
{
|
||||
chan->cc[num] = value;
|
||||
|
||||
switch (num) {
|
||||
|
||||
case SUSTAIN_SWITCH:
|
||||
{
|
||||
if (value < 64) {
|
||||
/* printf("** sustain off\n"); */
|
||||
fluid_synth_damp_voices(chan->synth, chan->channum);
|
||||
} else {
|
||||
/* printf("** sustain on\n"); */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BANK_SELECT_MSB:
|
||||
{
|
||||
chan->bank_msb = (unsigned char) (value & 0x7f);
|
||||
/* printf("** bank select msb recieved: %d\n", value); */
|
||||
|
||||
/* I fixed the handling of a MIDI bank select controller 0,
|
||||
e.g., bank select MSB (or "coarse" bank select according to
|
||||
my spec). Prior to this fix a channel's bank number was only
|
||||
changed upon reception of MIDI bank select controller 32,
|
||||
e.g, bank select LSB (or "fine" bank-select according to my
|
||||
spec). [KLE]
|
||||
|
||||
FIXME: is this correct? [PH] */
|
||||
fluid_channel_set_banknum(chan, (unsigned int)(value & 0x7f)); /* KLE */
|
||||
}
|
||||
break;
|
||||
|
||||
case BANK_SELECT_LSB:
|
||||
{
|
||||
/* FIXME: according to the Downloadable Sounds II specification,
|
||||
bit 31 should be set when we receive the message on channel
|
||||
10 (drum channel) */
|
||||
fluid_channel_set_banknum(chan, (((unsigned int) value & 0x7f)
|
||||
+ ((unsigned int) chan->bank_msb << 7)));
|
||||
}
|
||||
break;
|
||||
|
||||
case ALL_NOTES_OFF:
|
||||
fluid_synth_all_notes_off(chan->synth, chan->channum);
|
||||
break;
|
||||
|
||||
case ALL_SOUND_OFF:
|
||||
fluid_synth_all_sounds_off(chan->synth, chan->channum);
|
||||
break;
|
||||
|
||||
case ALL_CTRL_OFF:
|
||||
fluid_channel_init_ctrl(chan,1);
|
||||
fluid_synth_modulate_voices_all(chan->synth, chan->channum);
|
||||
break;
|
||||
|
||||
case DATA_ENTRY_MSB:
|
||||
{
|
||||
int data = (value << 7) + chan->cc[DATA_ENTRY_LSB];
|
||||
|
||||
if (chan->nrpn_active) /* NRPN is active? */
|
||||
{
|
||||
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
|
||||
if ((chan->cc[NRPN_MSB] == 120) && (chan->cc[NRPN_LSB] < 100))
|
||||
{
|
||||
if (chan->nrpn_select < GEN_LAST)
|
||||
{
|
||||
float val = fluid_gen_scale_nrpn(chan->nrpn_select, data);
|
||||
fluid_synth_set_gen(chan->synth, chan->channum, chan->nrpn_select, val);
|
||||
}
|
||||
|
||||
chan->nrpn_select = 0; /* Reset to 0 */
|
||||
}
|
||||
}
|
||||
else if (chan->cc[RPN_MSB] == 0) /* RPN is active: MSB = 0? */
|
||||
{
|
||||
switch (chan->cc[RPN_LSB])
|
||||
{
|
||||
case RPN_PITCH_BEND_RANGE:
|
||||
fluid_channel_pitch_wheel_sens (chan, value); /* Set bend range in semitones */
|
||||
/* FIXME - Handle LSB? (Fine bend range in cents) */
|
||||
break;
|
||||
case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over +/-1 semitone (+/- 100 cents, 8192 = center) */
|
||||
fluid_synth_set_gen(chan->synth, chan->channum, GEN_FINETUNE,
|
||||
(data - 8192) / 8192.0 * 100.0);
|
||||
break;
|
||||
case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */
|
||||
fluid_synth_set_gen(chan->synth, chan->channum, GEN_COARSETUNE,
|
||||
value - 64);
|
||||
break;
|
||||
case RPN_TUNING_PROGRAM_CHANGE:
|
||||
break;
|
||||
case RPN_TUNING_BANK_SELECT:
|
||||
break;
|
||||
case RPN_MODULATION_DEPTH_RANGE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NRPN_MSB:
|
||||
chan->cc[NRPN_LSB] = 0;
|
||||
chan->nrpn_select = 0;
|
||||
chan->nrpn_active = 1;
|
||||
break;
|
||||
|
||||
case NRPN_LSB:
|
||||
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
|
||||
if (chan->cc[NRPN_MSB] == 120) {
|
||||
if (value == 100) {
|
||||
chan->nrpn_select += 100;
|
||||
} else if (value == 101) {
|
||||
chan->nrpn_select += 1000;
|
||||
} else if (value == 102) {
|
||||
chan->nrpn_select += 10000;
|
||||
} else if (value < 100) {
|
||||
chan->nrpn_select += value;
|
||||
}
|
||||
}
|
||||
|
||||
chan->nrpn_active = 1;
|
||||
break;
|
||||
|
||||
case RPN_MSB:
|
||||
case RPN_LSB:
|
||||
chan->nrpn_active = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 1, num);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_cc
|
||||
*/
|
||||
int
|
||||
fluid_channel_get_cc(fluid_channel_t* chan, int num)
|
||||
{
|
||||
return ((num >= 0) && (num < 128))? chan->cc[num] : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_pressure
|
||||
*/
|
||||
int
|
||||
fluid_channel_pressure(fluid_channel_t* chan, int val)
|
||||
{
|
||||
chan->channel_pressure = val;
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_CHANNELPRESSURE);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_pitch_bend
|
||||
*/
|
||||
int
|
||||
fluid_channel_pitch_bend(fluid_channel_t* chan, int val)
|
||||
{
|
||||
chan->pitch_bend = val;
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_PITCHWHEEL);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_pitch_wheel_sens
|
||||
*/
|
||||
int
|
||||
fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val)
|
||||
{
|
||||
chan->pitch_wheel_sensitivity = val;
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_PITCHWHEELSENS);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_num
|
||||
*/
|
||||
int
|
||||
fluid_channel_get_num(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->channum;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* Sets the index of the interpolation method used on this channel,
|
||||
* as in fluid_interp in fluidlite.h
|
||||
*/
|
||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
|
||||
{
|
||||
chan->interp_method = new_method;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* Returns the index of the interpolation method used on this channel,
|
||||
* as in fluid_interp in fluidlite.h
|
||||
*/
|
||||
int fluid_channel_get_interp_method(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->interp_method;
|
||||
}
|
||||
|
||||
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->sfontnum;
|
||||
}
|
||||
|
||||
int fluid_channel_set_sfontnum(fluid_channel_t* chan, unsigned int sfontnum)
|
||||
{
|
||||
chan->sfontnum = sfontnum;
|
||||
return FLUID_OK;
|
||||
}
|
110
framework/audio/midi/3rdparty/fluidlite/src/fluid_chan.h
vendored
Normal file
110
framework/audio/midi/3rdparty/fluidlite/src/fluid_chan.h
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_CHAN_H
|
||||
#define _FLUID_CHAN_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_midi.h"
|
||||
#include "fluid_tuning.h"
|
||||
|
||||
/*
|
||||
* fluid_channel_t
|
||||
*/
|
||||
struct _fluid_channel_t
|
||||
{
|
||||
int channum;
|
||||
unsigned int sfontnum;
|
||||
unsigned int banknum;
|
||||
unsigned int prognum;
|
||||
fluid_preset_t* preset;
|
||||
fluid_synth_t* synth;
|
||||
short key_pressure;
|
||||
short channel_pressure;
|
||||
short pitch_bend;
|
||||
short pitch_wheel_sensitivity;
|
||||
|
||||
/* controller values */
|
||||
short cc[128];
|
||||
|
||||
/* cached values of last MSB values of MSB/LSB controllers */
|
||||
unsigned char bank_msb;
|
||||
int interp_method;
|
||||
|
||||
/* the micro-tuning */
|
||||
fluid_tuning_t* tuning;
|
||||
|
||||
/* NRPN system */
|
||||
short nrpn_select;
|
||||
short nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
|
||||
/* The values of the generators, set by NRPN messages, or by
|
||||
* fluid_synth_set_gen(), are cached in the channel so they can be
|
||||
* applied to future notes. They are copied to a voice's generators
|
||||
* in fluid_voice_init(), wihich calls fluid_gen_init(). */
|
||||
fluid_real_t gen[GEN_LAST];
|
||||
|
||||
/* By default, the NRPN values are relative to the values of the
|
||||
* generators set in the SoundFont. For example, if the NRPN
|
||||
* specifies an attack of 100 msec then 100 msec will be added to the
|
||||
* combined attack time of the sound font and the modulators.
|
||||
*
|
||||
* However, it is useful to be able to specify the generator value
|
||||
* absolutely, completely ignoring the generators of the sound font
|
||||
* and the values of modulators. The gen_abs field, is a boolean
|
||||
* flag indicating whether the NRPN value is absolute or not.
|
||||
*/
|
||||
char gen_abs[GEN_LAST];
|
||||
};
|
||||
|
||||
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
|
||||
int delete_fluid_channel(fluid_channel_t* chan);
|
||||
void fluid_channel_init(fluid_channel_t* chan);
|
||||
void fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off);
|
||||
void fluid_channel_reset(fluid_channel_t* chan);
|
||||
int fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset);
|
||||
fluid_preset_t* fluid_channel_get_preset(fluid_channel_t* chan);
|
||||
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan);
|
||||
int fluid_channel_set_sfontnum(fluid_channel_t* chan, unsigned int sfont);
|
||||
unsigned int fluid_channel_get_banknum(fluid_channel_t* chan);
|
||||
int fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int bank);
|
||||
int fluid_channel_set_prognum(fluid_channel_t* chan, int prognum);
|
||||
int fluid_channel_get_prognum(fluid_channel_t* chan);
|
||||
int fluid_channel_cc(fluid_channel_t* chan, int ctrl, int val);
|
||||
int fluid_channel_pressure(fluid_channel_t* chan, int val);
|
||||
int fluid_channel_pitch_bend(fluid_channel_t* chan, int val);
|
||||
int fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val);
|
||||
int fluid_channel_get_cc(fluid_channel_t* chan, int num);
|
||||
int fluid_channel_get_num(fluid_channel_t* chan);
|
||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
|
||||
int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
||||
|
||||
#define fluid_channel_set_tuning(_c, _t) { (_c)->tuning = _t; }
|
||||
#define fluid_channel_has_tuning(_c) ((_c)->tuning != NULL)
|
||||
#define fluid_channel_get_tuning(_c) ((_c)->tuning)
|
||||
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
|
||||
#define fluid_channel_set_gen(_c, _n, _v, _a) { (_c)->gen[_n] = _v; (_c)->gen_abs[_n] = _a; }
|
||||
#define fluid_channel_get_gen(_c, _n) ((_c)->gen[_n])
|
||||
#define fluid_channel_get_gen_abs(_c, _n) ((_c)->gen_abs[_n])
|
||||
|
||||
#define fluid_channel_get_min_note_length_ticks(chan) \
|
||||
((chan)->synth->min_note_length_ticks)
|
||||
|
||||
#endif /* _FLUID_CHAN_H */
|
606
framework/audio/midi/3rdparty/fluidlite/src/fluid_chorus.c
vendored
Normal file
606
framework/audio/midi/3rdparty/fluidlite/src/fluid_chorus.c
vendored
Normal file
|
@ -0,0 +1,606 @@
|
|||
/*
|
||||
* August 24, 1998
|
||||
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
|
||||
* This source code is freely redistributable and may be used for
|
||||
* any purpose. This copyright notice must be maintained.
|
||||
* Juergen Mueller And Sundry Contributors are not responsible for
|
||||
* the consequences of using this software.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
CHANGES
|
||||
|
||||
- Adapted for fluidsynth, Peter Hanappe, March 2002
|
||||
|
||||
- Variable delay line implementation using bandlimited
|
||||
interpolation, code reorganization: Markus Nentwig May 2002
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Chorus effect.
|
||||
*
|
||||
* Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ):
|
||||
*
|
||||
* * gain-in ___
|
||||
* ibuff -----+--------------------------------------------->| |
|
||||
* | _________ | |
|
||||
* | | | * level 1 | |
|
||||
* +---->| delay 1 |----------------------------->| |
|
||||
* | |_________| | |
|
||||
* | /|\ | |
|
||||
* : | | |
|
||||
* : +-----------------+ +--------------+ | + |
|
||||
* : | Delay control 1 |<--| mod. speed 1 | | |
|
||||
* : +-----------------+ +--------------+ | |
|
||||
* | _________ | |
|
||||
* | | | * level n | |
|
||||
* +---->| delay n |----------------------------->| |
|
||||
* |_________| | |
|
||||
* /|\ |___|
|
||||
* | |
|
||||
* +-----------------+ +--------------+ | * gain-out
|
||||
* | Delay control n |<--| mod. speed n | |
|
||||
* +-----------------+ +--------------+ +----->obuff
|
||||
*
|
||||
*
|
||||
* The delay i is controlled by a sine or triangle modulation i ( 1 <= i <= n).
|
||||
*
|
||||
* The delay of each block is modulated between 0..depth ms
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Variable delay line implementation
|
||||
* ==================================
|
||||
*
|
||||
* The modulated delay needs the value of the delayed signal between
|
||||
* samples. A lowpass filter is used to obtain intermediate values
|
||||
* between samples (bandlimited interpolation). The sample pulse
|
||||
* train is convoluted with the impulse response of the low pass
|
||||
* filter (sinc function). To make it work with a small number of
|
||||
* samples, the sinc function is windowed (Hamming window).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fluid_chorus.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#define MAX_CHORUS 99
|
||||
#define MAX_DELAY 100
|
||||
#define MAX_DEPTH 10
|
||||
#define MIN_SPEED_HZ 0.29
|
||||
#define MAX_SPEED_HZ 5
|
||||
|
||||
/* Length of one delay line in samples:
|
||||
* Set through MAX_SAMPLES_LN2.
|
||||
* For example:
|
||||
* MAX_SAMPLES_LN2=12
|
||||
* => MAX_SAMPLES=pow(2,12)=4096
|
||||
* => MAX_SAMPLES_ANDMASK=4095
|
||||
*/
|
||||
#define MAX_SAMPLES_LN2 12
|
||||
|
||||
#define MAX_SAMPLES (1 << (MAX_SAMPLES_LN2-1))
|
||||
#define MAX_SAMPLES_ANDMASK (MAX_SAMPLES-1)
|
||||
|
||||
|
||||
/* Interpolate how many steps between samples? Must be power of two
|
||||
For example: 8 => use a resolution of 256 steps between any two
|
||||
samples
|
||||
*/
|
||||
#define INTERPOLATION_SUBSAMPLES_LN2 8
|
||||
#define INTERPOLATION_SUBSAMPLES (1 << (INTERPOLATION_SUBSAMPLES_LN2-1))
|
||||
#define INTERPOLATION_SUBSAMPLES_ANDMASK (INTERPOLATION_SUBSAMPLES-1)
|
||||
|
||||
/* Use how many samples for interpolation? Must be odd. '7' sounds
|
||||
relatively clean, when listening to the modulated delay signal
|
||||
alone. For a demo on aliasing try '1' With '3', the aliasing is
|
||||
still quite pronounced for some input frequencies
|
||||
*/
|
||||
#define INTERPOLATION_SAMPLES 5
|
||||
|
||||
/* Private data for SKEL file */
|
||||
struct _fluid_chorus_t {
|
||||
/* Store the values between fluid_chorus_set_xxx and fluid_chorus_update
|
||||
* Logic behind this:
|
||||
* - both 'parameter' and 'new_parameter' hold the same value.
|
||||
* - To change the chorus settings, 'new_parameter' is modified and
|
||||
* fluid_chorus_update is called.
|
||||
* - If the new value is valid, it is copied to 'parameter'.
|
||||
* - If it is invalid, 'new_parameter' is restored to 'parameter'.
|
||||
*/
|
||||
int type; /* current value */
|
||||
int new_type; /* next value, if parameter check is OK */
|
||||
fluid_real_t depth_ms; /* current value */
|
||||
fluid_real_t new_depth_ms; /* next value, if parameter check is OK */
|
||||
fluid_real_t level; /* current value */
|
||||
fluid_real_t new_level; /* next value, if parameter check is OK */
|
||||
fluid_real_t speed_Hz; /* current value */
|
||||
fluid_real_t new_speed_Hz; /* next value, if parameter check is OK */
|
||||
int number_blocks; /* current value */
|
||||
int new_number_blocks; /* next value, if parameter check is OK */
|
||||
|
||||
fluid_real_t *chorusbuf;
|
||||
int counter;
|
||||
long phase[MAX_CHORUS];
|
||||
long modulation_period_samples;
|
||||
int *lookup_tab;
|
||||
fluid_real_t sample_rate;
|
||||
|
||||
/* sinc lookup table */
|
||||
fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
|
||||
};
|
||||
|
||||
void fluid_chorus_triangle(int *buf, int len, int depth);
|
||||
void fluid_chorus_sine(int *buf, int len, int depth);
|
||||
|
||||
fluid_chorus_t*
|
||||
new_fluid_chorus(fluid_real_t sample_rate)
|
||||
{
|
||||
int i; int ii;
|
||||
fluid_chorus_t* chorus;
|
||||
|
||||
chorus = FLUID_NEW(fluid_chorus_t);
|
||||
if (chorus == NULL) {
|
||||
fluid_log(FLUID_PANIC, "chorus: Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
|
||||
|
||||
chorus->sample_rate = sample_rate;
|
||||
|
||||
/* Lookup table for the SI function (impulse response of an ideal low pass) */
|
||||
|
||||
/* i: Offset in terms of whole samples */
|
||||
for (i = 0; i < INTERPOLATION_SAMPLES; i++){
|
||||
|
||||
/* ii: Offset in terms of fractional samples ('subsamples') */
|
||||
for (ii = 0; ii < INTERPOLATION_SUBSAMPLES; ii++){
|
||||
/* Move the origin into the center of the table */
|
||||
double i_shifted = ((double) i- ((double) INTERPOLATION_SAMPLES) / 2.
|
||||
+ (double) ii / (double) INTERPOLATION_SUBSAMPLES);
|
||||
if (fabs(i_shifted) < 0.000001) {
|
||||
/* sinc(0) cannot be calculated straightforward (limit needed
|
||||
for 0/0) */
|
||||
chorus->sinc_table[i][ii] = (fluid_real_t)1.;
|
||||
|
||||
} else {
|
||||
chorus->sinc_table[i][ii] = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
|
||||
/* Hamming window */
|
||||
chorus->sinc_table[i][ii] *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)INTERPOLATION_SAMPLES));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* allocate lookup tables */
|
||||
chorus->lookup_tab = FLUID_ARRAY(int, (int) (chorus->sample_rate / MIN_SPEED_HZ));
|
||||
if (chorus->lookup_tab == NULL) {
|
||||
fluid_log(FLUID_PANIC, "chorus: Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
/* allocate sample buffer */
|
||||
|
||||
chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
|
||||
if (chorus->chorusbuf == NULL) {
|
||||
fluid_log(FLUID_PANIC, "chorus: Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (fluid_chorus_init(chorus) != FLUID_OK){
|
||||
goto error_recovery;
|
||||
};
|
||||
|
||||
return chorus;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_chorus(chorus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
fluid_chorus_init(fluid_chorus_t* chorus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SAMPLES; i++) {
|
||||
chorus->chorusbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
/* initialize the chorus with the default settings */
|
||||
fluid_chorus_set_nr(chorus, FLUID_CHORUS_DEFAULT_N);
|
||||
fluid_chorus_set_level(chorus, FLUID_CHORUS_DEFAULT_LEVEL);
|
||||
fluid_chorus_set_speed_Hz(chorus, FLUID_CHORUS_DEFAULT_SPEED);
|
||||
fluid_chorus_set_depth_ms(chorus, FLUID_CHORUS_DEFAULT_DEPTH);
|
||||
fluid_chorus_set_type(chorus, FLUID_CHORUS_MOD_SINE);
|
||||
|
||||
return fluid_chorus_update(chorus);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* Sets the number of stages.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Range checking is performed there.*/
|
||||
void fluid_chorus_set_nr(fluid_chorus_t* chorus, int nr)
|
||||
{
|
||||
chorus->new_number_blocks = nr;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
int fluid_chorus_get_nr(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->number_blocks;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the mixing level of the signal from each delay line (linear).
|
||||
* Requires calling fluid_chorus_update afterwards.*/
|
||||
void fluid_chorus_set_level(fluid_chorus_t* chorus, fluid_real_t level)
|
||||
{
|
||||
chorus->new_level = level;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
fluid_real_t fluid_chorus_get_level(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->level;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the modulation frequency.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Range checking is performed there.*/
|
||||
void fluid_chorus_set_speed_Hz(fluid_chorus_t* chorus, fluid_real_t speed_Hz)
|
||||
{
|
||||
chorus->new_speed_Hz = speed_Hz;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
fluid_real_t fluid_chorus_get_speed_Hz(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->speed_Hz;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the modulation depth in ms.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Range checking is performed there.*/
|
||||
void fluid_chorus_set_depth_ms(fluid_chorus_t* chorus, fluid_real_t depth_ms)
|
||||
{
|
||||
chorus->new_depth_ms=depth_ms;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
fluid_real_t fluid_chorus_get_depth_ms(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->depth_ms;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the type of the modulation waveform.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Check for meaningful values is performed there.*/
|
||||
void fluid_chorus_set_type(fluid_chorus_t* chorus, int type)
|
||||
{
|
||||
chorus->new_type=type;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
int fluid_chorus_get_type(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->type;
|
||||
};
|
||||
|
||||
void
|
||||
delete_fluid_chorus(fluid_chorus_t* chorus)
|
||||
{
|
||||
if (chorus == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chorus->chorusbuf != NULL) {
|
||||
FLUID_FREE(chorus->chorusbuf);
|
||||
}
|
||||
|
||||
if (chorus->lookup_tab != NULL) {
|
||||
FLUID_FREE(chorus->lookup_tab);
|
||||
}
|
||||
|
||||
FLUID_FREE(chorus);
|
||||
}
|
||||
|
||||
|
||||
/* Purpose:
|
||||
* Calculates the internal chorus parameters using the settings from
|
||||
* fluid_chorus_set_xxx. */
|
||||
int
|
||||
fluid_chorus_update(fluid_chorus_t* chorus)
|
||||
{
|
||||
int i;
|
||||
int modulation_depth_samples;
|
||||
|
||||
if (chorus->new_number_blocks < 0) {
|
||||
fluid_log(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
|
||||
chorus->new_number_blocks = 0;
|
||||
} else if (chorus->new_number_blocks > MAX_CHORUS) {
|
||||
fluid_log(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
|
||||
MAX_CHORUS);
|
||||
chorus->new_number_blocks = MAX_CHORUS;
|
||||
};
|
||||
|
||||
if (chorus->new_speed_Hz < MIN_SPEED_HZ) {
|
||||
fluid_log(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.",
|
||||
(double) MIN_SPEED_HZ);
|
||||
chorus->new_speed_Hz = MIN_SPEED_HZ;
|
||||
} else if (chorus->new_speed_Hz > MAX_SPEED_HZ) {
|
||||
fluid_log(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.",
|
||||
(double) MAX_SPEED_HZ);
|
||||
chorus->new_speed_Hz = MAX_SPEED_HZ;
|
||||
}
|
||||
if (chorus->new_depth_ms < 0.0) {
|
||||
fluid_log(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
|
||||
chorus->new_depth_ms = 0.0;
|
||||
}
|
||||
/* Depth: Check for too high value through modulation_depth_samples. */
|
||||
|
||||
if (chorus->new_level < 0.0) {
|
||||
fluid_log(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
|
||||
chorus->new_level = 0.0;
|
||||
} else if (chorus->new_level > 10) {
|
||||
fluid_log(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
|
||||
"Setting it to 0.1.");
|
||||
chorus->new_level = 0.1;
|
||||
}
|
||||
|
||||
/* The modulating LFO goes through a full period every x samples: */
|
||||
chorus->modulation_period_samples = chorus->sample_rate / chorus->new_speed_Hz;
|
||||
|
||||
/* The variation in delay time is x: */
|
||||
modulation_depth_samples = (int)
|
||||
(chorus->new_depth_ms / 1000.0 /* convert modulation depth in ms to s*/
|
||||
* chorus->sample_rate);
|
||||
|
||||
if (modulation_depth_samples > MAX_SAMPLES) {
|
||||
fluid_log(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
|
||||
modulation_depth_samples = MAX_SAMPLES;
|
||||
}
|
||||
|
||||
/* initialize LFO table */
|
||||
if (chorus->type == FLUID_CHORUS_MOD_SINE) {
|
||||
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
} else if (chorus->type == FLUID_CHORUS_MOD_TRIANGLE) {
|
||||
fluid_chorus_triangle(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
} else {
|
||||
fluid_log(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave.");
|
||||
chorus->type = FLUID_CHORUS_MOD_SINE;
|
||||
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
};
|
||||
|
||||
for (i = 0; i < chorus->number_blocks; i++) {
|
||||
/* Set the phase of the chorus blocks equally spaced */
|
||||
chorus->phase[i] = (int) ((double) chorus->modulation_period_samples
|
||||
* (double) i / (double) chorus->number_blocks);
|
||||
}
|
||||
|
||||
/* Start of the circular buffer */
|
||||
chorus->counter = 0;
|
||||
|
||||
chorus->type = chorus->new_type;
|
||||
chorus->depth_ms = chorus->new_depth_ms;
|
||||
chorus->level = chorus->new_level;
|
||||
chorus->speed_Hz = chorus->new_speed_Hz;
|
||||
chorus->number_blocks = chorus->new_number_blocks;
|
||||
return FLUID_OK;
|
||||
|
||||
/* failure: */
|
||||
/* Note: This lives on the assumption, that the last chorus values were correct.
|
||||
* If not, this will loop forever and a day. */
|
||||
/* fluid_log(FLUID_WARN, "chorus: Restoring last good settings"); */
|
||||
/* chorus->new_type = chorus->type; */
|
||||
/* chorus->new_depth_ms = chorus->depth_ms; */
|
||||
/* chorus->new_level = chorus->level; */
|
||||
/* chorus->new_speed_Hz = chorus->speed_Hz; */
|
||||
/* chorus->new_number_blocks = chorus->number_blocks; */
|
||||
/* return FLUID_FAILED; */
|
||||
}
|
||||
|
||||
|
||||
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int sample_index;
|
||||
int i;
|
||||
fluid_real_t d_in, d_out;
|
||||
|
||||
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
|
||||
|
||||
d_in = in[sample_index];
|
||||
d_out = 0.0f;
|
||||
|
||||
# if 0
|
||||
/* Debug: Listen to the chorus signal only */
|
||||
left_out[sample_index]=0;
|
||||
right_out[sample_index]=0;
|
||||
#endif
|
||||
|
||||
/* Write the current sample into the circular buffer */
|
||||
chorus->chorusbuf[chorus->counter] = d_in;
|
||||
|
||||
for (i = 0; i < chorus->number_blocks; i++) {
|
||||
int ii;
|
||||
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
|
||||
|
||||
/* The value in the lookup table is so, that this expression
|
||||
* will always be positive. It will always include a number of
|
||||
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
|
||||
* remain positive at all times. */
|
||||
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
|
||||
- chorus->lookup_tab[chorus->phase[i]]);
|
||||
|
||||
int pos_samples = pos_subsamples/INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* modulo divide by INTERPOLATION_SUBSAMPLES */
|
||||
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
|
||||
|
||||
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
|
||||
/* Add the delayed signal to the chorus sum d_out Note: The
|
||||
* delay in the delay line moves backwards for increasing
|
||||
* delay!*/
|
||||
|
||||
/* The & in chorusbuf[...] is equivalent to a division modulo
|
||||
MAX_SAMPLES, only faster. */
|
||||
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
|
||||
* chorus->sinc_table[ii][pos_subsamples];
|
||||
|
||||
pos_samples--;
|
||||
};
|
||||
/* Cycle the phase of the modulating LFO */
|
||||
chorus->phase[i]++;
|
||||
chorus->phase[i] %= (chorus->modulation_period_samples);
|
||||
} /* foreach chorus block */
|
||||
|
||||
d_out *= chorus->level;
|
||||
|
||||
/* Add the chorus sum d_out to output */
|
||||
left_out[sample_index] += d_out;
|
||||
right_out[sample_index] += d_out;
|
||||
|
||||
/* Move forward in circular buffer */
|
||||
chorus->counter++;
|
||||
chorus->counter %= MAX_SAMPLES;
|
||||
|
||||
} /* foreach sample */
|
||||
}
|
||||
|
||||
/* Duplication of code ... (replaces sample data instead of mixing) */
|
||||
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int sample_index;
|
||||
int i;
|
||||
fluid_real_t d_in, d_out;
|
||||
|
||||
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
|
||||
|
||||
d_in = in[sample_index];
|
||||
d_out = 0.0f;
|
||||
|
||||
# if 0
|
||||
/* Debug: Listen to the chorus signal only */
|
||||
left_out[sample_index]=0;
|
||||
right_out[sample_index]=0;
|
||||
#endif
|
||||
|
||||
/* Write the current sample into the circular buffer */
|
||||
chorus->chorusbuf[chorus->counter] = d_in;
|
||||
|
||||
for (i = 0; i < chorus->number_blocks; i++) {
|
||||
int ii;
|
||||
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
|
||||
|
||||
/* The value in the lookup table is so, that this expression
|
||||
* will always be positive. It will always include a number of
|
||||
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
|
||||
* remain positive at all times. */
|
||||
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
|
||||
- chorus->lookup_tab[chorus->phase[i]]);
|
||||
|
||||
int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* modulo divide by INTERPOLATION_SUBSAMPLES */
|
||||
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
|
||||
|
||||
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
|
||||
/* Add the delayed signal to the chorus sum d_out Note: The
|
||||
* delay in the delay line moves backwards for increasing
|
||||
* delay!*/
|
||||
|
||||
/* The & in chorusbuf[...] is equivalent to a division modulo
|
||||
MAX_SAMPLES, only faster. */
|
||||
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
|
||||
* chorus->sinc_table[ii][pos_subsamples];
|
||||
|
||||
pos_samples--;
|
||||
};
|
||||
/* Cycle the phase of the modulating LFO */
|
||||
chorus->phase[i]++;
|
||||
chorus->phase[i] %= (chorus->modulation_period_samples);
|
||||
} /* foreach chorus block */
|
||||
|
||||
d_out *= chorus->level;
|
||||
|
||||
/* Store the chorus sum d_out to output */
|
||||
left_out[sample_index] = d_out;
|
||||
right_out[sample_index] = d_out;
|
||||
|
||||
/* Move forward in circular buffer */
|
||||
chorus->counter++;
|
||||
chorus->counter %= MAX_SAMPLES;
|
||||
|
||||
} /* foreach sample */
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
*
|
||||
* Calculates a modulation waveform (sine) Its value ( modulo
|
||||
* MAXSAMPLES) varies between 0 and depth*INTERPOLATION_SUBSAMPLES.
|
||||
* Its period length is len. The waveform data will be used modulo
|
||||
* MAXSAMPLES only. Since MAXSAMPLES is substracted from the waveform
|
||||
* a couple of times here, the resulting (current position in
|
||||
* buffer)-(waveform sample) will always be positive.
|
||||
*/
|
||||
void fluid_chorus_sine(int *buf, int len, int depth)
|
||||
{
|
||||
int i;
|
||||
double val;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
val = sin((double) i / (double)len * 2.0 * M_PI);
|
||||
buf[i] = (int) ((1.0 + val) * (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES);
|
||||
buf[i] -= 3* MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||
// printf("%i %i\n",i,buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* Calculates a modulation waveform (triangle)
|
||||
* See fluid_chorus_sine for comments.
|
||||
*/
|
||||
void fluid_chorus_triangle(int *buf, int len, int depth)
|
||||
{
|
||||
int i=0;
|
||||
int ii=len-1;
|
||||
double val;
|
||||
double val2;
|
||||
|
||||
while (i <= ii){
|
||||
val = i * 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
|
||||
val2= (int) (val + 0.5) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||
buf[i++] = (int) val2;
|
||||
buf[ii--] = (int) val2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_chorus_reset(fluid_chorus_t* chorus)
|
||||
{
|
||||
fluid_chorus_init(chorus);
|
||||
}
|
56
framework/audio/midi/3rdparty/fluidlite/src/fluid_chorus.h
vendored
Normal file
56
framework/audio/midi/3rdparty/fluidlite/src/fluid_chorus.h
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_CHORUS_H
|
||||
#define _FLUID_CHORUS_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
typedef struct _fluid_chorus_t fluid_chorus_t;
|
||||
|
||||
/*
|
||||
* chorus
|
||||
*/
|
||||
fluid_chorus_t* new_fluid_chorus(fluid_real_t sample_rate);
|
||||
void delete_fluid_chorus(fluid_chorus_t* chorus);
|
||||
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
int fluid_chorus_init(fluid_chorus_t* chorus);
|
||||
void fluid_chorus_reset(fluid_chorus_t* chorus);
|
||||
|
||||
void fluid_chorus_set_nr(fluid_chorus_t* chorus, int nr);
|
||||
void fluid_chorus_set_level(fluid_chorus_t* chorus, fluid_real_t level);
|
||||
void fluid_chorus_set_speed_Hz(fluid_chorus_t* chorus, fluid_real_t speed_Hz);
|
||||
void fluid_chorus_set_depth_ms(fluid_chorus_t* chorus, fluid_real_t depth_ms);
|
||||
void fluid_chorus_set_type(fluid_chorus_t* chorus, int type);
|
||||
int fluid_chorus_update(fluid_chorus_t* chorus);
|
||||
int fluid_chorus_get_nr(fluid_chorus_t* chorus);
|
||||
fluid_real_t fluid_chorus_get_level(fluid_chorus_t* chorus);
|
||||
fluid_real_t fluid_chorus_get_speed_Hz(fluid_chorus_t* chorus);
|
||||
fluid_real_t fluid_chorus_get_depth_ms(fluid_chorus_t* chorus);
|
||||
int fluid_chorus_get_type(fluid_chorus_t* chorus);
|
||||
|
||||
|
||||
#endif /* _FLUID_CHORUS_H */
|
30
framework/audio/midi/3rdparty/fluidlite/src/fluid_config.h
vendored
Normal file
30
framework/audio/midi/3rdparty/fluidlite/src/fluid_config.h
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* src/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
|
||||
/* Define to activate debugging message */
|
||||
#undef DEBUG
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.0.9"
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
|
||||
#define SF3_SUPPORT 0
|
||||
#define WITH_FLOAT 1
|
||||
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_STDIO_H 1
|
||||
#define HAVE_MATH_H 1
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_FCNTL_H 1
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
|
||||
//#pragma warning(disable : 4244)
|
||||
//#pragma warning(disable : 4101)
|
||||
//#pragma warning(disable : 4305)
|
||||
//#pragma warning(disable : 4996)
|
320
framework/audio/midi/3rdparty/fluidlite/src/fluid_conv.c
vendored
Normal file
320
framework/audio/midi/3rdparty/fluidlite/src/fluid_conv.c
vendored
Normal file
|
@ -0,0 +1,320 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluid_conv.h"
|
||||
|
||||
|
||||
/* conversion tables */
|
||||
fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||
fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||
fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
|
||||
fluid_real_t fluid_posbp_tab[128];
|
||||
fluid_real_t fluid_concave_tab[128];
|
||||
fluid_real_t fluid_convex_tab[128];
|
||||
fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
|
||||
/*
|
||||
* void fluid_synth_init
|
||||
*
|
||||
* Does all the initialization for this module.
|
||||
*/
|
||||
void
|
||||
fluid_conversion_config(void)
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
|
||||
for (i = 0; i < FLUID_CENTS_HZ_SIZE; i++) {
|
||||
fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
|
||||
}
|
||||
|
||||
/* centibels to amplitude conversion
|
||||
* Note: SF2.01 section 8.1.3: Initial attenuation range is
|
||||
* between 0 and 144 dB. Therefore a negative attenuation is
|
||||
* not allowed.
|
||||
*/
|
||||
for (i = 0; i < FLUID_CB_AMP_SIZE; i++) {
|
||||
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
|
||||
}
|
||||
|
||||
/* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
|
||||
* specification in regards to volume attenuation. The below calculation
|
||||
* is an approx. equation for generating a table equivelant to the
|
||||
* cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
|
||||
* was generated from device testing. By the spec this should be centibels.
|
||||
*/
|
||||
for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
|
||||
fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
|
||||
}
|
||||
|
||||
/* initialize the conversion tables (see fluid_mod.c
|
||||
fluid_mod_get_value cases 4 and 8) */
|
||||
|
||||
/* concave unipolar positive transform curve */
|
||||
fluid_concave_tab[0] = 0.0;
|
||||
fluid_concave_tab[127] = 1.0;
|
||||
|
||||
/* convex unipolar positive transform curve */
|
||||
fluid_convex_tab[0] = 0;
|
||||
fluid_convex_tab[127] = 1.0;
|
||||
x = log10(128.0 / 127.0);
|
||||
|
||||
/* There seems to be an error in the specs. The equations are
|
||||
implemented according to the pictures on SF2.01 page 73. */
|
||||
|
||||
for (i = 1; i < 127; i++) {
|
||||
x = -20.0 / 96.0 * log((i * i) / (127.0 * 127.0)) / log(10.0);
|
||||
fluid_convex_tab[i] = (fluid_real_t) (1.0 - x);
|
||||
fluid_concave_tab[127 - i] = (fluid_real_t) x;
|
||||
}
|
||||
|
||||
/* initialize the pan conversion table */
|
||||
x = PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
|
||||
for (i = 0; i < FLUID_PAN_SIZE; i++) {
|
||||
fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_ct2hz
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_ct2hz_real(fluid_real_t cents)
|
||||
{
|
||||
if (cents < 0)
|
||||
return (fluid_real_t) 1.0;
|
||||
else if (cents < 900) {
|
||||
return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int) (cents + 300)];
|
||||
} else if (cents < 2100) {
|
||||
return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int) (cents - 900)];
|
||||
} else if (cents < 3300) {
|
||||
return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int) (cents - 2100)];
|
||||
} else if (cents < 4500) {
|
||||
return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int) (cents - 3300)];
|
||||
} else if (cents < 5700) {
|
||||
return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int) (cents - 4500)];
|
||||
} else if (cents < 6900) {
|
||||
return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int) (cents - 5700)];
|
||||
} else if (cents < 8100) {
|
||||
return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int) (cents - 6900)];
|
||||
} else if (cents < 9300) {
|
||||
return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int) (cents - 8100)];
|
||||
} else if (cents < 10500) {
|
||||
return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int) (cents - 9300)];
|
||||
} else if (cents < 11700) {
|
||||
return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int) (cents - 10500)];
|
||||
} else if (cents < 12900) {
|
||||
return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int) (cents - 11700)];
|
||||
} else if (cents < 14100) {
|
||||
return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int) (cents - 12900)];
|
||||
} else {
|
||||
return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_ct2hz
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_ct2hz(fluid_real_t cents)
|
||||
{
|
||||
/* Filter fc limit: SF2.01 page 48 # 8 */
|
||||
if (cents >= 13500){
|
||||
cents = 13500; /* 20 kHz */
|
||||
} else if (cents < 1500){
|
||||
cents = 1500; /* 20 Hz */
|
||||
}
|
||||
return fluid_ct2hz_real(cents);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_cb2amp
|
||||
*
|
||||
* in: a value between 0 and 960, 0 is no attenuation
|
||||
* out: a value between 1 and 0
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_cb2amp(fluid_real_t cb)
|
||||
{
|
||||
/*
|
||||
* cb: an attenuation in 'centibels' (1/10 dB)
|
||||
* SF2.01 page 49 # 48 limits it to 144 dB.
|
||||
* 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
|
||||
*/
|
||||
|
||||
/* minimum attenuation: 0 dB */
|
||||
if (cb < 0) {
|
||||
return 1.0;
|
||||
}
|
||||
if (cb >= FLUID_CB_AMP_SIZE) {
|
||||
return 0.0;
|
||||
}
|
||||
return fluid_cb2amp_tab[(int) cb];
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_atten2amp
|
||||
*
|
||||
* in: a value between 0 and 1440, 0 is no attenuation
|
||||
* out: a value between 1 and 0
|
||||
*
|
||||
* Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
|
||||
* follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_atten2amp(fluid_real_t atten)
|
||||
{
|
||||
if (atten < 0) return 1.0;
|
||||
else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
|
||||
else return fluid_atten2amp_tab[(int) atten];
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_tc2sec_delay
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_tc2sec_delay(fluid_real_t tc)
|
||||
{
|
||||
/* SF2.01 section 8.1.2 items 21, 23, 25, 33
|
||||
* SF2.01 section 8.1.3 items 21, 23, 25, 33
|
||||
*
|
||||
* The most negative number indicates a delay of 0. Range is limited
|
||||
* from -12000 to 5000 */
|
||||
if (tc <= -32768.0f) {
|
||||
return (fluid_real_t) 0.0f;
|
||||
};
|
||||
if (tc < -12000.) {
|
||||
tc = (fluid_real_t) -12000.0f;
|
||||
}
|
||||
if (tc > 5000.0f) {
|
||||
tc = (fluid_real_t) 5000.0f;
|
||||
}
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_tc2sec_attack
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_tc2sec_attack(fluid_real_t tc)
|
||||
{
|
||||
/* SF2.01 section 8.1.2 items 26, 34
|
||||
* SF2.01 section 8.1.3 items 26, 34
|
||||
* The most negative number indicates a delay of 0
|
||||
* Range is limited from -12000 to 8000 */
|
||||
if (tc<=-32768.){return (fluid_real_t) 0.0;};
|
||||
if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
|
||||
if (tc>8000.){tc=(fluid_real_t) 8000.0;};
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_tc2sec
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_tc2sec(fluid_real_t tc)
|
||||
{
|
||||
/* No range checking here! */
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_tc2sec_release
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_tc2sec_release(fluid_real_t tc)
|
||||
{
|
||||
/* SF2.01 section 8.1.2 items 30, 38
|
||||
* SF2.01 section 8.1.3 items 30, 38
|
||||
* No 'most negative number' rule here!
|
||||
* Range is limited from -12000 to 8000 */
|
||||
if (tc<=-32768.){return (fluid_real_t) 0.0;};
|
||||
if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
|
||||
if (tc>8000.){tc=(fluid_real_t) 8000.0;};
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_act2hz
|
||||
*
|
||||
* Convert from absolute cents to Hertz
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_act2hz(fluid_real_t c)
|
||||
{
|
||||
return (fluid_real_t) (8.176 * pow(2.0, (double) c / 1200.0));
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_hz2ct
|
||||
*
|
||||
* Convert from Hertz to cents
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_hz2ct(fluid_real_t f)
|
||||
{
|
||||
return (fluid_real_t) (6900 + 1200 * log(f / 440.0) / log(2.0));
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_pan
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_pan(fluid_real_t c, int left)
|
||||
{
|
||||
if (left) {
|
||||
c = -c;
|
||||
}
|
||||
if (c < -500) {
|
||||
return (fluid_real_t) 0.0;
|
||||
} else if (c > 500) {
|
||||
return (fluid_real_t) 1.0;
|
||||
} else {
|
||||
return fluid_pan_tab[(int) (c + 500)];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_concave
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_concave(fluid_real_t val)
|
||||
{
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
} else if (val > 127) {
|
||||
return 1;
|
||||
}
|
||||
return fluid_concave_tab[(int) val];
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_convex
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_convex(fluid_real_t val)
|
||||
{
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
} else if (val > 127) {
|
||||
return 1;
|
||||
}
|
||||
return fluid_convex_tab[(int) val];
|
||||
}
|
63
framework/audio/midi/3rdparty/fluidlite/src/fluid_conv.h
vendored
Normal file
63
framework/audio/midi/3rdparty/fluidlite/src/fluid_conv.h
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_CONV_H
|
||||
#define _FLUID_CONV_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#define FLUID_CENTS_HZ_SIZE 1200
|
||||
#define FLUID_VEL_CB_SIZE 128
|
||||
#define FLUID_CB_AMP_SIZE 961
|
||||
#define FLUID_ATTEN_AMP_SIZE 1441
|
||||
#define FLUID_PAN_SIZE 1002
|
||||
|
||||
/* EMU 8k/10k don't follow spec in regards to volume attenuation.
|
||||
* This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
|
||||
* By the standard this should be -200.0. */
|
||||
/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity. Now it equals the response of EMU10K1 programming.*/
|
||||
#define FLUID_ATTEN_POWER_FACTOR (-200.0) /* was (-531.509)*/
|
||||
|
||||
void fluid_conversion_config(void);
|
||||
|
||||
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
|
||||
fluid_real_t fluid_ct2hz(fluid_real_t cents);
|
||||
fluid_real_t fluid_cb2amp(fluid_real_t cb);
|
||||
fluid_real_t fluid_atten2amp(fluid_real_t atten);
|
||||
fluid_real_t fluid_tc2sec(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_release(fluid_real_t tc);
|
||||
fluid_real_t fluid_act2hz(fluid_real_t c);
|
||||
fluid_real_t fluid_hz2ct(fluid_real_t c);
|
||||
fluid_real_t fluid_pan(fluid_real_t c, int left);
|
||||
fluid_real_t fluid_concave(fluid_real_t val);
|
||||
fluid_real_t fluid_convex(fluid_real_t val);
|
||||
|
||||
extern fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||
extern fluid_real_t fluid_vel2cb_tab[FLUID_VEL_CB_SIZE];
|
||||
extern fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||
extern fluid_real_t fluid_posbp_tab[128];
|
||||
extern fluid_real_t fluid_concave_tab[128];
|
||||
extern fluid_real_t fluid_convex_tab[128];
|
||||
extern fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
|
||||
|
||||
#endif /* _FLUID_CONV_H */
|
3358
framework/audio/midi/3rdparty/fluidlite/src/fluid_defsfont.c
vendored
Normal file
3358
framework/audio/midi/3rdparty/fluidlite/src/fluid_defsfont.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
608
framework/audio/midi/3rdparty/fluidlite/src/fluid_defsfont.h
vendored
Normal file
608
framework/audio/midi/3rdparty/fluidlite/src/fluid_defsfont.h
vendored
Normal file
|
@ -0,0 +1,608 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_DEFSFONT_H
|
||||
#define _FLUID_DEFSFONT_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fluidlite.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_list.h"
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/*-----------------------------------sfont.h----------------------------*/
|
||||
|
||||
#define SF_SAMPMODES_LOOP 1
|
||||
#define SF_SAMPMODES_UNROLL 2
|
||||
|
||||
#define SF_MIN_SAMPLERATE 400
|
||||
#define SF_MAX_SAMPLERATE 50000
|
||||
|
||||
#define SF_MIN_SAMPLE_LENGTH 32
|
||||
|
||||
/* Sound Font structure defines */
|
||||
|
||||
typedef struct _SFVersion
|
||||
{ /* version structure */
|
||||
unsigned short major;
|
||||
unsigned short minor;
|
||||
}
|
||||
SFVersion;
|
||||
|
||||
typedef struct _SFMod
|
||||
{ /* Modulator structure */
|
||||
unsigned short src; /* source modulator */
|
||||
unsigned short dest; /* destination generator */
|
||||
signed short amount; /* signed, degree of modulation */
|
||||
unsigned short amtsrc; /* second source controls amnt of first */
|
||||
unsigned short trans; /* transform applied to source */
|
||||
}
|
||||
SFMod;
|
||||
|
||||
typedef union _SFGenAmount
|
||||
{ /* Generator amount structure */
|
||||
signed short sword; /* signed 16 bit value */
|
||||
unsigned short uword; /* unsigned 16 bit value */
|
||||
struct
|
||||
{
|
||||
unsigned char lo; /* low value for ranges */
|
||||
unsigned char hi; /* high value for ranges */
|
||||
}
|
||||
range;
|
||||
}
|
||||
SFGenAmount;
|
||||
|
||||
typedef struct _SFGen
|
||||
{ /* Generator structure */
|
||||
unsigned short id; /* generator ID */
|
||||
SFGenAmount amount; /* generator value */
|
||||
}
|
||||
SFGen;
|
||||
|
||||
typedef struct _SFZone
|
||||
{ /* Sample/instrument zone structure */
|
||||
fluid_list_t *instsamp; /* instrument/sample pointer for zone */
|
||||
fluid_list_t *gen; /* list of generators */
|
||||
fluid_list_t *mod; /* list of modulators */
|
||||
}
|
||||
SFZone;
|
||||
|
||||
typedef struct _SFSample
|
||||
{ /* Sample structure */
|
||||
char name[21]; /* Name of sample */
|
||||
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
|
||||
unsigned int start; /* Offset in sample area to start of sample */
|
||||
unsigned int end; /* Offset from start to end of sample,
|
||||
this is the last point of the
|
||||
sample, the SF spec has this as the
|
||||
1st point after, corrected on
|
||||
load/save */
|
||||
unsigned int loopstart; /* Offset from start to start of loop */
|
||||
unsigned int loopend; /* Offset from start to end of loop,
|
||||
marks the first point after loop,
|
||||
whose sample value is ideally
|
||||
equivalent to loopstart */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
}
|
||||
SFSample;
|
||||
|
||||
typedef struct _SFInst
|
||||
{ /* Instrument structure */
|
||||
char name[21]; /* Name of instrument */
|
||||
fluid_list_t *zone; /* list of instrument zones */
|
||||
}
|
||||
SFInst;
|
||||
|
||||
typedef struct _SFPreset
|
||||
{ /* Preset structure */
|
||||
char name[21]; /* preset name */
|
||||
unsigned short prenum; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned int libr; /* Not used (preserved) */
|
||||
unsigned int genre; /* Not used (preserved) */
|
||||
unsigned int morph; /* Not used (preserved) */
|
||||
fluid_list_t *zone; /* list of preset zones */
|
||||
}
|
||||
SFPreset;
|
||||
|
||||
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
|
||||
typedef struct _SFData
|
||||
{ /* Sound font data structure */
|
||||
SFVersion version; /* sound font version */
|
||||
SFVersion romver; /* ROM version */
|
||||
unsigned int samplepos; /* position within sffd of the sample chunk */
|
||||
unsigned int samplesize; /* length within sffd of the sample chunk */
|
||||
char *fname; /* file name */
|
||||
FILE *sffd; /* loaded sfont file descriptor */
|
||||
fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
|
||||
fluid_list_t *preset; /* linked list of preset info */
|
||||
fluid_list_t *inst; /* linked list of instrument info */
|
||||
fluid_list_t *sample; /* linked list of sample info */
|
||||
}
|
||||
SFData;
|
||||
|
||||
/* sf file chunk IDs */
|
||||
enum
|
||||
{ UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
|
||||
INFO_ID, SDTA_ID, PDTA_ID, /* info/sample/preset */
|
||||
|
||||
IFIL_ID, ISNG_ID, INAM_ID, IROM_ID, /* info ids (1st byte of info strings) */
|
||||
IVER_ID, ICRD_ID, IENG_ID, IPRD_ID, /* more info ids */
|
||||
ICOP_ID, ICMT_ID, ISFT_ID, /* and yet more info ids */
|
||||
|
||||
SNAM_ID, SMPL_ID, /* sample ids */
|
||||
PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, /* preset ids */
|
||||
IHDR_ID, IBAG_ID, IMOD_ID, IGEN_ID, /* instrument ids */
|
||||
SHDR_ID /* sample info */
|
||||
};
|
||||
|
||||
/* generator types */
|
||||
typedef enum
|
||||
{ Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
|
||||
Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_ModLFO2Pitch,
|
||||
Gen_VibLFO2Pitch, Gen_ModEnv2Pitch, Gen_FilterFc, Gen_FilterQ,
|
||||
Gen_ModLFO2FilterFc, Gen_ModEnv2FilterFc, Gen_EndAddrCoarseOfs,
|
||||
Gen_ModLFO2Vol, Gen_Unused1, Gen_ChorusSend, Gen_ReverbSend, Gen_Pan,
|
||||
Gen_Unused2, Gen_Unused3, Gen_Unused4,
|
||||
Gen_ModLFODelay, Gen_ModLFOFreq, Gen_VibLFODelay, Gen_VibLFOFreq,
|
||||
Gen_ModEnvDelay, Gen_ModEnvAttack, Gen_ModEnvHold, Gen_ModEnvDecay,
|
||||
Gen_ModEnvSustain, Gen_ModEnvRelease, Gen_Key2ModEnvHold,
|
||||
Gen_Key2ModEnvDecay, Gen_VolEnvDelay, Gen_VolEnvAttack,
|
||||
Gen_VolEnvHold, Gen_VolEnvDecay, Gen_VolEnvSustain, Gen_VolEnvRelease,
|
||||
Gen_Key2VolEnvHold, Gen_Key2VolEnvDecay, Gen_Instrument,
|
||||
Gen_Reserved1, Gen_KeyRange, Gen_VelRange,
|
||||
Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
|
||||
Gen_Attenuation, Gen_Reserved2, Gen_EndLoopAddrCoarseOfs,
|
||||
Gen_CoarseTune, Gen_FineTune, Gen_SampleId, Gen_SampleModes,
|
||||
Gen_Reserved3, Gen_ScaleTune, Gen_ExclusiveClass, Gen_OverrideRootKey,
|
||||
Gen_Dummy
|
||||
}
|
||||
Gen_Type;
|
||||
|
||||
#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
|
||||
#define Gen_Count Gen_Dummy /* count of generators */
|
||||
#define GenArrSize sizeof(SFGenAmount)*Gen_Count /* gen array size */
|
||||
|
||||
/* generator unit type */
|
||||
typedef enum
|
||||
{
|
||||
None, /* No unit type */
|
||||
Unit_Smpls, /* in samples */
|
||||
Unit_32kSmpls, /* in 32k samples */
|
||||
Unit_Cent, /* in cents (1/100th of a semitone) */
|
||||
Unit_HzCent, /* in Hz Cents */
|
||||
Unit_TCent, /* in Time Cents */
|
||||
Unit_cB, /* in centibels (1/100th of a decibel) */
|
||||
Unit_Percent, /* in percentage */
|
||||
Unit_Semitone, /* in semitones */
|
||||
Unit_Range /* a range of values */
|
||||
}
|
||||
Gen_Unit;
|
||||
|
||||
/* global data */
|
||||
|
||||
extern unsigned short badgen[]; /* list of bad generators */
|
||||
extern unsigned short badpgen[]; /* list of bad preset generators */
|
||||
|
||||
/* functions */
|
||||
void sfont_init_chunks (void);
|
||||
|
||||
void sfont_close (SFData * sf);
|
||||
void sfont_free_zone (SFZone * zone);
|
||||
int sfont_preset_compare_func (void* a, void* b);
|
||||
|
||||
void sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone);
|
||||
|
||||
fluid_list_t *gen_inlist (int gen, fluid_list_t * genlist);
|
||||
int gen_valid (int gen);
|
||||
int gen_validp (int gen);
|
||||
|
||||
|
||||
/*-----------------------------------sffile.h----------------------------*/
|
||||
/*
|
||||
File structures and routines (used to be in sffile.h)
|
||||
*/
|
||||
|
||||
#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
|
||||
|
||||
/* sfont file chunk sizes */
|
||||
#define SFPHDRSIZE 38
|
||||
#define SFBAGSIZE 4
|
||||
#define SFMODSIZE 10
|
||||
#define SFGENSIZE 4
|
||||
#define SFIHDRSIZE 22
|
||||
#define SFSHDRSIZE 46
|
||||
|
||||
/* sfont file data structures */
|
||||
typedef struct _SFChunk
|
||||
{ /* RIFF file chunk structure */
|
||||
unsigned int id; /* chunk id */
|
||||
unsigned int size; /* size of the following chunk */
|
||||
}
|
||||
SFChunk;
|
||||
|
||||
typedef struct _SFPhdr
|
||||
{
|
||||
unsigned char name[20]; /* preset name */
|
||||
unsigned short preset; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned short pbagndx; /* index into preset bag */
|
||||
unsigned int library; /* just for preserving them */
|
||||
unsigned int genre; /* Not used */
|
||||
unsigned int morphology; /* Not used */
|
||||
}
|
||||
SFPhdr;
|
||||
|
||||
typedef struct _SFBag
|
||||
{
|
||||
unsigned short genndx; /* index into generator list */
|
||||
unsigned short modndx; /* index into modulator list */
|
||||
}
|
||||
SFBag;
|
||||
|
||||
typedef struct _SFIhdr
|
||||
{
|
||||
char name[20]; /* Name of instrument */
|
||||
unsigned short ibagndx; /* Instrument bag index */
|
||||
}
|
||||
SFIhdr;
|
||||
|
||||
typedef struct _SFShdr
|
||||
{ /* Sample header loading struct */
|
||||
char name[20]; /* Sample name */
|
||||
unsigned int start; /* Offset to start of sample */
|
||||
unsigned int end; /* Offset to end of sample */
|
||||
unsigned int loopstart; /* Offset to start of loop */
|
||||
unsigned int loopend; /* Offset to end of loop */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short samplelink; /* Not used */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
}
|
||||
SFShdr;
|
||||
|
||||
/* data */
|
||||
extern char idlist[];
|
||||
|
||||
/* functions */
|
||||
SFData *sfload_file (const char * fname);
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
/* Provide definitions for some commonly used macros.
|
||||
* Some of them are only provided if they haven't already
|
||||
* been defined. It is assumed that if they are already
|
||||
* defined then the current definition is correct.
|
||||
*/
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#define GPOINTER_TO_INT(p) ((int) (p))
|
||||
#define GINT_TO_POINTER(i) ((void *) (uintptr_t)(i))
|
||||
|
||||
char* g_strdup (const char *str);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Provide simple macro statement wrappers (adapted from Perl):
|
||||
* G_STMT_START { statements; } G_STMT_END;
|
||||
* can be used as a single statement, as in
|
||||
* if (x) G_STMT_START { ... } G_STMT_END; else ...
|
||||
*
|
||||
* For gcc we will wrap the statements within `({' and `})' braces.
|
||||
* For SunOS they will be wrapped within `if (1)' and `else (void) 0',
|
||||
* and otherwise within `do' and `while (0)'.
|
||||
*/
|
||||
#if !(defined (G_STMT_START) && defined (G_STMT_END))
|
||||
# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
|
||||
# define G_STMT_START (void)(
|
||||
# define G_STMT_END )
|
||||
# else
|
||||
# if (defined (sun) || defined (__sun__))
|
||||
# define G_STMT_START if (1)
|
||||
# define G_STMT_END else (void)0
|
||||
# else
|
||||
# define G_STMT_START do
|
||||
# define G_STMT_END while (0)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Basic bit swapping functions
|
||||
*/
|
||||
#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((unsigned short) ( \
|
||||
(((unsigned short) (val) & (unsigned short) 0x00ffU) << 8) | \
|
||||
(((unsigned short) (val) & (unsigned short) 0xff00U) >> 8)))
|
||||
#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((unsigned int) ( \
|
||||
(((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \
|
||||
(((unsigned int) (val) & (unsigned int) 0x0000ff00U) << 8) | \
|
||||
(((unsigned int) (val) & (unsigned int) 0x00ff0000U) >> 8) | \
|
||||
(((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24)))
|
||||
|
||||
#define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
|
||||
#define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
|
||||
|
||||
#define GINT16_TO_LE(val) ((signed short) (val))
|
||||
#define GUINT16_TO_LE(val) ((unsigned short) (val))
|
||||
#define GINT16_TO_BE(val) ((signed short) GUINT16_SWAP_LE_BE (val))
|
||||
#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
|
||||
#define GINT32_TO_LE(val) ((signed int) (val))
|
||||
#define GUINT32_TO_LE(val) ((unsigned int) (val))
|
||||
#define GINT32_TO_BE(val) ((signed int) GUINT32_SWAP_LE_BE (val))
|
||||
#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
|
||||
|
||||
/* The G*_TO_?E() macros are defined in glibconfig.h.
|
||||
* The transformation is symmetric, so the FROM just maps to the TO.
|
||||
*/
|
||||
#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
|
||||
#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
|
||||
#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
|
||||
#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
|
||||
#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
|
||||
#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
|
||||
#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
|
||||
#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
|
||||
|
||||
|
||||
/*-----------------------------------util.h----------------------------*/
|
||||
/*
|
||||
Utility functions (formerly in util.h)
|
||||
*/
|
||||
#define FAIL 0
|
||||
#define OK 1
|
||||
|
||||
enum
|
||||
{ ErrWarn, ErrFatal, ErrStatus, ErrCorr, ErrEof, ErrMem, Errno,
|
||||
ErrRead, ErrWrite
|
||||
};
|
||||
|
||||
#define ErrMax ErrWrite
|
||||
#define ErrnoStart Errno
|
||||
#define ErrnoEnd ErrWrite
|
||||
|
||||
int gerr (int ev, char * fmt, ...);
|
||||
int safe_fread (void *buf, int count, FILE * fd);
|
||||
int safe_fwrite (void *buf, int count, FILE * fd);
|
||||
int safe_fseek (FILE * fd, long ofs, int whence);
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* FORWARD DECLARATIONS
|
||||
*/
|
||||
typedef struct _fluid_defsfont_t fluid_defsfont_t;
|
||||
typedef struct _fluid_defpreset_t fluid_defpreset_t;
|
||||
typedef struct _fluid_preset_zone_t fluid_preset_zone_t;
|
||||
typedef struct _fluid_inst_t fluid_inst_t;
|
||||
typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
|
||||
|
||||
/*
|
||||
|
||||
Public interface
|
||||
|
||||
*/
|
||||
|
||||
fluid_sfloader_t* new_fluid_defsfloader(void);
|
||||
int delete_fluid_defsfloader(fluid_sfloader_t* loader);
|
||||
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename);
|
||||
|
||||
|
||||
int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont);
|
||||
char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont);
|
||||
fluid_preset_t* fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont);
|
||||
int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
|
||||
|
||||
int fluid_defpreset_preset_delete(fluid_preset_t* preset);
|
||||
char* fluid_defpreset_preset_get_name(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_get_num(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
|
||||
/*
|
||||
* fluid_defsfont_t
|
||||
*/
|
||||
struct _fluid_defsfont_t
|
||||
{
|
||||
char* filename; /* the filename of this soundfont */
|
||||
unsigned int samplepos; /* the position in the file at which the sample data starts */
|
||||
unsigned int samplesize; /* the size of the sample data */
|
||||
short* sampledata; /* the sample data, loaded in ram */
|
||||
fluid_list_t* sample; /* the samples in this soundfont */
|
||||
fluid_defpreset_t* preset; /* the presets of this soundfont */
|
||||
|
||||
fluid_preset_t iter_preset; /* preset interface used in the iteration */
|
||||
fluid_defpreset_t* iter_cur; /* the current preset in the iteration */
|
||||
};
|
||||
|
||||
|
||||
fluid_defsfont_t* new_fluid_defsfont(void);
|
||||
int delete_fluid_defsfont(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file);
|
||||
char* fluid_defsfont_get_name(fluid_defsfont_t* sfont);
|
||||
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset);
|
||||
int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample);
|
||||
int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset);
|
||||
fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s);
|
||||
|
||||
|
||||
/*
|
||||
* fluid_preset_t
|
||||
*/
|
||||
struct _fluid_defpreset_t
|
||||
{
|
||||
fluid_defpreset_t* next;
|
||||
fluid_defsfont_t* sfont; /* the soundfont this preset belongs to */
|
||||
char name[21]; /* the name of the preset */
|
||||
unsigned int bank; /* the bank number */
|
||||
unsigned int num; /* the preset number */
|
||||
fluid_preset_zone_t* global_zone; /* the global zone of the preset */
|
||||
fluid_preset_zone_t* zone; /* the chained list of preset zones */
|
||||
};
|
||||
|
||||
fluid_defpreset_t* new_fluid_defpreset(fluid_defsfont_t* sfont);
|
||||
int delete_fluid_defpreset(fluid_defpreset_t* preset);
|
||||
fluid_defpreset_t* fluid_defpreset_next(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t* preset, SFPreset* sfpreset, fluid_defsfont_t* sfont);
|
||||
int fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
|
||||
int fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_zone(fluid_defpreset_t* preset);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_global_zone(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_get_banknum(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_get_num(fluid_defpreset_t* preset);
|
||||
char* fluid_defpreset_get_name(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/*
|
||||
* fluid_preset_zone
|
||||
*/
|
||||
struct _fluid_preset_zone_t
|
||||
{
|
||||
fluid_preset_zone_t* next;
|
||||
char* name;
|
||||
fluid_inst_t* inst;
|
||||
int keylo;
|
||||
int keyhi;
|
||||
int vello;
|
||||
int velhi;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t * mod; /* List of modulators */
|
||||
};
|
||||
|
||||
fluid_preset_zone_t* new_fluid_preset_zone(char* name);
|
||||
int delete_fluid_preset_zone(fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_preset_zone_next(fluid_preset_zone_t* preset);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone* sfzone, fluid_defsfont_t* sfont);
|
||||
int fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel);
|
||||
fluid_inst_t* fluid_preset_zone_get_inst(fluid_preset_zone_t* zone);
|
||||
|
||||
/*
|
||||
* fluid_inst_t
|
||||
*/
|
||||
struct _fluid_inst_t
|
||||
{
|
||||
char name[21];
|
||||
fluid_inst_zone_t* global_zone;
|
||||
fluid_inst_zone_t* zone;
|
||||
};
|
||||
|
||||
fluid_inst_t* new_fluid_inst(void);
|
||||
int delete_fluid_inst(fluid_inst_t* inst);
|
||||
int fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont);
|
||||
int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
|
||||
int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
|
||||
fluid_inst_zone_t* fluid_inst_get_zone(fluid_inst_t* inst);
|
||||
fluid_inst_zone_t* fluid_inst_get_global_zone(fluid_inst_t* inst);
|
||||
|
||||
/*
|
||||
* fluid_inst_zone_t
|
||||
*/
|
||||
struct _fluid_inst_zone_t
|
||||
{
|
||||
fluid_inst_zone_t* next;
|
||||
char* name;
|
||||
fluid_sample_t* sample;
|
||||
int keylo;
|
||||
int keyhi;
|
||||
int vello;
|
||||
int velhi;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t * mod; /* List of modulators */
|
||||
};
|
||||
|
||||
fluid_inst_zone_t* new_fluid_inst_zone(char* name);
|
||||
int delete_fluid_inst_zone(fluid_inst_zone_t* zone);
|
||||
fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone);
|
||||
int fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont);
|
||||
int fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel);
|
||||
fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);
|
||||
|
||||
|
||||
|
||||
fluid_sample_t* new_fluid_sample(void);
|
||||
int delete_fluid_sample(fluid_sample_t* sample);
|
||||
int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont);
|
||||
int fluid_sample_in_rom(fluid_sample_t* sample);
|
||||
|
||||
|
||||
#endif /* _FLUID_SFONT_H */
|
685
framework/audio/midi/3rdparty/fluidlite/src/fluid_dsp_float.c
vendored
Normal file
685
framework/audio/midi/3rdparty/fluidlite/src/fluid_dsp_float.c
vendored
Normal file
|
@ -0,0 +1,685 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_phase.h"
|
||||
|
||||
/* Purpose:
|
||||
*
|
||||
* Interpolates audio data (obtains values between the samples of the original
|
||||
* waveform data).
|
||||
*
|
||||
* Variables loaded from the voice structure (assigned in fluid_voice_write()):
|
||||
* - dsp_data: Pointer to the original waveform data
|
||||
* - dsp_phase: The position in the original waveform data.
|
||||
* This has an integer and a fractional part (between samples).
|
||||
* - dsp_phase_incr: For each output sample, the position in the original
|
||||
* waveform advances by dsp_phase_incr. This also has an integer
|
||||
* part and a fractional part.
|
||||
* If a sample is played at root pitch (no pitch change),
|
||||
* dsp_phase_incr is integer=1 and fractional=0.
|
||||
* - dsp_amp: The current amplitude envelope value.
|
||||
* - dsp_amp_incr: The changing rate of the amplitude envelope.
|
||||
*
|
||||
* A couple of variables are used internally, their results are discarded:
|
||||
* - dsp_i: Index through the output buffer
|
||||
* - dsp_buf: Output buffer of floating point values (FLUID_BUFSIZE in length)
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_voice.h"
|
||||
|
||||
|
||||
/* Interpolation (find a value between two samples of the original waveform) */
|
||||
|
||||
/* Linear interpolation table (2 coefficients centered on 1st) */
|
||||
static fluid_real_t interp_coeff_linear[FLUID_INTERP_MAX][2];
|
||||
|
||||
/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */
|
||||
static fluid_real_t interp_coeff[FLUID_INTERP_MAX][4];
|
||||
|
||||
/* 7th order interpolation (7 coefficients centered on 3rd) */
|
||||
static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7];
|
||||
|
||||
|
||||
#define SINC_INTERP_ORDER 7 /* 7th order constant */
|
||||
|
||||
|
||||
/* Initializes interpolation tables */
|
||||
void fluid_dsp_float_config (void)
|
||||
{
|
||||
int i, i2;
|
||||
double x, v;
|
||||
double i_shifted;
|
||||
|
||||
/* Initialize the coefficients for the interpolation. The math comes
|
||||
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
|
||||
* list (I found it in the music-dsp archives
|
||||
* http://www.smartelectronix.com/musicdsp/). */
|
||||
|
||||
for (i = 0; i < FLUID_INTERP_MAX; i++)
|
||||
{
|
||||
x = (double) i / (double) FLUID_INTERP_MAX;
|
||||
|
||||
interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x)));
|
||||
interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5));
|
||||
interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x)));
|
||||
interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0));
|
||||
|
||||
interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x);
|
||||
interp_coeff_linear[i][1] = (fluid_real_t)x;
|
||||
}
|
||||
|
||||
/* i: Offset in terms of whole samples */
|
||||
for (i = 0; i < SINC_INTERP_ORDER; i++)
|
||||
{ /* i2: Offset in terms of fractional samples ('subsamples') */
|
||||
for (i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
|
||||
{
|
||||
/* center on middle of table */
|
||||
i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
|
||||
+ (double)i2 / (double)FLUID_INTERP_MAX;
|
||||
|
||||
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
|
||||
if (fabs (i_shifted) > 0.000001)
|
||||
{
|
||||
v = (fluid_real_t)sin (i_shifted * M_PI) / (M_PI * i_shifted);
|
||||
/* Hamming window */
|
||||
v *= (fluid_real_t)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (fluid_real_t)SINC_INTERP_ORDER));
|
||||
}
|
||||
else v = 1.0;
|
||||
|
||||
sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < FLUID_INTERP_MAX; i++)
|
||||
{
|
||||
printf ("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
|
||||
i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i],
|
||||
sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* No interpolation. Just take the sample, which is closest to
|
||||
* the playback pointer. Questionable quality, but very
|
||||
* efficient. */
|
||||
int
|
||||
fluid_dsp_float_interpolate_none (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int end_index;
|
||||
int looping;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
end_index = looping ? voice->loopend - 1 : voice->end;
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
|
||||
|
||||
/* interpolate sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* break out if not looping (buffer may not be full) */
|
||||
if (!looping) break;
|
||||
|
||||
/* go back to loop start */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
voice->has_looped = 1;
|
||||
}
|
||||
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
}
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
/* Straight line interpolation.
|
||||
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
|
||||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_dsp_float_interpolate_linear (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int end_index;
|
||||
short int point;
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
/* last index before 2nd interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
|
||||
|
||||
/* 2nd interpolation point to use at end of loop or sample */
|
||||
if (looping) point = dsp_data[voice->loopstart]; /* loop start */
|
||||
else point = dsp_data[voice->end]; /* duplicate end for samples no longer looping */
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
|
||||
/* interpolate the sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index+1]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* break out if buffer filled */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index++; /* we're now interpolating the last point */
|
||||
|
||||
/* interpolate within last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[1] * point);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr; /* increment amplitude */
|
||||
}
|
||||
|
||||
if (!looping) break; /* break out if not looping (end of sample) */
|
||||
|
||||
/* go back to loop start (if past */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
voice->has_looped = 1;
|
||||
}
|
||||
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index--; /* set end back to second to last sample point */
|
||||
}
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
/* 4th order (cubic) interpolation.
|
||||
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
|
||||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int start_index, end_index;
|
||||
short int start_point, end_point1, end_point2;
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
/* last index before 4th interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
|
||||
|
||||
if (voice->has_looped) /* set start_index and start point if looped or not */
|
||||
{
|
||||
start_index = voice->loopstart;
|
||||
start_point = dsp_data[voice->loopend - 1]; /* last point in loop (wrap around) */
|
||||
}
|
||||
else
|
||||
{
|
||||
start_index = voice->start;
|
||||
start_point = dsp_data[voice->start]; /* just duplicate the point */
|
||||
}
|
||||
|
||||
/* get points off the end (loop start if looping, duplicate point if end) */
|
||||
if (looping)
|
||||
{
|
||||
end_point1 = dsp_data[voice->loopstart];
|
||||
end_point2 = dsp_data[voice->loopstart + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
end_point1 = dsp_data[voice->end];
|
||||
end_point2 = end_point1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
|
||||
/* interpolate first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * start_point
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* interpolate the sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* break out if buffer filled */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index++; /* we're now interpolating the 2nd to last point */
|
||||
|
||||
/* interpolate within 2nd to last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[3] * end_point1);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
end_index++; /* we're now interpolating the last point */
|
||||
|
||||
/* interpolate within the last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * end_point1
|
||||
+ coeffs[3] * end_point2);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
if (!looping) break; /* break out if not looping (end of sample) */
|
||||
|
||||
/* go back to loop start */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
|
||||
if (!voice->has_looped)
|
||||
{
|
||||
voice->has_looped = 1;
|
||||
start_index = voice->loopstart;
|
||||
start_point = dsp_data[voice->loopend - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index -= 2; /* set end back to third to last sample point */
|
||||
}
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
/* 7th order interpolation.
|
||||
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
|
||||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int start_index, end_index;
|
||||
short int start_points[3];
|
||||
short int end_points[3];
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* add 1/2 sample to dsp_phase since 7th order interpolation is centered on
|
||||
* the 4th sample point */
|
||||
fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
/* last index before 7th interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
|
||||
|
||||
if (voice->has_looped) /* set start_index and start point if looped or not */
|
||||
{
|
||||
start_index = voice->loopstart;
|
||||
start_points[0] = dsp_data[voice->loopend - 1];
|
||||
start_points[1] = dsp_data[voice->loopend - 2];
|
||||
start_points[2] = dsp_data[voice->loopend - 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
start_index = voice->start;
|
||||
start_points[0] = dsp_data[voice->start]; /* just duplicate the start point */
|
||||
start_points[1] = start_points[0];
|
||||
start_points[2] = start_points[0];
|
||||
}
|
||||
|
||||
/* get the 3 points off the end (loop start if looping, duplicate point if end) */
|
||||
if (looping)
|
||||
{
|
||||
end_points[0] = dsp_data[voice->loopstart];
|
||||
end_points[1] = dsp_data[voice->loopstart + 1];
|
||||
end_points[2] = dsp_data[voice->loopstart + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
end_points[0] = dsp_data[voice->end];
|
||||
end_points[1] = end_points[0];
|
||||
end_points[2] = end_points[0];
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
|
||||
/* interpolate first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)start_points[2]
|
||||
+ coeffs[1] * (fluid_real_t)start_points[1]
|
||||
+ coeffs[2] * (fluid_real_t)start_points[0]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
start_index++;
|
||||
|
||||
/* interpolate 2nd to first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)start_points[1]
|
||||
+ coeffs[1] * (fluid_real_t)start_points[0]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
start_index++;
|
||||
|
||||
/* interpolate 3rd to first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)start_points[0]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
start_index -= 2; /* set back to original start index */
|
||||
|
||||
|
||||
/* interpolate the sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* break out if buffer filled */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index++; /* we're now interpolating the 3rd to last point */
|
||||
|
||||
/* interpolate within 3rd to last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)end_points[0]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
end_index++; /* we're now interpolating the 2nd to last point */
|
||||
|
||||
/* interpolate within 2nd to last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)end_points[0]
|
||||
+ coeffs[6] * (fluid_real_t)end_points[1]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
end_index++; /* we're now interpolating the last point */
|
||||
|
||||
/* interpolate within last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)end_points[0]
|
||||
+ coeffs[5] * (fluid_real_t)end_points[1]
|
||||
+ coeffs[6] * (fluid_real_t)end_points[2]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
if (!looping) break; /* break out if not looping (end of sample) */
|
||||
|
||||
/* go back to loop start */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
|
||||
if (!voice->has_looped)
|
||||
{
|
||||
voice->has_looped = 1;
|
||||
start_index = voice->loopstart;
|
||||
start_points[0] = dsp_data[voice->loopend - 1];
|
||||
start_points[1] = dsp_data[voice->loopend - 2];
|
||||
start_points[2] = dsp_data[voice->loopend - 3];
|
||||
}
|
||||
}
|
||||
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index -= 3; /* set end back to 4th to last sample point */
|
||||
}
|
||||
|
||||
/* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on
|
||||
* the 4th sample point (correct back to real value) */
|
||||
fluid_phase_decr (dsp_phase, (fluid_phase_t)0x80000000);
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
120
framework/audio/midi/3rdparty/fluidlite/src/fluid_dsp_simple.c
vendored
Normal file
120
framework/audio/midi/3rdparty/fluidlite/src/fluid_dsp_simple.c
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
/* Purpose:
|
||||
* Low-level voice processing:
|
||||
*
|
||||
* - interpolates (obtains values between the samples of the original waveform data)
|
||||
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
|
||||
* - mixes the processed sample to left and right output using the pan setting
|
||||
* - sends the processed sample to chorus and reverb
|
||||
*
|
||||
*
|
||||
* This file does -not- generate an object file.
|
||||
* Instead, it is #included in several places in fluid_voice.c.
|
||||
* The motivation for this is
|
||||
* - Calling it as a subroutine may be time consuming, especially with optimization off
|
||||
* - The previous implementation as a macro was clumsy to handle
|
||||
*
|
||||
*
|
||||
* Fluid_voice.c sets a couple of variables before #including this:
|
||||
* - dsp_data: Pointer to the original waveform data
|
||||
* - dsp_left_buf: The generated signal goes here, left channel
|
||||
* - dsp_right_buf: right channel
|
||||
* - dsp_reverb_buf: Send to reverb unit
|
||||
* - dsp_chorus_buf: Send to chorus unit
|
||||
* - dsp_start: Start processing at this output buffer index
|
||||
* - dsp_end: End processing just before this output buffer index
|
||||
* - dsp_a1: Coefficient for the filter
|
||||
* - dsp_a2: same
|
||||
* - dsp_b0: same
|
||||
* - dsp_b1: same
|
||||
* - dsp_b2: same
|
||||
* - dsp_filter_flag: Set, the filter is needed (many sound fonts don't use
|
||||
* the filter at all. If it is left at its default setting
|
||||
* of roughly 20 kHz, there is no need to apply filterling.)
|
||||
* - dsp_interp_method: Which interpolation method to use.
|
||||
* - voice holds the voice structure
|
||||
*
|
||||
* Some variables are set and modified:
|
||||
* - dsp_phase: The position in the original waveform data.
|
||||
* This has an integer and a fractional part (between samples).
|
||||
* - dsp_phase_incr: For each output sample, the position in the original
|
||||
* waveform advances by dsp_phase_incr. This also has an integer
|
||||
* part and a fractional part.
|
||||
* If a sample is played at root pitch (no pitch change),
|
||||
* dsp_phase_incr is integer=1 and fractional=0.
|
||||
* - dsp_amp: The current amplitude envelope value.
|
||||
* - dsp_amp_incr: The changing rate of the amplitude envelope.
|
||||
*
|
||||
* A couple of variables are used internally, their results are discarded:
|
||||
* - dsp_i: Index through the output buffer
|
||||
* - dsp_phase_fractional: The fractional part of dsp_phase
|
||||
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
|
||||
* Used to interpolate between samples.
|
||||
* - dsp_process_buffer: Holds the processed signal between stages
|
||||
* - dsp_centernode: delay line for the IIR filter
|
||||
* - dsp_hist1: same
|
||||
* - dsp_hist2: same
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Nonoptimized DSP loop */
|
||||
#warning "This code is meant for experiments only.";
|
||||
|
||||
/* wave table interpolation */
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
|
||||
dsp_coeff = &interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
dsp_sample = (dsp_amp *
|
||||
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
|
||||
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]
|
||||
+ dsp_coeff->a2 * dsp_data[dsp_phase_index+2]
|
||||
+ dsp_coeff->a3 * dsp_data[dsp_phase_index+3]));
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
|
||||
/* filter */
|
||||
/* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_sample - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_sample = dsp_b0 * dsp_centernode + dsp_b1 * dsp_hist1 + dsp_b2 * dsp_hist2;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
|
||||
/* pan */
|
||||
dsp_left_buf[dsp_i] += voice->amp_left * dsp_sample;
|
||||
dsp_right_buf[dsp_i] += voice->amp_right * dsp_sample;
|
||||
|
||||
/* reverb */
|
||||
if (dsp_reverb_buf){
|
||||
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_sample;
|
||||
}
|
||||
|
||||
/* chorus */
|
||||
if (dsp_chorus_buf){
|
||||
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_sample;
|
||||
}
|
||||
}
|
||||
|
149
framework/audio/midi/3rdparty/fluidlite/src/fluid_gen.c
vendored
Normal file
149
framework/audio/midi/3rdparty/fluidlite/src/fluid_gen.c
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#include "fluid_gen.h"
|
||||
#include "fluid_chan.h"
|
||||
|
||||
|
||||
/* See SFSpec21 $8.1.3 */
|
||||
fluid_gen_info_t fluid_gen_info[] = {
|
||||
/* number/name init scale min max def */
|
||||
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
|
||||
{ GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
|
||||
{ GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
|
||||
{ GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
|
||||
{ GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
|
||||
{ GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
|
||||
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set an array of generators to their default values.
|
||||
* @param gen Array of generators (should be #GEN_LAST in size).
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int
|
||||
fluid_gen_set_default_values(fluid_gen_t* gen)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GEN_LAST; i++) {
|
||||
gen[i].flags = GEN_UNUSED;
|
||||
gen[i].mod = 0.0;
|
||||
gen[i].nrpn = 0.0;
|
||||
gen[i].val = fluid_gen_info[i].def;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
/* fluid_gen_init
|
||||
*
|
||||
* Set an array of generators to their initial value
|
||||
*/
|
||||
int
|
||||
fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel)
|
||||
{
|
||||
int i;
|
||||
|
||||
fluid_gen_set_default_values(gen);
|
||||
|
||||
for (i = 0; i < GEN_LAST; i++) {
|
||||
gen[i].nrpn = fluid_channel_get_gen(channel, i);
|
||||
|
||||
/* This is an extension to the SoundFont standard. More
|
||||
* documentation is available at the fluid_synth_set_gen2()
|
||||
* function. */
|
||||
if (fluid_channel_get_gen_abs(channel, i)) {
|
||||
gen[i].flags = GEN_ABS_NRPN;
|
||||
}
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
fluid_real_t fluid_gen_scale(int gen, float value)
|
||||
{
|
||||
return (fluid_gen_info[gen].min
|
||||
+ value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
|
||||
}
|
||||
|
||||
fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
|
||||
{
|
||||
fluid_real_t value = (float) data - 8192.0f;
|
||||
fluid_clip(value, -8192, 8192);
|
||||
return value * (float) fluid_gen_info[gen].nrpn_scale;
|
||||
}
|
44
framework/audio/midi/3rdparty/fluidlite/src/fluid_gen.h
vendored
Normal file
44
framework/audio/midi/3rdparty/fluidlite/src/fluid_gen.h
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_GEN_H
|
||||
#define _FLUID_GEN_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
typedef struct _fluid_gen_info_t {
|
||||
char num; /* Generator number */
|
||||
char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
|
||||
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||
float min; /* The minimum value */
|
||||
float max; /* The maximum value */
|
||||
float def; /* The default value (cfr. fluid_gen_set_default_values()) */
|
||||
} fluid_gen_info_t;
|
||||
|
||||
#define fluid_gen_set_mod(_gen, _val) { (_gen)->mod = (double) (_val); }
|
||||
#define fluid_gen_set_nrpn(_gen, _val) { (_gen)->nrpn = (double) (_val); }
|
||||
|
||||
fluid_real_t fluid_gen_scale(int gen, float value);
|
||||
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
|
||||
int fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel);
|
||||
|
||||
|
||||
#endif /* _FLUID_GEN_H */
|
388
framework/audio/midi/3rdparty/fluidlite/src/fluid_hash.c
vendored
Normal file
388
framework/audio/midi/3rdparty/fluidlite/src/fluid_hash.c
vendored
Normal file
|
@ -0,0 +1,388 @@
|
|||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GLib Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MT safe
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_hash.h"
|
||||
|
||||
|
||||
#define HASH_TABLE_MIN_SIZE 7
|
||||
#define HASH_TABLE_MAX_SIZE 13845163
|
||||
|
||||
|
||||
typedef struct _fluid_hashnode_t fluid_hashnode_t;
|
||||
|
||||
struct _fluid_hashnode_t {
|
||||
char* key;
|
||||
void* value;
|
||||
int type;
|
||||
fluid_hashnode_t *next;
|
||||
};
|
||||
|
||||
static fluid_hashnode_t* new_fluid_hashnode(char* key, void* value, int type);
|
||||
static void delete_fluid_hashnode(fluid_hashnode_t *hash_node, fluid_hash_delete_t del);
|
||||
static void delete_fluid_hashnodes(fluid_hashnode_t *hash_node, fluid_hash_delete_t del);
|
||||
|
||||
struct _fluid_hashtable_t {
|
||||
unsigned int size;
|
||||
unsigned int nnodes;
|
||||
fluid_hashnode_t **nodes;
|
||||
fluid_hash_delete_t del;
|
||||
};
|
||||
|
||||
#define FLUID_HASHTABLE_RESIZE(hash_table) \
|
||||
if ((3 * hash_table->size <= hash_table->nnodes) \
|
||||
&& (hash_table->size < HASH_TABLE_MAX_SIZE)) { \
|
||||
fluid_hashtable_resize(hash_table); \
|
||||
}
|
||||
|
||||
static void fluid_hashtable_resize(fluid_hashtable_t *hash_table);
|
||||
static fluid_hashnode_t** fluid_hashtable_lookup_node(fluid_hashtable_t *hash_table, char* key);
|
||||
|
||||
/**
|
||||
* new_fluid_hashtable:
|
||||
*
|
||||
* Creates a new #fluid_hashtable_t.
|
||||
*
|
||||
* Return value: a new #fluid_hashtable_t.
|
||||
**/
|
||||
fluid_hashtable_t*
|
||||
new_fluid_hashtable(fluid_hash_delete_t del)
|
||||
{
|
||||
fluid_hashtable_t *hash_table;
|
||||
unsigned int i;
|
||||
|
||||
hash_table = FLUID_NEW(fluid_hashtable_t);
|
||||
hash_table->size = HASH_TABLE_MIN_SIZE;
|
||||
hash_table->nnodes = 0;
|
||||
hash_table->nodes = FLUID_ARRAY(fluid_hashnode_t*, hash_table->size);
|
||||
hash_table->del = del;
|
||||
|
||||
for (i = 0; i < hash_table->size; i++) {
|
||||
hash_table->nodes[i] = NULL;
|
||||
}
|
||||
|
||||
return hash_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete_fluid_hashtable:
|
||||
* @hash_table: a #fluid_hashtable_t.
|
||||
*
|
||||
* Destroys the #fluid_hashtable_t. If keys and/or values are dynamically
|
||||
* allocated, you should either free them first or create the #fluid_hashtable_t
|
||||
* using fluid_hashtable_new_full(). In the latter case the destroy functions
|
||||
* you supplied will be called on all keys and values before destroying
|
||||
* the #fluid_hashtable_t.
|
||||
**/
|
||||
void
|
||||
delete_fluid_hashtable(fluid_hashtable_t *hash_table)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (hash_table == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < hash_table->size; i++) {
|
||||
delete_fluid_hashnodes(hash_table->nodes[i], hash_table->del);
|
||||
}
|
||||
|
||||
FLUID_FREE(hash_table->nodes);
|
||||
FLUID_FREE(hash_table);
|
||||
}
|
||||
|
||||
|
||||
static /*inline*/ fluid_hashnode_t**
|
||||
fluid_hashtable_lookup_node (fluid_hashtable_t* hash_table, char* key)
|
||||
{
|
||||
fluid_hashnode_t **node;
|
||||
|
||||
node = &hash_table->nodes[fluid_str_hash(key) % hash_table->size];
|
||||
|
||||
while (*node && (FLUID_STRCMP((*node)->key, key) != 0)) {
|
||||
node = &(*node)->next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* fluid_hashtable_lookup:
|
||||
* @hash_table: a #fluid_hashtable_t.
|
||||
* @key: the key to look up.
|
||||
*
|
||||
* Looks up a key in a #fluid_hashtable_t.
|
||||
*
|
||||
* Return value: the associated value, or %NULL if the key is not found.
|
||||
**/
|
||||
int
|
||||
fluid_hashtable_lookup(fluid_hashtable_t *hash_table, char* key, void** value, int* type)
|
||||
{
|
||||
fluid_hashnode_t *node;
|
||||
|
||||
node = *fluid_hashtable_lookup_node(hash_table, key);
|
||||
|
||||
if (node) {
|
||||
if (value) {
|
||||
*value = node->value;
|
||||
}
|
||||
if (type) {
|
||||
*type = node->type;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fluid_hashtable_insert:
|
||||
* @hash_table: a #fluid_hashtable_t.
|
||||
* @key: a key to insert.
|
||||
* @value: the value to associate with the key.
|
||||
*
|
||||
* Inserts a new key and value into a #fluid_hashtable_t.
|
||||
*
|
||||
* If the key already exists in the #fluid_hashtable_t its current value is replaced
|
||||
* with the new value. If you supplied a @value_destroy_func when creating the
|
||||
* #fluid_hashtable_t, the old value is freed using that function. If you supplied
|
||||
* a @key_destroy_func when creating the #fluid_hashtable_t, the passed key is freed
|
||||
* using that function.
|
||||
**/
|
||||
void
|
||||
fluid_hashtable_insert(fluid_hashtable_t *hash_table, char* key, void* value, int type)
|
||||
{
|
||||
fluid_hashnode_t **node;
|
||||
|
||||
node = fluid_hashtable_lookup_node(hash_table, key);
|
||||
|
||||
if (*node) {
|
||||
(*node)->value = value;
|
||||
(*node)->type = type;
|
||||
} else {
|
||||
*node = new_fluid_hashnode(key, value, type);
|
||||
hash_table->nnodes++;
|
||||
FLUID_HASHTABLE_RESIZE(hash_table);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fluid_hashtable_replace:
|
||||
* @hash_table: a #GHashTable.
|
||||
* @key: a key to insert.
|
||||
* @value: the value to associate with the key.
|
||||
*
|
||||
* Inserts a new key and value into a #GHashTable similar to
|
||||
* fluid_hashtable_insert(). The difference is that if the key already exists
|
||||
* in the #GHashTable, it gets replaced by the new key. If you supplied a
|
||||
* @value_destroy_func when creating the #GHashTable, the old value is freed
|
||||
* using that function. If you supplied a @key_destroy_func when creating the
|
||||
* #GHashTable, the old key is freed using that function.
|
||||
**/
|
||||
void
|
||||
fluid_hashtable_replace(fluid_hashtable_t *hash_table, char* key, void* value, int type)
|
||||
{
|
||||
fluid_hashnode_t **node;
|
||||
|
||||
node = fluid_hashtable_lookup_node(hash_table, key);
|
||||
|
||||
if (*node) {
|
||||
if (hash_table->del) {
|
||||
hash_table->del((*node)->value, (*node)->type);
|
||||
}
|
||||
(*node)->value = value;
|
||||
|
||||
} else {
|
||||
*node = new_fluid_hashnode(key, value, type);
|
||||
hash_table->nnodes++;
|
||||
FLUID_HASHTABLE_RESIZE(hash_table);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fluid_hashtable_remove:
|
||||
* @hash_table: a #fluid_hashtable_t.
|
||||
* @key: the key to remove.
|
||||
*
|
||||
* Removes a key and its associated value from a #fluid_hashtable_t.
|
||||
*
|
||||
* If the #fluid_hashtable_t was created using fluid_hashtable_new_full(), the
|
||||
* key and value are freed using the supplied destroy functions, otherwise
|
||||
* you have to make sure that any dynamically allocated values are freed
|
||||
* yourself.
|
||||
*
|
||||
* Return value: %TRUE if the key was found and removed from the #fluid_hashtable_t.
|
||||
**/
|
||||
int
|
||||
fluid_hashtable_remove (fluid_hashtable_t *hash_table, char* key)
|
||||
{
|
||||
fluid_hashnode_t **node, *dest;
|
||||
|
||||
node = fluid_hashtable_lookup_node(hash_table, key);
|
||||
if (*node) {
|
||||
dest = *node;
|
||||
(*node) = dest->next;
|
||||
delete_fluid_hashnode(dest, hash_table->del);
|
||||
hash_table->nnodes--;
|
||||
|
||||
FLUID_HASHTABLE_RESIZE (hash_table);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fluid_hashtable_foreach:
|
||||
* @hash_table: a #fluid_hashtable_t.
|
||||
* @func: the function to call for each key/value pair.
|
||||
* @user_data: user data to pass to the function.
|
||||
*
|
||||
* Calls the given function for each of the key/value pairs in the
|
||||
* #fluid_hashtable_t. The function is passed the key and value of each
|
||||
* pair, and the given @user_data parameter. The hash table may not
|
||||
* be modified while iterating over it (you can't add/remove
|
||||
* items). To remove all items matching a predicate, use
|
||||
* fluid_hashtable_remove().
|
||||
**/
|
||||
void
|
||||
fluid_hashtable_foreach(fluid_hashtable_t *hash_table, fluid_hash_iter_t func, void* data)
|
||||
{
|
||||
fluid_hashnode_t *node = NULL;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < hash_table->size; i++) {
|
||||
for (node = hash_table->nodes[i]; node != NULL; node = node->next) {
|
||||
(*func)(node->key, node->value, node->type, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fluid_hashtable_size:
|
||||
* @hash_table: a #fluid_hashtable_t.
|
||||
*
|
||||
* Returns the number of elements contained in the #fluid_hashtable_t.
|
||||
*
|
||||
* Return value: the number of key/value pairs in the #fluid_hashtable_t.
|
||||
**/
|
||||
unsigned int
|
||||
fluid_hashtable_size(fluid_hashtable_t *hash_table)
|
||||
{
|
||||
return hash_table->nnodes;
|
||||
}
|
||||
|
||||
static void
|
||||
fluid_hashtable_resize(fluid_hashtable_t *hash_table)
|
||||
{
|
||||
fluid_hashnode_t **new_nodes;
|
||||
fluid_hashnode_t *node;
|
||||
fluid_hashnode_t *next;
|
||||
unsigned int hash_val;
|
||||
int new_size;
|
||||
unsigned int i;
|
||||
|
||||
new_size = 3 * hash_table->size + 1;
|
||||
new_size = (new_size > HASH_TABLE_MAX_SIZE)? HASH_TABLE_MAX_SIZE : new_size;
|
||||
|
||||
/* printf("%s: %d: resizing, new size = %d\n", __FILE__, __LINE__, new_size); */
|
||||
|
||||
new_nodes = FLUID_ARRAY(fluid_hashnode_t*, new_size);
|
||||
FLUID_MEMSET(new_nodes, 0, new_size * sizeof(fluid_hashnode_t*));
|
||||
|
||||
for (i = 0; i < hash_table->size; i++) {
|
||||
for (node = hash_table->nodes[i]; node; node = next) {
|
||||
next = node->next;
|
||||
hash_val = fluid_str_hash(node->key) % new_size;
|
||||
node->next = new_nodes[hash_val];
|
||||
new_nodes[hash_val] = node;
|
||||
}
|
||||
}
|
||||
|
||||
FLUID_FREE(hash_table->nodes);
|
||||
hash_table->nodes = new_nodes;
|
||||
hash_table->size = new_size;
|
||||
}
|
||||
|
||||
static fluid_hashnode_t*
|
||||
new_fluid_hashnode(char* key, void* value, int type)
|
||||
{
|
||||
fluid_hashnode_t *hash_node;
|
||||
|
||||
hash_node = FLUID_NEW(fluid_hashnode_t);
|
||||
|
||||
hash_node->key = FLUID_STRDUP(key);
|
||||
hash_node->value = value;
|
||||
hash_node->type = type;
|
||||
hash_node->next = NULL;
|
||||
|
||||
return hash_node;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_fluid_hashnode(fluid_hashnode_t *hash_node, fluid_hash_delete_t del)
|
||||
{
|
||||
if (del) {
|
||||
(*del)(hash_node->value, hash_node->type);
|
||||
}
|
||||
if (hash_node->key) {
|
||||
FLUID_FREE(hash_node->key);
|
||||
}
|
||||
FLUID_FREE(hash_node);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_fluid_hashnodes(fluid_hashnode_t *hash_node, fluid_hash_delete_t del)
|
||||
{
|
||||
while (hash_node) {
|
||||
fluid_hashnode_t *next = hash_node->next;
|
||||
delete_fluid_hashnode(hash_node, del);
|
||||
hash_node = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 31 bit hash function */
|
||||
unsigned int
|
||||
fluid_str_hash(char* key)
|
||||
{
|
||||
char *p = key;
|
||||
unsigned int h = *p;
|
||||
|
||||
if (h) {
|
||||
for (p += 1; *p != '\0'; p++) {
|
||||
h = (h << 5) - h + *p;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
64
framework/audio/midi/3rdparty/fluidlite/src/fluid_hash.h
vendored
Normal file
64
framework/audio/midi/3rdparty/fluidlite/src/fluid_hash.h
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GLib Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Demolished by Peter Hanappe [December 2002]
|
||||
*
|
||||
* - only string as key
|
||||
* - stores additional type info
|
||||
* - removed use of GLib types (gpointer, gint, ...)
|
||||
* - reduced the number of API functions
|
||||
* - changed names to fluid_hashtable_...
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_HASH_H
|
||||
#define _FLUID_HASH_H
|
||||
|
||||
|
||||
typedef int (*fluid_hash_iter_t)(char* key, void* value, int type, void* data);
|
||||
typedef void (*fluid_hash_delete_t)(void* value, int type);
|
||||
|
||||
fluid_hashtable_t* new_fluid_hashtable(fluid_hash_delete_t delete);
|
||||
void delete_fluid_hashtable(fluid_hashtable_t *hash_table);
|
||||
|
||||
void fluid_hashtable_insert(fluid_hashtable_t *hash_table, char* key, void* value, int type);
|
||||
|
||||
void fluid_hashtable_replace(fluid_hashtable_t *hash_table, char* key, void* value, int type);
|
||||
|
||||
/* Returns non-zero if found, 0 if not found */
|
||||
int fluid_hashtable_lookup(fluid_hashtable_t *hash_table, char* key, void** value, int* type);
|
||||
|
||||
/* Returns non-zero if removed, 0 if not removed */
|
||||
int fluid_hashtable_remove(fluid_hashtable_t *hash_table, char* key);
|
||||
|
||||
void fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hash_iter_t fun, void* data);
|
||||
|
||||
unsigned int fluid_hashtable_size(fluid_hashtable_t *hash_table);
|
||||
|
||||
unsigned int fluid_str_hash(char* v);
|
||||
|
||||
#endif /* _FLUID_HASH_H */
|
||||
|
257
framework/audio/midi/3rdparty/fluidlite/src/fluid_list.c
vendored
Normal file
257
framework/audio/midi/3rdparty/fluidlite/src/fluid_list.c
vendored
Normal file
|
@ -0,0 +1,257 @@
|
|||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GLib Team and others 1997-1999. See the AUTHORS
|
||||
* file for a list of people on the GLib Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "fluid_list.h"
|
||||
|
||||
|
||||
fluid_list_t*
|
||||
new_fluid_list(void)
|
||||
{
|
||||
fluid_list_t* list;
|
||||
list = (fluid_list_t*) FLUID_MALLOC(sizeof(fluid_list_t));
|
||||
list->data = NULL;
|
||||
list->next = NULL;
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_list(fluid_list_t *list)
|
||||
{
|
||||
fluid_list_t *next;
|
||||
while (list) {
|
||||
next = list->next;
|
||||
FLUID_FREE(list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delete1_fluid_list(fluid_list_t *list)
|
||||
{
|
||||
if (list) {
|
||||
FLUID_FREE(list);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_append(fluid_list_t *list, void* data)
|
||||
{
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *last;
|
||||
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
|
||||
if (list)
|
||||
{
|
||||
last = fluid_list_last(list);
|
||||
/* g_assert (last != NULL); */
|
||||
last->next = new_list;
|
||||
|
||||
return list;
|
||||
}
|
||||
else
|
||||
return new_list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_prepend(fluid_list_t *list, void* data)
|
||||
{
|
||||
fluid_list_t *new_list;
|
||||
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
new_list->next = list;
|
||||
|
||||
return new_list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_nth(fluid_list_t *list, int n)
|
||||
{
|
||||
while ((n-- > 0) && list) {
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_remove(fluid_list_t *list, void* data)
|
||||
{
|
||||
fluid_list_t *tmp;
|
||||
fluid_list_t *prev;
|
||||
|
||||
prev = NULL;
|
||||
tmp = list;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->data == data) {
|
||||
if (prev) {
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
if (list == tmp) {
|
||||
list = list->next;
|
||||
}
|
||||
tmp->next = NULL;
|
||||
delete_fluid_list(tmp);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_remove_link(fluid_list_t *list, fluid_list_t *link)
|
||||
{
|
||||
fluid_list_t *tmp;
|
||||
fluid_list_t *prev;
|
||||
|
||||
prev = NULL;
|
||||
tmp = list;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp == link) {
|
||||
if (prev) {
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
if (list == tmp) {
|
||||
list = list->next;
|
||||
}
|
||||
tmp->next = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static fluid_list_t*
|
||||
fluid_list_sort_merge(fluid_list_t *l1, fluid_list_t *l2, fluid_compare_func_t compare_func)
|
||||
{
|
||||
fluid_list_t list, *l;
|
||||
|
||||
l = &list;
|
||||
|
||||
while (l1 && l2) {
|
||||
if (compare_func(l1->data,l2->data) < 0) {
|
||||
l = l->next = l1;
|
||||
l1 = l1->next;
|
||||
} else {
|
||||
l = l->next = l2;
|
||||
l2 = l2->next;
|
||||
}
|
||||
}
|
||||
l->next= l1 ? l1 : l2;
|
||||
|
||||
return list.next;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func)
|
||||
{
|
||||
fluid_list_t *l1, *l2;
|
||||
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
if (!list->next) {
|
||||
return list;
|
||||
}
|
||||
|
||||
l1 = list;
|
||||
l2 = list->next;
|
||||
|
||||
while ((l2 = l2->next) != NULL) {
|
||||
if ((l2 = l2->next) == NULL)
|
||||
break;
|
||||
l1=l1->next;
|
||||
}
|
||||
l2 = l1->next;
|
||||
l1->next = NULL;
|
||||
|
||||
return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
|
||||
fluid_list_sort(l2, compare_func),
|
||||
compare_func);
|
||||
}
|
||||
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_last(fluid_list_t *list)
|
||||
{
|
||||
if (list) {
|
||||
while (list->next)
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int
|
||||
fluid_list_size(fluid_list_t *list)
|
||||
{
|
||||
int n = 0;
|
||||
while (list) {
|
||||
n++;
|
||||
list = list->next;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data)
|
||||
{
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *cur;
|
||||
fluid_list_t *prev = NULL;
|
||||
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
|
||||
cur = list;
|
||||
while ((n-- > 0) && cur) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
new_list->next = cur;
|
||||
|
||||
if (prev) {
|
||||
prev->next = new_list;
|
||||
return list;
|
||||
} else {
|
||||
return new_list;
|
||||
}
|
||||
}
|
61
framework/audio/midi/3rdparty/fluidlite/src/fluid_list.h
vendored
Normal file
61
framework/audio/midi/3rdparty/fluidlite/src/fluid_list.h
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_LIST_H
|
||||
#define _FLUID_LIST_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
/*
|
||||
*
|
||||
* Lists
|
||||
*
|
||||
* A sound font loader has to pack the data from the .SF2 file into
|
||||
* list structures of this type.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct _fluid_list_t fluid_list_t;
|
||||
|
||||
typedef int (*fluid_compare_func_t)(void* a, void* b);
|
||||
|
||||
struct _fluid_list_t
|
||||
{
|
||||
void* data;
|
||||
fluid_list_t *next;
|
||||
};
|
||||
|
||||
fluid_list_t* new_fluid_list(void);
|
||||
void delete_fluid_list(fluid_list_t *list);
|
||||
void delete1_fluid_list(fluid_list_t *list);
|
||||
fluid_list_t* fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func);
|
||||
fluid_list_t* fluid_list_append(fluid_list_t *list, void* data);
|
||||
fluid_list_t* fluid_list_prepend(fluid_list_t *list, void* data);
|
||||
fluid_list_t* fluid_list_remove(fluid_list_t *list, void* data);
|
||||
fluid_list_t* fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
|
||||
fluid_list_t* fluid_list_nth(fluid_list_t *list, int n);
|
||||
fluid_list_t* fluid_list_last(fluid_list_t *list);
|
||||
fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data);
|
||||
int fluid_list_size(fluid_list_t *list);
|
||||
|
||||
#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL)
|
||||
#define fluid_list_get(slist) ((slist) ? ((slist)->data) : NULL)
|
||||
|
||||
|
||||
#endif /* _FLUID_LIST_H */
|
247
framework/audio/midi/3rdparty/fluidlite/src/fluid_midi.h
vendored
Normal file
247
framework/audio/midi/3rdparty/fluidlite/src/fluid_midi.h
vendored
Normal file
|
@ -0,0 +1,247 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_MIDI_H
|
||||
#define _FLUID_MIDI_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_list.h"
|
||||
|
||||
typedef struct _fluid_midi_parser_t fluid_midi_parser_t;
|
||||
|
||||
fluid_midi_parser_t* new_fluid_midi_parser(void);
|
||||
int delete_fluid_midi_parser(fluid_midi_parser_t* parser);
|
||||
fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c);
|
||||
|
||||
int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player, fluid_midi_event_t* evt);
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* CONSTANTS & ENUM
|
||||
*/
|
||||
|
||||
|
||||
#define MAX_NUMBER_OF_TRACKS 128
|
||||
|
||||
enum fluid_midi_event_type {
|
||||
/* channel messages */
|
||||
NOTE_OFF = 0x80,
|
||||
NOTE_ON = 0x90,
|
||||
KEY_PRESSURE = 0xa0,
|
||||
CONTROL_CHANGE = 0xb0,
|
||||
PROGRAM_CHANGE = 0xc0,
|
||||
CHANNEL_PRESSURE = 0xd0,
|
||||
PITCH_BEND = 0xe0,
|
||||
/* system exclusive */
|
||||
MIDI_SYSEX = 0xf0,
|
||||
/* system common - never in midi files */
|
||||
MIDI_TIME_CODE = 0xf1,
|
||||
MIDI_SONG_POSITION = 0xf2,
|
||||
MIDI_SONG_SELECT = 0xf3,
|
||||
MIDI_TUNE_REQUEST = 0xf6,
|
||||
MIDI_EOX = 0xf7,
|
||||
/* system real-time - never in midi files */
|
||||
MIDI_SYNC = 0xf8,
|
||||
MIDI_TICK = 0xf9,
|
||||
MIDI_START = 0xfa,
|
||||
MIDI_CONTINUE = 0xfb,
|
||||
MIDI_STOP = 0xfc,
|
||||
MIDI_ACTIVE_SENSING = 0xfe,
|
||||
MIDI_SYSTEM_RESET = 0xff,
|
||||
/* meta event - for midi files only */
|
||||
MIDI_META_EVENT = 0xff
|
||||
};
|
||||
|
||||
enum fluid_midi_control_change {
|
||||
BANK_SELECT_MSB = 0x00,
|
||||
MODULATION_MSB = 0x01,
|
||||
BREATH_MSB = 0x02,
|
||||
FOOT_MSB = 0x04,
|
||||
PORTAMENTO_TIME_MSB = 0x05,
|
||||
DATA_ENTRY_MSB = 0x06,
|
||||
VOLUME_MSB = 0x07,
|
||||
BALANCE_MSB = 0x08,
|
||||
PAN_MSB = 0x0A,
|
||||
EXPRESSION_MSB = 0x0B,
|
||||
EFFECTS1_MSB = 0x0C,
|
||||
EFFECTS2_MSB = 0x0D,
|
||||
GPC1_MSB = 0x10, /* general purpose controller */
|
||||
GPC2_MSB = 0x11,
|
||||
GPC3_MSB = 0x12,
|
||||
GPC4_MSB = 0x13,
|
||||
BANK_SELECT_LSB = 0x20,
|
||||
MODULATION_WHEEL_LSB = 0x21,
|
||||
BREATH_LSB = 0x22,
|
||||
FOOT_LSB = 0x24,
|
||||
PORTAMENTO_TIME_LSB = 0x25,
|
||||
DATA_ENTRY_LSB = 0x26,
|
||||
VOLUME_LSB = 0x27,
|
||||
BALANCE_LSB = 0x28,
|
||||
PAN_LSB = 0x2A,
|
||||
EXPRESSION_LSB = 0x2B,
|
||||
EFFECTS1_LSB = 0x2C,
|
||||
EFFECTS2_LSB = 0x2D,
|
||||
GPC1_LSB = 0x30,
|
||||
GPC2_LSB = 0x31,
|
||||
GPC3_LSB = 0x32,
|
||||
GPC4_LSB = 0x33,
|
||||
SUSTAIN_SWITCH = 0x40,
|
||||
PORTAMENTO_SWITCH = 0x41,
|
||||
SOSTENUTO_SWITCH = 0x42,
|
||||
SOFT_PEDAL_SWITCH = 0x43,
|
||||
LEGATO_SWITCH = 0x45,
|
||||
HOLD2_SWITCH = 0x45,
|
||||
SOUND_CTRL1 = 0x46,
|
||||
SOUND_CTRL2 = 0x47,
|
||||
SOUND_CTRL3 = 0x48,
|
||||
SOUND_CTRL4 = 0x49,
|
||||
SOUND_CTRL5 = 0x4A,
|
||||
SOUND_CTRL6 = 0x4B,
|
||||
SOUND_CTRL7 = 0x4C,
|
||||
SOUND_CTRL8 = 0x4D,
|
||||
SOUND_CTRL9 = 0x4E,
|
||||
SOUND_CTRL10 = 0x4F,
|
||||
GPC5 = 0x50,
|
||||
GPC6 = 0x51,
|
||||
GPC7 = 0x52,
|
||||
GPC8 = 0x53,
|
||||
PORTAMENTO_CTRL = 0x54,
|
||||
EFFECTS_DEPTH1 = 0x5B,
|
||||
EFFECTS_DEPTH2 = 0x5C,
|
||||
EFFECTS_DEPTH3 = 0x5D,
|
||||
EFFECTS_DEPTH4 = 0x5E,
|
||||
EFFECTS_DEPTH5 = 0x5F,
|
||||
DATA_ENTRY_INCR = 0x60,
|
||||
DATA_ENTRY_DECR = 0x61,
|
||||
NRPN_LSB = 0x62,
|
||||
NRPN_MSB = 0x63,
|
||||
RPN_LSB = 0x64,
|
||||
RPN_MSB = 0x65,
|
||||
ALL_SOUND_OFF = 0x78,
|
||||
ALL_CTRL_OFF = 0x79,
|
||||
LOCAL_CONTROL = 0x7A,
|
||||
ALL_NOTES_OFF = 0x7B,
|
||||
OMNI_OFF = 0x7C,
|
||||
OMNI_ON = 0x7D,
|
||||
POLY_OFF = 0x7E,
|
||||
POLY_ON = 0x7F
|
||||
};
|
||||
|
||||
/* General MIDI RPN event numbers (LSB, MSB = 0) */
|
||||
enum midi_rpn_event {
|
||||
RPN_PITCH_BEND_RANGE = 0x00,
|
||||
RPN_CHANNEL_FINE_TUNE = 0x01,
|
||||
RPN_CHANNEL_COARSE_TUNE = 0x02,
|
||||
RPN_TUNING_PROGRAM_CHANGE = 0x03,
|
||||
RPN_TUNING_BANK_SELECT = 0x04,
|
||||
RPN_MODULATION_DEPTH_RANGE = 0x05
|
||||
};
|
||||
|
||||
enum midi_meta_event {
|
||||
MIDI_COPYRIGHT = 0x02,
|
||||
MIDI_TRACK_NAME = 0x03,
|
||||
MIDI_INST_NAME = 0x04,
|
||||
MIDI_LYRIC = 0x05,
|
||||
MIDI_MARKER = 0x06,
|
||||
MIDI_CUE_POINT = 0x07,
|
||||
MIDI_EOT = 0x2f,
|
||||
MIDI_SET_TEMPO = 0x51,
|
||||
MIDI_SMPTE_OFFSET = 0x54,
|
||||
MIDI_TIME_SIGNATURE = 0x58,
|
||||
MIDI_KEY_SIGNATURE = 0x59,
|
||||
MIDI_SEQUENCER_EVENT = 0x7f
|
||||
};
|
||||
|
||||
/* MIDI SYSEX useful manufacturer values */
|
||||
enum midi_sysex_manuf {
|
||||
MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
|
||||
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
|
||||
MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
|
||||
};
|
||||
|
||||
#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */
|
||||
|
||||
/* SYSEX sub-ID #1 which follows device ID */
|
||||
#define MIDI_SYSEX_MIDI_TUNING_ID 0x08 /**< Sysex sub-ID #1 for MIDI tuning messages */
|
||||
#define MIDI_SYSEX_GM_ID 0x09 /**< Sysex sub-ID #1 for General MIDI messages */
|
||||
|
||||
/**
|
||||
* SYSEX tuning message IDs.
|
||||
*/
|
||||
enum midi_sysex_tuning_msg_id {
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
|
||||
};
|
||||
|
||||
/* General MIDI sub-ID #2 */
|
||||
#define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */
|
||||
#define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */
|
||||
|
||||
|
||||
enum fluid_player_status
|
||||
{
|
||||
FLUID_PLAYER_READY,
|
||||
FLUID_PLAYER_PLAYING,
|
||||
FLUID_PLAYER_DONE
|
||||
};
|
||||
|
||||
enum fluid_driver_status
|
||||
{
|
||||
FLUID_MIDI_READY,
|
||||
FLUID_MIDI_LISTENING,
|
||||
FLUID_MIDI_DONE
|
||||
};
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* TYPE DEFINITIONS & FUNCTION DECLARATIONS
|
||||
*/
|
||||
|
||||
/* From ctype.h */
|
||||
#define fluid_isascii(c) (((c) & ~0x7f) == 0)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* fluid_midi_event_t
|
||||
*/
|
||||
struct _fluid_midi_event_t {
|
||||
fluid_midi_event_t* next; /* Don't use it, it will dissappear. Used in midi tracks. */
|
||||
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
|
||||
unsigned char type; /* MIDI event type */
|
||||
unsigned char channel; /* MIDI channel */
|
||||
unsigned int param1; /* First parameter */
|
||||
unsigned int param2; /* Second parameter */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _FLUID_MIDI_H */
|
434
framework/audio/midi/3rdparty/fluidlite/src/fluid_mod.c
vendored
Normal file
434
framework/audio/midi/3rdparty/fluidlite/src/fluid_mod.c
vendored
Normal file
|
@ -0,0 +1,434 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluid_mod.h"
|
||||
#include "fluid_chan.h"
|
||||
#include "fluid_voice.h"
|
||||
|
||||
/*
|
||||
* fluid_mod_clone
|
||||
*/
|
||||
void
|
||||
fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src)
|
||||
{
|
||||
mod->dest = src->dest;
|
||||
mod->src1 = src->src1;
|
||||
mod->flags1 = src->flags1;
|
||||
mod->src2 = src->src2;
|
||||
mod->flags2 = src->flags2;
|
||||
mod->amount = src->amount;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_mod_set_source1
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags)
|
||||
{
|
||||
mod->src1 = src;
|
||||
mod->flags1 = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_mod_set_source2
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags)
|
||||
{
|
||||
mod->src2 = src;
|
||||
mod->flags2 = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_mod_set_dest
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_dest(fluid_mod_t* mod, int dest)
|
||||
{
|
||||
mod->dest = dest;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_mod_set_amount
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_amount(fluid_mod_t* mod, double amount)
|
||||
{
|
||||
mod->amount = (double) amount;
|
||||
}
|
||||
|
||||
int fluid_mod_get_source1(fluid_mod_t* mod)
|
||||
{
|
||||
return mod->src1;
|
||||
}
|
||||
|
||||
int fluid_mod_get_flags1(fluid_mod_t* mod)
|
||||
{
|
||||
return mod->flags1;
|
||||
}
|
||||
|
||||
int fluid_mod_get_source2(fluid_mod_t* mod)
|
||||
{
|
||||
return mod->src2;
|
||||
}
|
||||
|
||||
int fluid_mod_get_flags2(fluid_mod_t* mod)
|
||||
{
|
||||
return mod->flags2;
|
||||
}
|
||||
|
||||
int fluid_mod_get_dest(fluid_mod_t* mod)
|
||||
{
|
||||
return mod->dest;
|
||||
}
|
||||
|
||||
double fluid_mod_get_amount(fluid_mod_t* mod)
|
||||
{
|
||||
return (fluid_real_t) mod->amount;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fluid_mod_get_value
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice)
|
||||
{
|
||||
fluid_real_t v1 = 0.0, v2 = 1.0;
|
||||
fluid_real_t range1 = 127.0, range2 = 127.0;
|
||||
|
||||
if (chan == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* 'special treatment' for default controller
|
||||
*
|
||||
* Reference: SF2.01 section 8.4.2
|
||||
*
|
||||
* The GM default controller 'vel-to-filter cut off' is not clearly
|
||||
* defined: If implemented according to the specs, the filter
|
||||
* frequency jumps between vel=63 and vel=64. To maintain
|
||||
* compatibility with existing sound fonts, the implementation is
|
||||
* 'hardcoded', it is impossible to implement using only one
|
||||
* modulator otherwise.
|
||||
*
|
||||
* I assume here, that the 'intention' of the paragraph is one
|
||||
* octave (1200 cents) filter frequency shift between vel=127 and
|
||||
* vel=64. 'amount' is (-2400), at least as long as the controller
|
||||
* is set to default.
|
||||
*
|
||||
* Further, the 'appearance' of the modulator (source enumerator,
|
||||
* destination enumerator, flags etc) is different from that
|
||||
* described in section 8.4.2, but it matches the definition used in
|
||||
* several SF2.1 sound fonts (where it is used only to turn it off).
|
||||
* */
|
||||
if ((mod->src2 == FLUID_MOD_VELOCITY) &&
|
||||
(mod->src1 == FLUID_MOD_VELOCITY) &&
|
||||
(mod->flags1 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
|
||||
| FLUID_MOD_NEGATIVE | FLUID_MOD_LINEAR)) &&
|
||||
(mod->flags2 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
|
||||
| FLUID_MOD_POSITIVE | FLUID_MOD_SWITCH)) &&
|
||||
(mod->dest == GEN_FILTERFC)) {
|
||||
// S. Christian Collins' mod, to stop forcing velocity based filtering
|
||||
/*
|
||||
if (voice->vel < 64){
|
||||
return (fluid_real_t) mod->amount / 2.0;
|
||||
} else {
|
||||
return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
|
||||
}
|
||||
*/
|
||||
return 0; // (fluid_real_t) mod->amount / 2.0;
|
||||
}
|
||||
// end S. Christian Collins' mod
|
||||
|
||||
/* get the initial value of the first source */
|
||||
if (mod->src1 > 0) {
|
||||
if (mod->flags1 & FLUID_MOD_CC) {
|
||||
v1 = fluid_channel_get_cc(chan, mod->src1);
|
||||
} else { /* source 1 is one of the direct controllers */
|
||||
switch (mod->src1) {
|
||||
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
|
||||
v1 = range1;
|
||||
break;
|
||||
case FLUID_MOD_VELOCITY:
|
||||
v1 = voice->vel;
|
||||
break;
|
||||
case FLUID_MOD_KEY:
|
||||
v1 = voice->key;
|
||||
break;
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
v1 = chan->key_pressure;
|
||||
break;
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
v1 = chan->channel_pressure;
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
v1 = chan->pitch_bend;
|
||||
range1 = 0x4000;
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
v1 = chan->pitch_wheel_sensitivity;
|
||||
break;
|
||||
default:
|
||||
v1 = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* transform the input value */
|
||||
switch (mod->flags1 & 0x0f) {
|
||||
case 0: /* linear, unipolar, positive */
|
||||
v1 /= range1;
|
||||
break;
|
||||
case 1: /* linear, unipolar, negative */
|
||||
v1 = 1.0f - v1 / range1;
|
||||
break;
|
||||
case 2: /* linear, bipolar, positive */
|
||||
v1 = -1.0f + 2.0f * v1 / range1;
|
||||
break;
|
||||
case 3: /* linear, bipolar, negative */
|
||||
v1 = 1.0f - 2.0f * v1 / range1;
|
||||
break;
|
||||
case 4: /* concave, unipolar, positive */
|
||||
v1 = fluid_concave(v1);
|
||||
break;
|
||||
case 5: /* concave, unipolar, negative */
|
||||
v1 = fluid_concave(127 - v1);
|
||||
break;
|
||||
case 6: /* concave, bipolar, positive */
|
||||
v1 = (v1 > 64)? fluid_concave(2 * (v1 - 64)) : -fluid_concave(2 * (64 - v1));
|
||||
break;
|
||||
case 7: /* concave, bipolar, negative */
|
||||
v1 = (v1 > 64)? -fluid_concave(2 * (v1 - 64)) : fluid_concave(2 * (64 - v1));
|
||||
break;
|
||||
case 8: /* convex, unipolar, positive */
|
||||
v1 = fluid_convex(v1);
|
||||
break;
|
||||
case 9: /* convex, unipolar, negative */
|
||||
v1 = fluid_convex(127 - v1);
|
||||
break;
|
||||
case 10: /* convex, bipolar, positive */
|
||||
v1 = (v1 > 64)? fluid_convex(2 * (v1 - 64)) : -fluid_convex(2 * (64 - v1));
|
||||
break;
|
||||
case 11: /* convex, bipolar, negative */
|
||||
v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1));
|
||||
break;
|
||||
case 12: /* switch, unipolar, positive */
|
||||
v1 = (v1 >= 64)? 1.0f : 0.0f;
|
||||
break;
|
||||
case 13: /* switch, unipolar, negative */
|
||||
v1 = (v1 >= 64)? 0.0f : 1.0f;
|
||||
break;
|
||||
case 14: /* switch, bipolar, positive */
|
||||
v1 = (v1 >= 64)? 1.0f : -1.0f;
|
||||
break;
|
||||
case 15: /* switch, bipolar, negative */
|
||||
v1 = (v1 >= 64)? -1.0f : 1.0f;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* no need to go further */
|
||||
if (v1 == 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* get the second input source */
|
||||
if (mod->src2 > 0) {
|
||||
if (mod->flags2 & FLUID_MOD_CC) {
|
||||
v2 = fluid_channel_get_cc(chan, mod->src2);
|
||||
} else {
|
||||
switch (mod->src2) {
|
||||
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
|
||||
v2 = range2;
|
||||
break;
|
||||
case FLUID_MOD_VELOCITY:
|
||||
v2 = voice->vel;
|
||||
break;
|
||||
case FLUID_MOD_KEY:
|
||||
v2 = voice->key;
|
||||
break;
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
v2 = chan->key_pressure;
|
||||
break;
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
v2 = chan->channel_pressure;
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
v2 = chan->pitch_bend;
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
v2 = chan->pitch_wheel_sensitivity;
|
||||
break;
|
||||
default:
|
||||
v1 = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* transform the second input value */
|
||||
switch (mod->flags2 & 0x0f) {
|
||||
case 0: /* linear, unipolar, positive */
|
||||
v2 /= range2;
|
||||
break;
|
||||
case 1: /* linear, unipolar, negative */
|
||||
v2 = 1.0f - v2 / range2;
|
||||
break;
|
||||
case 2: /* linear, bipolar, positive */
|
||||
v2 = -1.0f + 2.0f * v2 / range2;
|
||||
break;
|
||||
case 3: /* linear, bipolar, negative */
|
||||
v2 = -1.0f + 2.0f * v2 / range2;
|
||||
break;
|
||||
case 4: /* concave, unipolar, positive */
|
||||
v2 = fluid_concave(v2);
|
||||
break;
|
||||
case 5: /* concave, unipolar, negative */
|
||||
v2 = fluid_concave(127 - v2);
|
||||
break;
|
||||
case 6: /* concave, bipolar, positive */
|
||||
v2 = (v2 > 64)? fluid_concave(2 * (v2 - 64)) : -fluid_concave(2 * (64 - v2));
|
||||
break;
|
||||
case 7: /* concave, bipolar, negative */
|
||||
v2 = (v2 > 64)? -fluid_concave(2 * (v2 - 64)) : fluid_concave(2 * (64 - v2));
|
||||
break;
|
||||
case 8: /* convex, unipolar, positive */
|
||||
v2 = fluid_convex(v2);
|
||||
break;
|
||||
case 9: /* convex, unipolar, negative */
|
||||
v2 = 1.0f - fluid_convex(v2);
|
||||
break;
|
||||
case 10: /* convex, bipolar, positive */
|
||||
v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
|
||||
break;
|
||||
case 11: /* convex, bipolar, negative */
|
||||
v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
|
||||
break;
|
||||
case 12: /* switch, unipolar, positive */
|
||||
v2 = (v2 >= 64)? 1.0f : 0.0f;
|
||||
break;
|
||||
case 13: /* switch, unipolar, negative */
|
||||
v2 = (v2 >= 64)? 0.0f : 1.0f;
|
||||
break;
|
||||
case 14: /* switch, bipolar, positive */
|
||||
v2 = (v2 >= 64)? 1.0f : -1.0f;
|
||||
break;
|
||||
case 15: /* switch, bipolar, negative */
|
||||
v2 = (v2 >= 64)? -1.0f : 1.0f;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
v2 = 1.0f;
|
||||
}
|
||||
|
||||
/* it's as simple as that: */
|
||||
return (fluid_real_t) mod->amount * v1 * v2;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_mod_new
|
||||
*/
|
||||
fluid_mod_t*
|
||||
fluid_mod_new()
|
||||
{
|
||||
fluid_mod_t* mod = FLUID_NEW(fluid_mod_t);
|
||||
if (mod == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
|
||||
/*
|
||||
* fluid_mod_delete
|
||||
*/
|
||||
void
|
||||
fluid_mod_delete(fluid_mod_t * mod)
|
||||
{
|
||||
FLUID_FREE(mod);
|
||||
};
|
||||
|
||||
/*
|
||||
* fluid_mod_test_identity
|
||||
*/
|
||||
/* Purpose:
|
||||
* Checks, if two modulators are identical.
|
||||
* SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'.
|
||||
*/
|
||||
int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2){
|
||||
if (mod1->dest != mod2->dest){return 0;};
|
||||
if (mod1->src1 != mod2->src1){return 0;};
|
||||
if (mod1->src2 != mod2->src2){return 0;};
|
||||
if (mod1->flags1 != mod2->flags1){return 0;}
|
||||
if (mod1->flags2 != mod2->flags2){return 0;}
|
||||
return 1;
|
||||
};
|
||||
|
||||
/* debug function: Prints the contents of a modulator */
|
||||
void fluid_dump_modulator(fluid_mod_t * mod){
|
||||
int src1=mod->src1;
|
||||
int dest=mod->dest;
|
||||
int src2=mod->src2;
|
||||
int flags1=mod->flags1;
|
||||
int flags2=mod->flags2;
|
||||
fluid_real_t amount=(fluid_real_t)mod->amount;
|
||||
|
||||
printf("Src: ");
|
||||
if (flags1 & FLUID_MOD_CC){
|
||||
printf("MIDI CC=%i",src1);
|
||||
} else {
|
||||
switch(src1){
|
||||
case FLUID_MOD_NONE:
|
||||
printf("None"); break;
|
||||
case FLUID_MOD_VELOCITY:
|
||||
printf("note-on velocity"); break;
|
||||
case FLUID_MOD_KEY:
|
||||
printf("Key nr"); break;
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
printf("Poly pressure"); break;
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
printf("Chan pressure"); break;
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
printf("Pitch Wheel"); break;
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
printf("Pitch Wheel sens"); break;
|
||||
default:
|
||||
printf("(unknown: %i)", src1);
|
||||
}; /* switch src1 */
|
||||
}; /* if not CC */
|
||||
if (flags1 & FLUID_MOD_NEGATIVE){printf("- ");} else {printf("+ ");};
|
||||
if (flags1 & FLUID_MOD_BIPOLAR){printf("bip ");} else {printf("unip ");};
|
||||
printf("-> ");
|
||||
switch(dest){
|
||||
case GEN_FILTERQ: printf("Q"); break;
|
||||
case GEN_FILTERFC: printf("fc"); break;
|
||||
case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
|
||||
case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
|
||||
case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
|
||||
case GEN_CHORUSSEND: printf("Chorus send"); break;
|
||||
case GEN_REVERBSEND: printf("Reverb send"); break;
|
||||
case GEN_PAN: printf("pan"); break;
|
||||
case GEN_ATTENUATION: printf("att"); break;
|
||||
default: printf("dest %i",dest);
|
||||
}; /* switch dest */
|
||||
printf(", amount %f flags %i src2 %i flags2 %i\n",amount, flags1, src2, flags2);
|
||||
};
|
||||
|
||||
|
40
framework/audio/midi/3rdparty/fluidlite/src/fluid_mod.h
vendored
Normal file
40
framework/audio/midi/3rdparty/fluidlite/src/fluid_mod.h
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_MOD_H
|
||||
#define _FLUID_MOD_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_conv.h"
|
||||
|
||||
void fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src);
|
||||
fluid_real_t fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice);
|
||||
void fluid_dump_modulator(fluid_mod_t * mod);
|
||||
|
||||
#define fluid_mod_has_source(mod,cc,ctrl) \
|
||||
( ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) != 0) && (cc != 0)) \
|
||||
|| ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) == 0) && (cc == 0)))) \
|
||||
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) != 0) && (cc != 0)) \
|
||||
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) == 0) && (cc == 0)))))
|
||||
|
||||
#define fluid_mod_has_dest(mod,gen) ((mod)->dest == gen)
|
||||
|
||||
|
||||
#endif /* _FLUID_MOD_H */
|
115
framework/audio/midi/3rdparty/fluidlite/src/fluid_phase.h
vendored
Normal file
115
framework/audio/midi/3rdparty/fluidlite/src/fluid_phase.h
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_PHASE_H
|
||||
#define _FLUID_PHASE_H
|
||||
|
||||
#include "fluid_config.h"
|
||||
|
||||
/*
|
||||
* phase
|
||||
*/
|
||||
|
||||
#define FLUID_INTERP_BITS 8
|
||||
#define FLUID_INTERP_BITS_MASK 0xff000000
|
||||
#define FLUID_INTERP_BITS_SHIFT 24
|
||||
#define FLUID_INTERP_MAX 256
|
||||
|
||||
#define FLUID_FRACT_MAX ((double)4294967296.0)
|
||||
|
||||
/* fluid_phase_t
|
||||
* Purpose:
|
||||
* Playing pointer for voice playback
|
||||
*
|
||||
* When a sample is played back at a different pitch, the playing pointer in the
|
||||
* source sample will not advance exactly one sample per output sample.
|
||||
* This playing pointer is implemented using fluid_phase_t.
|
||||
* It is a 64 bit number. The higher 32 bits contain the 'index' (number of
|
||||
* the current sample), the lower 32 bits the fractional part.
|
||||
*/
|
||||
typedef unsigned long long fluid_phase_t;
|
||||
|
||||
/* Purpose:
|
||||
* Set a to b.
|
||||
* a: fluid_phase_t
|
||||
* b: fluid_phase_t
|
||||
*/
|
||||
#define fluid_phase_set(a,b) a=b;
|
||||
|
||||
#define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
|
||||
|
||||
/* Purpose:
|
||||
* Sets the phase a to a phase increment given in b.
|
||||
* For example, assume b is 0.9. After setting a to it, adding a to
|
||||
* the playing pointer will advance it by 0.9 samples. */
|
||||
#define fluid_phase_set_float(a, b) \
|
||||
(a) = (((unsigned long long)(b)) << 32) \
|
||||
| (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
|
||||
|
||||
/* create a fluid_phase_t from an index and a fraction value */
|
||||
#define fluid_phase_from_index_fract(index, fract) \
|
||||
((((unsigned long long)(index)) << 32) + (fract))
|
||||
|
||||
/* Purpose:
|
||||
* Return the index and the fractional part, respectively. */
|
||||
#define fluid_phase_index(_x) \
|
||||
((unsigned int)((_x) >> 32))
|
||||
#define fluid_phase_fract(_x) \
|
||||
((uint32)((_x) & 0xFFFFFFFF))
|
||||
|
||||
/* Get the phase index with fractional rounding */
|
||||
#define fluid_phase_index_round(_x) \
|
||||
((unsigned int)(((_x) + 0x80000000) >> 32))
|
||||
|
||||
|
||||
/* Purpose:
|
||||
* Takes the fractional part of the argument phase and
|
||||
* calculates the corresponding position in the interpolation table.
|
||||
* The fractional position of the playing pointer is calculated with a quite high
|
||||
* resolution (32 bits). It would be unpractical to keep a set of interpolation
|
||||
* coefficients for each possible fractional part...
|
||||
*/
|
||||
#define fluid_phase_fract_to_tablerow(_x) \
|
||||
((unsigned int)(fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT)
|
||||
|
||||
#define fluid_phase_double(_x) \
|
||||
((double)(fluid_phase_index(_x)) + ((double)fluid_phase_fract(_x) / FLUID_FRACT_MAX))
|
||||
|
||||
/* Purpose:
|
||||
* Advance a by a step of b (both are fluid_phase_t).
|
||||
*/
|
||||
#define fluid_phase_incr(a, b) a += b
|
||||
|
||||
/* Purpose:
|
||||
* Subtract b from a (both are fluid_phase_t).
|
||||
*/
|
||||
#define fluid_phase_decr(a, b) a -= b
|
||||
|
||||
/* Purpose:
|
||||
* Subtract b samples from a.
|
||||
*/
|
||||
#define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
|
||||
|
||||
/* Purpose:
|
||||
* Creates the expression a.index++. */
|
||||
#define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL)
|
||||
|
||||
#endif /* _FLUID_PHASE_H */
|
1117
framework/audio/midi/3rdparty/fluidlite/src/fluid_ramsfont.c
vendored
Normal file
1117
framework/audio/midi/3rdparty/fluidlite/src/fluid_ramsfont.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
114
framework/audio/midi/3rdparty/fluidlite/src/fluid_ramsfont.h
vendored
Normal file
114
framework/audio/midi/3rdparty/fluidlite/src/fluid_ramsfont.h
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_RAMSFONT_H
|
||||
#define _FLUID_RAMSFONT_H
|
||||
|
||||
|
||||
#include "fluidlite.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#include "fluid_defsfont.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Public interface
|
||||
|
||||
*/
|
||||
|
||||
int fluid_ramsfont_sfont_delete(fluid_sfont_t* sfont);
|
||||
char* fluid_ramsfont_sfont_get_name(fluid_sfont_t* sfont);
|
||||
fluid_preset_t* fluid_ramsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont);
|
||||
int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
|
||||
|
||||
int fluid_rampreset_preset_delete(fluid_preset_t* preset);
|
||||
char* fluid_rampreset_preset_get_name(fluid_preset_t* preset);
|
||||
int fluid_rampreset_preset_get_banknum(fluid_preset_t* preset);
|
||||
int fluid_rampreset_preset_get_num(fluid_preset_t* preset);
|
||||
int fluid_rampreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
|
||||
/*
|
||||
* fluid_ramsfont_t
|
||||
*/
|
||||
struct _fluid_ramsfont_t
|
||||
{
|
||||
char name[21]; /* the name of the soundfont */
|
||||
fluid_list_t* sample; /* the samples in this soundfont */
|
||||
fluid_rampreset_t* preset; /* the presets of this soundfont */
|
||||
|
||||
fluid_preset_t iter_preset; /* preset interface used in the iteration */
|
||||
fluid_rampreset_t* iter_cur; /* the current preset in the iteration */
|
||||
};
|
||||
|
||||
/* interface */
|
||||
fluid_ramsfont_t* new_fluid_ramsfont(void);
|
||||
int delete_fluid_ramsfont(fluid_ramsfont_t* sfont);
|
||||
char* fluid_ramsfont_get_name(fluid_ramsfont_t* sfont);
|
||||
fluid_rampreset_t* fluid_ramsfont_get_preset(fluid_ramsfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_ramsfont_iteration_start(fluid_ramsfont_t* sfont);
|
||||
int fluid_ramsfont_iteration_next(fluid_ramsfont_t* sfont, fluid_preset_t* preset);
|
||||
/* specific */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* fluid_preset_t
|
||||
*/
|
||||
struct _fluid_rampreset_t
|
||||
{
|
||||
fluid_rampreset_t* next;
|
||||
fluid_ramsfont_t* sfont; /* the soundfont this preset belongs to */
|
||||
char name[21]; /* the name of the preset */
|
||||
unsigned int bank; /* the bank number */
|
||||
unsigned int num; /* the preset number */
|
||||
fluid_preset_zone_t* global_zone; /* the global zone of the preset */
|
||||
fluid_preset_zone_t* zone; /* the chained list of preset zones */
|
||||
fluid_list_t *presetvoices; /* chained list of used voices */
|
||||
};
|
||||
|
||||
/* interface */
|
||||
fluid_rampreset_t* new_fluid_rampreset(fluid_ramsfont_t* sfont);
|
||||
int delete_fluid_rampreset(fluid_rampreset_t* preset);
|
||||
fluid_rampreset_t* fluid_rampreset_next(fluid_rampreset_t* preset);
|
||||
char* fluid_rampreset_get_name(fluid_rampreset_t* preset);
|
||||
int fluid_rampreset_get_banknum(fluid_rampreset_t* preset);
|
||||
int fluid_rampreset_get_num(fluid_rampreset_t* preset);
|
||||
int fluid_rampreset_noteon(fluid_rampreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FLUID_SFONT_H */
|
561
framework/audio/midi/3rdparty/fluidlite/src/fluid_rev.c
vendored
Normal file
561
framework/audio/midi/3rdparty/fluidlite/src/fluid_rev.c
vendored
Normal file
|
@ -0,0 +1,561 @@
|
|||
/*
|
||||
|
||||
Freeverb
|
||||
|
||||
Written by Jezar at Dreampoint, June 2000
|
||||
http://www.dreampoint.co.uk
|
||||
This code is public domain
|
||||
|
||||
Translated to C by Peter Hanappe, Mai 2001
|
||||
*/
|
||||
|
||||
#include "fluid_rev.h"
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* REVERB
|
||||
*/
|
||||
|
||||
/* Denormalising:
|
||||
*
|
||||
* According to music-dsp thread 'Denormalise', Pentium processors
|
||||
* have a hardware 'feature', that is of interest here, related to
|
||||
* numeric underflow. We have a recursive filter. The output decays
|
||||
* exponentially, if the input stops. So the numbers get smaller and
|
||||
* smaller... At some point, they reach 'denormal' level. This will
|
||||
* lead to drastic spikes in the CPU load. The effect was reproduced
|
||||
* with the reverb - sometimes the average load over 10 s doubles!!.
|
||||
*
|
||||
* The 'undenormalise' macro fixes the problem: As soon as the number
|
||||
* is close enough to denormal level, the macro forces the number to
|
||||
* 0.0f. The original macro is:
|
||||
*
|
||||
* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
|
||||
*
|
||||
* This will zero out a number when it reaches the denormal level.
|
||||
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
|
||||
* every sample, expensive. The alternative macro comes from a later
|
||||
* mail from Jon Watte. It will zap a number before it reaches
|
||||
* denormal level. Jon suggests to run it once per block instead of
|
||||
* every sample.
|
||||
*/
|
||||
|
||||
# if defined(WITH_FLOATX)
|
||||
# define zap_almost_zero(sample) (((*(unsigned int*)&(sample))&0x7f800000) < 0x08000000)?0.0f:(sample)
|
||||
# else
|
||||
/* 1e-20 was chosen as an arbitrary (small) threshold. */
|
||||
#define zap_almost_zero(sample) fabs(sample)<1e-10 ? 0 : sample;
|
||||
#endif
|
||||
|
||||
/* Denormalising part II:
|
||||
*
|
||||
* Another method fixes the problem cheaper: Use a small DC-offset in
|
||||
* the filter calculations. Now the signals converge not against 0,
|
||||
* but against the offset. The constant offset is invisible from the
|
||||
* outside world (i.e. it does not appear at the output. There is a
|
||||
* very small turn-on transient response, which should not cause
|
||||
* problems.
|
||||
*/
|
||||
|
||||
|
||||
//#define DC_OFFSET 0
|
||||
#define DC_OFFSET 1e-8
|
||||
//#define DC_OFFSET 0.001f
|
||||
typedef struct _fluid_allpass fluid_allpass;
|
||||
typedef struct _fluid_comb fluid_comb;
|
||||
|
||||
struct _fluid_allpass {
|
||||
fluid_real_t feedback;
|
||||
fluid_real_t *buffer;
|
||||
int bufsize;
|
||||
int bufidx;
|
||||
};
|
||||
|
||||
void fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size);
|
||||
void fluid_allpass_init(fluid_allpass* allpass);
|
||||
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
|
||||
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
|
||||
|
||||
void
|
||||
fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size)
|
||||
{
|
||||
allpass->bufidx = 0;
|
||||
allpass->buffer = buf;
|
||||
allpass->bufsize = size;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_allpass_init(fluid_allpass* allpass)
|
||||
{
|
||||
int i;
|
||||
int len = allpass->bufsize;
|
||||
fluid_real_t* buf = allpass->buffer;
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = DC_OFFSET; /* this is not 100 % correct. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val)
|
||||
{
|
||||
allpass->feedback = val;
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_allpass_getfeedback(fluid_allpass* allpass)
|
||||
{
|
||||
return allpass->feedback;
|
||||
}
|
||||
|
||||
#define fluid_allpass_process(_allpass, _input) \
|
||||
{ \
|
||||
fluid_real_t output; \
|
||||
fluid_real_t bufout; \
|
||||
bufout = _allpass.buffer[_allpass.bufidx]; \
|
||||
output = bufout-_input; \
|
||||
_allpass.buffer[_allpass.bufidx] = _input + (bufout * _allpass.feedback); \
|
||||
if (++_allpass.bufidx >= _allpass.bufsize) { \
|
||||
_allpass.bufidx = 0; \
|
||||
} \
|
||||
_input = output; \
|
||||
}
|
||||
|
||||
/* fluid_real_t fluid_allpass_process(fluid_allpass* allpass, fluid_real_t input) */
|
||||
/* { */
|
||||
/* fluid_real_t output; */
|
||||
/* fluid_real_t bufout; */
|
||||
/* bufout = allpass->buffer[allpass->bufidx]; */
|
||||
/* undenormalise(bufout); */
|
||||
/* output = -input + bufout; */
|
||||
/* allpass->buffer[allpass->bufidx] = input + (bufout * allpass->feedback); */
|
||||
/* if (++allpass->bufidx >= allpass->bufsize) { */
|
||||
/* allpass->bufidx = 0; */
|
||||
/* } */
|
||||
/* return output; */
|
||||
/* } */
|
||||
|
||||
struct _fluid_comb {
|
||||
fluid_real_t feedback;
|
||||
fluid_real_t filterstore;
|
||||
fluid_real_t damp1;
|
||||
fluid_real_t damp2;
|
||||
fluid_real_t *buffer;
|
||||
int bufsize;
|
||||
int bufidx;
|
||||
};
|
||||
|
||||
void fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size);
|
||||
void fluid_comb_init(fluid_comb* comb);
|
||||
void fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getdamp(fluid_comb* comb);
|
||||
void fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getfeedback(fluid_comb* comb);
|
||||
|
||||
void
|
||||
fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size)
|
||||
{
|
||||
comb->filterstore = 0;
|
||||
comb->bufidx = 0;
|
||||
comb->buffer = buf;
|
||||
comb->bufsize = size;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_init(fluid_comb* comb)
|
||||
{
|
||||
int i;
|
||||
fluid_real_t* buf = comb->buffer;
|
||||
int len = comb->bufsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = DC_OFFSET; /* This is not 100 % correct. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val)
|
||||
{
|
||||
comb->damp1 = val;
|
||||
comb->damp2 = 1 - val;
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_comb_getdamp(fluid_comb* comb)
|
||||
{
|
||||
return comb->damp1;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val)
|
||||
{
|
||||
comb->feedback = val;
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_comb_getfeedback(fluid_comb* comb)
|
||||
{
|
||||
return comb->feedback;
|
||||
}
|
||||
|
||||
#define fluid_comb_process(_comb, _input, _output) \
|
||||
{ \
|
||||
fluid_real_t _tmp = _comb.buffer[_comb.bufidx]; \
|
||||
_comb.filterstore = (_tmp * _comb.damp2) + (_comb.filterstore * _comb.damp1); \
|
||||
_comb.buffer[_comb.bufidx] = _input + (_comb.filterstore * _comb.feedback); \
|
||||
if (++_comb.bufidx >= _comb.bufsize) { \
|
||||
_comb.bufidx = 0; \
|
||||
} \
|
||||
_output += _tmp; \
|
||||
}
|
||||
|
||||
/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
|
||||
/* { */
|
||||
/* fluid_real_t output; */
|
||||
|
||||
/* output = comb->buffer[comb->bufidx]; */
|
||||
/* undenormalise(output); */
|
||||
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
|
||||
/* undenormalise(comb->filterstore); */
|
||||
/* comb->buffer[comb->bufidx] = input + (comb->filterstore * comb->feedback); */
|
||||
/* if (++comb->bufidx >= comb->bufsize) { */
|
||||
/* comb->bufidx = 0; */
|
||||
/* } */
|
||||
|
||||
/* return output; */
|
||||
/* } */
|
||||
|
||||
#define numcombs 8
|
||||
#define numallpasses 4
|
||||
#define fixedgain 0.015f
|
||||
#define scalewet 3.0f
|
||||
#define scaledamp 1.0f
|
||||
#define scaleroom 0.28f
|
||||
#define offsetroom 0.7f
|
||||
#define initialroom 0.5f
|
||||
#define initialdamp 0.2f
|
||||
#define initialwet 1
|
||||
#define initialdry 0
|
||||
#define initialwidth 1
|
||||
#define stereospread 23
|
||||
|
||||
/*
|
||||
These values assume 44.1KHz sample rate
|
||||
they will probably be OK for 48KHz sample rate
|
||||
but would need scaling for 96KHz (or other) sample rates.
|
||||
The values were obtained by listening tests.
|
||||
*/
|
||||
#define combtuningL1 1116
|
||||
#define combtuningR1 1116 + stereospread
|
||||
#define combtuningL2 1188
|
||||
#define combtuningR2 1188 + stereospread
|
||||
#define combtuningL3 1277
|
||||
#define combtuningR3 1277 + stereospread
|
||||
#define combtuningL4 1356
|
||||
#define combtuningR4 1356 + stereospread
|
||||
#define combtuningL5 1422
|
||||
#define combtuningR5 1422 + stereospread
|
||||
#define combtuningL6 1491
|
||||
#define combtuningR6 1491 + stereospread
|
||||
#define combtuningL7 1557
|
||||
#define combtuningR7 1557 + stereospread
|
||||
#define combtuningL8 1617
|
||||
#define combtuningR8 1617 + stereospread
|
||||
#define allpasstuningL1 556
|
||||
#define allpasstuningR1 556 + stereospread
|
||||
#define allpasstuningL2 441
|
||||
#define allpasstuningR2 441 + stereospread
|
||||
#define allpasstuningL3 341
|
||||
#define allpasstuningR3 341 + stereospread
|
||||
#define allpasstuningL4 225
|
||||
#define allpasstuningR4 225 + stereospread
|
||||
|
||||
struct _fluid_revmodel_t {
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t wet, wet1, wet2;
|
||||
fluid_real_t width;
|
||||
fluid_real_t gain;
|
||||
/*
|
||||
The following are all declared inline
|
||||
to remove the need for dynamic allocation
|
||||
with its subsequent error-checking messiness
|
||||
*/
|
||||
/* Comb filters */
|
||||
fluid_comb combL[numcombs];
|
||||
fluid_comb combR[numcombs];
|
||||
/* Allpass filters */
|
||||
fluid_allpass allpassL[numallpasses];
|
||||
fluid_allpass allpassR[numallpasses];
|
||||
/* Buffers for the combs */
|
||||
fluid_real_t bufcombL1[combtuningL1];
|
||||
fluid_real_t bufcombR1[combtuningR1];
|
||||
fluid_real_t bufcombL2[combtuningL2];
|
||||
fluid_real_t bufcombR2[combtuningR2];
|
||||
fluid_real_t bufcombL3[combtuningL3];
|
||||
fluid_real_t bufcombR3[combtuningR3];
|
||||
fluid_real_t bufcombL4[combtuningL4];
|
||||
fluid_real_t bufcombR4[combtuningR4];
|
||||
fluid_real_t bufcombL5[combtuningL5];
|
||||
fluid_real_t bufcombR5[combtuningR5];
|
||||
fluid_real_t bufcombL6[combtuningL6];
|
||||
fluid_real_t bufcombR6[combtuningR6];
|
||||
fluid_real_t bufcombL7[combtuningL7];
|
||||
fluid_real_t bufcombR7[combtuningR7];
|
||||
fluid_real_t bufcombL8[combtuningL8];
|
||||
fluid_real_t bufcombR8[combtuningR8];
|
||||
/* Buffers for the allpasses */
|
||||
fluid_real_t bufallpassL1[allpasstuningL1];
|
||||
fluid_real_t bufallpassR1[allpasstuningR1];
|
||||
fluid_real_t bufallpassL2[allpasstuningL2];
|
||||
fluid_real_t bufallpassR2[allpasstuningR2];
|
||||
fluid_real_t bufallpassL3[allpasstuningL3];
|
||||
fluid_real_t bufallpassR3[allpasstuningR3];
|
||||
fluid_real_t bufallpassL4[allpasstuningL4];
|
||||
fluid_real_t bufallpassR4[allpasstuningR4];
|
||||
};
|
||||
|
||||
void fluid_revmodel_update(fluid_revmodel_t* rev);
|
||||
void fluid_revmodel_init(fluid_revmodel_t* rev);
|
||||
|
||||
fluid_revmodel_t*
|
||||
new_fluid_revmodel()
|
||||
{
|
||||
fluid_revmodel_t* rev;
|
||||
rev = FLUID_NEW(fluid_revmodel_t);
|
||||
if (rev == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Tie the components to their buffers */
|
||||
fluid_comb_setbuffer(&rev->combL[0], rev->bufcombL1, combtuningL1);
|
||||
fluid_comb_setbuffer(&rev->combR[0], rev->bufcombR1, combtuningR1);
|
||||
fluid_comb_setbuffer(&rev->combL[1], rev->bufcombL2, combtuningL2);
|
||||
fluid_comb_setbuffer(&rev->combR[1], rev->bufcombR2, combtuningR2);
|
||||
fluid_comb_setbuffer(&rev->combL[2], rev->bufcombL3, combtuningL3);
|
||||
fluid_comb_setbuffer(&rev->combR[2], rev->bufcombR3, combtuningR3);
|
||||
fluid_comb_setbuffer(&rev->combL[3], rev->bufcombL4, combtuningL4);
|
||||
fluid_comb_setbuffer(&rev->combR[3], rev->bufcombR4, combtuningR4);
|
||||
fluid_comb_setbuffer(&rev->combL[4], rev->bufcombL5, combtuningL5);
|
||||
fluid_comb_setbuffer(&rev->combR[4], rev->bufcombR5, combtuningR5);
|
||||
fluid_comb_setbuffer(&rev->combL[5], rev->bufcombL6, combtuningL6);
|
||||
fluid_comb_setbuffer(&rev->combR[5], rev->bufcombR6, combtuningR6);
|
||||
fluid_comb_setbuffer(&rev->combL[6], rev->bufcombL7, combtuningL7);
|
||||
fluid_comb_setbuffer(&rev->combR[6], rev->bufcombR7, combtuningR7);
|
||||
fluid_comb_setbuffer(&rev->combL[7], rev->bufcombL8, combtuningL8);
|
||||
fluid_comb_setbuffer(&rev->combR[7], rev->bufcombR8, combtuningR8);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[0], rev->bufallpassL1, allpasstuningL1);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[0], rev->bufallpassR1, allpasstuningR1);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[1], rev->bufallpassL2, allpasstuningL2);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[1], rev->bufallpassR2, allpasstuningR2);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[2], rev->bufallpassL3, allpasstuningL3);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[2], rev->bufallpassR3, allpasstuningR3);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[3], rev->bufallpassL4, allpasstuningL4);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[3], rev->bufallpassR4, allpasstuningR4);
|
||||
/* Set default values */
|
||||
fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
|
||||
|
||||
/* set values manually, since calling set functions causes update
|
||||
and all values should be initialized for an update */
|
||||
rev->roomsize = initialroom * scaleroom + offsetroom;
|
||||
rev->damp = initialdamp * scaledamp;
|
||||
rev->wet = initialwet * scalewet;
|
||||
rev->width = initialwidth;
|
||||
rev->gain = fixedgain;
|
||||
|
||||
/* now its okay to update reverb */
|
||||
fluid_revmodel_update(rev);
|
||||
|
||||
/* Clear all buffers */
|
||||
fluid_revmodel_init(rev);
|
||||
return rev;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_revmodel(fluid_revmodel_t* rev)
|
||||
{
|
||||
FLUID_FREE(rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_init(fluid_revmodel_t* rev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < numcombs;i++) {
|
||||
fluid_comb_init(&rev->combL[i]);
|
||||
fluid_comb_init(&rev->combR[i]);
|
||||
}
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_init(&rev->allpassL[i]);
|
||||
fluid_allpass_init(&rev->allpassR[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_reset(fluid_revmodel_t* rev)
|
||||
{
|
||||
fluid_revmodel_init(rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int i, k = 0;
|
||||
fluid_real_t outL, outR, input;
|
||||
|
||||
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
||||
|
||||
outL = outR = 0;
|
||||
|
||||
/* The original Freeverb code expects a stereo signal and 'input'
|
||||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2 * in[k] + DC_OFFSET) * rev->gain;
|
||||
|
||||
/* Accumulate comb filters in parallel */
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_process(rev->combL[i], input, outL);
|
||||
fluid_comb_process(rev->combR[i], input, outR);
|
||||
}
|
||||
/* Feed through allpasses in series */
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_process(rev->allpassL[i], outL);
|
||||
fluid_allpass_process(rev->allpassR[i], outR);
|
||||
}
|
||||
|
||||
/* Remove the DC offset */
|
||||
outL -= DC_OFFSET;
|
||||
outR -= DC_OFFSET;
|
||||
|
||||
/* Calculate output REPLACING anything already there */
|
||||
left_out[k] = outL * rev->wet1 + outR * rev->wet2;
|
||||
right_out[k] = outR * rev->wet1 + outL * rev->wet2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int i, k = 0;
|
||||
fluid_real_t outL, outR, input;
|
||||
|
||||
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
||||
|
||||
outL = outR = 0;
|
||||
|
||||
/* The original Freeverb code expects a stereo signal and 'input'
|
||||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2 * in[k] + DC_OFFSET) * rev->gain;
|
||||
|
||||
/* Accumulate comb filters in parallel */
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_process(rev->combL[i], input, outL);
|
||||
fluid_comb_process(rev->combR[i], input, outR);
|
||||
}
|
||||
/* Feed through allpasses in series */
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_process(rev->allpassL[i], outL);
|
||||
fluid_allpass_process(rev->allpassR[i], outR);
|
||||
}
|
||||
|
||||
/* Remove the DC offset */
|
||||
outL -= DC_OFFSET;
|
||||
outR -= DC_OFFSET;
|
||||
|
||||
/* Calculate output MIXING with anything already there */
|
||||
left_out[k] += outL * rev->wet1 + outR * rev->wet2;
|
||||
right_out[k] += outR * rev->wet1 + outL * rev->wet2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_update(fluid_revmodel_t* rev)
|
||||
{
|
||||
/* Recalculate internal values after parameter change */
|
||||
int i;
|
||||
|
||||
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
|
||||
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
|
||||
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
|
||||
}
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_setdamp(&rev->combL[i], rev->damp);
|
||||
fluid_comb_setdamp(&rev->combR[i], rev->damp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The following get/set functions are not inlined, because
|
||||
speed is never an issue when calling them, and also
|
||||
because as you develop the reverb model, you may
|
||||
wish to take dynamic action when they are called.
|
||||
*/
|
||||
void
|
||||
fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||
rev->roomsize = (value * scaleroom) + offsetroom;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getroomsize(fluid_revmodel_t* rev)
|
||||
{
|
||||
return (rev->roomsize - offsetroom) / scaleroom;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||
rev->damp = value * scaledamp;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getdamp(fluid_revmodel_t* rev)
|
||||
{
|
||||
return rev->damp / scaledamp;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
fluid_clip(value, 0.0f, 1.0f);
|
||||
rev->wet = value * scalewet;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getlevel(fluid_revmodel_t* rev)
|
||||
{
|
||||
return rev->wet / scalewet;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||
rev->width = value;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getwidth(fluid_revmodel_t* rev)
|
||||
{
|
||||
return rev->width;
|
||||
}
|
67
framework/audio/midi/3rdparty/fluidlite/src/fluid_rev.h
vendored
Normal file
67
framework/audio/midi/3rdparty/fluidlite/src/fluid_rev.h
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_REV_H
|
||||
#define _FLUID_REV_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
typedef struct _fluid_revmodel_t fluid_revmodel_t;
|
||||
|
||||
|
||||
/*
|
||||
* reverb
|
||||
*/
|
||||
fluid_revmodel_t* new_fluid_revmodel(void);
|
||||
void delete_fluid_revmodel(fluid_revmodel_t* rev);
|
||||
|
||||
void fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
void fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
void fluid_revmodel_reset(fluid_revmodel_t* rev);
|
||||
|
||||
void fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setmode(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
|
||||
fluid_real_t fluid_revmodel_getroomsize(fluid_revmodel_t* rev);
|
||||
fluid_real_t fluid_revmodel_getdamp(fluid_revmodel_t* rev);
|
||||
fluid_real_t fluid_revmodel_getlevel(fluid_revmodel_t* rev);
|
||||
fluid_real_t fluid_revmodel_getwidth(fluid_revmodel_t* rev);
|
||||
|
||||
/*
|
||||
* reverb preset
|
||||
*/
|
||||
typedef struct _fluid_revmodel_presets_t {
|
||||
char* name;
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t width;
|
||||
fluid_real_t level;
|
||||
} fluid_revmodel_presets_t;
|
||||
|
||||
|
||||
#endif /* _FLUID_REV_H */
|
827
framework/audio/midi/3rdparty/fluidlite/src/fluid_settings.c
vendored
Normal file
827
framework/audio/midi/3rdparty/fluidlite/src/fluid_settings.c
vendored
Normal file
|
@ -0,0 +1,827 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_hash.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_settings.h"
|
||||
|
||||
/* maximum allowed components of a settings variable (separated by '.') */
|
||||
#define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */
|
||||
#define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */
|
||||
|
||||
static void fluid_settings_init(fluid_settings_t* settings);
|
||||
static void fluid_settings_hash_delete(void* value, int type);
|
||||
static int fluid_settings_tokenize(const char* s, char *buf, char** ptr);
|
||||
|
||||
|
||||
typedef struct {
|
||||
char* value;
|
||||
char* def;
|
||||
int hints;
|
||||
fluid_list_t* options;
|
||||
fluid_str_update_t update;
|
||||
void* data;
|
||||
} fluid_str_setting_t;
|
||||
|
||||
static fluid_str_setting_t*
|
||||
new_fluid_str_setting(const char* value, char* def, int hints, fluid_str_update_t fun, void* data)
|
||||
{
|
||||
fluid_str_setting_t* str;
|
||||
str = FLUID_NEW(fluid_str_setting_t);
|
||||
str->value = value? FLUID_STRDUP(value) : NULL;
|
||||
str->def = def? FLUID_STRDUP(def) : NULL;
|
||||
str->hints = hints;
|
||||
str->options = NULL;
|
||||
str->update = fun;
|
||||
str->data = data;
|
||||
return str;
|
||||
}
|
||||
|
||||
static void delete_fluid_str_setting(fluid_str_setting_t* str)
|
||||
{
|
||||
if (str) {
|
||||
if (str->value) {
|
||||
FLUID_FREE(str->value);
|
||||
}
|
||||
if (str->def) {
|
||||
FLUID_FREE(str->def);
|
||||
}
|
||||
if (str->options) {
|
||||
fluid_list_t* list = str->options;
|
||||
|
||||
while (list) {
|
||||
FLUID_FREE (list->data);
|
||||
list = fluid_list_next(list);
|
||||
}
|
||||
|
||||
delete_fluid_list(str->options);
|
||||
}
|
||||
FLUID_FREE(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
double value;
|
||||
double def;
|
||||
double min;
|
||||
double max;
|
||||
int hints;
|
||||
fluid_num_update_t update;
|
||||
void* data;
|
||||
} fluid_num_setting_t;
|
||||
|
||||
|
||||
static fluid_num_setting_t*
|
||||
new_fluid_num_setting(double min, double max, double def,
|
||||
int hints, fluid_num_update_t fun, void* data)
|
||||
{
|
||||
fluid_num_setting_t* setting;
|
||||
setting = FLUID_NEW(fluid_num_setting_t);
|
||||
setting->value = def;
|
||||
setting->def = def;
|
||||
setting->min = min;
|
||||
setting->max = max;
|
||||
setting->hints = hints;
|
||||
setting->update = fun;
|
||||
setting->data = data;
|
||||
return setting;
|
||||
}
|
||||
|
||||
static void delete_fluid_num_setting(fluid_num_setting_t* setting)
|
||||
{
|
||||
if (setting) {
|
||||
FLUID_FREE(setting);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
int value;
|
||||
int def;
|
||||
int min;
|
||||
int max;
|
||||
int hints;
|
||||
fluid_int_update_t update;
|
||||
void* data;
|
||||
} fluid_int_setting_t;
|
||||
|
||||
|
||||
static fluid_int_setting_t*
|
||||
new_fluid_int_setting(int min, int max, int def,
|
||||
int hints, fluid_int_update_t fun, void* data)
|
||||
{
|
||||
fluid_int_setting_t* setting;
|
||||
setting = FLUID_NEW(fluid_int_setting_t);
|
||||
setting->value = def;
|
||||
setting->def = def;
|
||||
setting->min = min;
|
||||
setting->max = max;
|
||||
setting->hints = hints;
|
||||
setting->update = fun;
|
||||
setting->data = data;
|
||||
return setting;
|
||||
}
|
||||
|
||||
static void delete_fluid_int_setting(fluid_int_setting_t* setting)
|
||||
{
|
||||
if (setting) {
|
||||
FLUID_FREE(setting);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fluid_settings_t* new_fluid_settings()
|
||||
{
|
||||
fluid_settings_t* settings = new_fluid_hashtable(fluid_settings_hash_delete);
|
||||
if (settings == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
fluid_settings_init(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
void delete_fluid_settings(fluid_settings_t* settings)
|
||||
{
|
||||
delete_fluid_hashtable(settings);
|
||||
}
|
||||
|
||||
void fluid_settings_hash_delete(void* value, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case FLUID_NUM_TYPE:
|
||||
delete_fluid_num_setting((fluid_num_setting_t*) value);
|
||||
break;
|
||||
case FLUID_INT_TYPE:
|
||||
delete_fluid_int_setting((fluid_int_setting_t*) value);
|
||||
break;
|
||||
case FLUID_STR_TYPE:
|
||||
delete_fluid_str_setting((fluid_str_setting_t*) value);
|
||||
break;
|
||||
case FLUID_SET_TYPE:
|
||||
delete_fluid_hashtable((fluid_hashtable_t*) value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_settings_init(fluid_settings_t* settings)
|
||||
{
|
||||
fluid_synth_settings(settings);
|
||||
}
|
||||
|
||||
static int fluid_settings_tokenize(const char* s, char *buf, char** ptr)
|
||||
{
|
||||
char *tokstr, *tok;
|
||||
int n = 0;
|
||||
|
||||
if (strlen (s) > MAX_SETTINGS_LABEL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
|
||||
MAX_SETTINGS_LABEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
|
||||
tokstr = buf;
|
||||
|
||||
while ((tok = fluid_strtok (&tokstr, ".")))
|
||||
{
|
||||
if (n > MAX_SETTINGS_TOKENS)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
|
||||
MAX_SETTINGS_TOKENS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr[n++] = tok;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
static int fluid_settings_get(fluid_settings_t* settings,
|
||||
char** name, int len,
|
||||
void** value, int* type)
|
||||
{
|
||||
fluid_hashtable_t* table = settings;
|
||||
int t;
|
||||
void* v;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
|
||||
if (table == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fluid_hashtable_lookup(table, name[n], &v, &t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
table = (t == FLUID_SET_TYPE)? (fluid_hashtable_t*) v : NULL;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
*value = v;
|
||||
}
|
||||
|
||||
if (type) {
|
||||
*type = t;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** returns 1 if the value has been set, zero otherwise */
|
||||
static int fluid_settings_set(fluid_settings_t* settings,
|
||||
char** name, int len,
|
||||
void* value, int type)
|
||||
{
|
||||
fluid_hashtable_t* table = settings;
|
||||
int t;
|
||||
void* v;
|
||||
int n, num = len - 1;
|
||||
|
||||
for (n = 0; n < num; n++) {
|
||||
|
||||
if (fluid_hashtable_lookup(table, name[n], &v, &t)) {
|
||||
|
||||
if (t == FLUID_SET_TYPE) {
|
||||
table = (fluid_hashtable_t*) v;
|
||||
} else {
|
||||
/* path ends prematurely */
|
||||
FLUID_LOG(FLUID_WARN, "'%s' is not a node", name[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* create a new node */
|
||||
fluid_hashtable_t* tmp;
|
||||
tmp = new_fluid_hashtable(fluid_settings_hash_delete);
|
||||
fluid_hashtable_insert(table, name[n], tmp, FLUID_SET_TYPE);
|
||||
table = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
fluid_hashtable_replace(table, name[num], value, type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** returns 1 if the value has been registered correctly, 0
|
||||
otherwise */
|
||||
int fluid_settings_register_str(fluid_settings_t* settings, const char* name, char* def, int hints,
|
||||
fluid_str_update_t fun, void* data)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
fluid_str_setting_t* setting;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (!fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
setting = new_fluid_str_setting(def, def, hints, fun, data);
|
||||
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_STR_TYPE);
|
||||
|
||||
} else {
|
||||
/* if variable already exists, don't change its value. */
|
||||
if (type == FLUID_STR_TYPE) {
|
||||
setting = (fluid_str_setting_t*) value;
|
||||
setting->update = fun;
|
||||
setting->data = data;
|
||||
setting->def = def? FLUID_STRDUP(def) : NULL;
|
||||
setting->hints = hints;
|
||||
return 1;
|
||||
} else {
|
||||
FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** returns 1 if the value has been register correctly, zero
|
||||
otherwise */
|
||||
int fluid_settings_register_num(fluid_settings_t* settings, const char* name, double def,
|
||||
double min, double max, int hints,
|
||||
fluid_num_update_t fun, void* data)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (!fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
/* insert a new setting */
|
||||
fluid_num_setting_t* setting;
|
||||
setting = new_fluid_num_setting(min, max, def, hints, fun, data);
|
||||
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_NUM_TYPE);
|
||||
|
||||
} else {
|
||||
if (type == FLUID_NUM_TYPE) {
|
||||
/* update the existing setting but don't change its value */
|
||||
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
|
||||
setting->update = fun;
|
||||
setting->data = data;
|
||||
setting->min = min;
|
||||
setting->max = max;
|
||||
setting->def = def;
|
||||
setting->hints = hints;
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* type mismatch */
|
||||
FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** returns 1 if the value has been register correctly, zero
|
||||
otherwise */
|
||||
int fluid_settings_register_int(fluid_settings_t* settings, const char* name, int def,
|
||||
int min, int max, int hints,
|
||||
fluid_int_update_t fun, void* data)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (!fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
/* insert a new setting */
|
||||
fluid_int_setting_t* setting;
|
||||
setting = new_fluid_int_setting(min, max, def, hints, fun, data);
|
||||
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_INT_TYPE);
|
||||
|
||||
} else {
|
||||
if (type == FLUID_INT_TYPE) {
|
||||
/* update the existing setting but don't change its value */
|
||||
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
|
||||
setting->update = fun;
|
||||
setting->data = data;
|
||||
setting->min = min;
|
||||
setting->max = max;
|
||||
setting->def = def;
|
||||
setting->hints = hints;
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* type mismatch */
|
||||
FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_get_type(fluid_settings_t* settings, const char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
return (fluid_settings_get(settings, tokens, ntokens, &value, &type))? type : FLUID_NO_TYPE;
|
||||
}
|
||||
|
||||
int fluid_settings_get_hints(fluid_settings_t* settings, const char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
if (type == FLUID_NUM_TYPE) {
|
||||
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
|
||||
return setting->hints;
|
||||
} else if (type == FLUID_STR_TYPE) {
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
return setting->hints;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_is_realtime(fluid_settings_t* settings, const char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
if (type == FLUID_NUM_TYPE) {
|
||||
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
|
||||
return setting->update != NULL;
|
||||
|
||||
} else if (type == FLUID_STR_TYPE) {
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
return setting->update != NULL;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_setstr(fluid_settings_t* settings, const char* name, const char* str)
|
||||
{
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
int type;
|
||||
void* value;
|
||||
fluid_str_setting_t* setting;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
|
||||
if (type != FLUID_STR_TYPE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setting = (fluid_str_setting_t*) value;
|
||||
|
||||
if (setting->value) {
|
||||
FLUID_FREE(setting->value);
|
||||
}
|
||||
setting->value = str? FLUID_STRDUP(str) : NULL;
|
||||
|
||||
if (setting->update) {
|
||||
(*setting->update)(setting->data, name, setting->value);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* insert a new setting */
|
||||
fluid_str_setting_t* setting;
|
||||
setting = new_fluid_str_setting(str, NULL, 0, NULL, NULL);
|
||||
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_STR_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_getstr(fluid_settings_t* settings, const char* name, char** str)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_STR_TYPE)) {
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
*str = setting->value;
|
||||
return 1;
|
||||
}
|
||||
*str = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fluid_settings_str_equal(fluid_settings_t* settings, const char* name, char* s)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_STR_TYPE)) {
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
return FLUID_STRCMP(setting->value, s) == 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char*
|
||||
fluid_settings_getstr_default(fluid_settings_t* settings, const char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_STR_TYPE)) {
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
return setting->def;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_add_option(fluid_settings_t* settings, const char* name, char* s)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_STR_TYPE)) {
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
char* copy = FLUID_STRDUP(s);
|
||||
setting->options = fluid_list_append(setting->options, copy);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_remove_option(fluid_settings_t* settings, const char* name, char* s)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_STR_TYPE)) {
|
||||
|
||||
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
|
||||
fluid_list_t* list = setting->options;
|
||||
|
||||
while (list) {
|
||||
char* option = (char*) fluid_list_get(list);
|
||||
if (FLUID_STRCMP(s, option) == 0) {
|
||||
FLUID_FREE (option);
|
||||
setting->options = fluid_list_remove_link(setting->options, list);
|
||||
return 1;
|
||||
}
|
||||
list = fluid_list_next(list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_setnum(fluid_settings_t* settings, const char* name, double val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
fluid_num_setting_t* setting;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
|
||||
if (type != FLUID_NUM_TYPE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setting = (fluid_num_setting_t*) value;
|
||||
|
||||
if (val < setting->min) {
|
||||
val = setting->min;
|
||||
} else if (val > setting->max) {
|
||||
val = setting->max;
|
||||
}
|
||||
|
||||
setting->value = val;
|
||||
|
||||
if (setting->update) {
|
||||
(*setting->update)(setting->data, name, val);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* insert a new setting */
|
||||
fluid_num_setting_t* setting;
|
||||
setting = new_fluid_num_setting(-1e10, 1e10, 0.0f, 0, NULL, NULL);
|
||||
setting->value = val;
|
||||
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_NUM_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_getnum(fluid_settings_t* settings, const char* name, double* val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_NUM_TYPE)) {
|
||||
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
|
||||
*val = setting->value;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void fluid_settings_getnum_range(fluid_settings_t* settings, const char* name, double* min, double* max)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_NUM_TYPE)) {
|
||||
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
|
||||
*min = setting->min;
|
||||
*max = setting->max;
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
fluid_settings_getnum_default(fluid_settings_t* settings, const char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_NUM_TYPE)) {
|
||||
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
|
||||
return setting->def;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fluid_settings_setint(fluid_settings_t* settings, const char* name, int val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
fluid_int_setting_t* setting;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
|
||||
|
||||
if (type != FLUID_INT_TYPE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setting = (fluid_int_setting_t*) value;
|
||||
|
||||
if (val < setting->min) {
|
||||
val = setting->min;
|
||||
} else if (val > setting->max) {
|
||||
val = setting->max;
|
||||
}
|
||||
|
||||
setting->value = val;
|
||||
|
||||
if (setting->update) {
|
||||
(*setting->update)(setting->data, name, val);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* insert a new setting */
|
||||
fluid_int_setting_t* setting;
|
||||
setting = new_fluid_int_setting(INT_MIN, INT_MAX, 0, 0, NULL, NULL);
|
||||
setting->value = val;
|
||||
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_INT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
int fluid_settings_getint(fluid_settings_t* settings, const char* name, int* val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_INT_TYPE)) {
|
||||
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
|
||||
*val = setting->value;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void fluid_settings_getint_range(fluid_settings_t* settings, const char* name, int* min, int* max)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_INT_TYPE)) {
|
||||
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
|
||||
*min = setting->min;
|
||||
*max = setting->max;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fluid_settings_getint_default(fluid_settings_t* settings, const char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
|
||||
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
|
||||
&& (type == FLUID_INT_TYPE)) {
|
||||
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
|
||||
return setting->def;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
55
framework/audio/midi/3rdparty/fluidlite/src/fluid_settings.h
vendored
Normal file
55
framework/audio/midi/3rdparty/fluidlite/src/fluid_settings.h
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_SETTINGS_H
|
||||
#define _FLUID_SETTINGS_H
|
||||
|
||||
|
||||
|
||||
/** returns 1 if the option was added, 0 otherwise */
|
||||
int fluid_settings_add_option(fluid_settings_t* settings, const char* name, char* s);
|
||||
|
||||
/** returns 1 if the option was added, 0 otherwise */
|
||||
int fluid_settings_remove_option(fluid_settings_t* settings, const char* name, char* s);
|
||||
|
||||
|
||||
typedef int (*fluid_num_update_t)(void* data, const char* name, double value);
|
||||
typedef int (*fluid_str_update_t)(void* data, const char* name, char* value);
|
||||
typedef int (*fluid_int_update_t)(void* data, const char* name, int value);
|
||||
|
||||
/** returns 0 if the value has been resgister correctly, non-zero
|
||||
otherwise */
|
||||
int fluid_settings_register_str(fluid_settings_t* settings, const char* name, char* def, int hints,
|
||||
fluid_str_update_t fun, void* data);
|
||||
|
||||
/** returns 0 if the value has been resgister correctly, non-zero
|
||||
otherwise */
|
||||
int fluid_settings_register_num(fluid_settings_t* settings, const char* name, double min, double max,
|
||||
double def, int hints, fluid_num_update_t fun, void* data);
|
||||
|
||||
|
||||
/** returns 0 if the value has been resgister correctly, non-zero
|
||||
otherwise */
|
||||
int fluid_settings_register_int(fluid_settings_t* settings, const char* name, int min, int max,
|
||||
int def, int hints, fluid_int_update_t fun, void* data);
|
||||
|
||||
|
||||
#endif /* _FLUID_SETTINGS_H */
|
68
framework/audio/midi/3rdparty/fluidlite/src/fluid_sfont.h
vendored
Normal file
68
framework/audio/midi/3rdparty/fluidlite/src/fluid_sfont.h
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _PRIV_FLUID_SFONT_H
|
||||
#define _PRIV_FLUID_SFONT_H
|
||||
|
||||
|
||||
/*
|
||||
* Utility macros to access soundfonts, presets, and samples
|
||||
*/
|
||||
|
||||
#define fluid_sfloader_delete(_loader) { if ((_loader) && (_loader)->free) (*(_loader)->free)(_loader); }
|
||||
#define fluid_sfloader_load(_loader, _filename) (*(_loader)->load)(_loader, _filename)
|
||||
|
||||
|
||||
#define delete_fluid_sfont(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
|
||||
#define fluid_sfont_get_name(_sf) (*(_sf)->get_name)(_sf)
|
||||
#define fluid_sfont_get_preset(_sf,_bank,_prenum) (*(_sf)->get_preset)(_sf,_bank,_prenum)
|
||||
#define fluid_sfont_iteration_start(_sf) (*(_sf)->iteration_start)(_sf)
|
||||
#define fluid_sfont_iteration_next(_sf,_pr) (*(_sf)->iteration_next)(_sf,_pr)
|
||||
#define fluid_sfont_get_data(_sf) (_sf)->data
|
||||
#define fluid_sfont_set_data(_sf,_p) { (_sf)->data = (void*) (_p); }
|
||||
|
||||
|
||||
#define delete_fluid_preset(_preset) \
|
||||
{ if ((_preset) && (_preset)->free) { (*(_preset)->free)(_preset); }}
|
||||
|
||||
#define fluid_preset_get_data(_preset) (_preset)->data
|
||||
#define fluid_preset_set_data(_preset,_p) { (_preset)->data = (void*) (_p); }
|
||||
#define fluid_preset_get_name(_preset) (*(_preset)->get_name)(_preset)
|
||||
#define fluid_preset_get_banknum(_preset) (*(_preset)->get_banknum)(_preset)
|
||||
#define fluid_preset_get_num(_preset) (*(_preset)->get_num)(_preset)
|
||||
|
||||
#define fluid_preset_noteon(_preset,_synth,_ch,_key,_vel) \
|
||||
(*(_preset)->noteon)(_preset,_synth,_ch,_key,_vel)
|
||||
|
||||
#define fluid_preset_notify(_preset,_reason,_chan) \
|
||||
{ if ((_preset) && (_preset)->notify) { (*(_preset)->notify)(_preset,_reason,_chan); }}
|
||||
|
||||
|
||||
#define fluid_sample_incr_ref(_sample) { (_sample)->refcount++; }
|
||||
|
||||
#define fluid_sample_decr_ref(_sample) \
|
||||
(_sample)->refcount--; \
|
||||
if (((_sample)->refcount == 0) && ((_sample)->notify)) \
|
||||
(*(_sample)->notify)(_sample, FLUID_SAMPLE_DONE);
|
||||
|
||||
|
||||
|
||||
#endif /* _PRIV_FLUID_SFONT_H */
|
3557
framework/audio/midi/3rdparty/fluidlite/src/fluid_synth.c
vendored
Normal file
3557
framework/audio/midi/3rdparty/fluidlite/src/fluid_synth.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
204
framework/audio/midi/3rdparty/fluidlite/src/fluid_synth.h
vendored
Normal file
204
framework/audio/midi/3rdparty/fluidlite/src/fluid_synth.h
vendored
Normal file
|
@ -0,0 +1,204 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_SYNTH_H
|
||||
#define _FLUID_SYNTH_H
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* INCLUDES
|
||||
*/
|
||||
|
||||
#include "fluid_config.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_rev.h"
|
||||
#include "fluid_voice.h"
|
||||
#include "fluid_chorus.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* DEFINES
|
||||
*/
|
||||
#define FLUID_NUM_PROGRAMS 128
|
||||
#define DRUM_INST_BANK 128
|
||||
|
||||
#if defined(WITH_FLOAT)
|
||||
#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_FLOAT
|
||||
#else
|
||||
#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_DOUBLE
|
||||
#endif
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* ENUM
|
||||
*/
|
||||
enum fluid_loop {
|
||||
FLUID_UNLOOPED = 0,
|
||||
FLUID_LOOP_DURING_RELEASE = 1,
|
||||
FLUID_NOTUSED = 2,
|
||||
FLUID_LOOP_UNTIL_RELEASE = 3
|
||||
};
|
||||
|
||||
enum fluid_synth_status
|
||||
{
|
||||
FLUID_SYNTH_CLEAN,
|
||||
FLUID_SYNTH_PLAYING,
|
||||
FLUID_SYNTH_QUIET,
|
||||
FLUID_SYNTH_STOPPED
|
||||
};
|
||||
|
||||
|
||||
typedef struct _fluid_bank_offset_t fluid_bank_offset_t;
|
||||
|
||||
struct _fluid_bank_offset_t {
|
||||
int sfont_id;
|
||||
int offset;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fluid_synth_t
|
||||
*/
|
||||
|
||||
struct _fluid_synth_t
|
||||
{
|
||||
/* fluid_settings_old_t settings_old; the old synthesizer settings */
|
||||
fluid_settings_t* settings; /** the synthesizer settings */
|
||||
int polyphony; /** maximum polyphony */
|
||||
char with_reverb; /** Should the synth use the built-in reverb unit? */
|
||||
char with_chorus; /** Should the synth use the built-in chorus unit? */
|
||||
char verbose; /** Turn verbose mode on? */
|
||||
char dump; /** Dump events to stdout to hook up a user interface? */
|
||||
double sample_rate; /** The sample rate */
|
||||
int midi_channels; /** the number of MIDI channels (>= 16) */
|
||||
int audio_channels; /** the number of audio channels (1 channel=left+right) */
|
||||
int audio_groups; /** the number of (stereo) 'sub'groups from the synth.
|
||||
Typically equal to audio_channels. */
|
||||
int effects_channels; /** the number of effects channels (= 2) */
|
||||
unsigned int state; /** the synthesizer state */
|
||||
unsigned int ticks; /** the number of audio samples since the start */
|
||||
|
||||
fluid_list_t *loaders; /** the soundfont loaders */
|
||||
fluid_list_t* sfont; /** the loaded soundfont */
|
||||
unsigned int sfont_id;
|
||||
fluid_list_t* bank_offsets; /** the offsets of the soundfont banks */
|
||||
|
||||
#if defined(MACOS9)
|
||||
fluid_list_t* unloading; /** the soundfonts that need to be unloaded */
|
||||
#endif
|
||||
|
||||
double gain; /** master gain */
|
||||
fluid_channel_t** channel; /** the channels */
|
||||
int num_channels; /** the number of channels */
|
||||
int nvoice; /** the length of the synthesis process array */
|
||||
fluid_voice_t** voice; /** the synthesis processes */
|
||||
unsigned int noteid; /** the id is incremented for every new note. it's used for noteoff's */
|
||||
unsigned int storeid;
|
||||
int nbuf; /** How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
||||
|
||||
fluid_real_t** left_buf;
|
||||
fluid_real_t** right_buf;
|
||||
fluid_real_t** fx_left_buf;
|
||||
fluid_real_t** fx_right_buf;
|
||||
|
||||
fluid_revmodel_t* reverb;
|
||||
fluid_chorus_t* chorus;
|
||||
int cur; /** the current sample in the audio buffers to be output */
|
||||
int dither_index; /* current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
|
||||
|
||||
char outbuf[256]; /** buffer for message output */
|
||||
|
||||
fluid_tuning_t*** tuning; /** 128 banks of 128 programs for the tunings */
|
||||
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
||||
|
||||
unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */
|
||||
};
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
int fluid_synth_setstr(fluid_synth_t* synth, char* name, char* str);
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
int fluid_synth_getstr(fluid_synth_t* synth, char* name, char** str);
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
int fluid_synth_setnum(fluid_synth_t* synth, char* name, double val);
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
int fluid_synth_getnum(fluid_synth_t* synth, char* name, double* val);
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
int fluid_synth_setint(fluid_synth_t* synth, char* name, int val);
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
int fluid_synth_getint(fluid_synth_t* synth, char* name, int* val);
|
||||
|
||||
|
||||
int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num);
|
||||
|
||||
int fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out);
|
||||
|
||||
fluid_preset_t* fluid_synth_get_preset(fluid_synth_t* synth,
|
||||
unsigned int sfontnum,
|
||||
unsigned int banknum,
|
||||
unsigned int prognum);
|
||||
|
||||
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
|
||||
unsigned int banknum,
|
||||
unsigned int prognum);
|
||||
|
||||
//int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
|
||||
//int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_modulate_voices(fluid_synth_t* synth, int chan, int is_cc, int ctrl);
|
||||
int fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_damp_voices(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_kill_voice(fluid_synth_t* synth, fluid_voice_t * voice);
|
||||
void fluid_synth_kill_by_exclusive_class(fluid_synth_t* synth, fluid_voice_t* voice);
|
||||
void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int key);
|
||||
void fluid_synth_sfunload_macos9(fluid_synth_t* synth);
|
||||
|
||||
void fluid_synth_print_voice(fluid_synth_t* synth);
|
||||
|
||||
/** This function assures that every MIDI channels has a valid preset
|
||||
* (NULL is okay). This function is called after a SoundFont is
|
||||
* unloaded or reloaded. */
|
||||
void fluid_synth_update_presets(fluid_synth_t* synth);
|
||||
|
||||
|
||||
int fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value);
|
||||
int fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value);
|
||||
|
||||
fluid_bank_offset_t* fluid_synth_get_bank_offset0(fluid_synth_t* synth, int sfont_id);
|
||||
void fluid_synth_remove_bank_offset(fluid_synth_t* synth, int sfont_id);
|
||||
|
||||
void fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
|
||||
void fluid_synth_settings(fluid_settings_t* settings);
|
||||
|
||||
#endif /* _FLUID_SYNTH_H */
|
364
framework/audio/midi/3rdparty/fluidlite/src/fluid_sys.c
vendored
Normal file
364
framework/audio/midi/3rdparty/fluidlite/src/fluid_sys.c
vendored
Normal file
|
@ -0,0 +1,364 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#include "fluid_sys.h"
|
||||
|
||||
static char fluid_errbuf[512]; /* buffer for error message */
|
||||
|
||||
static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
|
||||
static void* fluid_log_user_data[LAST_LOG_LEVEL];
|
||||
static int fluid_log_initialized = 0;
|
||||
|
||||
static char* fluid_libname = "fluidsynth";
|
||||
|
||||
|
||||
void fluid_sys_config()
|
||||
{
|
||||
fluid_log_config();
|
||||
}
|
||||
|
||||
|
||||
unsigned int fluid_debug_flags = 0;
|
||||
|
||||
#if DEBUG
|
||||
/*
|
||||
* fluid_debug
|
||||
*/
|
||||
int fluid_debug(int level, char * fmt, ...)
|
||||
{
|
||||
if (fluid_debug_flags & level) {
|
||||
fluid_log_function_t fun;
|
||||
va_list args;
|
||||
|
||||
va_start (args, fmt);
|
||||
vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
|
||||
va_end (args);
|
||||
|
||||
fun = fluid_log_function[FLUID_DBG];
|
||||
if (fun != NULL) {
|
||||
(*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Installs a new log function for a specified log level.
|
||||
* @param level Log level to install handler for.
|
||||
* @param fun Callback function handler to call for logged messages
|
||||
* @param data User supplied data pointer to pass to log function
|
||||
* @return The previously installed function.
|
||||
*/
|
||||
fluid_log_function_t
|
||||
fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
|
||||
{
|
||||
fluid_log_function_t old = NULL;
|
||||
|
||||
if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
|
||||
old = fluid_log_function[level];
|
||||
fluid_log_function[level] = fun;
|
||||
fluid_log_user_data[level] = data;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default log function which prints to the stderr.
|
||||
* @param level Log level
|
||||
* @param message Log message
|
||||
* @param data User supplied data (not used)
|
||||
*/
|
||||
void
|
||||
fluid_default_log_function(int level, char* message, void* data)
|
||||
{
|
||||
FILE* out;
|
||||
|
||||
#if defined(WIN32)
|
||||
out = stdout;
|
||||
#else
|
||||
out = stderr;
|
||||
#endif
|
||||
|
||||
if (fluid_log_initialized == 0) {
|
||||
fluid_log_config();
|
||||
}
|
||||
|
||||
switch (level) {
|
||||
case FLUID_PANIC:
|
||||
FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
|
||||
break;
|
||||
case FLUID_ERR:
|
||||
FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
|
||||
break;
|
||||
case FLUID_WARN:
|
||||
FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
|
||||
break;
|
||||
case FLUID_INFO:
|
||||
FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
|
||||
break;
|
||||
case FLUID_DBG:
|
||||
#if DEBUG
|
||||
FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
|
||||
break;
|
||||
}
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_init_log
|
||||
*/
|
||||
void
|
||||
fluid_log_config(void)
|
||||
{
|
||||
if (fluid_log_initialized == 0) {
|
||||
|
||||
fluid_log_initialized = 1;
|
||||
|
||||
if (fluid_log_function[FLUID_PANIC] == NULL) {
|
||||
fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
|
||||
}
|
||||
|
||||
if (fluid_log_function[FLUID_ERR] == NULL) {
|
||||
fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
|
||||
}
|
||||
|
||||
if (fluid_log_function[FLUID_WARN] == NULL) {
|
||||
fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
|
||||
}
|
||||
|
||||
if (fluid_log_function[FLUID_INFO] == NULL) {
|
||||
fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
|
||||
}
|
||||
|
||||
if (fluid_log_function[FLUID_DBG] == NULL) {
|
||||
fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a message to the log.
|
||||
* @param level Log level (#fluid_log_level).
|
||||
* @param fmt Printf style format string for log message
|
||||
* @param ... Arguments for printf 'fmt' message string
|
||||
* @return Always returns -1
|
||||
*/
|
||||
int
|
||||
fluid_log(int level, char* fmt, ...)
|
||||
{
|
||||
fluid_log_function_t fun = NULL;
|
||||
|
||||
va_list args;
|
||||
va_start (args, fmt);
|
||||
vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
|
||||
va_end (args);
|
||||
|
||||
if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
|
||||
fun = fluid_log_function[level];
|
||||
if (fun != NULL) {
|
||||
(*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
|
||||
}
|
||||
}
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* An improved strtok, still trashes the input string, but is portable and
|
||||
* thread safe. Also skips token chars at beginning of token string and never
|
||||
* returns an empty token (will return NULL if source ends in token chars though).
|
||||
* NOTE: NOT part of public API
|
||||
* @internal
|
||||
* @param str Pointer to a string pointer of source to tokenize. Pointer gets
|
||||
* updated on each invocation to point to beginning of next token. Note that
|
||||
* token char get's overwritten with a 0 byte. String pointer is set to NULL
|
||||
* when final token is returned.
|
||||
* @param delim String of delimiter chars.
|
||||
* @return Pointer to the next token or NULL if no more tokens.
|
||||
*/
|
||||
char *fluid_strtok (char **str, char *delim)
|
||||
{
|
||||
char *s, *d, *token;
|
||||
char c;
|
||||
|
||||
if (str == NULL || delim == NULL || !*delim)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = *str;
|
||||
if (!s) return NULL; /* str points to a NULL pointer? (tokenize already ended) */
|
||||
|
||||
/* skip delimiter chars at beginning of token */
|
||||
do
|
||||
{
|
||||
c = *s;
|
||||
if (!c) /* end of source string? */
|
||||
{
|
||||
*str = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (d = delim; *d; d++) /* is source char a token char? */
|
||||
{
|
||||
if (c == *d) /* token char match? */
|
||||
{
|
||||
s++; /* advance to next source char */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (*d); /* while token char match */
|
||||
|
||||
token = s; /* start of token found */
|
||||
|
||||
/* search for next token char or end of source string */
|
||||
for (s = s+1; *s; s++)
|
||||
{
|
||||
c = *s;
|
||||
|
||||
for (d = delim; *d; d++) /* is source char a token char? */
|
||||
{
|
||||
if (c == *d) /* token char match? */
|
||||
{
|
||||
*s = '\0'; /* overwrite token char with zero byte to terminate token */
|
||||
*str = s+1; /* update str to point to beginning of next token */
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we get here only if source string ended */
|
||||
*str = NULL;
|
||||
return token;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_error
|
||||
*/
|
||||
char*
|
||||
fluid_error()
|
||||
{
|
||||
return fluid_errbuf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* fluid_is_midifile
|
||||
*/
|
||||
int
|
||||
fluid_is_midifile(char* filename)
|
||||
{
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
char id[4];
|
||||
|
||||
if (fp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (fread((void*) id, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return strncmp(id, "MThd", 4) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_is_soundfont
|
||||
*
|
||||
*/
|
||||
int
|
||||
fluid_is_soundfont(char* filename)
|
||||
{
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
char id[4];
|
||||
|
||||
if (fp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (fread((void*) id, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return strncmp(id, "RIFF", 4) == 0;
|
||||
}
|
||||
|
||||
/*=============================================================*/
|
||||
/* */
|
||||
/* Win32 */
|
||||
/* */
|
||||
/*=============================================================*/
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Timer
|
||||
*
|
||||
*/
|
||||
|
||||
//timer disabled
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Floating point exceptions
|
||||
*
|
||||
* The floating point exception functions were taken from Ircam's
|
||||
* jMax source code. http://www.ircam.fr/jmax
|
||||
*
|
||||
* FIXME: check in config for i386 machine
|
||||
*
|
||||
* Currently not used. I leave the code here in case we want to pick
|
||||
* this up again some time later.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Profiling (Linux, i586 only)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Threads
|
||||
*
|
||||
*/
|
||||
|
||||
//thread disabled
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Sockets
|
||||
*
|
||||
*/
|
||||
|
||||
//socket disabled
|
141
framework/audio/midi/3rdparty/fluidlite/src/fluid_sys.h
vendored
Normal file
141
framework/audio/midi/3rdparty/fluidlite/src/fluid_sys.h
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
|
||||
This header contains a bunch of (mostly) system and machine
|
||||
dependent functions:
|
||||
|
||||
- timers
|
||||
- current time in milliseconds and microseconds
|
||||
- debug logging
|
||||
- profiling
|
||||
- memory locking
|
||||
- checking for floating point exceptions
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_SYS_H
|
||||
#define _FLUID_SYS_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
void fluid_sys_config(void);
|
||||
void fluid_log_config(void);
|
||||
|
||||
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
char *fluid_strtok (char **str, char *delim);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Additional debugging system, separate from the log system. This
|
||||
allows to print selected debug messages of a specific subsystem.
|
||||
|
||||
*/
|
||||
|
||||
extern unsigned int fluid_debug_flags;
|
||||
|
||||
#if DEBUG
|
||||
|
||||
enum fluid_debug_level {
|
||||
FLUID_DBG_DRIVER = 1
|
||||
};
|
||||
|
||||
int fluid_debug(int level, char * fmt, ...);
|
||||
|
||||
#else
|
||||
#define fluid_debug
|
||||
#endif
|
||||
|
||||
//timer disabled
|
||||
|
||||
/**
|
||||
|
||||
Muteces
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Threads
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
Sockets
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Profiling
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
Profile numbers. List all the pieces of code you want to profile
|
||||
here. Be sure to add an entry in the fluid_profile_data table in
|
||||
fluid_sys.c
|
||||
*/
|
||||
enum {
|
||||
FLUID_PROF_WRITE_S16,
|
||||
FLUID_PROF_ONE_BLOCK,
|
||||
FLUID_PROF_ONE_BLOCK_CLEAR,
|
||||
FLUID_PROF_ONE_BLOCK_VOICE,
|
||||
FLUID_PROF_ONE_BLOCK_VOICES,
|
||||
FLUID_PROF_ONE_BLOCK_REVERB,
|
||||
FLUID_PROF_ONE_BLOCK_CHORUS,
|
||||
FLUID_PROF_VOICE_NOTE,
|
||||
FLUID_PROF_VOICE_RELEASE,
|
||||
FLUID_PROF_LAST
|
||||
};
|
||||
|
||||
|
||||
/* Profiling */
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Memory locking
|
||||
|
||||
Memory locking is used to avoid swapping of the large block of
|
||||
sample data.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Floating point exceptions
|
||||
|
||||
fluid_check_fpe() checks for "unnormalized numbers" and other
|
||||
exceptions of the floating point processsor.
|
||||
*/
|
||||
|
||||
|
||||
#endif /* _FLUID_SYS_H */
|
144
framework/audio/midi/3rdparty/fluidlite/src/fluid_tuning.c
vendored
Normal file
144
framework/audio/midi/3rdparty/fluidlite/src/fluid_tuning.c
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#include "fluid_tuning.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog)
|
||||
{
|
||||
fluid_tuning_t* tuning;
|
||||
int i;
|
||||
|
||||
tuning = FLUID_NEW(fluid_tuning_t);
|
||||
if (tuning == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tuning->name = NULL;
|
||||
|
||||
if (name != NULL) {
|
||||
tuning->name = FLUID_STRDUP(name);
|
||||
}
|
||||
|
||||
tuning->bank = bank;
|
||||
tuning->prog = prog;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
tuning->pitch[i] = i * 100.0;
|
||||
}
|
||||
|
||||
return tuning;
|
||||
}
|
||||
|
||||
/* Duplicate a tuning */
|
||||
fluid_tuning_t *
|
||||
fluid_tuning_duplicate (fluid_tuning_t *tuning)
|
||||
{
|
||||
fluid_tuning_t *new_tuning;
|
||||
int i;
|
||||
|
||||
new_tuning = FLUID_NEW (fluid_tuning_t);
|
||||
|
||||
if (!new_tuning) {
|
||||
FLUID_LOG (FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tuning->name)
|
||||
{
|
||||
new_tuning->name = FLUID_STRDUP (tuning->name);
|
||||
|
||||
if (!new_tuning->name)
|
||||
{
|
||||
FLUID_FREE (new_tuning);
|
||||
FLUID_LOG (FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else new_tuning->name = NULL;
|
||||
|
||||
new_tuning->bank = tuning->bank;
|
||||
new_tuning->prog = tuning->prog;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
new_tuning->pitch[i] = tuning->pitch[i];
|
||||
|
||||
return new_tuning;
|
||||
}
|
||||
|
||||
void delete_fluid_tuning(fluid_tuning_t* tuning)
|
||||
{
|
||||
if (tuning == NULL) {
|
||||
return;
|
||||
}
|
||||
if (tuning->name != NULL) {
|
||||
FLUID_FREE(tuning->name);
|
||||
}
|
||||
FLUID_FREE(tuning);
|
||||
}
|
||||
|
||||
void fluid_tuning_set_name(fluid_tuning_t* tuning, const char* name)
|
||||
{
|
||||
if (tuning->name != NULL) {
|
||||
FLUID_FREE(tuning->name);
|
||||
tuning->name = NULL;
|
||||
}
|
||||
if (name != NULL) {
|
||||
tuning->name = FLUID_STRDUP(name);
|
||||
}
|
||||
}
|
||||
|
||||
char* fluid_tuning_get_name(fluid_tuning_t* tuning)
|
||||
{
|
||||
return tuning->name;
|
||||
}
|
||||
|
||||
void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
|
||||
{
|
||||
tuning->pitch[key] = pitch;
|
||||
}
|
||||
|
||||
void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_tuning_set_all(fluid_tuning_t* tuning, double* pitch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
tuning->pitch[i] = pitch[i];
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch)
|
||||
{
|
||||
if ((key >= 0) && (key < 128)) {
|
||||
tuning->pitch[key] = pitch;
|
||||
}
|
||||
}
|
65
framework/audio/midi/3rdparty/fluidlite/src/fluid_tuning.h
vendored
Normal file
65
framework/audio/midi/3rdparty/fluidlite/src/fluid_tuning.h
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
More information about micro tuning can be found at:
|
||||
|
||||
http://www.midi.org/about-midi/tuning.htm
|
||||
http://www.midi.org/about-midi/tuning-scale.htm
|
||||
http://www.midi.org/about-midi/tuning_extens.htm
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_TUNING_H
|
||||
#define _FLUID_TUNING_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
struct _fluid_tuning_t {
|
||||
char* name;
|
||||
int bank;
|
||||
int prog;
|
||||
double pitch[128]; /* the pitch of every key, in cents */
|
||||
};
|
||||
|
||||
fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog);
|
||||
fluid_tuning_t* fluid_tuning_duplicate(fluid_tuning_t *tuning);
|
||||
void delete_fluid_tuning(fluid_tuning_t* tuning);
|
||||
|
||||
void fluid_tuning_set_name(fluid_tuning_t* tuning, const char* name);
|
||||
char* fluid_tuning_get_name(fluid_tuning_t* tuning);
|
||||
|
||||
#define fluid_tuning_get_bank(_t) ((_t)->bank)
|
||||
#define fluid_tuning_get_prog(_t) ((_t)->prog)
|
||||
|
||||
void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch);
|
||||
#define fluid_tuning_get_pitch(_t, _key) ((_t)->pitch[_key])
|
||||
|
||||
void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv);
|
||||
|
||||
void fluid_tuning_set_all(fluid_tuning_t* tuning, double* pitch);
|
||||
#define fluid_tuning_get_all(_t) (&(_t)->pitch[0])
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _FLUID_TUNING_H */
|
1998
framework/audio/midi/3rdparty/fluidlite/src/fluid_voice.c
vendored
Normal file
1998
framework/audio/midi/3rdparty/fluidlite/src/fluid_voice.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
291
framework/audio/midi/3rdparty/fluidlite/src/fluid_voice.h
vendored
Normal file
291
framework/audio/midi/3rdparty/fluidlite/src/fluid_voice.h
vendored
Normal file
|
@ -0,0 +1,291 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_VOICE_H
|
||||
#define _FLUID_VOICE_H
|
||||
|
||||
#include "fluid_phase.h"
|
||||
#include "fluid_gen.h"
|
||||
#include "fluid_mod.h"
|
||||
|
||||
#define NO_CHANNEL 0xff
|
||||
|
||||
enum fluid_voice_status
|
||||
{
|
||||
FLUID_VOICE_CLEAN,
|
||||
FLUID_VOICE_ON,
|
||||
FLUID_VOICE_SUSTAINED,
|
||||
FLUID_VOICE_OFF
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* envelope data
|
||||
*/
|
||||
struct _fluid_env_data_t {
|
||||
unsigned int count;
|
||||
fluid_real_t coeff;
|
||||
fluid_real_t incr;
|
||||
fluid_real_t min;
|
||||
fluid_real_t max;
|
||||
};
|
||||
|
||||
/* Indices for envelope tables */
|
||||
enum fluid_voice_envelope_index_t{
|
||||
FLUID_VOICE_ENVDELAY,
|
||||
FLUID_VOICE_ENVATTACK,
|
||||
FLUID_VOICE_ENVHOLD,
|
||||
FLUID_VOICE_ENVDECAY,
|
||||
FLUID_VOICE_ENVSUSTAIN,
|
||||
FLUID_VOICE_ENVRELEASE,
|
||||
FLUID_VOICE_ENVFINISHED,
|
||||
FLUID_VOICE_ENVLAST
|
||||
};
|
||||
|
||||
/*
|
||||
* fluid_voice_t
|
||||
*/
|
||||
struct _fluid_voice_t
|
||||
{
|
||||
unsigned int id; /* the id is incremented for every new noteon.
|
||||
it's used for noteoff's */
|
||||
unsigned char status;
|
||||
unsigned char chan; /* the channel number, quick access for channel messages */
|
||||
unsigned char key; /* the key, quick acces for noteoff */
|
||||
unsigned char vel; /* the velocity */
|
||||
fluid_channel_t* channel;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||
int mod_count;
|
||||
int has_looped; /* Flag that is set as soon as the first loop is completed. */
|
||||
fluid_sample_t* sample;
|
||||
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
|
||||
have to be checked. */
|
||||
#if 0
|
||||
/* Instead of keeping a pointer to a fluid_sample_t structure,
|
||||
* I think it would be better to copy the sample data in the
|
||||
* voice structure. SoundFont loader then do not have to
|
||||
* allocate and maintain the fluid_sample_t structure. [PH]
|
||||
*
|
||||
* The notify callback may be used also for streaming samples.
|
||||
*/
|
||||
short* sample_data; /* pointer to the sample data */
|
||||
int sample_data_offset; /* the offset of data[0] in the whole sample */
|
||||
int sample_data_length; /* the length of the data array */
|
||||
unsigned int sample_start;
|
||||
unsigned int sample_end;
|
||||
unsigned int sample_loopstart;
|
||||
unsigned int sample_loopend;
|
||||
unsigned int sample_rate;
|
||||
int sample_origpitch;
|
||||
int sample_pitchadj;
|
||||
int sample_type;
|
||||
int (*sample_notify)(fluid_voice_t* voice, int reason);
|
||||
void* sample_userdata;
|
||||
#endif
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t output_rate; /* the sample rate of the synthesizer */
|
||||
|
||||
unsigned int start_time;
|
||||
unsigned int ticks;
|
||||
unsigned int noteoff_ticks; /* Delay note-off until this tick */
|
||||
|
||||
fluid_real_t amp; /* current linear amplitude */
|
||||
fluid_phase_t phase; /* the phase of the sample wave */
|
||||
|
||||
/* Temporary variables used in fluid_voice_write() */
|
||||
|
||||
fluid_real_t phase_incr; /* the phase increment for the next 64 samples */
|
||||
fluid_real_t amp_incr; /* amplitude increment value */
|
||||
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
|
||||
|
||||
/* End temporary variables */
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t pitch; /* the pitch in midicents */
|
||||
fluid_real_t attenuation; /* the attenuation in centibels */
|
||||
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
|
||||
* during the lifetime of the voice */
|
||||
fluid_real_t root_pitch;
|
||||
|
||||
/* sample and loop start and end points (offset in sample memory). */
|
||||
int start;
|
||||
int end;
|
||||
int loopstart;
|
||||
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
|
||||
/* master gain */
|
||||
fluid_real_t synth_gain;
|
||||
|
||||
/* vol env */
|
||||
fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
|
||||
unsigned int volenv_count;
|
||||
int volenv_section;
|
||||
fluid_real_t volenv_val;
|
||||
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
|
||||
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
||||
|
||||
/* mod env */
|
||||
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
|
||||
unsigned int modenv_count;
|
||||
int modenv_section;
|
||||
fluid_real_t modenv_val; /* the value of the modulation envelope */
|
||||
fluid_real_t modenv_to_fc;
|
||||
fluid_real_t modenv_to_pitch;
|
||||
|
||||
/* mod lfo */
|
||||
fluid_real_t modlfo_val; /* the value of the modulation LFO */
|
||||
unsigned int modlfo_delay; /* the delay of the lfo in samples */
|
||||
fluid_real_t modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */
|
||||
fluid_real_t modlfo_to_fc;
|
||||
fluid_real_t modlfo_to_pitch;
|
||||
fluid_real_t modlfo_to_vol;
|
||||
|
||||
/* vib lfo */
|
||||
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
|
||||
unsigned int viblfo_delay; /* the delay of the lfo in samples */
|
||||
fluid_real_t viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */
|
||||
fluid_real_t viblfo_to_pitch;
|
||||
|
||||
/* resonant filter */
|
||||
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
|
||||
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
|
||||
/* Serves as a flag: A deviation between fres and last_fres */
|
||||
/* indicates, that the filter has to be recalculated. */
|
||||
fluid_real_t q_lin; /* the q-factor on a linear scale */
|
||||
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
|
||||
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
|
||||
int filter_startup; /* Flag: If set, the filter will be set directly.
|
||||
Else it changes smoothly. */
|
||||
|
||||
/* filter coefficients */
|
||||
/* The coefficients are normalized to a0. */
|
||||
/* b0 and b2 are identical => b02 */
|
||||
fluid_real_t b02; /* b0 / a0 */
|
||||
fluid_real_t b1; /* b1 / a0 */
|
||||
fluid_real_t a1; /* a0 / a0 */
|
||||
fluid_real_t a2; /* a1 / a0 */
|
||||
|
||||
fluid_real_t b02_incr;
|
||||
fluid_real_t b1_incr;
|
||||
fluid_real_t a1_incr;
|
||||
fluid_real_t a2_incr;
|
||||
int filter_coeff_incr_count;
|
||||
|
||||
/* pan */
|
||||
fluid_real_t pan;
|
||||
fluid_real_t amp_left;
|
||||
fluid_real_t amp_right;
|
||||
|
||||
/* reverb */
|
||||
fluid_real_t reverb_send;
|
||||
fluid_real_t amp_reverb;
|
||||
|
||||
/* chorus */
|
||||
fluid_real_t chorus_send;
|
||||
fluid_real_t amp_chorus;
|
||||
|
||||
/* interpolation method, as in fluid_interp in fluidlite.h */
|
||||
int interp_method;
|
||||
|
||||
/* for debugging */
|
||||
int debug;
|
||||
};
|
||||
|
||||
|
||||
fluid_voice_t* new_fluid_voice(fluid_real_t output_rate);
|
||||
int delete_fluid_voice(fluid_voice_t* voice);
|
||||
|
||||
void fluid_voice_start(fluid_voice_t* voice);
|
||||
|
||||
int fluid_voice_write(fluid_voice_t* voice,
|
||||
fluid_real_t* left, fluid_real_t* right,
|
||||
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
|
||||
|
||||
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||
fluid_channel_t* channel, int key, int vel,
|
||||
unsigned int id, unsigned int time, fluid_real_t gain);
|
||||
|
||||
int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl);
|
||||
int fluid_voice_modulate_all(fluid_voice_t* voice);
|
||||
|
||||
/** Set the NRPN value of a generator. */
|
||||
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t value, int abs);
|
||||
|
||||
|
||||
/** Set the gain. */
|
||||
int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain);
|
||||
|
||||
|
||||
/** Update all the synthesis parameters, which depend on generator
|
||||
'gen'. This is only necessary after changing a generator of an
|
||||
already operating voice. Most applications will not need this
|
||||
function.*/
|
||||
void fluid_voice_update_param(fluid_voice_t* voice, int gen);
|
||||
|
||||
int fluid_voice_noteoff(fluid_voice_t* voice);
|
||||
int fluid_voice_off(fluid_voice_t* voice);
|
||||
int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice);
|
||||
fluid_channel_t* fluid_voice_get_channel(fluid_voice_t* voice);
|
||||
int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
|
||||
int gen_key2base, int is_decay);
|
||||
int fluid_voice_kill_excl(fluid_voice_t* voice);
|
||||
fluid_real_t fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
|
||||
fluid_real_t fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(fluid_voice_t* voice);
|
||||
void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
|
||||
|
||||
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
|
||||
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
||||
|
||||
|
||||
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || ((voice)->status == FLUID_VOICE_SUSTAINED))
|
||||
|
||||
/* A voice is 'ON', if it has not yet received a noteoff
|
||||
* event. Sending a noteoff event will advance the envelopes to
|
||||
* section 5 (release). */
|
||||
#define _ON(voice) ((voice)->status == FLUID_VOICE_ON && (voice)->volenv_section < FLUID_VOICE_ENVRELEASE)
|
||||
#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
|
||||
#define _AVAILABLE(voice) (((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF))
|
||||
#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL)
|
||||
#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val)
|
||||
|
||||
|
||||
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
|
||||
|
||||
#define _GEN(_voice, _n) \
|
||||
((fluid_real_t)(_voice)->gen[_n].val \
|
||||
+ (fluid_real_t)(_voice)->gen[_n].mod \
|
||||
+ (fluid_real_t)(_voice)->gen[_n].nrpn)
|
||||
|
||||
#define FLUID_SAMPLESANITY_CHECK (1 << 0)
|
||||
#define FLUID_SAMPLESANITY_STARTUP (1 << 1)
|
||||
|
||||
|
||||
/* defined in fluid_dsp_float.c */
|
||||
|
||||
void fluid_dsp_float_config (void);
|
||||
int fluid_dsp_float_interpolate_none (fluid_voice_t *voice);
|
||||
int fluid_dsp_float_interpolate_linear (fluid_voice_t *voice);
|
||||
int fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice);
|
||||
int fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice);
|
||||
|
||||
#endif /* _FLUID_VOICE_H */
|
710
framework/audio/midi/3rdparty/fluidlite/src/fluidsynth.c
vendored
Normal file
710
framework/audio/midi/3rdparty/fluidlite/src/fluidsynth.c
vendored
Normal file
|
@ -0,0 +1,710 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluid_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#if !defined(WIN32) && !defined(MACINTOSH)
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "fluidsynth.h"
|
||||
|
||||
#if defined(WIN32) && !defined(MINGW32)
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include "signal.h"
|
||||
#endif
|
||||
|
||||
#include "fluid_lash.h"
|
||||
|
||||
#ifndef WITH_MIDI
|
||||
#define WITH_MIDI 1
|
||||
#endif
|
||||
|
||||
/* default audio fragment count (if none specified) */
|
||||
#ifdef WIN32
|
||||
#define DEFAULT_FRAG_COUNT 32
|
||||
#else
|
||||
#define DEFAULT_FRAG_COUNT 16
|
||||
#endif
|
||||
|
||||
void print_usage(void);
|
||||
void print_help(void);
|
||||
void print_welcome(void);
|
||||
|
||||
static fluid_cmd_handler_t* newclient(void* data, char* addr);
|
||||
|
||||
/*
|
||||
* the globals
|
||||
*/
|
||||
fluid_cmd_handler_t* cmd_handler = NULL;
|
||||
int option_help = 0; /* set to 1 if "-o help" is specified */
|
||||
|
||||
/*
|
||||
* support for the getopt function
|
||||
*/
|
||||
#if !defined(WIN32) && !defined(MACINTOSH)
|
||||
#define GETOPT_SUPPORT 1
|
||||
int getopt(int argc, char * const argv[], const char *optstring);
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
#endif
|
||||
|
||||
|
||||
/* process_o_cmd_line_option
|
||||
*
|
||||
* Purpose:
|
||||
* Process a command line option -o setting=value,
|
||||
* for example: -o synth.polyhony=16
|
||||
*/
|
||||
void process_o_cmd_line_option(fluid_settings_t* settings, char* optarg){
|
||||
char* val;
|
||||
for (val = optarg; *val != '\0'; val++) {
|
||||
if (*val == '=') {
|
||||
*val++ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* did user request list of settings */
|
||||
if (strcmp (optarg, "help") == 0)
|
||||
{
|
||||
option_help = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* At this point:
|
||||
* optarg => "synth.polyphony"
|
||||
* val => "16"
|
||||
*/
|
||||
switch(fluid_settings_get_type(settings, optarg)){
|
||||
case FLUID_NUM_TYPE:
|
||||
if (fluid_settings_setnum(settings, optarg, atof(val))){
|
||||
break;
|
||||
};
|
||||
case FLUID_INT_TYPE:
|
||||
if (fluid_settings_setint(settings, optarg, atoi(val))){
|
||||
break;
|
||||
};
|
||||
case FLUID_STR_TYPE:
|
||||
if (fluid_settings_setstr(settings, optarg, val)){
|
||||
break;
|
||||
};
|
||||
default:
|
||||
fprintf (stderr, "Settings argument on command line: Failed to set \"%s\" to \"%s\".\n"
|
||||
"Most likely the parameter \"%s\" does not exist.\n", optarg, val, optarg);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_pretty_int (int i)
|
||||
{
|
||||
if (i == INT_MAX) printf ("MAXINT");
|
||||
else if (i == INT_MIN) printf ("MININT");
|
||||
else printf ("%d", i);
|
||||
}
|
||||
|
||||
/* fluid_settings_foreach function for displaying option help "-o help" */
|
||||
static void
|
||||
settings_foreach_func (void *data, char *name, int type)
|
||||
{
|
||||
fluid_settings_t *settings = (fluid_settings_t *)data;
|
||||
double dmin, dmax, ddef;
|
||||
int imin, imax, idef;
|
||||
char *defstr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FLUID_NUM_TYPE:
|
||||
fluid_settings_getnum_range (settings, name, &dmin, &dmax);
|
||||
ddef = fluid_settings_getnum_default (settings, name);
|
||||
printf ("%-24s FLOAT [min=%0.3f, max=%0.3f, def=%0.3f]\n",
|
||||
name, dmin, dmax, ddef);
|
||||
break;
|
||||
case FLUID_INT_TYPE:
|
||||
fluid_settings_getint_range (settings, name, &imin, &imax);
|
||||
idef = fluid_settings_getint_default (settings, name);
|
||||
printf ("%-24s INT [min=", name);
|
||||
print_pretty_int (imin);
|
||||
printf (", max=");
|
||||
print_pretty_int (imax);
|
||||
printf (", def=");
|
||||
print_pretty_int (idef);
|
||||
printf ("]\n");
|
||||
break;
|
||||
case FLUID_STR_TYPE:
|
||||
defstr = fluid_settings_getstr_default (settings, name);
|
||||
printf ("%-24s STR", name);
|
||||
if (defstr) printf (" [def='%s']\n", defstr);
|
||||
else printf ("\n");
|
||||
break;
|
||||
case FLUID_SET_TYPE:
|
||||
printf ("%-24s SET\n", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
/*
|
||||
* handle_signal
|
||||
*/
|
||||
void handle_signal(int sig_num)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* main
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
fluid_settings_t* settings;
|
||||
int arg1 = 1;
|
||||
char buf[512];
|
||||
int c, i, fragcount = DEFAULT_FRAG_COUNT;
|
||||
int interactive = 1;
|
||||
int midi_in = 1;
|
||||
fluid_player_t* player = NULL;
|
||||
fluid_midi_router_t* router = NULL;
|
||||
fluid_midi_driver_t* mdriver = NULL;
|
||||
fluid_audio_driver_t* adriver = NULL;
|
||||
fluid_synth_t* synth = NULL;
|
||||
fluid_server_t* server = NULL;
|
||||
char* midi_id = NULL;
|
||||
char* midi_driver = NULL;
|
||||
char* midi_device = NULL;
|
||||
char* config_file = NULL;
|
||||
int audio_groups = 0;
|
||||
int audio_channels = 0;
|
||||
int with_server = 0;
|
||||
int dump = 0;
|
||||
int connect_lash = 1;
|
||||
char *optchars = "a:C:c:df:G:g:hijK:L:lm:no:p:R:r:sVvz:";
|
||||
#ifdef LASH_ENABLED
|
||||
int enabled_lash = 0; /* set to TRUE if lash gets enabled */
|
||||
fluid_lash_args_t *lash_args;
|
||||
|
||||
lash_args = fluid_lash_extract_args (&argc, &argv);
|
||||
#endif
|
||||
|
||||
settings = new_fluid_settings();
|
||||
|
||||
#ifdef GETOPT_SUPPORT /* pre section of GETOPT supported argument handling */
|
||||
opterr = 0;
|
||||
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"audio-bufcount", 1, 0, 'c'},
|
||||
{"audio-bufsize", 1, 0, 'z'},
|
||||
{"audio-channels", 1, 0, 'L'},
|
||||
{"audio-driver", 1, 0, 'a'},
|
||||
{"audio-groups", 1, 0, 'G'},
|
||||
{"chorus", 1, 0, 'C'},
|
||||
{"connect-jack-outputs", 0, 0, 'j'},
|
||||
{"disable-lash", 0, 0, 'l'},
|
||||
{"dump", 0, 0, 'd'},
|
||||
{"gain", 1, 0, 'g'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"load-config", 1, 0, 'f'},
|
||||
{"midi-channels", 1, 0, 'K'},
|
||||
{"midi-driver", 1, 0, 'm'},
|
||||
{"no-midi-in", 0, 0, 'n'},
|
||||
{"no-shell", 0, 0, 'i'},
|
||||
{"option", 1, 0, 'o'},
|
||||
{"portname", 1, 0, 'p'},
|
||||
{"reverb", 1, 0, 'R'},
|
||||
{"sample-rate", 1, 0, 'r'},
|
||||
{"server", 0, 0, 's'},
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"version", 0, 0, 'V'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, optchars, long_options, &option_index);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
#else /* "pre" section to non getopt argument handling */
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *optarg;
|
||||
|
||||
/* Skip non switch arguments (assume they are file names) */
|
||||
if ((argv[i][0] != '-') || (argv[i][1] == '\0')) break;
|
||||
|
||||
c = argv[i][1];
|
||||
|
||||
optarg = strchr (optchars, c); /* find the option character in optchars */
|
||||
if (optarg && optarg[1] == ':') /* colon follows if switch argument expected */
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf ("Option -%c requires an argument\n", c);
|
||||
print_usage();
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
optarg = argv[i];
|
||||
if (optarg[0] == '-')
|
||||
{
|
||||
printf ("Expected argument to option -%c found switch instead\n", c);
|
||||
print_usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else optarg = "";
|
||||
#endif
|
||||
|
||||
switch (c) {
|
||||
#ifdef GETOPT_SUPPORT
|
||||
case 0: /* shouldn't normally happen, a long option's flag is set to NULL */
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg) {
|
||||
printf (" with arg %s", optarg);
|
||||
}
|
||||
printf ("\n");
|
||||
break;
|
||||
#endif
|
||||
case 'a':
|
||||
fluid_settings_setstr(settings, "audio.driver", optarg);
|
||||
break;
|
||||
case 'C':
|
||||
if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) {
|
||||
fluid_settings_setstr(settings, "synth.chorus.active", "no");
|
||||
} else {
|
||||
fluid_settings_setstr(settings, "synth.chorus.active", "yes");
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
fluid_settings_setint(settings, "audio.periods", atoi(optarg));
|
||||
break;
|
||||
case 'd':
|
||||
fluid_settings_setstr(settings, "synth.dump", "yes");
|
||||
dump = 1;
|
||||
break;
|
||||
case 'f':
|
||||
config_file = optarg;
|
||||
break;
|
||||
case 'G':
|
||||
audio_groups = atoi(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
fluid_settings_setnum(settings, "synth.gain", atof(optarg));
|
||||
break;
|
||||
case 'h':
|
||||
print_help();
|
||||
break;
|
||||
case 'i':
|
||||
interactive = 0;
|
||||
break;
|
||||
case 'j':
|
||||
fluid_settings_setint(settings, "audio.jack.autoconnect", 1);
|
||||
break;
|
||||
case 'K':
|
||||
fluid_settings_setint(settings, "synth.midi-channels", atoi(optarg));
|
||||
break;
|
||||
case 'L':
|
||||
audio_channels = atoi(optarg);
|
||||
fluid_settings_setint(settings, "synth.audio-channels", audio_channels);
|
||||
break;
|
||||
case 'l': /* disable LASH */
|
||||
connect_lash = 0;
|
||||
break;
|
||||
case 'm':
|
||||
fluid_settings_setstr(settings, "midi.driver", optarg);
|
||||
break;
|
||||
case 'n':
|
||||
midi_in = 0;
|
||||
break;
|
||||
case 'o':
|
||||
process_o_cmd_line_option(settings, optarg);
|
||||
break;
|
||||
case 'p' :
|
||||
fluid_settings_setstr(settings, "midi.portname", optarg);
|
||||
break;
|
||||
case 'R':
|
||||
if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) {
|
||||
fluid_settings_setstr(settings, "synth.reverb.active", "no");
|
||||
} else {
|
||||
fluid_settings_setstr(settings, "synth.reverb.active", "yes");
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
|
||||
break;
|
||||
case 's':
|
||||
with_server = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf("FluidSynth %s\n", VERSION);
|
||||
exit (0);
|
||||
break;
|
||||
case 'v':
|
||||
fluid_settings_setstr(settings, "synth.verbose", "yes");
|
||||
break;
|
||||
case 'z':
|
||||
fluid_settings_setint(settings, "audio.period-size", atoi(optarg));
|
||||
break;
|
||||
#ifdef GETOPT_SUPPORT
|
||||
case '?':
|
||||
printf ("Unknown option %c\n", optopt);
|
||||
print_usage();
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
break;
|
||||
#else /* Non getopt default case */
|
||||
default:
|
||||
printf ("Unknown switch '%c'\n", c);
|
||||
print_usage();
|
||||
exit(0);
|
||||
break;
|
||||
#endif
|
||||
} /* end of switch statement */
|
||||
} /* end of loop */
|
||||
|
||||
#ifdef GETOPT_SUPPORT
|
||||
arg1 = optind;
|
||||
#else
|
||||
arg1 = i;
|
||||
#endif
|
||||
|
||||
/* option help requested? "-o help" */
|
||||
if (option_help)
|
||||
{
|
||||
print_welcome ();
|
||||
printf ("FluidSynth settings:\n");
|
||||
fluid_settings_foreach (settings, settings, settings_foreach_func);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
|
||||
#endif
|
||||
|
||||
#ifdef LASH_ENABLED
|
||||
/* connect to the lash server */
|
||||
if (connect_lash)
|
||||
{
|
||||
enabled_lash = fluid_lash_connect (lash_args);
|
||||
fluid_settings_setint (settings, "lash.enable", enabled_lash ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The 'groups' setting is only relevant for LADSPA operation
|
||||
* If not given, set number groups to number of audio channels, because
|
||||
* they are the same (there is nothing between synth output and 'sound card')
|
||||
*/
|
||||
if ((audio_groups == 0) && (audio_channels != 0)) {
|
||||
audio_groups = audio_channels;
|
||||
}
|
||||
fluid_settings_setint(settings, "synth.audio-groups", audio_groups);
|
||||
|
||||
/* create the synthesizer */
|
||||
synth = new_fluid_synth(settings);
|
||||
if (synth == NULL) {
|
||||
fprintf(stderr, "Failed to create the synthesizer\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cmd_handler = new_fluid_cmd_handler(synth);
|
||||
if (cmd_handler == NULL) {
|
||||
fprintf(stderr, "Failed to create the command handler\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* try to load the user or system configuration */
|
||||
if (config_file != NULL) {
|
||||
fluid_source(cmd_handler, config_file);
|
||||
} else if (fluid_get_userconf(buf, 512) != NULL) {
|
||||
fluid_source(cmd_handler, buf);
|
||||
} else if (fluid_get_sysconf(buf, 512) != NULL) {
|
||||
fluid_source(cmd_handler, buf);
|
||||
}
|
||||
|
||||
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
|
||||
for (i = arg1; i < argc; i++) {
|
||||
if (fluid_is_soundfont(argv[i]))
|
||||
{
|
||||
if (fluid_synth_sfload(synth, argv[i], 1) == -1)
|
||||
fprintf(stderr, "Failed to load the SoundFont %s\n", argv[i]);
|
||||
}
|
||||
else if (!fluid_is_midifile(argv[i]))
|
||||
fprintf (stderr, "Parameter '%s' not a SoundFont or MIDI file or error occurred identifying it.\n",
|
||||
argv[i]);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
/* signal(SIGINT, handle_signal); */
|
||||
#endif
|
||||
|
||||
/* start the synthesis thread */
|
||||
adriver = new_fluid_audio_driver(settings, synth);
|
||||
if (adriver == NULL) {
|
||||
fprintf(stderr, "Failed to create the audio driver\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* start the midi router and link it to the synth */
|
||||
#if WITH_MIDI
|
||||
if (midi_in) {
|
||||
/* In dump mode, text output is generated for events going into and out of the router.
|
||||
* The example dump functions are put into the chain before and after the router..
|
||||
*/
|
||||
|
||||
router = new_fluid_midi_router(
|
||||
settings,
|
||||
dump ? fluid_midi_dump_postrouter : fluid_synth_handle_midi_event,
|
||||
(void*)synth);
|
||||
|
||||
if (router == NULL) {
|
||||
fprintf(stderr, "Failed to create the MIDI input router; no MIDI input\n"
|
||||
"will be available. You can access the synthesizer \n"
|
||||
"through the console.\n");
|
||||
} else {
|
||||
fluid_synth_set_midi_router(synth, router); /* Fixme, needed for command handler */
|
||||
mdriver = new_fluid_midi_driver(
|
||||
settings,
|
||||
dump ? fluid_midi_dump_prerouter : fluid_midi_router_handle_midi_event,
|
||||
(void*) router);
|
||||
if (mdriver == NULL) {
|
||||
fprintf(stderr, "Failed to create the MIDI thread; no MIDI input\n"
|
||||
"will be available. You can access the synthesizer \n"
|
||||
"through the console.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* play the midi files, if any */
|
||||
for (i = arg1; i < argc; i++) {
|
||||
if ((argv[i][0] != '-') && fluid_is_midifile(argv[i])) {
|
||||
|
||||
if (player == NULL) {
|
||||
player = new_fluid_player(synth);
|
||||
if (player == NULL) {
|
||||
fprintf(stderr, "Failed to create the midifile player.\n"
|
||||
"Continuing without a player.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fluid_player_add(player, argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (player != NULL) {
|
||||
fluid_player_play(player);
|
||||
}
|
||||
|
||||
/* run the server, if requested */
|
||||
#if !defined(MACINTOSH) && !defined(WIN32)
|
||||
if (with_server) {
|
||||
server = new_fluid_server(settings, newclient, synth);
|
||||
if (server == NULL) {
|
||||
fprintf(stderr, "Failed to create the server.\n"
|
||||
"Continuing without it.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LASH_ENABLED
|
||||
if (enabled_lash)
|
||||
fluid_lash_create_thread (synth);
|
||||
#endif
|
||||
|
||||
/* run the shell */
|
||||
if (interactive) {
|
||||
print_welcome();
|
||||
|
||||
printf ("Type 'help' for information on commands and 'help help' for help topics.\n\n");
|
||||
|
||||
/* In dump mode we set the prompt to "". The UI cannot easily
|
||||
* handle lines, which don't end with CR. Changing the prompt
|
||||
* cannot be done through a command, because the current shell
|
||||
* does not handle empty arguments. The ordinary case is dump ==
|
||||
* 0.
|
||||
*/
|
||||
fluid_settings_setstr(settings, "shell.prompt", dump ? "" : "> ");
|
||||
fluid_usershell(settings, cmd_handler);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
#if !defined(MACINTOSH) && !defined(WIN32)
|
||||
if (server != NULL) {
|
||||
/* if the user typed 'quit' in the shell, kill the server */
|
||||
if (!interactive) {
|
||||
fluid_server_join(server);
|
||||
}
|
||||
delete_fluid_server(server);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cmd_handler != NULL) {
|
||||
delete_fluid_cmd_handler(cmd_handler);
|
||||
}
|
||||
|
||||
if (player != NULL) {
|
||||
/* if the user typed 'quit' in the shell, stop the player */
|
||||
if (interactive) {
|
||||
fluid_player_stop(player);
|
||||
}
|
||||
fluid_player_join(player);
|
||||
delete_fluid_player(player);
|
||||
}
|
||||
|
||||
if (router) {
|
||||
#if WITH_MIDI
|
||||
if (mdriver) {
|
||||
delete_fluid_midi_driver(mdriver);
|
||||
}
|
||||
delete_fluid_midi_router(router);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (adriver) {
|
||||
delete_fluid_audio_driver(adriver);
|
||||
}
|
||||
|
||||
if (synth) {
|
||||
delete_fluid_synth(synth);
|
||||
}
|
||||
|
||||
if (settings) {
|
||||
delete_fluid_settings(settings);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static fluid_cmd_handler_t* newclient(void* data, char* addr)
|
||||
{
|
||||
fluid_synth_t* synth = (fluid_synth_t*) data;
|
||||
return new_fluid_cmd_handler(synth);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* print_usage
|
||||
*/
|
||||
void
|
||||
print_usage()
|
||||
{
|
||||
print_welcome ();
|
||||
fprintf(stderr, "Usage: fluidsynth [options] [soundfonts]\n");
|
||||
fprintf(stderr, "Try -h for help.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* print_welcome
|
||||
*/
|
||||
void
|
||||
print_welcome()
|
||||
{
|
||||
printf("FluidSynth version %s\n"
|
||||
"Copyright (C) 2000-2006 Peter Hanappe and others.\n"
|
||||
"Distributed under the LGPL license.\n"
|
||||
"SoundFont(R) is a registered trademark of E-mu Systems, Inc.\n\n",
|
||||
FLUIDSYNTH_VERSION);
|
||||
}
|
||||
|
||||
/*
|
||||
* print_help
|
||||
*/
|
||||
void
|
||||
print_help()
|
||||
{
|
||||
print_welcome ();
|
||||
printf("Usage: \n");
|
||||
printf(" fluidsynth [options] [soundfonts] [midifiles]\n");
|
||||
printf("Possible options:\n");
|
||||
printf(" -a, --audio-driver=[label]\n"
|
||||
" The audio driver [alsa,jack,oss,dsound,...]\n");
|
||||
printf(" -C, --chorus\n"
|
||||
" Turn the chorus on or off [0|1|yes|no, default = on]\n");
|
||||
printf(" -c, --audio-bufcount=[count]\n"
|
||||
" Number of audio buffers\n");
|
||||
printf(" -d, --dump\n"
|
||||
" Dump incoming and outgoing MIDI events to stdout\n");
|
||||
printf(" -f, --load-config\n"
|
||||
" Load command configuration file (shell commands)\n");
|
||||
printf(" -G, --audio-groups\n"
|
||||
" Defines the number of LADSPA audio nodes\n");
|
||||
printf(" -g, --gain\n"
|
||||
" Set the master gain [0 < gain < 10, default = 0.2]\n");
|
||||
printf(" -h, --help\n"
|
||||
" Print out this help summary\n");
|
||||
printf(" -i, --no-shell\n"
|
||||
" Don't read commands from the shell [default = yes]\n");
|
||||
printf(" -j, --connect-jack-outputs\n"
|
||||
" Attempt to connect the jack outputs to the physical ports\n");
|
||||
printf(" -K, --midi-channels=[num]\n"
|
||||
" The number of midi channels [default = 16]\n");
|
||||
printf(" -L, --audio-channels=[num]\n"
|
||||
" The number of stereo audio channels [default = 1]\n");
|
||||
#ifdef LASH_ENABLED
|
||||
printf(" -l, --disable-lash\n"
|
||||
" Don't connect to LASH server\n");
|
||||
#endif
|
||||
printf(" -m, --midi-driver=[label]\n"
|
||||
" The name of the midi driver to use [oss,alsa,alsa_seq,...]\n");
|
||||
printf(" -n, --no-midi-in\n"
|
||||
" Don't create a midi driver to read MIDI input events [default = yes]\n");
|
||||
printf(" -p, --portname=[label]\n"
|
||||
" Set MIDI port name (alsa_seq, coremidi drivers)\n");
|
||||
printf(" -o\n"
|
||||
" Define a setting, -o name=value (\"-o help\" to dump current values)\n");
|
||||
printf(" -R, --reverb\n"
|
||||
" Turn the reverb on or off [0|1|yes|no, default = on]\n");
|
||||
printf(" -r, --sample-rate\n"
|
||||
" Set the sample rate\n");
|
||||
printf(" -s, --server\n"
|
||||
" Start FluidSynth as a server process\n");
|
||||
printf(" -V, --version\n"
|
||||
" Show version of program\n");
|
||||
printf(" -v, --verbose\n"
|
||||
" Print out verbose messages about midi events\n");
|
||||
printf(" -z, --audio-bufsize=[size]\n"
|
||||
" Size of each audio buffer\n");
|
||||
exit(0);
|
||||
}
|
220
framework/audio/midi/3rdparty/fluidlite/src/fluidsynth_priv.h
vendored
Normal file
220
framework/audio/midi/3rdparty/fluidlite/src/fluidsynth_priv.h
vendored
Normal file
|
@ -0,0 +1,220 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUIDSYNTH_PRIV_H
|
||||
#define _FLUIDSYNTH_PRIV_H
|
||||
|
||||
#include "fluid_config.h"
|
||||
|
||||
#if HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_MATH_H
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "fluidlite.h"
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* BASIC TYPES
|
||||
*/
|
||||
|
||||
#if defined(WITH_FLOAT)
|
||||
typedef float fluid_real_t;
|
||||
#else
|
||||
typedef double fluid_real_t;
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum {
|
||||
FLUID_OK = 0,
|
||||
FLUID_FAILED = -1
|
||||
} fluid_status;
|
||||
|
||||
|
||||
//socket disabled
|
||||
|
||||
/** Integer types */
|
||||
|
||||
typedef signed char sint8;
|
||||
typedef unsigned char uint8;
|
||||
typedef signed short sint16;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed int sint32;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
//#if defined(MINGW32)
|
||||
|
||||
///* Windows using MinGW32 */
|
||||
//typedef int8_t sint8;
|
||||
//typedef uint8_t uint8;
|
||||
//typedef int16_t sint16;
|
||||
//typedef uint16_t uint16;
|
||||
//typedef int32_t sint32;
|
||||
//typedef uint32_t uint32;
|
||||
//typedef int64_t sint64;
|
||||
//typedef uint64_t uint64;
|
||||
|
||||
//#elif defined(_WIN32)
|
||||
|
||||
///* Windows */
|
||||
//typedef signed __int8 sint8;
|
||||
//typedef unsigned __int8 uint8;
|
||||
//typedef signed __int16 sint16;
|
||||
//typedef unsigned __int16 uint16;
|
||||
//typedef signed __int32 sint32;
|
||||
//typedef unsigned __int32 uint32;
|
||||
//typedef signed __int64 sint64;
|
||||
//typedef unsigned __int64 uint64;
|
||||
|
||||
//#elif defined(MACOS9)
|
||||
|
||||
///* Macintosh */
|
||||
//typedef signed char sint8;
|
||||
//typedef unsigned char uint8;
|
||||
//typedef signed short sint16;
|
||||
//typedef unsigned short uint16;
|
||||
//typedef signed int sint32;
|
||||
//typedef unsigned int uint32;
|
||||
///* FIXME: needs to be verified */
|
||||
//typedef long long sint64;
|
||||
//typedef unsigned long long uint64;
|
||||
|
||||
//#else
|
||||
|
||||
///* Linux & Darwin */
|
||||
//typedef int8_t sint8;
|
||||
//typedef u_int8_t uint8;
|
||||
//typedef int16_t sint16;
|
||||
//typedef u_int16_t uint16;
|
||||
//typedef int32_t sint32;
|
||||
//typedef u_int32_t uint32;
|
||||
//typedef int64_t sint64;
|
||||
//typedef u_int64_t uint64;
|
||||
|
||||
//#endif
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* FORWARD DECLARATIONS
|
||||
*/
|
||||
typedef struct _fluid_env_data_t fluid_env_data_t;
|
||||
typedef struct _fluid_adriver_definition_t fluid_adriver_definition_t;
|
||||
typedef struct _fluid_channel_t fluid_channel_t;
|
||||
typedef struct _fluid_tuning_t fluid_tuning_t;
|
||||
typedef struct _fluid_hashtable_t fluid_hashtable_t;
|
||||
typedef struct _fluid_client_t fluid_client_t;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*/
|
||||
|
||||
#define FLUID_BUFSIZE 64
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.141592654
|
||||
#endif
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* SYSTEM INTERFACE
|
||||
*/
|
||||
typedef FILE* fluid_file;
|
||||
|
||||
#define FLUID_MALLOC(_n) malloc(_n)
|
||||
#define FLUID_REALLOC(_p,_n) realloc(_p,_n)
|
||||
#define FLUID_NEW(_t) (_t*)malloc(sizeof(_t))
|
||||
#define FLUID_ARRAY(_t,_n) (_t*)malloc((_n)*sizeof(_t))
|
||||
#define FLUID_FREE(_p) free(_p)
|
||||
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
|
||||
#define FLUID_FCLOSE(_f) fclose(_f)
|
||||
#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
|
||||
#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
|
||||
#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
|
||||
#define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n)
|
||||
#define FLUID_STRLEN(_s) strlen(_s)
|
||||
#define FLUID_STRCMP(_s,_t) strcmp(_s,_t)
|
||||
#define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
|
||||
#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src)
|
||||
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
|
||||
#ifdef strdup
|
||||
#define FLUID_STRDUP(s) strdup(s)
|
||||
#else
|
||||
#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s)
|
||||
#endif
|
||||
#define FLUID_SPRINTF sprintf
|
||||
#define FLUID_FPRINTF fprintf
|
||||
|
||||
#define fluid_clip(_val, _min, _max) \
|
||||
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); }
|
||||
|
||||
#if WITH_FTS
|
||||
#define FLUID_PRINTF post
|
||||
#define FLUID_FLUSH()
|
||||
#else
|
||||
#define FLUID_PRINTF printf
|
||||
#define FLUID_FLUSH() fflush(stdout)
|
||||
#endif
|
||||
|
||||
#define FLUID_LOG fluid_log
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
|
||||
|
||||
#define FLUID_ASSERT(a,b)
|
||||
#define FLUID_ASSERT_P(a,b)
|
||||
|
||||
char* fluid_error(void);
|
||||
|
||||
|
||||
/* Internationalization */
|
||||
#define _(s) s
|
||||
|
||||
|
||||
#endif /* _FLUIDSYNTH_PRIV_H */
|
48
framework/audio/midi/CMakeLists.txt
Normal file
48
framework/audio/midi/CMakeLists.txt
Normal file
|
@ -0,0 +1,48 @@
|
|||
#=============================================================================
|
||||
# MuseScore
|
||||
# Music Composition & Notation
|
||||
#
|
||||
# Copyright (C) 2020 MuseScore BVBA and others
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2.
|
||||
#
|
||||
# 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; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#=============================================================================
|
||||
|
||||
set(MODULE audio_midi)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/3rdparty/fluidlite.cmake)
|
||||
|
||||
set(MODULE_SRC
|
||||
${FLUIDSYNTH_SRC}
|
||||
${CMAKE_CURRENT_LIST_DIR}/midimodule.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/midimodule.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/isynthesizer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/isequencer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/isoundfontfileprovider.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/miditypes.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/fluidlitesynth.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/fluidlitesynth.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/sequencer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/sequencer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/sffproviderlocalfile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/sffproviderlocalfile.h
|
||||
)
|
||||
|
||||
set (MODULE_INCLUDE
|
||||
${FLUIDSYNTH_INC}
|
||||
)
|
||||
|
||||
set (MODULE_HAS_C_CODE 1)
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/build/module.cmake)
|
||||
|
||||
|
388
framework/audio/midi/internal/fluidlitesynth.cpp
Normal file
388
framework/audio/midi/internal/fluidlitesynth.cpp
Normal file
|
@ -0,0 +1,388 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#include "fluidlitesynth.h"
|
||||
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <fluidlite.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace {
|
||||
static double GLOBAL_VOLUME_GAIN{ 1.8 };
|
||||
}
|
||||
|
||||
enum fluid_status {
|
||||
FLUID_OK = 0,
|
||||
FLUID_FAILED = -1
|
||||
};
|
||||
|
||||
template<class T>
|
||||
static const T& clamp(const T& v, const T& lo, const T& hi)
|
||||
{
|
||||
return (v < lo) ? lo : (hi < v) ? hi : v;
|
||||
}
|
||||
|
||||
using namespace mu::audio::midi;
|
||||
|
||||
struct mu::audio::midi::Fluid {
|
||||
fluid_settings_t* settings{ nullptr };
|
||||
fluid_synth_t* synth{ nullptr };
|
||||
|
||||
~Fluid()
|
||||
{
|
||||
delete_fluid_synth(synth);
|
||||
delete_fluid_settings(settings);
|
||||
}
|
||||
};
|
||||
|
||||
FluidLiteSynth::FluidLiteSynth()
|
||||
{
|
||||
m_fluid = std::make_shared<Fluid>();
|
||||
}
|
||||
|
||||
FluidLiteSynth::~FluidLiteSynth()
|
||||
{
|
||||
}
|
||||
|
||||
void FluidLiteSynth::loadSF(const Programs& programs,
|
||||
const std::string& overridden_sf,
|
||||
const OnLoadingChanged& onloading)
|
||||
{
|
||||
m_sf.programs = programs;
|
||||
m_sf.loaded = false;
|
||||
|
||||
if (!overridden_sf.empty()) {
|
||||
m_sf.loaded = true;
|
||||
m_sf.file_path = overridden_sf;
|
||||
|
||||
if (onloading) {
|
||||
onloading(100);
|
||||
}
|
||||
|
||||
if (m_sf.onLoaded) {
|
||||
m_sf.onLoaded();
|
||||
}
|
||||
} else {
|
||||
sfprovider()->loadSF(programs,
|
||||
[onloading](uint16_t percent) {
|
||||
if (onloading) {
|
||||
onloading(percent);
|
||||
}
|
||||
},
|
||||
[this](bool success, const std::string& sf_path, const std::vector<Program>& programs) {
|
||||
if (!success) {
|
||||
LOGE() << "failed load sound font\n";
|
||||
} else {
|
||||
LOGD() << "success load sound font: " << sf_path << "\n";
|
||||
}
|
||||
m_sf.loaded = success;
|
||||
m_sf.file_path = sf_path;
|
||||
m_sf.programs = programs;
|
||||
if (m_sf.onLoaded) {
|
||||
m_sf.onLoaded();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void FluidLiteSynth::init(float samplerate, float gain, const OnInited& oninited)
|
||||
{
|
||||
if (m_sf.loaded) {
|
||||
doInit(samplerate, gain, oninited);
|
||||
} else {
|
||||
m_sf.onLoaded = [this, samplerate, gain, oninited]() {
|
||||
doInit(samplerate, gain, oninited);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void FluidLiteSynth::doInit(float samplerate, float gain, const OnInited& oninited)
|
||||
{
|
||||
bool success = m_sf.loaded;
|
||||
|
||||
if (!success) {
|
||||
LOGE() << "failed make sound font\n";
|
||||
} else {
|
||||
LOGD() << "success make sound font\n";
|
||||
success = init_synth(m_sf.file_path, samplerate, gain);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
fluid_synth_program_reset(m_fluid->synth);
|
||||
fluid_synth_system_reset(m_fluid->synth);
|
||||
|
||||
for (const Program& prog : m_sf.programs) {
|
||||
fluid_synth_reset_tuning(m_fluid->synth, prog.ch);
|
||||
|
||||
fluid_synth_bank_select(m_fluid->synth, prog.ch, prog.bank);
|
||||
fluid_synth_program_change(m_fluid->synth, prog.ch, prog.prog);
|
||||
|
||||
fluid_synth_set_interp_method(m_fluid->synth, prog.ch, FLUID_INTERP_DEFAULT);
|
||||
fluid_synth_pitch_wheel_sens(m_fluid->synth, prog.ch, 12);
|
||||
|
||||
//LOGD() << "ch: " << prog.ch << ", prog: " << prog.prog << ", bank: " << prog.bank << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (oninited) {
|
||||
oninited(success);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
m_sampleRate = samplerate;
|
||||
// preallocated buffer size must be at least (sample rate) * (channels number)
|
||||
m_preallocated.resize(int(m_sampleRate) * 2);
|
||||
LOGI() << "success inited synth (fluid)\n";
|
||||
} else {
|
||||
LOGE() << "failed inited synth (fluid)\n";
|
||||
}
|
||||
}
|
||||
|
||||
void FluidLiteSynth::setGain(float gain)
|
||||
{
|
||||
m_gain = gain;
|
||||
|
||||
if (!m_fluid->synth) {
|
||||
return;
|
||||
}
|
||||
|
||||
fluid_synth_set_gain(m_fluid->synth, m_gain);
|
||||
}
|
||||
|
||||
bool FluidLiteSynth::init_synth(const std::string& sf_path, float samplerate, float gain)
|
||||
{
|
||||
auto fluid_log_out = [](int level, char* message, void*) {
|
||||
switch (level) {
|
||||
case FLUID_PANIC:
|
||||
case FLUID_ERR: {
|
||||
LOGE() << message;
|
||||
} break;
|
||||
case FLUID_WARN: {
|
||||
LOGW() << message;
|
||||
} break;
|
||||
case FLUID_INFO: {
|
||||
LOGI() << message;
|
||||
} break;
|
||||
case FLUID_DBG: {
|
||||
LOGD() << message;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (level < FLUID_DBG) {
|
||||
bool debugme = true;
|
||||
(void)debugme;
|
||||
}
|
||||
};
|
||||
|
||||
fluid_set_log_function(FLUID_PANIC, fluid_log_out, nullptr);
|
||||
fluid_set_log_function(FLUID_ERR, fluid_log_out, nullptr);
|
||||
fluid_set_log_function(FLUID_WARN, fluid_log_out, nullptr);
|
||||
fluid_set_log_function(FLUID_INFO, fluid_log_out, nullptr);
|
||||
fluid_set_log_function(FLUID_DBG, fluid_log_out, nullptr);
|
||||
|
||||
m_gain = gain;
|
||||
m_fluid->settings = new_fluid_settings();
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.gain", GLOBAL_VOLUME_GAIN * m_gain);
|
||||
fluid_settings_setint(m_fluid->settings, "synth.audio-channels", 1);
|
||||
fluid_settings_setint(m_fluid->settings, "synth.lock-memory", 0);
|
||||
fluid_settings_setint(m_fluid->settings, "synth.threadsafe-api", 0);
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.sample-rate", static_cast<double>(samplerate));
|
||||
fluid_settings_setint(m_fluid->settings, "synth.midi-channels", 80);
|
||||
|
||||
//fluid_settings_setint(_fluid->settings, "synth.min-note-length", 50);
|
||||
//fluid_settings_setint(_fluid->settings, "synth.polyphony", conf.polyphony);
|
||||
|
||||
fluid_settings_setstr(m_fluid->settings, "synth.chorus.active", "no");
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.chorus.depth", 8);
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.chorus.level", 10);
|
||||
fluid_settings_setint(m_fluid->settings, "synth.chorus.nr", 4);
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.chorus.speed", 1);
|
||||
|
||||
/*
|
||||
https://github.com/FluidSynth/fluidsynth/wiki/UserManual
|
||||
rev_preset
|
||||
num:0 roomsize:0.2 damp:0.0 width:0.5 level:0.9
|
||||
num:1 roomsize:0.4 damp:0.2 width:0.5 level:0.8
|
||||
num:2 roomsize:0.6 damp:0.4 width:0.5 level:0.7
|
||||
num:3 roomsize:0.8 damp:0.7 width:0.5 level:0.6
|
||||
num:4 roomsize:0.8 damp:1.0 width:0.5 level:0.5
|
||||
*/
|
||||
|
||||
fluid_settings_setstr(m_fluid->settings, "synth.reverb.active", "no");
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.reverb.room-size", 0.8);
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.reverb.damp", 1.0);
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.reverb.width", 0.5);
|
||||
fluid_settings_setnum(m_fluid->settings, "synth.reverb.level", 0.5);
|
||||
|
||||
fluid_settings_setstr(m_fluid->settings, "audio.sample-format", "float");
|
||||
|
||||
m_fluid->synth = new_fluid_synth(m_fluid->settings);
|
||||
|
||||
int sfont_id = fluid_synth_sfload(m_fluid->synth, sf_path.c_str(), 0);
|
||||
if (sfont_id == FLUID_FAILED) {
|
||||
LOGE() << "failed load soundfont: " << sf_path;
|
||||
return false;
|
||||
} else {
|
||||
LOGI() << "success load soundfont: " << sf_path;
|
||||
}
|
||||
|
||||
LOGD() << "synth inited\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
const Program& FluidLiteSynth::program(uint16_t chan) const
|
||||
{
|
||||
for (const Program& p : m_sf.programs) {
|
||||
if (p.ch == chan) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
static Program dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
bool FluidLiteSynth::handleEvent(uint16_t chan, const Event& e)
|
||||
{
|
||||
if (m_isLoggingSynthEvents) {
|
||||
const Program& p = program(chan);
|
||||
LOGD() << "chan: " << chan << " bank: " << p.bank << " prog: " << p.prog << " " << e.to_string();
|
||||
}
|
||||
|
||||
int ret = FLUID_OK;
|
||||
switch (e.type) {
|
||||
case ME_NOTEON: {
|
||||
ret = fluid_synth_noteon(m_fluid->synth, chan, e.a, e.b);
|
||||
} break;
|
||||
case ME_NOTEOFF: { //msb << 7 | lsb
|
||||
ret = fluid_synth_noteoff(m_fluid->synth, chan, e.b << 7 | e.a);
|
||||
} break;
|
||||
case ME_CONTROLLER: {
|
||||
ret = fluid_synth_cc(m_fluid->synth, chan, e.a, e.b);
|
||||
} break;
|
||||
case ME_PROGRAMCHANGE: {
|
||||
fluid_synth_program_change(m_fluid->synth, chan, e.b);
|
||||
} break;
|
||||
case ME_PITCHBEND: {
|
||||
int pitch = e.b << 7 | e.a;
|
||||
ret = fluid_synth_pitch_bend(m_fluid->synth, chan, pitch);
|
||||
} break;
|
||||
case META_TEMPO: {
|
||||
// noop
|
||||
} break;
|
||||
default: {
|
||||
LOGW() << "not supported event type: " << static_cast<int>(e.type) << "\n";
|
||||
ret = FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return ret == FLUID_OK;
|
||||
}
|
||||
|
||||
void FluidLiteSynth::allSoundsOff()
|
||||
{
|
||||
IF_ASSERT_FAILED(m_fluid->synth) {
|
||||
return;
|
||||
}
|
||||
|
||||
fluid_synth_all_notes_off(m_fluid->synth, -1);
|
||||
fluid_synth_all_sounds_off(m_fluid->synth, -1);
|
||||
}
|
||||
|
||||
void FluidLiteSynth::flushSound()
|
||||
{
|
||||
IF_ASSERT_FAILED(m_fluid->synth) {
|
||||
return;
|
||||
}
|
||||
|
||||
fluid_synth_all_notes_off(m_fluid->synth, -1);
|
||||
fluid_synth_all_sounds_off(m_fluid->synth, -1);
|
||||
|
||||
int size = int(m_sampleRate);
|
||||
|
||||
fluid_synth_write_float(m_fluid->synth, size, &m_preallocated[0], 0, 1, &m_preallocated[0], size, 1);
|
||||
}
|
||||
|
||||
void FluidLiteSynth::channelSoundsOff(uint16_t chan)
|
||||
{
|
||||
IF_ASSERT_FAILED(m_fluid->synth) {
|
||||
return;
|
||||
}
|
||||
|
||||
fluid_synth_all_sounds_off(m_fluid->synth, chan);
|
||||
}
|
||||
|
||||
bool FluidLiteSynth::channelVolume(uint16_t chan, float volume)
|
||||
{
|
||||
IF_ASSERT_FAILED(m_fluid->synth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int val = static_cast<int>(volume * 100.f);
|
||||
val = clamp(val, 0, 127);
|
||||
|
||||
int ret = fluid_synth_cc(m_fluid->synth, chan, VOLUME_MSB, val);
|
||||
return ret == FLUID_OK;
|
||||
}
|
||||
|
||||
bool FluidLiteSynth::channelBalance(uint16_t chan, float balance)
|
||||
{
|
||||
IF_ASSERT_FAILED(m_fluid->synth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
balance = clamp(balance, -1.f, 1.f);
|
||||
float normalized = (balance < 0 ? 63 : 64) + 63 * balance;
|
||||
int val = static_cast<int>(std::lround(normalized));
|
||||
val = clamp(val, 0, 127);
|
||||
|
||||
int ret = fluid_synth_cc(m_fluid->synth, chan, PAN_MSB, val);
|
||||
return ret == FLUID_OK;
|
||||
}
|
||||
|
||||
bool FluidLiteSynth::channelPitch(uint16_t chan, int16_t pitch)
|
||||
{
|
||||
// 0-16383 with 8192 being center
|
||||
|
||||
IF_ASSERT_FAILED(m_fluid->synth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pitch = clamp(pitch, static_cast<int16_t>(-12), static_cast<int16_t>(12));
|
||||
|
||||
int32_t val = (8192 * pitch) / 12;
|
||||
val = 8192 + val;
|
||||
val = clamp(val, 0, 16383);
|
||||
|
||||
int ret = fluid_synth_pitch_bend(m_fluid->synth, chan, val);
|
||||
return ret == FLUID_OK;
|
||||
}
|
||||
|
||||
void FluidLiteSynth::writeBuf(float* stream, unsigned int len)
|
||||
{
|
||||
IF_ASSERT_FAILED(len > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fluid_synth_write_float(m_fluid->synth, static_cast<int>(len), stream, 0, 1, stream, static_cast<int>(len), 1);
|
||||
}
|
103
framework/audio/midi/internal/fluidlitesynth.h
Normal file
103
framework/audio/midi/internal/fluidlitesynth.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_FLUIDLITESYNTH_H
|
||||
#define MU_AUDIO_FLUIDLITESYNTH_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
#include "../isynthesizer.h"
|
||||
#include "../miditypes.h"
|
||||
|
||||
#include "modularity/ioc.h"
|
||||
#include "isoundfontfileprovider.h"
|
||||
|
||||
//! NOTE Used for the test, the main synthesizer will not be this one.
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
struct Fluid;
|
||||
class FluidLiteSynth : public ISynthesizer
|
||||
{
|
||||
INJECT(midi, ISoundFontFileProvider, sfprovider)
|
||||
|
||||
public:
|
||||
FluidLiteSynth();
|
||||
~FluidLiteSynth() override;
|
||||
|
||||
void loadSF(const Programs& programs,const std::string& overridden_sf,const OnLoadingChanged& onloading) override;
|
||||
|
||||
void init(float samplerate, float gain, const OnInited& oninited) override;
|
||||
|
||||
void setGain(float gain) override;
|
||||
|
||||
bool handleEvent(uint16_t chan, const Event& e) override;
|
||||
|
||||
void allSoundsOff() override; // all channels
|
||||
void flushSound() override;
|
||||
|
||||
void channelSoundsOff(uint16_t chan) override;
|
||||
bool channelVolume(uint16_t chan, float val) override; // 0. - 1.
|
||||
bool channelBalance(uint16_t chan, float val) override; // -1. - 1.
|
||||
bool channelPitch(uint16_t chan, int16_t pitch) override; // -12 - 12
|
||||
|
||||
void writeBuf(float* stream, unsigned int len) override;
|
||||
|
||||
private:
|
||||
|
||||
void doInit(float samplerate, float gain, const OnInited& oninited);
|
||||
bool init_synth(const std::string& sf_path, float samplerate, float gain);
|
||||
|
||||
const Program& program(uint16_t chan) const;
|
||||
|
||||
enum midi_control
|
||||
{
|
||||
BANK_SELECT_MSB = 0x00,
|
||||
VOLUME_MSB = 0x07,
|
||||
BALANCE_MSB = 0x08,
|
||||
PAN_MSB = 0x0A
|
||||
};
|
||||
|
||||
struct SF {
|
||||
bool loaded{ false };
|
||||
std::vector<Program> programs;
|
||||
std::string file_path;
|
||||
std::function<void()> onLoaded;
|
||||
};
|
||||
|
||||
SF m_sf;
|
||||
std::shared_ptr<Fluid> m_fluid{ nullptr };
|
||||
float m_gain = 1.0f;
|
||||
int16_t m_generalPitch = 0;
|
||||
bool m_isLoggingSynthEvents = false;
|
||||
|
||||
std::vector<float> m_preallocated; // used to flush a sound
|
||||
float m_sampleRate = 44100.0f;
|
||||
|
||||
int m_sfontID = -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //MU_AUDIO_FLUIDLITESYNTH_H
|
410
framework/audio/midi/internal/sequencer.cpp
Normal file
410
framework/audio/midi/internal/sequencer.cpp
Normal file
|
@ -0,0 +1,410 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#include "sequencer.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "log.h"
|
||||
#include "realfn.h"
|
||||
|
||||
using namespace mu::audio::midi;
|
||||
|
||||
Sequencer::~Sequencer()
|
||||
{
|
||||
if (m_status == Running) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void Sequencer::loadMIDI(const std::shared_ptr<MidiData>& midi)
|
||||
{
|
||||
m_midi = midi;
|
||||
buildTempoMap();
|
||||
synth()->loadSF(m_midi->programs(), "", [this](uint16_t percent) {
|
||||
LOGI() << "sf loading: " << percent;
|
||||
});
|
||||
}
|
||||
|
||||
void Sequencer::init(float samplerate, float gain)
|
||||
{
|
||||
reset();
|
||||
|
||||
m_sampleRate = samplerate;
|
||||
|
||||
synth()->init(samplerate, gain, [this, samplerate](bool success) {
|
||||
if (!success) {
|
||||
m_status = Error;
|
||||
LOGE() << "failed init sequencer (failed init synth)\n";
|
||||
} else {
|
||||
LOGD() << "success init sequencer, samplerate: " << samplerate << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Sequencer::changeGain(float gain)
|
||||
{
|
||||
synth()->setGain(gain);
|
||||
}
|
||||
|
||||
void Sequencer::process(float sec)
|
||||
{
|
||||
if (!m_internalRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t msec = static_cast<uint64_t>(sec * 1000);
|
||||
uint64_t delta = msec - m_lastTimerMsec;
|
||||
|
||||
if (delta < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
player_callback(delta);
|
||||
m_lastTimerMsec = msec;
|
||||
}
|
||||
|
||||
float Sequencer::getAudio(float sec, float* buf, unsigned int len)
|
||||
{
|
||||
process(sec);
|
||||
|
||||
synth()->writeBuf(buf, len);
|
||||
|
||||
float cur_sec = static_cast<float>(m_curMsec) / 1000.f;
|
||||
return cur_sec;
|
||||
}
|
||||
|
||||
bool Sequencer::hasEnded() const
|
||||
{
|
||||
for (const Track& t : m_midi->tracks) {
|
||||
for (const Channel& c : t.channels) {
|
||||
if (!channel_eot(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Sequencer::Status Sequencer::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
bool Sequencer::run(float init_sec)
|
||||
{
|
||||
if (m_status == Running) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_status == Error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IF_ASSERT_FAILED(m_midi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastTimerMsec = static_cast<uint64_t>(init_sec * 1000);
|
||||
doRun();
|
||||
m_status = Running;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sequencer::stop()
|
||||
{
|
||||
LOGI() << "Sequencer::stop\n";
|
||||
doStop();
|
||||
reset();
|
||||
m_status = Stoped;
|
||||
}
|
||||
|
||||
void Sequencer::reset()
|
||||
{
|
||||
m_curMsec = 0;
|
||||
m_seekMsec = 0;
|
||||
for (auto it = m_chanStates.begin(); it != m_chanStates.end(); ++it) {
|
||||
it->second.eventIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sequencer::doRun()
|
||||
{
|
||||
m_curMsec = m_seekMsec;
|
||||
m_internalRunning = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sequencer::doStop()
|
||||
{
|
||||
m_internalRunning = false;
|
||||
synth()->flushSound();
|
||||
}
|
||||
|
||||
void Sequencer::doSeekChan(uint32_t seek_ticks, const Channel& c)
|
||||
{
|
||||
ChanState& state = m_chanStates[c.num];
|
||||
state.eventIndex = 0;
|
||||
|
||||
for (size_t i = 0; i < c.events.size(); ++i) {
|
||||
state.eventIndex = i;
|
||||
const Event& event = c.events.at(i);
|
||||
if (event.tick >= seek_ticks) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sequencer::doSeek(uint64_t seek_msec)
|
||||
{
|
||||
m_internalRunning = false;
|
||||
|
||||
m_seekMsec = seek_msec;
|
||||
uint32_t seek_ticks = ticks(m_seekMsec);
|
||||
|
||||
for (const Track& t : m_midi->tracks) {
|
||||
for (const Channel& c : t.channels) {
|
||||
doSeekChan(seek_ticks, c);
|
||||
}
|
||||
}
|
||||
|
||||
m_curMsec = m_seekMsec;
|
||||
m_internalRunning = true;
|
||||
}
|
||||
|
||||
float Sequencer::playbackPosition() const
|
||||
{
|
||||
return m_curMsec / 1000.f;
|
||||
}
|
||||
|
||||
void Sequencer::seek(float sec)
|
||||
{
|
||||
doSeek(static_cast<uint64_t>(sec * 1000.f));
|
||||
synth()->flushSound();
|
||||
}
|
||||
|
||||
uint64_t Sequencer::max_ticks(const std::vector<Track>& tracks) const
|
||||
{
|
||||
uint64_t maxTicks = 0;
|
||||
|
||||
auto findMaxTicks = [&maxTicks](const Channel& c) {
|
||||
for (const Event& e : c.events) {
|
||||
if (e.tick > maxTicks) {
|
||||
maxTicks = e.tick;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const Track& t : tracks) {
|
||||
for (const Channel& c : t.channels) {
|
||||
findMaxTicks(c);
|
||||
}
|
||||
}
|
||||
|
||||
return maxTicks;
|
||||
}
|
||||
|
||||
bool Sequencer::channel_eot(const Channel& chan) const
|
||||
{
|
||||
const ChanState& s = m_chanStates[chan.num];
|
||||
if (s.eventIndex >= chan.events.size()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sequencer::buildTempoMap()
|
||||
{
|
||||
IF_ASSERT_FAILED(m_midi) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_tempoMap.clear();
|
||||
|
||||
std::vector<std::pair<uint32_t, uint32_t> > tempos;
|
||||
for (const auto& it : m_midi->tempomap) {
|
||||
tempos.push_back({ it.first, it.second });
|
||||
}
|
||||
|
||||
if (tempos.empty()) {
|
||||
//! NOTE If temp is not set, then set the default temp to 120
|
||||
tempos.push_back({ 0, 500000 });
|
||||
}
|
||||
|
||||
uint64_t msec{ 0 };
|
||||
for (size_t i = 0; i < tempos.size(); ++i) {
|
||||
TempoItem t;
|
||||
|
||||
t.tempo = tempos.at(i).second;
|
||||
t.startTicks = tempos.at(i).first;
|
||||
t.startMsec = msec;
|
||||
t.onetickMsec = static_cast<double>(t.tempo)
|
||||
/ static_cast<double>(m_midi->division)
|
||||
/ 1000.;
|
||||
|
||||
uint32_t end_ticks = ((i + 1) < tempos.size()) ? tempos.at(i + 1).first : std::numeric_limits<uint32_t>::max();
|
||||
|
||||
uint32_t delta_ticks = end_ticks - t.startTicks;
|
||||
msec += static_cast<uint64_t>(delta_ticks * t.onetickMsec);
|
||||
|
||||
m_tempoMap.insert({ msec, std::move(t) });
|
||||
|
||||
// LOGI() << "TempoItem t.tick: " << t.start_ticks
|
||||
// << ", t.tempo: " << t.tempo
|
||||
// << ", t.onetick_msec: " << t.onetick_msec
|
||||
// << ", end_msec: " << msec;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Sequencer::ticks(uint64_t msec) const
|
||||
{
|
||||
auto it = m_tempoMap.lower_bound(msec);
|
||||
|
||||
const TempoItem& t = it->second;
|
||||
|
||||
uint64_t delta = msec - t.startMsec;
|
||||
uint32_t ticks = static_cast<uint32_t>(delta / t.onetickMsec);
|
||||
return t.startTicks + ticks;
|
||||
}
|
||||
|
||||
bool Sequencer::player_callback(uint64_t timer_msec)
|
||||
{
|
||||
// static uint64_t last_msec{0};
|
||||
// LOGI() << "msec: " << timer_msec << ", delta: " << (timer_msec - last_msec) << "\n";
|
||||
// last_msec = timer_msec;
|
||||
|
||||
m_curMsec += (timer_msec * m_playSpeed);
|
||||
|
||||
uint32_t cur_ticks = ticks(m_curMsec);
|
||||
// LOGI() << "timer_msec: " << timer_msec
|
||||
// << ", cur_msec: " << _cur_msec
|
||||
// << ", cur_ticks: " << cur_ticks
|
||||
// << "\n";
|
||||
|
||||
auto sendEvents = [this, cur_ticks](const Channel& c) {
|
||||
if (!channel_eot(c)) {
|
||||
if (!send_chan_events(c, cur_ticks)) {
|
||||
LOGE() << "failed send events\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const Track& t : m_midi->tracks) {
|
||||
for (const Channel& c : t.channels) {
|
||||
sendEvents(c);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sequencer::send_chan_events(const Channel& chan, uint32_t ticks)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
ChanState& state = m_chanStates[chan.num];
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (channel_eot(chan)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const Event& event = chan.events.at(state.eventIndex);
|
||||
if (event.tick > ticks) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (state.muted || event.type == MIDI_EOT || event.type == META_TEMPO) {
|
||||
// noop
|
||||
} else {
|
||||
synth()->handleEvent(chan.num, event);
|
||||
}
|
||||
|
||||
++state.eventIndex;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float Sequencer::playbackSpeed() const
|
||||
{
|
||||
return m_playSpeed;
|
||||
}
|
||||
|
||||
void Sequencer::setPlaybackSpeed(float speed)
|
||||
{
|
||||
m_playSpeed = speed;
|
||||
}
|
||||
|
||||
bool Sequencer::isHasTrack(uint16_t ti) const
|
||||
{
|
||||
if (!m_midi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ti < m_midi->tracks.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sequencer::setIsTrackMuted(int ti, bool mute)
|
||||
{
|
||||
IF_ASSERT_FAILED(isHasTrack(ti)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto setMuted = [this, mute](const Channel& c) {
|
||||
ChanState& state = m_chanStates[c.num];
|
||||
state.muted = mute;
|
||||
synth()->channelSoundsOff(c.num);
|
||||
};
|
||||
|
||||
const Track& track = m_midi->tracks[ti];
|
||||
for (const Channel& c : track.channels) {
|
||||
setMuted(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Sequencer::setTrackVolume(int ti, float volume)
|
||||
{
|
||||
IF_ASSERT_FAILED(isHasTrack(ti)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Track& track = m_midi->tracks[ti];
|
||||
for (const Channel& c : track.channels) {
|
||||
synth()->channelVolume(c.num, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void Sequencer::setTrackBalance(int ti, float balance)
|
||||
{
|
||||
IF_ASSERT_FAILED(isHasTrack(ti)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Track& track = m_midi->tracks[ti];
|
||||
for (const Channel& c : track.channels) {
|
||||
synth()->channelBalance(c.num, balance);
|
||||
}
|
||||
}
|
130
framework/audio/midi/internal/sequencer.h
Normal file
130
framework/audio/midi/internal/sequencer.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_SEQUENCER_H
|
||||
#define MU_AUDIO_SEQUENCER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include "../isequencer.h"
|
||||
#include "../miditypes.h"
|
||||
#include "modularity/ioc.h"
|
||||
#include "../isynthesizer.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
class ISynthesizer;
|
||||
class Sequencer : public ISequencer
|
||||
{
|
||||
INJECT(midi, ISynthesizer, synth)
|
||||
|
||||
public:
|
||||
Sequencer() = default;
|
||||
~Sequencer() override;
|
||||
|
||||
enum Status {
|
||||
Stoped = 0,
|
||||
Running,
|
||||
Error
|
||||
};
|
||||
|
||||
Status status() const;
|
||||
|
||||
void loadMIDI(const std::shared_ptr<MidiData>& midi);
|
||||
void init(float samplerate, float gain = 1);
|
||||
|
||||
void changeGain(float gain);
|
||||
|
||||
bool run(float init_sec) override;
|
||||
void seek(float sec) override;
|
||||
void stop() override;
|
||||
|
||||
float getAudio(float sec, float* buf, unsigned int len) override;
|
||||
bool hasEnded() const override;
|
||||
|
||||
float playbackPosition() const;
|
||||
|
||||
float playbackSpeed() const override;
|
||||
void setPlaybackSpeed(float speed) override;
|
||||
|
||||
void setIsTrackMuted(int t, bool mute) override;
|
||||
void setTrackVolume(int ti, float volume) override;
|
||||
void setTrackBalance(int ti, float balance) override;
|
||||
|
||||
private:
|
||||
|
||||
void process(float sec);
|
||||
|
||||
void reset();
|
||||
uint64_t max_ticks(const std::vector<Track>& tracks) const;
|
||||
bool channel_eot(const Channel& chan) const;
|
||||
bool player_callback(uint64_t msec);
|
||||
bool send_chan_events(const Channel& chan, uint32_t ticks);
|
||||
|
||||
void buildTempoMap();
|
||||
|
||||
uint32_t ticks(uint64_t msec) const;
|
||||
|
||||
bool isHasTrack(uint16_t num) const;
|
||||
|
||||
bool doRun();
|
||||
void doStop();
|
||||
void doSeek(uint64_t seek_msec);
|
||||
void doSeekChan(uint32_t seek_ticks, const Channel& c);
|
||||
|
||||
struct TempoItem {
|
||||
uint32_t tempo = 500000;
|
||||
uint32_t startTicks = 0;
|
||||
uint64_t startMsec = 0;
|
||||
double onetickMsec = 0.0;
|
||||
};
|
||||
std::map<uint64_t /*msec*/, TempoItem> m_tempoMap;
|
||||
|
||||
Status m_status = Stoped;
|
||||
bool m_internalRunning = false;
|
||||
|
||||
std::shared_ptr<MidiData> m_midi;
|
||||
|
||||
double m_oneTickMsec = 1;
|
||||
|
||||
float m_sampleRate = 44100.0f;
|
||||
float m_playSpeed = 1.0;
|
||||
|
||||
uint64_t m_lastTimerMsec = 0;
|
||||
uint64_t m_curMsec = 0;
|
||||
uint64_t m_seekMsec = 0;
|
||||
|
||||
struct ChanState {
|
||||
bool muted = false;
|
||||
size_t eventIndex = 0;
|
||||
};
|
||||
mutable std::map<uint16_t, ChanState> m_chanStates;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_SEQUENCER_H
|
35
framework/audio/midi/internal/sffproviderlocalfile.cpp
Normal file
35
framework/audio/midi/internal/sffproviderlocalfile.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#include "sffproviderlocalfile.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
using namespace mu::audio::midi;
|
||||
|
||||
void SFFProviderLocalFile::loadSF(const midi::Programs& programs, const OnLoading& onloading, const OnLoaded& onloaded)
|
||||
{
|
||||
|
||||
//! NOTE For tests
|
||||
io::path sffilePath = globalConfiguration()->dataPath() + "/sound/GeneralUser GS v1.471.sf2";
|
||||
|
||||
onloading(100);
|
||||
onloaded(true, sffilePath, programs);
|
||||
}
|
||||
|
44
framework/audio/midi/internal/sffproviderlocalfile.h
Normal file
44
framework/audio/midi/internal/sffproviderlocalfile.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_SFFPROVIDER_LOCALFILE_H
|
||||
#define MU_SFFPROVIDER_LOCALFILE_H
|
||||
|
||||
#include <string>
|
||||
#include "../isoundfontfileprovider.h"
|
||||
|
||||
#include "modularity/ioc.h"
|
||||
#include "iglobalconfiguration.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
class SFFProviderLocalFile : public ISoundFontFileProvider
|
||||
{
|
||||
INJECT(midi, framework::IGlobalConfiguration, globalConfiguration)
|
||||
|
||||
public:
|
||||
|
||||
void loadSF(const midi::Programs& programs, const OnLoading& onloading, const OnLoaded& onloaded) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_SFFPROVIDER_LOCALFILE_H
|
61
framework/audio/midi/isequencer.h
Normal file
61
framework/audio/midi/isequencer.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_ISEQUENCER_H
|
||||
#define MU_AUDIO_ISEQUENCER_H
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "modularity/imoduleexport.h"
|
||||
#include "miditypes.h"
|
||||
#include "async/channel.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
class ISequencer : MODULE_EXPORT_INTERFACE
|
||||
{
|
||||
INTERFACE_ID(ISequencer)
|
||||
public:
|
||||
virtual ~ISequencer() = default;
|
||||
|
||||
virtual void loadMIDI(const std::shared_ptr<MidiData>& midi) = 0;
|
||||
virtual void init(float samplerate, float gain = 1) = 0;
|
||||
|
||||
virtual bool run(float init_sec) = 0;
|
||||
virtual void seek(float sec) = 0;
|
||||
virtual void stop() = 0;
|
||||
|
||||
virtual float getAudio(float sec, float* buf, unsigned int len) = 0;
|
||||
virtual bool hasEnded() const = 0;
|
||||
|
||||
virtual float playbackSpeed() const = 0;
|
||||
virtual void setPlaybackSpeed(float speed) = 0;
|
||||
|
||||
virtual void setIsTrackMuted(int t, bool mute) = 0;
|
||||
virtual void setTrackVolume(int ti, float volume) = 0;
|
||||
virtual void setTrackBalance(int ti, float balance) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_ISEQUENCER_H
|
48
framework/audio/midi/isoundfontfileprovider.h
Normal file
48
framework/audio/midi/isoundfontfileprovider.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_ISOUNDFONTFILEPROVIDER_H
|
||||
#define MU_AUDIO_ISOUNDFONTFILEPROVIDER_H
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include "modularity/imoduleexport.h"
|
||||
#include "miditypes.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
class ISoundFontFileProvider : MODULE_EXPORT_INTERFACE
|
||||
{
|
||||
INTERFACE_ID(ISoundFontFileProvider)
|
||||
|
||||
public:
|
||||
virtual ~ISoundFontFileProvider() = default;
|
||||
|
||||
using OnLoading = std::function<void (uint16_t percent)>;
|
||||
using OnLoaded = std::function<void (bool, const std::string& sf_path, const std::vector<midi::Program>& progs)>;
|
||||
|
||||
virtual void loadSF(const midi::Programs& programs, const OnLoading& onloading, const OnLoaded& onloaded) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_ISOUNDFONTFILEPROVIDER_H
|
64
framework/audio/midi/isynthesizer.h
Normal file
64
framework/audio/midi/isynthesizer.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_ISYNTHESIZER_H
|
||||
#define MU_AUDIO_ISYNTHESIZER_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "modularity/imoduleexport.h"
|
||||
|
||||
#include "miditypes.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
class ISynthesizer : MODULE_EXPORT_INTERFACE
|
||||
{
|
||||
INTERFACE_ID(ISynthesizer)
|
||||
|
||||
public:
|
||||
virtual ~ISynthesizer() = default;
|
||||
|
||||
using OnLoadingChanged = std::function<void (uint16_t percent)>;
|
||||
using OnInited = std::function<void (bool success)>;
|
||||
|
||||
virtual void loadSF(const Programs& programs, const std::string& overridden_sf,
|
||||
const OnLoadingChanged& onloading) = 0;
|
||||
|
||||
virtual void init(float samplerate, float gain, const OnInited& oninited) = 0;
|
||||
|
||||
virtual void setGain(float gain) = 0;
|
||||
|
||||
virtual bool handleEvent(uint16_t chan, const Event& e) = 0;
|
||||
|
||||
virtual void allSoundsOff() = 0; // all channels
|
||||
virtual void flushSound() = 0;
|
||||
virtual void channelSoundsOff(uint16_t chan) = 0;
|
||||
virtual bool channelVolume(uint16_t chan, float val) = 0; // 0. - 1.
|
||||
virtual bool channelBalance(uint16_t chan, float val) = 0; // -1. - 1.
|
||||
virtual bool channelPitch(uint16_t chan, int16_t val) = 0; // -12 - 12
|
||||
|
||||
virtual void writeBuf(float* stream, unsigned int len) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_ISYNTHESIZER_H
|
38
framework/audio/midi/midimodule.cpp
Normal file
38
framework/audio/midi/midimodule.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#include "midimodule.h"
|
||||
|
||||
#include "modularity/ioc.h"
|
||||
#include "internal/fluidlitesynth.h"
|
||||
#include "internal/sequencer.h"
|
||||
#include "internal/sffproviderlocalfile.h"
|
||||
|
||||
using namespace mu::audio::midi;
|
||||
|
||||
std::string MidiModule::moduleName() const
|
||||
{
|
||||
return "audio_midi";
|
||||
}
|
||||
|
||||
void MidiModule::registerExports()
|
||||
{
|
||||
framework::ioc()->registerExport<ISynthesizer>(moduleName(), new FluidLiteSynth());
|
||||
framework::ioc()->registerExport<ISequencer>(moduleName(), new Sequencer());
|
||||
framework::ioc()->registerExport<ISoundFontFileProvider>(moduleName(), new SFFProviderLocalFile());
|
||||
}
|
39
framework/audio/midi/midimodule.h
Normal file
39
framework/audio/midi/midimodule.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#ifndef MU_AUDIO_MIDIMODULE_H
|
||||
#define MU_AUDIO_MIDIMODULE_H
|
||||
|
||||
#include "modularity/imodulesetup.h"
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
class MidiModule : public framework::IModuleSetup
|
||||
{
|
||||
public:
|
||||
|
||||
std::string moduleName() const override;
|
||||
|
||||
void registerExports() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_MIDIMODULE_H
|
213
framework/audio/midi/miditypes.h
Normal file
213
framework/audio/midi/miditypes.h
Normal file
|
@ -0,0 +1,213 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MU_AUDIO_MIDITYPES_H
|
||||
#define MU_AUDIO_MIDITYPES_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
namespace mu {
|
||||
namespace audio {
|
||||
namespace midi {
|
||||
enum EventType {
|
||||
ME_INVALID = 0,
|
||||
ME_NOTEOFF,
|
||||
ME_NOTEON,
|
||||
ME_CONTROLLER,
|
||||
ME_PITCHBEND,
|
||||
ME_META,
|
||||
META_TEMPO,
|
||||
ME_PROGRAMCHANGE,
|
||||
ME_ALLNOTESOFF,
|
||||
|
||||
MIDI_EOT
|
||||
};
|
||||
|
||||
enum CntrType {
|
||||
CTRL_INVALID = 0,
|
||||
CTRL_PROGRAM
|
||||
};
|
||||
|
||||
struct Event {
|
||||
uint32_t tick{ 0 };
|
||||
EventType type{ ME_INVALID };
|
||||
int a{ 0 };
|
||||
int b{ 0 };
|
||||
|
||||
Event() = default;
|
||||
Event(uint32_t tick, EventType type, int a, int b)
|
||||
: tick(tick), type(type), a(a), b(b) {}
|
||||
|
||||
bool operator ==(const Event& other) const
|
||||
{
|
||||
return tick == other.tick && type == other.type
|
||||
&& a == other.a && b == other.b;
|
||||
}
|
||||
|
||||
bool operator !=(const Event& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
static std::string type_to_string(EventType t)
|
||||
{
|
||||
switch (t) {
|
||||
case EventType::ME_INVALID: return "INVALID";
|
||||
case EventType::ME_NOTEOFF: return "NOTEOFF";
|
||||
case EventType::ME_NOTEON: return "NOTEON";
|
||||
case EventType::ME_CONTROLLER: return "CONTROLLER";
|
||||
case EventType::ME_PITCHBEND: return "PITCHBEND";
|
||||
case EventType::ME_META: return "META";
|
||||
case EventType::META_TEMPO: return "TEMPO";
|
||||
case EventType::ME_PROGRAMCHANGE: return "PROGRAMCHANGE";
|
||||
case EventType::ME_ALLNOTESOFF: return "ALLNOTESOFF";
|
||||
case EventType::MIDI_EOT: return "EOT";
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string cc_to_string(int cc)
|
||||
{
|
||||
switch (cc) {
|
||||
case 2: return "BREATH_MSB";
|
||||
default: return std::to_string(cc);
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
std::string str;
|
||||
str += "tick: " + std::to_string(tick);
|
||||
str += ", type: " + type_to_string(type);
|
||||
switch (type) {
|
||||
case EventType::ME_NOTEON: {
|
||||
str += ", key: " + std::to_string(a);
|
||||
str += ", vel: " + std::to_string(b);
|
||||
} break;
|
||||
case EventType::ME_NOTEOFF: {
|
||||
str += ", key: " + std::to_string(a);
|
||||
} break;
|
||||
case EventType::ME_CONTROLLER: {
|
||||
str += ", cc: " + cc_to_string(a);
|
||||
str += ", val: " + std::to_string(b);
|
||||
} break;
|
||||
case EventType::ME_PITCHBEND: {
|
||||
int pitch = b << 7 | a;
|
||||
str += ", pitch: " + std::to_string(pitch);
|
||||
} break;
|
||||
default:
|
||||
str += ", a: " + std::to_string(a);
|
||||
str += ", b: " + std::to_string(b);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
uint16_t num{ 0 };
|
||||
uint16_t bank{ 0 };
|
||||
uint16_t program{ 0 };
|
||||
std::vector<Event> events;
|
||||
};
|
||||
|
||||
struct Track {
|
||||
std::vector<Channel> channels;
|
||||
};
|
||||
|
||||
struct Program {
|
||||
uint16_t ch{ 0 };
|
||||
uint16_t prog{ 0 };
|
||||
uint16_t bank{ 0 };
|
||||
};
|
||||
|
||||
using Programs = std::vector<midi::Program>;
|
||||
|
||||
struct MidiData {
|
||||
uint16_t division{ 480 };
|
||||
std::map<uint32_t /*tick*/, uint32_t /*tempo*/> tempomap;
|
||||
std::vector<Track> tracks;
|
||||
|
||||
Programs programs() const
|
||||
{
|
||||
Programs progs;
|
||||
for (const Track& t : tracks) {
|
||||
for (const Channel& ch : t.channels) {
|
||||
Program p;
|
||||
p.ch = ch.num;
|
||||
p.bank = ch.bank;
|
||||
p.prog = ch.program;
|
||||
progs.push_back(std::move(p));
|
||||
}
|
||||
}
|
||||
|
||||
return progs;
|
||||
}
|
||||
|
||||
uint16_t channelsCount() const
|
||||
{
|
||||
uint16_t c = 0;
|
||||
for (const Track& t : tracks) {
|
||||
c += t.channels.size();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::string dump(bool withEvents = false)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "division: " << division << "\n";
|
||||
ss << "tempo changes: " << tempomap.size() << "\n";
|
||||
for (const auto& it : tempomap) {
|
||||
ss << " tick: " << it.first << ", tempo: " << it.second << "\n";
|
||||
}
|
||||
ss << "\n";
|
||||
ss << "tracks count: " << tracks.size() << "\n";
|
||||
ss << "channels count: " << channelsCount() << "\n";
|
||||
for (size_t ti = 0; ti < tracks.size(); ++ti) {
|
||||
ss << "track: " << ti << ", channels: " << tracks.at(ti).channels.size() << "\n";
|
||||
for (const Channel& ch : tracks.at(ti).channels) {
|
||||
ss << " ch num: " << ch.num
|
||||
<< ", bank: " << ch.bank
|
||||
<< ", prog: " << ch.program
|
||||
<< ", events: " << ch.events.size()
|
||||
<< "\n";
|
||||
|
||||
if (withEvents) {
|
||||
for (const Event& e : ch.events) {
|
||||
ss << e.to_string() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ss.flush();
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_AUDIO_MIDITYPES_H
|
|
@ -88,6 +88,7 @@ if (BUILD_UI_MU4)
|
|||
shortcuts
|
||||
workspace
|
||||
audio_engine
|
||||
audio_midi
|
||||
scores
|
||||
extensions
|
||||
importexport
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "framework/shortcuts/shortcutsmodule.h"
|
||||
#include "framework/workspace/workspacemodule.h"
|
||||
#include "framework/audio/engine/audioenginemodule.h"
|
||||
#include "framework/audio/midi/midimodule.h"
|
||||
#include "mu4/appshell/appshellmodule.h"
|
||||
#include "mu4/cloud/cloudmodule.h"
|
||||
#include "mu4/context/contextmodule.h"
|
||||
|
@ -63,6 +64,7 @@ ModulesSetup::ModulesSetup()
|
|||
<< new mu::shortcuts::ShortcutsModule()
|
||||
<< new mu::workspace::WorkspaceModule()
|
||||
<< new mu::audio::engine::AudioEngineModule()
|
||||
<< new mu::audio::midi::MidiModule()
|
||||
<< new mu::scores::ScoresModule()
|
||||
<< new mu::extensions::ExtensionsModule()
|
||||
<< new mu::domain::notation::NotationDomainModule()
|
||||
|
|
|
@ -10,20 +10,61 @@ Rectangle {
|
|||
id: devtools
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 40
|
||||
FlatButton {
|
||||
text: "Play"
|
||||
width: 80
|
||||
onClicked: devtools.playSine()
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 40
|
||||
spacing: 8
|
||||
FlatButton {
|
||||
text: "Play Sine"
|
||||
width: 120
|
||||
onClicked: devtools.playSine()
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
text: "Stop Sine"
|
||||
width: 120
|
||||
onClicked: devtools.stopSine()
|
||||
}
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
text: "Stop"
|
||||
width: 80
|
||||
onClicked: devtools.stopSine()
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 40
|
||||
spacing: 8
|
||||
FlatButton {
|
||||
text: "Play Source Midi"
|
||||
width: 120
|
||||
onClicked: devtools.playSourceMidi()
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
text: "Stop Source Midi"
|
||||
width: 120
|
||||
onClicked: devtools.stopSourceMidi()
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 40
|
||||
spacing: 8
|
||||
FlatButton {
|
||||
text: "Play Player Midi"
|
||||
width: 120
|
||||
onClicked: devtools.playPlayerMidi()
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
text: "Stop Player Midi"
|
||||
width: 120
|
||||
onClicked: devtools.stopPlayerMidi()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue