MIDI: cross-fade via channel volume message?
-
13-05-2021 - |
문제
Using FM8.
I want to play the flute on channel 2 at volume 0 and the organ on channel 3 at full volume. I want to then gradually reduce the volume of the organ and raise the volume of the flute.
The problem is that I do not hear the flute sound raising at all, but only the organ volume going down.
I may be misunderstanding something very fundamental about MIDI?
I tinkered withe the value of 'MUTE' below replacing 0 with 1 (in the worry that 0 could be interpreted as some kind of "note off") to no avail.
Here's the relevant part of the code:
#define ORGAN 1
#define FLUTE 2
#define FULL 63
#define MUTE 1
#define BASE 0
#define M2nd 2
#define M3rd 4
#define M4th 5
#define M5th 7
#define FLUTE_CHANNEL 2
#define ORGAN_CHANNEL 3
#define CHANNEL_VOLUME 7
typedef enum {
MIDIStatusBytesNotOff = 0x80
, MIDIStatusBytesNotOn = 0x90
, MIDIStatusBytesAfterTouch = 0xa0
, MIDIStatusBytesControlChange = 0xb0
, MIDIStatusBytesProgramChange = 0xc0
, MIDIStatusBytesChannelPressure = 0xd0
, MIDIStatusBytesPitchWheel = 0xe0
} MIDIStatusBytes ;
- (void) sendSlowMo {
const UInt8 baseNote = 69 ;
const UInt8 start[] = {
MIDIStatusBytesProgramChange + FLUTE_CHANNEL, FLUTE
, MIDIStatusBytesProgramChange + ORGAN_CHANNEL, ORGAN
, MIDIStatusBytesNotOn + FLUTE_CHANNEL, baseNote+M4th, MUTE
, MIDIStatusBytesNotOn + ORGAN_CHANNEL, baseNote+BASE, FULL
} ;
const UInt8 stop[] = {
MIDIStatusBytesNotOff + FLUTE_CHANNEL, baseNote+M4th, MUTE
, MIDIStatusBytesNotOff + ORGAN_CHANNEL, baseNote+BASE, MUTE
, MIDIStatusBytesControlChange + FLUTE_CHANNEL, CHANNEL_VOLUME, FULL
, MIDIStatusBytesControlChange + ORGAN_CHANNEL, CHANNEL_VOLUME, FULL
} ;
UInt8 stepUpDown[] = {
MIDIStatusBytesControlChange + FLUTE_CHANNEL, CHANNEL_VOLUME, MUTE
, MIDIStatusBytesControlChange + ORGAN_CHANNEL, CHANNEL_VOLUME, FULL
} ;
[midi sendBytes:start size:sizeof(start)];
for (int i = 1 ; i < 128 ; ++i) {
stepUpDown[2] = (UInt8) i ;
stepUpDown[5] = (UInt8) (127 - i) ;
[midi sendBytes:stepUpDown size:sizeof(stepUpDown)];
[NSThread sleepForTimeInterval:0.10];
}
[midi sendBytes:stop size:sizeof(stop)];
}
I am using Pete Goodliffe's Excellent sample code as a starting point.
Any idea?
해결책
, MIDIStatusBytesNotOn + FLUTE_CHANNEL, baseNote+M4th, MUTE
If I'm not mistaken you are sending NoteOn with 0 velocity. This usually means NoteOff according to the MIDI specification. What you want is to set the controller value of the channel volume to 0 before issuing NoteOn with the final velocity. Note the velocity parameter tells how hard you hit a key. Everything else must be done either by aftertouch (channel pressure/key pressure) or using controllers like expression.
You can compare the situation with fading between audio tracks: Velocity tells something about the recorded volume of the note, while channel volume is the value of the slider you are using while performing the fade.
Edit: I overlooked that you define MUTE equal to 1. But that doesn't change the general discussion; its a (nearly) unhearable note that won't get much louder by channel volume messages.