////////////////////////////////////////////////////////////////////////////////
// Copyright 2013 Michael Schmalle - Teoti Graphix, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
//
// Author: Michael Schmalle, Principal Architect
// mschmalle at teotigraphix dot com
////////////////////////////////////////////////////////////////////////////////
package com.teotigraphix.caustk.sound;
import org.androidtransfuse.event.EventObserver;
import com.teotigraphix.caustk.controller.ICaustkController;
import com.teotigraphix.caustk.controller.SubControllerBase;
import com.teotigraphix.caustk.controller.SubControllerModel;
import com.teotigraphix.caustk.controller.command.CommandContext;
import com.teotigraphix.caustk.controller.command.CommandUtils;
import com.teotigraphix.caustk.controller.command.UndoCommand;
import com.teotigraphix.caustk.sound.ISoundSource.OnSoundSourceSongLoad;
import com.teotigraphix.caustk.sound.SoundSource.OnSoundSourceToneAdd;
import com.teotigraphix.caustk.sound.SoundSource.OnSoundSourceToneRemove;
import com.teotigraphix.caustk.tone.Tone;
public class SoundMixer extends SubControllerBase implements ISoundMixer {
//----------------------------------
// modelType
//----------------------------------
@Override
protected Class<? extends SubControllerModel> getModelType() {
return SoundMixerModel.class;
}
//----------------------------------
// model
//----------------------------------
SoundMixerModel getModel() {
return (SoundMixerModel)getInternalModel();
}
//--------------------------------------------------------------------------
// ISoundMixer API
//--------------------------------------------------------------------------
@Override
public MasterMixer getMasterMixer() {
return getModel().getMasterMixer();
}
@Override
public SoundMixerChannel getChannel(int index) {
return getModel().getChannels().get(index);
}
@Override
public SoundMixerChannel getChannel(Tone tone) {
return getChannel(tone.getIndex());
}
@Override
public void executeSetValue(int toneIndex, MixerInput input, Number value) {
getController().execute(COMMAND_SET_VALUE, toneIndex, input, value);
}
//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
public SoundMixer(ICaustkController controller) {
super(controller);
controller.addComponent(ISoundMixer.class, this);
// listen for tone add/remove
controller.getDispatcher().register(OnSoundSourceToneAdd.class,
new EventObserver<OnSoundSourceToneAdd>() {
@Override
public void trigger(OnSoundSourceToneAdd object) {
addTone(object.getTone());
}
});
controller.getDispatcher().register(OnSoundSourceToneRemove.class,
new EventObserver<OnSoundSourceToneRemove>() {
@Override
public void trigger(OnSoundSourceToneRemove object) {
removeTone(object.getTone());
}
});
controller.getSoundSource().getDispatcher()
.register(OnSoundSourceSongLoad.class, new EventObserver<OnSoundSourceSongLoad>() {
@Override
public void trigger(OnSoundSourceSongLoad object) {
restore();
}
});
controller.getCommandManager().put(ISoundMixer.COMMAND_SET_VALUE,
SoundMixerSetSendCommand.class);
}
@Override
public void restore() {
// restores the already created channels from the just previous song load
for (SoundMixerChannel channel : getModel().getChannels().values()) {
channel.restore();
}
}
public void update() {
for (SoundMixerChannel channel : getModel().getChannels().values()) {
channel.update();
}
}
@Override
public String serialize() {
String data = getController().getSerializeService().toString(getModel());
return data;
}
protected void addTone(Tone tone) {
getModel().toneAdded(tone);
}
protected void removeTone(Tone tone) {
getModel().toneRemoved(tone);
}
//--------------------------------------------------------------------------
// Command API
//--------------------------------------------------------------------------
public static class SoundMixerSetSendCommand extends UndoCommand {
private VO last;
@Override
protected void doExecute() {
VO current = new VO(getContext());
// save the current state into the 'last' state if this command
// has redo() called on it
last = new VO(getContext().getComponent(ISoundMixer.class), current);
// execute the OSC command for this current command
// the command is already in the command history right now
update(current);
}
@Override
protected void undoExecute() {
update(last);
}
private void update(VO vo) {
int index = vo.index;
SoundMixerChannel channel = getContext().getComponent(ISoundMixer.class).getChannel(
index);
final float value = vo.value;
switch (vo.type) {
case Bass:
channel.setBass(value);
break;
case Mid:
channel.setMid(value);
break;
case High:
channel.setHigh(value);
break;
case DelaySend:
channel.setDelaySend(value);
break;
case ReverbSend:
channel.setReverbSend(value);
break;
case Pan:
channel.setPan(value);
break;
case StereoWidth:
channel.setStereoWidth(value);
break;
case Mute:
channel.setMute(value == 0f ? false : true);
break;
case Solo:
channel.setSolo(value == 0f ? false : true);
break;
case Volume:
channel.setVolume(value);
break;
}
}
class VO {
private int index;
private MixerInput type;
private float value;
public VO(CommandContext context) {
index = CommandUtils.getInteger(getContext(), 0);
type = MixerInput.fromString(CommandUtils.getString(getContext(), 1));
value = CommandUtils.getFloat(getContext(), 2);
}
public VO(ISoundMixer api, VO current) {
index = current.index;
type = current.type;
SoundMixerChannel channel = api.getChannel(index);
switch (type) {
case Bass:
value = channel.getBass();
break;
case Mid:
value = channel.getMid();
break;
case High:
value = channel.getHigh();
break;
case DelaySend:
value = channel.getDelaySend();
break;
case ReverbSend:
value = channel.getReverbSend();
break;
case Pan:
value = channel.getPan();
break;
case StereoWidth:
value = channel.getStereoWidth();
break;
case Mute:
value = channel.isMute() ? 1 : 0;
break;
case Solo:
value = channel.isSolo() ? 1 : 0;
break;
case Volume:
value = channel.getVolume();
break;
}
}
}
}
public enum MixerInput {
Bass("bass"),
Mid("mid"),
High("high"),
DelaySend("delaySend"),
ReverbSend("reverbSend"),
Pan("pan"),
StereoWidth("stereoWidth"),
Mute("mute"),
Solo("solo"),
Volume("volume");
private String value;
public final String getValue() {
return value;
}
public static MixerInput fromString(String value) {
for (MixerInput mixerInput : values()) {
if (mixerInput.getValue().equals(value))
return mixerInput;
}
return null;
}
MixerInput(String value) {
this.value = value;
}
@Override
public String toString() {
return getValue();
}
}
}