|
|
|
|
File: [ls] / linuxsampler / src / Sampler.cpp
(download)
/
(as text)
Revision: 1.28, Tue Jun 27 21:57:35 2006 UTC (3 years, 7 months ago) by schoenebeck Branch: MAIN Changes since 1.27: +13 -13 lines just some refactoring work: - renamed class LinuxSamplerException -> Exception - encapsulated LS API relevant files into LS namespace - removed unnecessary header inclusions |
This file is part of LinuxSampler, which is licensed under the GNU GPL with the exception that USAGE of the source code, libraries and applications FOR COMMERCIAL HARDWARE OR SOFTWARE PRODUCTS IS NOT ALLOWED without prior written permission by the LinuxSampler authors. If you have questions on the subject, that are not yet covered by the FAQ, please contact us.
/***************************************************************************
* *
* LinuxSampler - modular, streaming capable sampler *
* *
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
* Copyright (C) 2005, 2006 Christian Schoenebeck *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
***************************************************************************/
#include <sstream>
#include "Sampler.h"
#include "engines/EngineFactory.h"
#include "engines/EngineChannelFactory.h"
#include "drivers/audio/AudioOutputDeviceFactory.h"
#include "drivers/midi/MidiInputDeviceFactory.h"
#include "network/lscpserver.h"
namespace LinuxSampler {
// ******************************************************************
// * SamplerChannel
SamplerChannel::SamplerChannel(Sampler* pS) {
pSampler = pS;
pEngineChannel = NULL;
pAudioOutputDevice = NULL;
pMidiInputDevice = NULL;
iMidiPort = 0;
midiChannel = midi_chan_all;
iIndex = -1;
}
SamplerChannel::~SamplerChannel() {
if (pEngineChannel) {
Engine* engine = pEngineChannel->GetEngine();
if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine);
MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort() : __GetMidiInputDevicePort(GetMidiInputChannel());
if (pMidiInputPort) pMidiInputPort->Disconnect(pEngineChannel);
if (pEngineChannel) {
if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice();
EngineChannelFactory::Destroy(pEngineChannel);
// reconnect engine if it still exists
const std::set<Engine*>& engines = EngineFactory::EngineInstances();
if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine);
}
}
}
void SamplerChannel::SetEngineType(String EngineType) throw (Exception) {
dmsg(2,("SamplerChannel: Assigning engine type..."));
// create new engine channel
EngineChannel* pNewEngineChannel = EngineChannelFactory::Create(EngineType);
if (!pNewEngineChannel) throw Exception("Unknown engine type");
//FIXME: hack to allow fast retrieval of engine channel's sampler channel index
pNewEngineChannel->iSamplerChannelIndex = Index();
// dereference midi input port.
MidiInputPort* pMidiInputPort = __GetMidiInputDevicePort(GetMidiInputPort());
// disconnect old engine channel
if (pEngineChannel) {
Engine* engine = pEngineChannel->GetEngine();
if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine);
if (pMidiInputPort) pMidiInputPort->Disconnect(pEngineChannel);
if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice();
EngineChannelFactory::Destroy(pEngineChannel);
// reconnect engine if it still exists
const std::set<Engine*>& engines = EngineFactory::EngineInstances();
if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine);
}
// connect new engine channel
if (pAudioOutputDevice) {
pNewEngineChannel->Connect(pAudioOutputDevice);
pAudioOutputDevice->Connect(pNewEngineChannel->GetEngine());
}
if (pMidiInputPort) pMidiInputPort->Connect(pNewEngineChannel, GetMidiInputChannel());
pEngineChannel = pNewEngineChannel;
// from now on get MIDI device and port from EngineChannel object
this->pMidiInputDevice = NULL;
this->iMidiPort = 0;
pEngineChannel->StatusChanged(true);
dmsg(2,("OK\n"));
}
void SamplerChannel::SetAudioOutputDevice(AudioOutputDevice* pDevice) {
// disconnect old device
if (pAudioOutputDevice && pEngineChannel) {
Engine* engine = pEngineChannel->GetEngine();
pAudioOutputDevice->Disconnect(engine);
pEngineChannel->DisconnectAudioOutputDevice();
// reconnect engine if it still exists
const std::set<Engine*>& engines = EngineFactory::EngineInstances();
if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine);
}
// connect new device
pAudioOutputDevice = pDevice;
if (pEngineChannel) {
pEngineChannel->Connect(pAudioOutputDevice);
pAudioOutputDevice->Connect(pEngineChannel->GetEngine());
}
}
void SamplerChannel::SetMidiInputDevice(MidiInputDevice* pDevice) {
SetMidiInput(pDevice, 0, GetMidiInputChannel());
}
void SamplerChannel::SetMidiInputPort(int MidiPort) {
SetMidiInput(GetMidiInputDevice(), MidiPort, GetMidiInputChannel());
}
void SamplerChannel::SetMidiInputChannel(midi_chan_t MidiChannel) {
SetMidiInput(GetMidiInputDevice(), GetMidiInputPort(), MidiChannel);
}
void SamplerChannel::SetMidiInput(MidiInputDevice* pDevice, int iMidiPort, midi_chan_t MidiChannel) {
if (!pDevice) throw Exception("No MIDI input device assigned.");
// get old and new midi input port
MidiInputPort* pOldMidiInputPort = __GetMidiInputDevicePort(GetMidiInputPort());
MidiInputPort* pNewMidiInputPort = pDevice->GetPort(iMidiPort);
// disconnect old device port
if (pOldMidiInputPort && pEngineChannel) pOldMidiInputPort->Disconnect(pEngineChannel);
// remember new device, port and channel if not engine channel yet created
if (!pEngineChannel) {
this->pMidiInputDevice = pDevice;
this->iMidiPort = iMidiPort;
this->midiChannel = MidiChannel;
}
// connect new device port
if (pNewMidiInputPort && pEngineChannel) pNewMidiInputPort->Connect(pEngineChannel, MidiChannel);
// Ooops.
if (pNewMidiInputPort == NULL)
throw Exception("There is no MIDI input port with index " + ToString(iMidiPort) + ".");
}
EngineChannel* SamplerChannel::GetEngineChannel() {
return pEngineChannel;
}
midi_chan_t SamplerChannel::GetMidiInputChannel() {
if (pEngineChannel) this->midiChannel = pEngineChannel->MidiChannel();
return this->midiChannel;
}
int SamplerChannel::GetMidiInputPort() {
MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort() : NULL;
if (pMidiInputPort) this->iMidiPort = (int) pMidiInputPort->GetPortNumber();
return iMidiPort;
}
AudioOutputDevice* SamplerChannel::GetAudioOutputDevice() {
return pAudioOutputDevice;
}
MidiInputDevice* SamplerChannel::GetMidiInputDevice() {
if (pEngineChannel)
pMidiInputDevice = (pEngineChannel->GetMidiInputPort()) ? pEngineChannel->GetMidiInputPort()->GetDevice() : NULL;
return pMidiInputDevice;
}
uint SamplerChannel::Index() {
if (iIndex >= 0) return iIndex;
Sampler::SamplerChannelMap::iterator iter = pSampler->mSamplerChannels.begin();
for (; iter != pSampler->mSamplerChannels.end(); iter++) {
if (iter->second == this) {
iIndex = iter->first;
return iIndex;
}
}
throw Exception("Internal error: SamplerChannel index not found");
}
MidiInputPort* SamplerChannel::__GetMidiInputDevicePort(int iMidiPort) {
MidiInputPort* pMidiInputPort = NULL;
MidiInputDevice* pMidiInputDevice = GetMidiInputDevice();
if (pMidiInputDevice)
pMidiInputPort = pMidiInputDevice->GetPort(iMidiPort);
return pMidiInputPort;
}
// ******************************************************************
// * Sampler
Sampler::Sampler() {
}
Sampler::~Sampler() {
Reset();
}
uint Sampler::SamplerChannels() {
return mSamplerChannels.size();
}
SamplerChannel* Sampler::AddSamplerChannel() {
// if there's no sampler channel yet
if (!mSamplerChannels.size()) {
SamplerChannel* pChannel = new SamplerChannel(this);
mSamplerChannels[0] = pChannel;
LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, 1));
return pChannel;
}
// get the highest used sampler channel index
uint lastIndex = (--(mSamplerChannels.end()))->first;
// check if we reached the index limit
if (lastIndex + 1 < lastIndex) {
// search for an unoccupied sampler channel index starting from 0
for (uint i = 0; i < lastIndex; i++) {
if (mSamplerChannels.find(i) != mSamplerChannels.end()) continue;
// we found an unused index, so insert the new channel there
SamplerChannel* pChannel = new SamplerChannel(this);
mSamplerChannels[i] = pChannel;
LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, i));
return pChannel;
}
throw Exception("Internal error: could not find unoccupied sampler channel index.");
}
// we have not reached the index limit so we just add the channel past the highest index
SamplerChannel* pChannel = new SamplerChannel(this);
mSamplerChannels[lastIndex + 1] = pChannel;
LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, lastIndex + 1));
return pChannel;
}
SamplerChannel* Sampler::GetSamplerChannel(uint uiSamplerChannel) {
return (mSamplerChannels.find(uiSamplerChannel) != mSamplerChannels.end()) ? mSamplerChannels[uiSamplerChannel] : NULL;
}
std::map<uint, SamplerChannel*> Sampler::GetSamplerChannels() {
return mSamplerChannels;
}
void Sampler::RemoveSamplerChannel(SamplerChannel* pSamplerChannel) {
SamplerChannelMap::iterator iterChan = mSamplerChannels.begin();
for (; iterChan != mSamplerChannels.end(); iterChan++) {
if (iterChan->second == pSamplerChannel) {
mSamplerChannels.erase(iterChan);
delete pSamplerChannel;
LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_channel_count, mSamplerChannels.size()));
return;
}
}
}
void Sampler::RemoveSamplerChannel(uint uiSamplerChannel) {
SamplerChannel* pChannel = GetSamplerChannel(uiSamplerChannel);
if (!pChannel) return;
RemoveSamplerChannel(pChannel);
}
std::vector<String> Sampler::AvailableAudioOutputDrivers() {
return AudioOutputDeviceFactory::AvailableDrivers();
}
AudioOutputDevice* Sampler::CreateAudioOutputDevice(String AudioDriver, std::map<String,String> Parameters) throw (Exception) {
// create new device
AudioOutputDevice* pDevice = AudioOutputDeviceFactory::Create(AudioDriver, Parameters);
// add new audio device to the audio device list
for (uint i = 0; ; i++) { // seek for a free place starting from the beginning
if (!mAudioOutputDevices[i]) {
mAudioOutputDevices[i] = pDevice;
break;
}
}
return pDevice;
}
uint Sampler::AudioOutputDevices() {
return mAudioOutputDevices.size();
}
uint Sampler::MidiInputDevices() {
return mMidiInputDevices.size();
}
std::map<uint, AudioOutputDevice*> Sampler::GetAudioOutputDevices() {
return mAudioOutputDevices;
}
std::map<uint, MidiInputDevice*> Sampler::GetMidiInputDevices() {
return mMidiInputDevices;
}
void Sampler::DestroyAudioOutputDevice(AudioOutputDevice* pDevice) throw (Exception) {
AudioOutputDeviceMap::iterator iter = mAudioOutputDevices.begin();
for (; iter != mAudioOutputDevices.end(); iter++) {
if (iter->second == pDevice) {
// check if there are still sampler engines connected to this device
for (uint i = 0; i < SamplerChannels(); i++)
if (GetSamplerChannel(i)->GetAudioOutputDevice() == pDevice) throw Exception("Sampler channel " + ToString(i) + " is still connected to the audio output device.");
// disable device
pDevice->Stop();
// remove device from the device list
mAudioOutputDevices.erase(iter);
// destroy and free device from memory
delete pDevice;
break;
}
}
}
void Sampler::DestroyMidiInputDevice(MidiInputDevice* pDevice) throw (Exception) {
MidiInputDeviceMap::iterator iter = mMidiInputDevices.begin();
for (; iter != mMidiInputDevices.end(); iter++) {
if (iter->second == pDevice) {
// check if there are still sampler engines connected to this device
for (uint i = 0; i < SamplerChannels(); i++)
if (GetSamplerChannel(i)->GetMidiInputDevice() == pDevice) throw Exception("Sampler channel " + ToString(i) + " is still connected to the midi input device.");
// disable device
pDevice->StopListen();
// remove device from the device list
mMidiInputDevices.erase(iter);
// destroy and free device from memory
delete pDevice;
break;
}
}
}
MidiInputDevice* Sampler::CreateMidiInputDevice(String MidiDriver, std::map<String,String> Parameters) throw (Exception) {
// create new device
MidiInputDevice* pDevice = MidiInputDeviceFactory::Create(MidiDriver, Parameters, this);
// add new device to the midi device list
for (uint i = 0; ; i++) { // seek for a free place starting from the beginning
if (!mMidiInputDevices[i]) {
mMidiInputDevices[i] = pDevice;
break;
}
}
return pDevice;
}
int Sampler::GetVoiceCount() {
int count = 0;
std::set<Engine*>::iterator it = EngineFactory::EngineInstances().begin();
for(; it != EngineFactory::EngineInstances().end(); it++) {
count += (*it)->VoiceCount();
}
return count;
}
void Sampler::Reset() {
// delete sampler channels
try {
while (true) {
SamplerChannelMap::iterator iter = mSamplerChannels.begin();
if (iter == mSamplerChannels.end()) break;
RemoveSamplerChannel(iter->second);
}
}
catch(...) {
std::cerr << "Sampler::Reset(): Exception occured while trying to delete all sampler channels, exiting.\n" << std::flush;
exit(EXIT_FAILURE);
}
// delete midi input devices
try {
while (true) {
MidiInputDeviceMap::iterator iter = mMidiInputDevices.begin();
if (iter == mMidiInputDevices.end()) break;
DestroyMidiInputDevice(iter->second);
}
}
catch(...) {
std::cerr << "Sampler::Reset(): Exception occured while trying to delete all MIDI input devices, exiting.\n" << std::flush;
exit(EXIT_FAILURE);
}
// delete audio output devices
try {
while (true) {
AudioOutputDeviceMap::iterator iter = mAudioOutputDevices.begin();
if (iter == mAudioOutputDevices.end()) break;
DestroyAudioOutputDevice(iter->second);
}
}
catch(...) {
std::cerr << "Sampler::Reset(): Exception occured while trying to delete all audio output devices, exiting.\n" << std::flush;
exit(EXIT_FAILURE);
}
}
} // namespace LinuxSampler
| LinuxSampler Developers |
Powered by ViewCVS |