ExcelFormulaParserSample\collected_soundfonts\FluidR3_GM.sf2
//////// Expression (CC 11) - Crescendo and Decrescendo
//////for (int i = 0; i <= 127; i += 8)
//////{
////// collection
////// .AddEvent
////// (new
////// ControlChangeEvent
////// (
////// absoluteTime___start___midstksunits+ i * 2
////// ,
////// ChannelNumber
////// , MidiController.Expression
////// ,
////// i
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 0; i <= 127; i += 8)
//////for (int i = 127; i >= 0; i -= 8)
//////{
////// collection
////// .AddEvent
////// (
////// new
////// ControlChangeEvent
////// (
////// // 256 + (127 - i) * 2
////// absoluteTime___start___midstksunits+ 256 + (127 - i) * 2
////// ,
////// ChannelNumber
////// , MidiController.Expression
////// ,
////// i
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 127; i >= 0; i -= 8)
//it was not playing even i stopped this
// Vibrato (CC 21) - Oscillating values
for (int i = 0; i < 3; i++)
{
collection.AddEvent
(
new ControlChangeEvent
(
// 600 + i * 120
absoluteTime___start___midstksunits + i * 120
, ChannelNumber
,
// (MidiController)21 // THIS ALSO WORKS
MidiController.SAANS_VIBRATO
//THIS ALSO WORKS MidiController.SAANS_VIBRATO
, 64
)
, TrackNumber
);
//////////////////
collection.AddEvent
(new
ControlChangeEvent
(
//660 + i * 120
absoluteTime___start___midstksunits + i * 120
,
ChannelNumber
,
// (MidiController)21 THIS WAS WORKING
MidiController.SAANS_VIBRATO
,
0
)
,
TrackNumber
);
}// for (int i = 0; i < 3; i++)
//it was not playing even i stopped this
// Modulation (CC 1) - Sweep
for (int i = 0; i <= 127; i += 10)
{
collection
.AddEvent
(new ControlChangeEvent
(
// 1000 + i * 2
absoluteTime___start___midstksunits+ i*2
,
ChannelNumber
,
MidiController.Modulation
,
i
)
,
TrackNumber);
}//for (int i = 0; i <= 127; i += 10)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ALL ARE WORKING AND SOME HAVE ISSUES //WHEN I AM USING THIS EXPRESSIONS THEN THE MIDI FILES ARE NOT PLAYING ANY SOUNDS //////// Expression (CC 11) - Crescendo and Decrescendo //////for (int i = 0; i <= 127; i += 8) //////{ ////// collection ////// .AddEvent ////// (new ////// ControlChangeEvent ////// ( ////// absoluteTime___start___midstksunits+ i * 2 ////// , ////// ChannelNumber ////// , MidiController.Expression ////// , ////// i ////// ) ////// , ////// TrackNumber ////// ); //////}//for (int i = 0; i <= 127; i += 8) //////for (int i = 127; i >= 0; i -= 8) //////{ ////// collection ////// .AddEvent ////// ( ////// new ////// ControlChangeEvent ////// ( ////// // 256 + (127 - i) * 2 ////// absoluteTime___start___midstksunits+ 256 + (127 - i) * 2 ////// , ////// ChannelNumber ////// , MidiController.Expression ////// , ////// i ////// ) ////// , ////// TrackNumber ////// ); //////}//for (int i = 127; i >= 0; i -= 8) //it was not playing even i stopped this // Vibrato (CC 21) - Oscillating values for (int i = 0; i < 3; i++) { SAANSMIDSEVENTScollection.AddEvent ( new ControlChangeEvent ( // 600 + i * 120 LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120 , ChannelNumber , // (MidiController)21 // THIS ALSO WORKS MidiController.SAANS_VIBRATO //THIS ALSO WORKS MidiController.SAANS_VIBRATO , 64 ) , //TrackNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER ); ////////////////// SAANSMIDSEVENTScollection.AddEvent (new ControlChangeEvent ( //660 + i * 120 LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120 , //ChannelNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_CHANNEL_NUMBER_0_TO_15 , // (MidiController)21 THIS WAS WORKING MidiController.SAANS_VIBRATO , 0 ) , // TrackNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER ); }// for (int i = 0; i < 3; i++) //it was not playing even i stopped this // Modulation (CC 1) - Sweep for (int i = 0; i <= 127; i += 10) { SAANSMIDSEVENTScollection .AddEvent (new ControlChangeEvent ( // 1000 + i * 2 LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2 , // ChannelNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_CHANNEL_NUMBER_0_TO_15 , MidiController.Modulation , i ) , // TrackNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER ); }//for (int i = 0; i <= 127; i += 10) THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
EXPLAIN THE LINES LINE TO LINE WHY THESE EFFECTS WORK AND WHAT THESE ITERATIONS DO??????? //WHEN I AM USING THIS EXPRESSIONS THEN THE MIDI FILES ARE NOT PLAYING ANY SOUNDS
//////// Expression (CC 11) - Crescendo and Decrescendo
//////for (int i = 0; i <= 127; i += 8)
//////{
////// collection
////// .AddEvent
////// (new
////// ControlChangeEvent
////// (
////// absoluteTime___start___midstksunits+ i * 2
////// ,
////// ChannelNumber
////// , MidiController.Expression
////// ,
////// i
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 0; i <= 127; i += 8)
//////for (int i = 127; i >= 0; i -= 8)
//////{
////// collection
////// .AddEvent
////// (
////// new
////// ControlChangeEvent
////// (
////// // 256 + (127 - i) * 2
////// absoluteTime___start___midstksunits+ 256 + (127 - i) * 2
////// ,
////// ChannelNumber
////// , MidiController.Expression
////// ,
////// i
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 127; i >= 0; i -= 8)
//it was not playing even i stopped this
// Vibrato (CC 21) - Oscillating values
for (int i = 0; i < 3; i++)
{
SAANSMIDSEVENTScollection.AddEvent
(
new ControlChangeEvent
(
// 600 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
, ChannelNumber
,
// (MidiController)21 // THIS ALSO WORKS
MidiController.SAANS_VIBRATO
//THIS ALSO WORKS MidiController.SAANS_VIBRATO
, 64
)
,
//TrackNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
//////////////////
SAANSMIDSEVENTScollection.AddEvent
(new
ControlChangeEvent
(
//660 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
,
//ChannelNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
// (MidiController)21 THIS WAS WORKING
MidiController.SAANS_VIBRATO
,
0
)
,
// TrackNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}// for (int i = 0; i < 3; i++)
//it was not playing even i stopped this
// Modulation (CC 1) - Sweep
for (int i = 0; i <= 127; i += 10)
{
SAANSMIDSEVENTScollection
.AddEvent
(new ControlChangeEvent
(
// 1000 + i * 2
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2
,
// ChannelNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
MidiController.Modulation
,
i
)
,
// TrackNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}//for (int i = 0; i <= 127; i += 10)
THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
SAANSMIDSEVENTScollection
.AddEvent
(
new SAANAUDS.Midi.TextEvent
(
( Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_LYR_FOUND
+"_"+
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_INDINOTE_FOUND
).Replace(",","_")
,
SAANAUDS.Midi.MetaEventType.TextEvent
,
// absoluteTime
//////(long)((absoluteTime___start___midstksunits + absoluteTime___final___midstksunits) / 6)
////// )
///
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
)
,
//TrackNumber
0
);
/////////////////////////////// interesting styles ////////////////////
///THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
Certainly! Let's break down the provided code and MIDI concepts line by line to understand how each part functions and contributes to the overall MIDI sequence.
Expression (CC11) – Crescendo and Decrescendo
csharp
CopyEdit
// Gradual increase in expression (volume) over time
for (int i = 0; i <= 127; i += 8)
{
collection.AddEvent(new ControlChangeEvent(
absoluteTime___start___midstksunits + i * 2,
ChannelNumber,
MidiController.Expression,
i
), TrackNumber);
}
// Gradual decrease in expression (volume) over time
for (int i = 127; i >= 0; i -= 8)
{
collection.AddEvent(new ControlChangeEvent(
absoluteTime___start___midstksunits + 256 + (127 - i) * 2,
ChannelNumber,
MidiController.Expression,
i
), TrackNumber);
}
- Purpose: These loops create a crescendo and decrescendo effect by gradually increasing and then decreasing the expression (volume) over time.
- Mechanism:
- The first loop increases the expression from 0 to 127 in steps of 8, simulating a crescendo.
- The second loop decreases the expression from 127 to 0 in steps of 8, simulating a decrescendo.
- absoluteTime___start___midstksunits is the starting point in the MIDI timeline, and i * 2 or (127 - i) * 2 determines the timing of each control change event.
- MidiController.Expression corresponds to Control Change (CC) number 11, which is commonly used for expression control in MIDI.
- Effect: This technique is often used to simulate dynamic changes in volume, akin to a musician gradually getting louder or softer during a performance.
Vibrato (CC21) – Oscillating Values
csharp
CopyEdit
for (int i = 0; i < 3; i++)
{
SAANSMIDSEVENTScollection.AddEvent(new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120,
ChannelNumber,
MidiController.SAANS_VIBRATO,
64
), TrackNumber);
SAANSMIDSEVENTScollection.AddEvent(new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120,
ChannelNumber,
MidiController.SAANS_VIBRATO,
0
), TrackNumber);
}
- Purpose: This loop simulates a vibrato effect by alternating between two values for the vibrato control.
- Mechanism:
- The loop runs three times, adding two control change events per iteration: one with a value of 64 and another with a value of 0.
- MidiController.SAANS_VIBRATO corresponds to Control Change (CC) number 21, which is often used for vibrato depth.
- The timing of each event is determined by LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120.
- Effect: This creates a rapid oscillation, simulating the effect of vibrato on the instrument.
Modulation (CC1) – Sweep
csharp
CopyEdit
for (int i = 0; i <= 127; i += 10)
{
SAANSMIDSEVENTScollection.AddEvent(new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2,
ChannelNumber,
MidiController.Modulation,
i
), TrackNumber);
}
- Purpose: This loop applies a modulation effect by gradually increasing the modulation control value.
- Mechanism:
- The loop runs from 0 to 127 in steps of 10, simulating a modulation sweep.
- MidiController.Modulation corresponds to Control Change (CC) number 1, which is commonly used for modulation effects like vibrato or filter changes.
- The timing of each event is determined by LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2.
- Effect: This creates a sweeping modulation effect, which can add movement and expressiveness to the sound.
Text Event – Metadata Annotation
csharp
CopyEdit
SAANSMIDSEVENTScollection.AddEvent(new SAANAUDS.Midi.TextEvent(
(Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_STRING_THE_LYR_FOUND + "_" +
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_STRING_THE_INDINOTE_FOUND).Replace(",", "_"),
SAANAUDS.Midi.MetaEventType.TextEvent,
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
), 0);
- Purpose: This line adds a text event to the MIDI sequence, which can be used for annotations or metadata.
- Mechanism:
- The text is constructed by concatenating two public strings and replacing commas with underscores.
- SAANAUDS.Midi.MetaEventType.TextEvent specifies that this is a text event.
- LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS determines the timing of the event.
- Effect: This embeds metadata into the MIDI sequence, which can be useful for labeling or identifying specific parts of the composition.
Final Event Counter Increment
csharp
CopyEdit
THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
- Purpose: This line increments a global counter that tracks the number of events added to the MIDI sequence.
- Effect: This helps in monitoring and managing the number of events, which can be useful for debugging or optimizing the MIDI generation process.
Summary of MIDI Control Change (CC) Functions
- CC1 (Modulation): Controls modulation effects like vibrato or filter changes. It's often used for dynamic expression in performance.
- CC11 (Expression): Adjusts the volume of the instrument without affecting the overall mix. It's used to simulate dynamics like crescendos and decrescendos.
- CC21 (Vibrato): Alters the depth of vibrato applied to the sound, adding expressiveness and realism.
By utilizing these MIDI CCs, you can create more expressive and dynamic performances, simulating the nuances of live instrument playing.
IS THIS IMPROVABLE WITH OTHER KINDS OF ITERATIONS????
ChatGPT said:
Absolutely! Your current approach to MIDI control changes (CCs) like Expression (CC11), Vibrato (CC21), and Modulation (CC1) is effective, but there are several advanced techniques and iteration strategies you can employ to enhance expressiveness, efficiency, and realism in your MIDI compositions.
🎛️ Advanced Iteration Techniques for MIDI CCs
1. Synchronized Control Changes
Instead of manually programming each CC, consider synchronizing multiple CCs to a single controller. For instance, you can map both CC1 (Modulation) and CC11 (Expression) to the same physical controller, like a mod wheel. This approach allows for simultaneous control, mimicking natural performance dynamics where modulation and expression often change together. DAWs like Cubase offer tools like the Input Transformer to duplicate and map CCs accordingly. RedditSteinberg ForumsReddit+3Steinberg Forums+3Steinberg Forums+3
2. Dynamic Scaling of CC Values
To achieve more nuanced control, you can scale the CC values dynamically. For example, in Cubase, you can use the Input Transformer to scale CC11 values to a percentage of their original value, allowing for finer control over expression. This technique is particularly useful when you want to limit the range of a CC without altering the original performance data. Steinberg Forums
3. Curve-Based Automation
Instead of using linear iterations, employ curve-based automation to create more natural and expressive transitions. Many DAWs allow you to draw automation curves for CCs, enabling you to shape the dynamics more organically. This method is especially effective for simulating real-world performance nuances, such as gradual crescendos or subtle vibrato variations. Reddit
4. MIDI Control via Expression Pedals
Utilizing expression pedals can provide continuous and real-time control over CCs. Assigning an expression pedal to control CC11 allows for smooth, hands-free dynamic adjustments during performance or recording. This technique is commonly used in orchestral mockups to emulate the subtle dynamic changes of live instruments. VI-Control
5. Linking Multiple Parameters
For complex instruments or articulations, linking multiple CCs can create a cohesive performance. For example, you can link CC1 (Modulation) with CC11 (Expression) so that changes in modulation automatically adjust expression, maintaining a balanced dynamic range. This linkage can be achieved through MIDI scripting or DAW-specific tools.
🧠 Practical Considerations
- Instrument-Specific Behavior: Different virtual instruments (VIs) respond uniquely to CCs. It's essential to understand how each instrument interprets CC1, CC11, and CC21 to ensure realistic playback. Some instruments may have dedicated controls for vibrato depth or expression, while others may require manual CC assignments.
- Performance Context: Consider the musical context when applying CC changes. For instance, rapid modulation sweeps may be appropriate for certain genres but could sound unnatural in others. Adjusting the timing and range of CC changes can help match the intended style and emotion of the piece.
- DAW Capabilities: Leverage the features of your DAW to streamline MIDI programming. Many DAWs offer MIDI scripting, automation curves, and MIDI mapping tools that can simplify the process of creating complex CC changes.Steinberg Forums+2Reddit+2VI-Control+2
By integrating these advanced iteration techniques, you can achieve more expressive and realistic MIDI performances. Experimenting with synchronized CCs, dynamic scaling, curve-based automation, expression pedals, and parameter linking will provide greater control and nuance in your compositions.
If you need assistance with implementing any of these techniques in your specific DAW or setup, feel free to ask!
IS THIS IMPROVABLE WITH OTHER KINDS OF ITERATIONS????
ChatGPT said:
Absolutely! Your current approach to MIDI control changes (CCs) like Expression (CC11), Vibrato (CC21), and Modulation (CC1) is effective, but there are several advanced techniques and iteration strategies you can employ to enhance expressiveness, efficiency, and realism in your MIDI compositions.
🎛️ Advanced Iteration Techniques for MIDI CCs
1. Synchronized Control Changes
Instead of manually programming each CC, consider synchronizing multiple CCs to a single controller. For instance, you can map both CC1 (Modulation) and CC11 (Expression) to the same physical controller, like a mod wheel. This approach allows for simultaneous control, mimicking natural performance dynamics where modulation and expression often change together. DAWs like Cubase offer tools like the Input Transformer to duplicate and map CCs accordingly. RedditSteinberg ForumsReddit+3Steinberg Forums+3Steinberg Forums+3
2. Dynamic Scaling of CC Values
To achieve more nuanced control, you can scale the CC values dynamically. For example, in Cubase, you can use the Input Transformer to scale CC11 values to a percentage of their original value, allowing for finer control over expression. This technique is particularly useful when you want to limit the range of a CC without altering the original performance data. Steinberg Forums
3. Curve-Based Automation
Instead of using linear iterations, employ curve-based automation to create more natural and expressive transitions. Many DAWs allow you to draw automation curves for CCs, enabling you to shape the dynamics more organically. This method is especially effective for simulating real-world performance nuances, such as gradual crescendos or subtle vibrato variations. Reddit
4. MIDI Control via Expression Pedals
Utilizing expression pedals can provide continuous and real-time control over CCs. Assigning an expression pedal to control CC11 allows for smooth, hands-free dynamic adjustments during performance or recording. This technique is commonly used in orchestral mockups to emulate the subtle dynamic changes of live instruments. VI-Control
5. Linking Multiple Parameters
For complex instruments or articulations, linking multiple CCs can create a cohesive performance. For example, you can link CC1 (Modulation) with CC11 (Expression) so that changes in modulation automatically adjust expression, maintaining a balanced dynamic range. This linkage can be achieved through MIDI scripting or DAW-specific tools.
🧠 Practical Considerations
- Instrument-Specific Behavior: Different virtual instruments (VIs) respond uniquely to CCs. It's essential to understand how each instrument interprets CC1, CC11, and CC21 to ensure realistic playback. Some instruments may have dedicated controls for vibrato depth or expression, while others may require manual CC assignments.
- Performance Context: Consider the musical context when applying CC changes. For instance, rapid modulation sweeps may be appropriate for certain genres but could sound unnatural in others. Adjusting the timing and range of CC changes can help match the intended style and emotion of the piece.
- DAW Capabilities: Leverage the features of your DAW to streamline MIDI programming. Many DAWs offer MIDI scripting, automation curves, and MIDI mapping tools that can simplify the process of creating complex CC changes.Steinberg Forums+2Reddit+2VI-Control+2
By integrating these advanced iteration techniques, you can achieve more expressive and realistic MIDI performances. Experimenting with synchronized CCs, dynamic scaling, curve-based automation, expression pedals, and parameter linking will provide greater control and nuance in your compositions.
If you need assistance with implementing any of these techniques in your specific DAW or setup, feel free to ask!
for (int i = 0; i <= 127; i += 8)
{
collection.AddEvent(
new ControlChangeEvent(
absoluteTime___start___midstksunits + i * 2, // Time of the event
ChannelNumber, // MIDI channel
MidiController.Expression, // CC 11
i // Value: 0 → 127
),
TrackNumber
);
}
for (int i = 127; i >= 0; i -= 8)
{
collection.AddEvent(
new ControlChangeEvent(
absoluteTime___start___midstksunits + 256 + (127 - i) * 2,
ChannelNumber,
MidiController.Expression,
i
),
TrackNumber
);
}
for (int i = 0; i < 3; i++)
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120,
ChannelNumber,
MidiController.SAANS_VIBRATO, // CC 21
64
),
TrackNumber
);
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120,
ChannelNumber,
MidiController.SAANS_VIBRATO,
0
),
TrackNumber
);
}
for (int i = 0; i <= 127; i += 10)
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2,
ChannelNumber,
MidiController.Modulation, // CC 1
i
),
TrackNumber
);
}
SAANSMIDSEVENTScollection.AddEvent(
new SAANAUDS.Midi.TextEvent(
(PUBLIC_STRING_THE_LYR_FOUND + "_" + PUBLIC_STRING_THE_INDINOTE_FOUND).Replace(",", "_"),
SAANAUDS.Midi.MetaEventType.TextEvent,
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
),
0
);
Absolutely! Let's break this down line by line and explain what each part does, why it works (or doesn't), and how the iterations affect the MIDI output.
🎚️ Section 1: Expression (CC 11) – Crescendo and Decrescendo
🔁 Loop 1: Crescendo (Volume Up)
✅ What it does:
· Sends Control Change (CC 11) messages to gradually increase expression (volume modifier).
· i
goes from 0 to 127 in steps of 8 → smooth crescendo.
· i * 2
spaces the events in time (tick units).
⚠️ Why it might not work:
· If CC 7 (Main Volume) is not set, CC 11 has no base to multiply → no sound.
· If the note is too short, you won’t hear the volume change.
· If the instrument doesn’t respond to CC 11, it will be ignored.
🔁 Loop 2: Decrescendo (Volume Down)
✅ What it does:
· Sends CC 11 values from 127 down to 0 → smooth decrescendo.
· Starts at a later time (+256
) to follow the crescendo.
· (127 - i) * 2
spaces the events evenly.
⚠️ Why it might not work:
· Same issues as above: no CC 7, short note, or unsupported controller.
🎻 Section 2: Vibrato (CC 21) – Oscillating Pitch
✅ What it does:
· Sends alternating vibrato intensity values (64 → 0) three times.
· Simulates a wobble effect in pitch.
⚠️ Why it might not work:
· Not all instruments respond to CC 21.
· If the instrument doesn’t map CC 21 to pitch modulation, it will do nothing.
🎛️ Section 3: Modulation (CC 1) – Sweep
✅ What it does:
· Sends a modulation sweep from 0 to 127.
· Often mapped to vibrato, filter cutoff, or LFO depth.
⚠️ Why it might not work:
· If the instrument doesn’t respond to CC 1, or if it’s not mapped to anything, it won’t have an effect.
📝 Final Text Event
✅ What it does:
· Adds a text marker to the MIDI file (e.g., for lyrics or debugging).
· Doesn’t affect sound but useful for DAW visualization.
✅ Summary of Fixes You Might Need
Problem | Fix |
No sound with CC 11 |
Add |
No audible effect |
Ensure the note is long enough |
Controller ignored |
Check if your instrument supports CC 11, 21, or 1 |
Timing issues |
Space events properly and align with note duration |
Would you like me to help you rewrite this with all fixes applied and a working example?
Great! Let's go line by line and explain why these MIDI controller effects work, what the iterations are doing, and how to improve them for better results across the full duration of a note.
for (int i = 0; i <= 127; i += 8)
{
collection.AddEvent(
new ControlChangeEvent(
absoluteTime___start___midstksunits + i * 2, // Time in ticks
ChannelNumber,
MidiController.Expression, // CC 11
i // Value from 0 to 127
),
TrackNumber
);
}
for (int i = 127; i >= 0; i -= 8)
{
collection.AddEvent(
new ControlChangeEvent(
absoluteTime___start___midstksunits + 256 + (127 - i) * 2,
ChannelNumber,
MidiController.Expression,
i
),
TrackNumber
);
}
collection.AddEvent(new ControlChangeEvent(absoluteTime___start___midstksunits, ChannelNumber, MidiController.MainVolume, 127), TrackNumber);
for (int i = 0; i < 3; i++)
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120,
ChannelNumber,
MidiController.SAANS_VIBRATO, // CC 21
64
),
TrackNumber
);
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120,
ChannelNumber,
MidiController.SAANS_VIBRATO,
0
),
TrackNumber
);
}
for (int i = 0; i < 20; i++)
{
int value = (i % 2 == 0) ? 64 : 0;
collection.AddEvent(new ControlChangeEvent(startTime + i * 30, channel, 21, value), track);
}
for (int i = 0; i < 20; i++)
{
int value = (i % 2 == 0) ? 64 : 0;
collection.AddEvent(new ControlChangeEvent(startTime + i * 30, channel, 21, value), track);
}
for (int i = 0; i <= 127; i += 10)
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2,
ChannelNumber,
MidiController.Modulation, // CC 1
i
),
TrackNumber
);
}
SAANSMIDSEVENTScollection.AddEvent(
new SAANAUDS.Midi.TextEvent(
(PUBLIC_STRING_THE_LYR_FOUND + "_" + PUBLIC_STRING_THE_INDINOTE_FOUND).Replace(",", "_"),
SAANAUDS.Midi.MetaEventType.TextEvent,
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
),
0
);
Summary: Best Practices for MIDI Effects
Effect | Best Practice |
Expression (CC 11) |
Always set CC
7 (Main Volume) first. Apply CC 11 gradually during a long
note. |
Vibrato (CC 21) |
Use fast,
alternating values. Ensure your instrument maps CC 21 to
pitch modulation. |
Modulation (CC 1) |
Use for sweeps
or LFO effects. Ensure your instrument responds to CC 1. |
Timing |
Space events evenly and align with NoteOn/NoteOff
durations. |
Testing |
Use a DAW or synth that visually
shows CC lanes to debug. |
🎚️ Expression (CC 11) – Crescendo and Decrescendo
🔁 Loop 1: Crescendo
✅ What it does:
· Gradually increases expression (volume modifier) from 0 to 127.
· i += 8
means it steps in increments of 8 (smooth but not too dense).
· i * 2
spaces the events in time (tick units), so they don’t all happen at once.
⚠️ Why it might silence sound:
· If CC 7 (Main Volume) is not set to a high value, CC 11 = 0 will mute the sound.
· If the note starts before this loop and ends before the crescendo finishes, you won’t hear the full effect.
🔁 Loop 2: Decrescendo
✅ What it does:
· Gradually decreases expression from 127 to 0.
· Starts at a later time (+256
) to follow the crescendo.
· (127 - i) * 2
spaces the decrescendo evenly.
✅ Better way:
· Ensure a NoteOn event starts before this and a NoteOff happens after.
· Add a CC 7 (Main Volume) at the beginning:
🎻 Vibrato (CC 21) – Oscillating Pitch
✅ What it does:
· Sends alternating values (64 → 0) to simulate vibrato.
· i * 120
spaces the vibrato pulses in time.
⚠️ Why it might not work:
· CC 21 must be mapped to pitch modulation in your instrument.
· If the instrument doesn’t support vibrato via CC 21, it will do nothing.
✅ Better way:
· Use faster, more frequent oscillations for realistic vibrato:
🎛️ Modulation (CC 1) – Sweep
✅ What it does:
· Gradually increases modulation from 0 to 127.
· Often mapped to vibrato, filter cutoff, or LFO depth.
⚠️ Why it might not work:
· If the instrument doesn’t respond to CC 1, or if it’s not mapped to anything, it won’t have an effect.
✅ Better way:
· Use modulation curves that match the musical phrasing.
· You can also oscillate modulation for tremolo or vibrato effects.
📝 Text Event
✅ What it does:
· Adds a text marker to the MIDI file (for lyrics, debugging, or DAW display).
· Doesn’t affect sound.
✅ Summary: Best Practices for MIDI Effects
Effect | Best Practice |
Expression (CC 11) |
Always set CC
7 (Main Volume) first. Apply CC 11 gradually during a long
note. |
Vibrato (CC 21) |
Use fast,
alternating values. Ensure your instrument maps CC 21 to
pitch modulation. |
Modulation (CC 1) |
Use for sweeps
or LFO effects. Ensure your instrument responds to CC 1. |
Timing |
Space events evenly and align with NoteOn/NoteOff
durations. |
Testing |
Use a DAW or synth that visually
shows CC lanes to debug. |
Would you like me to help you rewrite this into a clean, working example that applies all these effects properly across a sustained note?
IS THIS IMPROVABLE WITH OTHER KINDS OF ITERATIONS????
ChatGPT said:
Absolutely! Your current approach to MIDI control changes (CCs) like Expression (CC11), Vibrato (CC21), and Modulation (CC1) is effective, but there are several advanced techniques and iteration strategies you can employ to enhance expressiveness, efficiency, and realism in your MIDI compositions.
🎛️ Advanced Iteration Techniques for MIDI CCs
1. Synchronized Control Changes
Instead of manually programming each CC, consider synchronizing multiple CCs to a single controller. For instance, you can map both CC1 (Modulation) and CC11 (Expression) to the same physical controller, like a mod wheel. This approach allows for simultaneous control, mimicking natural performance dynamics where modulation and expression often change together. DAWs like Cubase offer tools like the Input Transformer to duplicate and map CCs accordingly. RedditSteinberg ForumsReddit+3Steinberg Forums+3Steinberg Forums+3
2. Dynamic Scaling of CC Values
To achieve more nuanced control, you can scale the CC values dynamically. For example, in Cubase, you can use the Input Transformer to scale CC11 values to a percentage of their original value, allowing for finer control over expression. This technique is particularly useful when you want to limit the range of a CC without altering the original performance data. Steinberg Forums
3. Curve-Based Automation
Instead of using linear iterations, employ curve-based automation to create more natural and expressive transitions. Many DAWs allow you to draw automation curves for CCs, enabling you to shape the dynamics more organically. This method is especially effective for simulating real-world performance nuances, such as gradual crescendos or subtle vibrato variations. Reddit
4. MIDI Control via Expression Pedals
Utilizing expression pedals can provide continuous and real-time control over CCs. Assigning an expression pedal to control CC11 allows for smooth, hands-free dynamic adjustments during performance or recording. This technique is commonly used in orchestral mockups to emulate the subtle dynamic changes of live instruments. VI-Control
5. Linking Multiple Parameters
For complex instruments or articulations, linking multiple CCs can create a cohesive performance. For example, you can link CC1 (Modulation) with CC11 (Expression) so that changes in modulation automatically adjust expression, maintaining a balanced dynamic range. This linkage can be achieved through MIDI scripting or DAW-specific tools.
🧠 Practical Considerations
- Instrument-Specific Behavior: Different virtual instruments (VIs) respond uniquely to CCs. It's essential to understand how each instrument interprets CC1, CC11, and CC21 to ensure realistic playback. Some instruments may have dedicated controls for vibrato depth or expression, while others may require manual CC assignments.
- Performance Context: Consider the musical context when applying CC changes. For instance, rapid modulation sweeps may be appropriate for certain genres but could sound unnatural in others. Adjusting the timing and range of CC changes can help match the intended style and emotion of the piece.
- DAW Capabilities: Leverage the features of your DAW to streamline MIDI programming. Many DAWs offer MIDI scripting, automation curves, and MIDI mapping tools that can simplify the process of creating complex CC changes.Steinberg Forums+2Reddit+2VI-Control+2
By integrating these advanced iteration techniques, you can achieve more expressive and realistic MIDI performances. Experimenting with synchronized CCs, dynamic scaling, curve-based automation, expression pedals, and parameter linking will provide greater control and nuance in your compositions.
If you need assistance with implementing any of these techniques in your specific DAW or setup, feel free to ask!
Sources
these are not silencing only the commented part are silensing the sounds and i think we can do these better effects i need the explainations what are better ways to implement these effects on whole durations of notes EXPLAIN THE LINES LINE TO LINE WHY THESE EFFECTS WORK AND WHAT THESE ITERATIONS DO??????? //WHEN I AM USING THIS EXPRESSIONS THEN THE MIDI FILES ARE NOT PLAYING ANY SOUNDS //////// Expression (CC 11) - Crescendo and Decrescendo //////for (int i = 0; i <= 127; i += 8) //////{ ////// collection ////// .AddEvent ////// (new ////// ControlChangeEvent ////// ( ////// absoluteTime___start___midstksunits+ i * 2 ////// , ////// ChannelNumber ////// , MidiController.Expression ////// , ////// i ////// ) ////// , ////// TrackNumber ////// ); //////}//for (int i = 0; i <= 127; i += 8) //////for (int i = 127; i >= 0; i -= 8) //////{ ////// collection ////// .AddEvent ////// ( ////// new ////// ControlChangeEvent ////// ( ////// // 256 + (127 - i) * 2 ////// absoluteTime___start___midstksunits+ 256 + (127 - i) * 2 ////// , ////// ChannelNumber ////// , MidiController.Expression ////// , ////// i ////// ) ////// , ////// TrackNumber ////// ); //////}//for (int i = 127; i >= 0; i -= 8) //it was not playing even i stopped this // Vibrato (CC 21) - Oscillating values for (int i = 0; i < 3; i++) { SAANSMIDSEVENTScollection.AddEvent ( new ControlChangeEvent ( // 600 + i * 120 LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120 , ChannelNumber , // (MidiController)21 // THIS ALSO WORKS MidiController.SAANS_VIBRATO //THIS ALSO WORKS MidiController.SAANS_VIBRATO , 64 ) , //TrackNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER ); ////////////////// SAANSMIDSEVENTScollection.AddEvent (new ControlChangeEvent ( //660 + i * 120 LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120 , //ChannelNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_CHANNEL_NUMBER_0_TO_15 , // (MidiController)21 THIS WAS WORKING MidiController.SAANS_VIBRATO , 0 ) , // TrackNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER ); }// for (int i = 0; i < 3; i++) //it was not playing even i stopped this // Modulation (CC 1) - Sweep for (int i = 0; i <= 127; i += 10) { SAANSMIDSEVENTScollection .AddEvent (new ControlChangeEvent ( // 1000 + i * 2 LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2 , // ChannelNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_CHANNEL_NUMBER_0_TO_15 , MidiController.Modulation , i ) , // TrackNumber Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER ); }//for (int i = 0; i <= 127; i += 10) THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++; ///////////////////////////////////////////////////////////////////////////////////////////////////////// SAANSMIDSEVENTScollection .AddEvent ( new SAANAUDS.Midi.TextEvent ( ( Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_STRING_THE_LYR_FOUND +"_"+ Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS .PUBLIC_STRING_THE_INDINOTE_FOUND ).Replace(",","_") , SAANAUDS.Midi.MetaEventType.TextEvent , // absoluteTime //////(long)((absoluteTime___start___midstksunits + absoluteTime___final___midstksunits) / 6) ////// ) /// LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS ) , //TrackNumber 0 ); /////////////////////////////// interesting styles //////////////////// ///THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
Certainly! Let's delve into the MIDI control changes (CC) you've implemented and explore how they function, their impact on note durations, and potential improvements.
🎼 Expression (CC11) – Crescendo and Decrescendo
What It Does:
- Purpose: CC11 is used to control the volume of a note or passage, allowing for dynamic changes such as crescendos (gradual increases in volume) and decrescendos (gradual decreases in volume).people.carleton.edu
- Implementation: In your code, you're iterating through values of CC11, gradually increasing and then decreasing them to create a crescendo and decrescendo effect.
Code Breakdown:
csharp
for (
int i =
0; i <=
127; i +=
8)
{
collection.AddEvent(
new ControlChangeEvent(
absoluteTime___start___midstksunits + i *
2,
ChannelNumber,
MidiController.Expression,
i
), TrackNumber);
}
- Iteration: This loop increases the CC11 value from 0 to 127 in steps of 8.
- Timing: The
absoluteTime___start___midstksunits + i * 2
ensures that each CC11 event occurs at a specific time, creating a smooth transition. - Effect: As CC11 increases, the volume of the note increases, achieving a crescendo.
csharp
for (
int i =
127; i >=
0; i -=
8)
{
collection.AddEvent(
new ControlChangeEvent(
absoluteTime___start___midstksunits +
256 + (
127 - i) *
2,
ChannelNumber,
MidiController.Expression,
i
), TrackNumber);
}
- Iteration: This loop decreases the CC11 value from 127 to 0 in steps of 8.
- Timing: The
absoluteTime___start___midstksunits + 256 + (127 - i) * 2
ensures that each CC11 event occurs at a specific time, creating a smooth transition. - Effect: As CC11 decreases, the volume of the note decreases, achieving a decrescendo.
Potential Improvements:
- Smoother Transitions: Instead of using fixed steps, consider using smaller increments for more subtle changes.
- Automation: Implement automation curves to dynamically adjust the CC11 values over time, allowing for more expressive control.
🎶 Vibrato (CC21) – Oscillating Values
What It Does:
- Purpose: CC21 controls the vibrato effect, which modulates the pitch of a note to create a trembling or oscillating sound.
- Implementation: You're adding CC21 events at specific times to simulate vibrato.
Code Breakdown:
csharp
for (
int i =
0; i <
3; i++)
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
120,
ChannelNumber,
MidiController.SAANS_VIBRATO,
64
), TrackNumber);
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
120,
ChannelNumber,
MidiController.SAANS_VIBRATO,
0
), TrackNumber);
}
- Iteration: This loop adds two CC21 events at each iteration: one with a value of 64 and another with a value of 0.
- Timing: The
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
ensures that each CC21 event occurs at a specific time, creating an oscillating effect. - Effect: The alternating CC21 values create a vibrato effect by modulating the pitch of the note.
Potential Improvements:
- Continuous Vibrato: Instead of discrete events, consider using a continuous range of values for CC21 to create a more natural vibrato effect.
- Randomization: Introduce slight variations in timing and CC21 values to simulate a more organic vibrato.
🎚️ Modulation (CC1) – Sweep
What It Does:
- Purpose: CC1 controls the modulation effect, which can be used to add subtle variations in pitch or timbre.
- Implementation: You're adding CC1 events at specific times to simulate a modulation sweep.
Code Breakdown:
csharp
for (
int i =
0; i <=
127; i +=
10)
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
2,
ChannelNumber,
MidiController.Modulation,
i
), TrackNumber);
}
- Iteration: This loop increases the CC1 value from 0 to 127 in steps of 10.
- Timing: The
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2
ensures that each CC1 event occurs at a specific time, creating a sweeping effect. - Effect: As CC1 increases, the modulation effect intensifies, creating a sweep.
Potential Improvements:
- Smooth Transitions: Use smaller increments for CC1 to create smoother modulation sweeps.
- Dynamic Control: Implement dynamic control over the modulation sweep, allowing for real-time adjustments.
📝 Summary of Enhancements
Effect | Current Approach | Suggested Improvement |
Crescendo/Decrescendo | Fixed step increments for CC11 | Use smaller increments and automation curves |
Vibrato | Discrete CC21 events with fixed values | Continuous CC21 values with randomization |
these are not silencing only the commented part are silensing the sounds and i think we can do these better effects i need the explainations what are better ways to implement these effects on whole durations of notes EXPLAIN THE LINES LINE TO LINE WHY THESE EFFECTS WORK AND WHAT THESE
ITERATIONS DO??????? //WHEN I AM USING THIS EXPRESSIONS THEN THE MIDI FILES ARE
NOT PLAYING ANY SOUNDS
//////// Expression (CC 11) - Crescendo and Decrescendo
//////for (int i = 0; i <= 127; i += 8)
//////{
////// collection
////// .AddEvent
////// (new
////// ControlChangeEvent
////// (
////// absoluteTime___start___midstksunits+ i * 2
////// ,
////// ChannelNumber
////// , MidiController.Expression
////// ,
////// i
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 0; i <= 127; i += 8)
//////for (int i = 127; i >= 0; i -= 8)
//////{
////// collection
////// .AddEvent
////// (
////// new
////// ControlChangeEvent
////// (
////// // 256 + (127 - i) * 2
////// absoluteTime___start___midstksunits+ 256 + (127 - i) * 2
////// ,
////// ChannelNumber
////// , MidiController.Expression
////// ,
////// i
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 127; i >= 0; i -= 8)
//it was not playing even i stopped this
// Vibrato (CC 21) - Oscillating values
for (int i = 0; i < 3; i++)
{
SAANSMIDSEVENTScollection.AddEvent
(
new ControlChangeEvent
(
// 600 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
, ChannelNumber
,
// (MidiController)21 // THIS ALSO WORKS
MidiController.SAANS_VIBRATO
//THIS ALSO WORKS MidiController.SAANS_VIBRATO
, 64
)
,
//TrackNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
//////////////////
SAANSMIDSEVENTScollection.AddEvent
(new
ControlChangeEvent
(
//660 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
,
//ChannelNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
// (MidiController)21 THIS WAS WORKING
MidiController.SAANS_VIBRATO
,
0
)
,
// TrackNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}// for (int i = 0; i < 3; i++)
//it was not playing even i stopped this
// Modulation (CC 1) - Sweep
for (int i = 0; i <= 127; i += 10)
{
SAANSMIDSEVENTScollection
.AddEvent
(new ControlChangeEvent
(
// 1000 + i * 2
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2
,
// ChannelNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
MidiController.Modulation
,
i
)
,
// TrackNumber
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}//for (int i = 0; i <= 127; i += 10)
THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
SAANSMIDSEVENTScollection
.AddEvent
(
new SAANAUDS.Midi.TextEvent
(
(
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_LYR_FOUND
+"_"+
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_INDINOTE_FOUND
).Replace(",","_")
,
SAANAUDS.Midi.MetaEventType.TextEvent
,
// absoluteTime
//////(long)((absoluteTime___start___midstksunits +
absoluteTime___final___midstksunits) / 6)
////// )
///
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
)
,
//TrackNumber
0
);
/////////////////////////////// interesting styles ////////////////////
///THE_DOUBLE_EVENT_COUNTER_TO_TRACK_ALL_INTERMEDIATE_EVENTS_IN_GLOBAL_LISTS++;
Let's dive into each section again, explaining why the effects work (or don't work as expected), what the iterations do, and then discuss better ways to implement these effects to span the whole duration of notes.
Understanding MIDI Control Changes (CCs)
Before we dissect the code, a quick refresher: MIDI Control Change (CC) messages are like digital knobs or sliders that let you adjust parameters of a sound in real-time. Each CC number (0-127) has a defined or common purpose, and its value (also 0-127) dictates the intensity of that parameter.
Expression (CC 11) - Crescendo and Decrescendo (The Silencer)
This section aims to control the volume of the sound using CC 11, the Expression controller. Think of Expression as a master volume knob for a particular instrument or channel. A value of 0 means the instrument is completely muted, and 127 means it's at its full expressive volume.
C#
//////for (int i = 0; i <= 127; i += 8)
//////{
////// collection
////// .AddEvent
////// (new
////// ControlChangeEvent
////// (
////// absoluteTime___start___midstksunits + i * 2 // This is the absolute time when this event will occur.
////// ,
////// ChannelNumber // The MIDI channel (0-15) to which this control change applies.
////// , MidiController.Expression // Specifies that this is CC 11 (Expression).
////// ,
////// i // The value of the expression, increasing from 0 to 127.
////// )
////// ,
////// TrackNumber // The MIDI track where this event is placed.
////// );
//////}//for (int i = 0; i <= 127; i += 8)
for (int i = 0; i <= 127; i += 8)
: This loop creates a crescendo (gradual increase in volume). It startsi
at 0 (silent) and increases it by 8 in each step until it reaches 127 (full volume).absoluteTime___start___midstksunits + i * 2
: This calculates the timestamp for each control change.absoluteTime___start___midstksunits
is a base time.i * 2
adds an increasing offset, ensuring each volume step happens slightly after the previous one, creating a smooth fade-in. The* 2
controls the speed of the crescendo; a larger multiplier would make it slower.MidiController.Expression
: This tells the MIDI player to adjust the Expression (CC 11) parameter.i
: This is the actual volume level being sent, increasing from 0 to 127.
C#
//////for (int i = 127; i >= 0; i -= 8)
//////{
////// collection
////// .AddEvent
////// (
////// new
////// ControlChangeEvent
////// (
////// // 256 + (127 - i) * 2
////// absoluteTime___start___midstksunits + 256 + (127 - i) * 2 // Absolute time for the decrescendo events.
////// ,
////// ChannelNumber
////// , MidiController.Expression // Specifies CC 11 (Expression).
////// ,
////// i // The value of the expression, decreasing from 127 to 0.
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 127; i >= 0; i -= 8)
for (int i = 127; i >= 0; i -= 8)
: This loop creates a decrescendo (gradual decrease in volume). It startsi
at 127 (full volume) and decreases it by 8 in each step until it reaches 0 (silent).absoluteTime___start___midstksunits + 256 + (127 - i) * 2
: This calculates the timestamp for the fade-out.256
is added to ensure these events happen after the crescendo. The(127 - i) * 2
term creates a progressive delay. Asi
decreases,(127 - i)
increases, meaning the events are spaced out, making the fade-out smooth.MidiController.Expression
: Again, targets Expression (CC 11).i
: This is the volume level, decreasing from 127 to 0.
Why this section caused silence: The core problem is the last event generated by the second loop sets Expression
to 0. If your MIDI file ends with Expression = 0
, any subsequent notes that play in that MIDI file (or if this file is played at the end of a sequence of files) will be silent because the instrument's master volume is effectively off. Even if you commented out the code, if a MIDI file was generated with this code active, it would have that Expression = 0
event embedded.
Better way to implement a crescendo/decrescendo over a note's duration:
To make these effects span the duration of a specific note, you'd integrate them directly with the note's Note On
and Note Off
times.
Let's assume you have a noteStartTime
and noteDuration
(in MIDI ticks).
C#
// Example: Crescendo over the first half of a note, then hold, then decrescendo over the last half
long noteStartTime = ...;
// The absolute start time of your note
long noteDuration = ...;
// The duration of your note in MIDI ticks
long noteEndTime = noteStartTime + noteDuration;
// --- Crescendo (first half of the note) ---
long crescendoEndTime = noteStartTime + (noteDuration /
2);
// Crescendo to the midpoint of the note
for (
int i =
0; i <=
127; i +=
8)
{
// Calculate a time within the crescendo phase
// This distributes 128 steps (0-127) evenly across the crescendo duration
long time = noteStartTime + (
long)((
double)i /
127.0 * (crescendoEndTime - noteStartTime));
collection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.Expression, i), TrackNumber);
}
// --- Decrescendo (second half of the note) ---
long decrescendoStartTime = noteStartTime + (noteDuration /
2);
// Decrescendo from the midpoint
for (
int i =
127; i >=
0; i -=
8)
{
// Calculate a time within the decrescendo phase
// This distributes 128 steps (0-127) evenly across the decrescendo duration
long time = decrescendoStartTime + (
long)(((
double)(
127 - i)) /
127.0 * (noteEndTime - decrescendoStartTime));
collection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.Expression, i), TrackNumber);
}
// Crucial: After the decrescendo, if you have subsequent notes, you must set expression back up!
// Or, if this is the last note, it's fine for it to fade out.
// For continuous playback, you might add:
// collection.AddEvent(new ControlChangeEvent(noteEndTime + 10, ChannelNumber, MidiController.Expression, 100), TrackNumber);
Explanation of the better way:
- We calculate
crescendoEndTime
anddecrescendoStartTime
to precisely control which part of the note's duration gets the effect. - The time calculation
(long)((double)i / 127.0 * (duration_of_phase))
ensures that the CC values (0-127) are mapped proportionally across the desired time range (e.g., the first half of the note). This creates a smoother and more predictable ramp. - For the decrescendo,
(127 - i)
is used to map the decreasingi
to an increasing position within the time range, ensuring the events are sent in the correct order.
Vibrato (CC 21) - Oscillating values (Ineffective)
This section tries to create a vibrato effect using CC 21, a General Purpose Controller (GPC 5). The term MidiController.SAANS_VIBRATO
suggests a custom or internal mapping, but by MIDI standard, CC 21 is just a general controller. Its effect depends entirely on how the specific instrument you're using is programmed to respond to it.
C#
for (
int i =
0; i <
3; i++)
{
SAANSMIDSEVENTScollection.AddEvent
(
new ControlChangeEvent
(
// 600 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
120
// Absolute time for the first part of the vibrato oscillation.
, ChannelNumber
,
// (MidiController)21 // THIS ALSO WORKS
MidiController.SAANS_VIBRATO
// Targets CC 21.
//THIS ALSO WORKS MidiController.SAANS_VIBRATO
,
64
// Sets CC 21 to a mid-range value (e.g., vibrato on).
)
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
//////////////////
SAANSMIDSEVENTScollection.AddEvent
(
new
ControlChangeEvent
(
//660 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
120
// Absolute time for the second part of the vibrato oscillation.
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
// (MidiController)21 THIS WAS WORKING
MidiController.SAANS_VIBRATO
// Targets CC 21.
,
0
// Sets CC 21 to 0 (e.g., vibrato off).
)
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
// for (int i = 0; i < 3; i++)
for (int i = 0; i < 3; i++)
: This loop runs 3 times, attempting to create 3 cycles of vibrato.- First
ControlChangeEvent
: LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
: This calculates the start time for a vibrato cycle.i * 120
means each cycle begins 120 time units after the previous one.MidiController.SAANS_VIBRATO
(CC 21): The controller., 64
: Sets the vibrato intensity to 64.- Second
ControlChangeEvent
: LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
: This is the key issue. It uses the exact same absolute time as the first event within the same iteration., 0
: Sets the vibrato intensity to 0.
Why this section was ineffective: Because both events in each iteration (value = 64
and value = 0
) happen at the identical absolute time, a MIDI player will likely receive them almost simultaneously. The value = 0
event will immediately overwrite the value = 64
event. This means the vibrato is effectively turned "on" and then immediately "off" in rapid succession, resulting in no audible vibrato or only a tiny flicker. You need a time difference between the "on" and "off" states to create an oscillation.
Better way to implement vibrato over a note's duration:
To create a continuous vibrato, you need to oscillate the CC value between two points (e.g., 0 and 127, or 32 and 96 for a more subtle effect) over time. You'll need to define the frequency (how fast it oscillates) and amplitude (how much it oscillates).
C#
// Example: Vibrato over the entire duration of a note
long noteStartTime = ...;
// The absolute start time of your note
long noteDuration = ...;
// The duration of your note in MIDI ticks
long noteEndTime = noteStartTime + noteDuration;
int vibratoPeak =
96;
// Maximum vibrato intensity
int vibratoTrough =
32;
// Minimum vibrato intensity
int vibratoSpeed =
20;
// How many MIDI ticks for one half-cycle (e.g., 20 ticks for half a wave)
// Generate vibrato events across the note's duration
for (
long time = noteStartTime; time < noteEndTime; time += vibratoSpeed)
{
// Send the "peak" value
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.SAANS_VIBRATO, vibratoPeak),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
// Send the "trough" value slightly later
if (time + vibratoSpeed < noteEndTime)
// Ensure we don't go past the note end
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(time + vibratoSpeed, ChannelNumber, MidiController.SAANS_VIBRATO, vibratoTrough),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
}
Explanation of the better way:
- We define
vibratoPeak
,vibratoTrough
, andvibratoSpeed
for control. - The loop iterates from
noteStartTime
tonoteEndTime
, stepping byvibratoSpeed
. - Inside the loop, we send
vibratoPeak
attime
andvibratoTrough
attime + vibratoSpeed
. This creates the crucial time delay between the high and low values, forming an actual oscillation that a MIDI player can interpret as vibrato.
Modulation (CC 1) - Sweep (Effective, but check instrument)
This section creates a sweep effect using CC 1, the Modulation Wheel controller. This is commonly used for vibrato, tremolo, filter sweeps, or other continuous modulations, depending on the instrument.
C#
for (
int i =
0; i <=
127; i +=
10)
{
SAANSMIDSEVENTScollection
.AddEvent
(
new ControlChangeEvent
(
// 1000 + i * 2
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
2
// Absolute time for each step of the sweep.
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
MidiController.Modulation
// Specifies CC 1 (Modulation Wheel).
,
i
// The value of the modulation, increasing from 0 to 127.
)
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
//for (int i = 0; i <= 127; i += 10)
for (int i = 0; i <= 127; i += 10)
: This loop iterates fromi = 0
(minimum modulation) up toi = 127
(maximum modulation), increasing by 10 each time. This creates a gradual increase in the modulation effect.LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2
: This calculates the time for each step.i * 2
provides a delay, making the sweep gradual.MidiController.Modulation
: This targets CC 1 (Modulation Wheel).i
: This is the value of the modulation controller, increasing from 0 to 127.
Why this section might not produce a noticeable effect (but wouldn't cause silence): This code is correctly generating a modulation sweep. The reason you might not hear a strong effect is because the instrument you're using might not have CC 1 mapped to an audible parameter, or it might be mapped to a subtle effect. For instance, if it's mapped to a slow LFO (Low-Frequency Oscillator) controlling pitch, a gradual sweep might be hard to perceive.
Better way to implement modulation over a note's duration:
This implementation is already decent for a sweep effect. To ensure it spans the whole note, you'd calculate its start and end times relative to the note.
C#
// Example: Modulate from 0 to 127 over the duration of a note
long noteStartTime = ...;
// The absolute start time of your note
long noteDuration = ...;
// The duration of your note in MIDI ticks
long noteEndTime = noteStartTime + noteDuration;
for (
int i =
0; i <=
127; i +=
10)
// Or use a smaller step for smoother modulation
{
// Calculate a time proportionally across the note's duration
long time = noteStartTime + (
long)((
double)i /
127.0 * noteDuration);
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.Modulation, i),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
Explanation of the better way:
- The
time
calculation ensures that the modulation sweep is distributed evenly across thenoteDuration
. This makes the effect directly tied to the length of the note.
Text Event (Informational)
This section adds a MIDI Text Event. These are "meta-events" in MIDI files, meaning they don't produce sound themselves but store textual information. They're useful for lyrics, markers, copyright, or general notes for a MIDI editor.
C#
SAANSMIDSEVENTScollection
.AddEvent
(
new SAANAUDS.Midi.TextEvent
(
(
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_LYR_FOUND
// Retrieves a string (likely lyrics).
+
"_"+
// Concatenates with an underscore.
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_INDINOTE_FOUND
// Retrieves another string (likely an Indian note name).
).Replace(
",",
"_")
// Replaces any commas in the combined string with underscores.
,
SAANAUDS.Midi.MetaEventType.TextEvent
// Specifies this is a Text Event.
,
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
// The absolute time when this text event appears in the MIDI file.
)
,
0
// Places this text event on MIDI track 0.
);
new SAANAUDS.Midi.TextEvent(...)
: Creates a new text event.- Text String Construction: The part in parentheses constructs the actual string: it combines a lyric string with an Indian note string, separated by an underscore, and replaces any commas with underscores. This is purely for informational purposes within the MIDI file.
SAANAUDS.Midi.MetaEventType.TextEvent
: This is a standard MIDI meta-event type.LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
: Sets the time at which this text event is recorded in the MIDI stream.0
: This meta-event is placed on track 0.
Why this doesn't affect sound: This is a non-audible event. It's like adding a comment to the musical score; it provides information but doesn't change how the music is played.
Overall Recommendation
To achieve better and more reliable effects:
- Always manage Expression (CC 11): Ensure it's at a desirable level (e.g., 100-127) when you want to hear notes. If you use fades, bring it back up afterward for subsequent notes.
- Understand your MIDI instrument's CC mappings: For effects like vibrato and modulation, the behavior depends on the specific virtual instrument or soundfont. Check its documentation or try different instruments to see how they respond to CC 1 and CC 21. If your
SAANS_VIBRATO
is a custom mapping, ensure it's correctly configured within your MIDI setup. - Use
Note On
/Note Off
times for effect durations: Integrate your CC loops with the actual note durations (noteStartTime
,noteDuration
,noteEndTime
) to ensure the effects start and end precisely with the notes. This allows for dynamic, per-note effects. - Introduce time differences for oscillating effects: For vibrato or tremolo, make sure there's a time gap between the "high" and "low" values of the controller to create a true oscillation.
The user wants a line-by-line explanation of the provided C# code snippet for generating MIDI control change events. They specifically want to understand:
- Why each effect works (or doesn't work as expected).
- What the iterations in the loops do.
- How to implement these effects better, specifically to span the whole duration of notes.
I need to address each commented and uncommented section, explain its purpose, analyze its current implementation, and then provide a "better way" to achieve the desired effect over a note's duration.
Plan:
- Introduction: Briefly explain MIDI CCs and the goal of the response.
- Expression (CC 11) - Crescendo and Decrescendo (Commented Out):
- Explain CC 11.
- Line-by-line breakdown of the first loop (crescendo):
for
loop,absoluteTime
,MidiController.Expression
,i
. - Line-by-line breakdown of the second loop (decrescendo):
for
loop,absoluteTime
(with256
offset),MidiController.Expression
,i
. - Why it caused silence: Reiterate that the final
i=0
event mutes the channel, and if a file was saved with this, it persists. - Better Implementation: Show how to calculate
absoluteTime
relative to anoteStartTime
andnoteDuration
to apply the effect precisely over a note's length. Emphasize ensuring expression is up for subsequent notes. - Vibrato (CC 21) - Oscillating values:
- Explain CC 21 (General Purpose Controller) and its dependency on instrument mapping.
- Line-by-line breakdown of the loop:
for
loop,absoluteTime
(for both 64 and 0 values),MidiController.SAANS_VIBRATO
,64
and0
. - Why it was ineffective: Highlight the critical issue of sending
64
and0
at the exact same absolute time, causing immediate overwrite. - Better Implementation: Show how to introduce a
vibratoSpeed
(time delay) between the high and low values to create a true oscillation over a note's duration. - Modulation (CC 1) - Sweep:
- Explain CC 1 (Modulation Wheel) and its common uses.
- Line-by-line breakdown of the loop:
for
loop,absoluteTime
,MidiController.Modulation
,i
. - Why it was less noticeable: Explain that the effect depends on instrument mapping, and a gradual sweep might be subtle.
- Better Implementation: Show how to scale the sweep across a note's duration using proportional time calculation.
- Text Event:
- Explain MIDI Text Events (meta-events).
- Line-by-line breakdown:
TextEvent
constructor, string concatenation,MetaEventType.TextEvent
,absoluteTime
,TrackNumber
. - Why it doesn't affect sound: Reiterate that it's informational.
- Conclusion: Summarize the importance of timing, instrument mapping, and managing CC 11.
You've provided a great code snippet that demonstrates how MIDI control changes (CCs) are used to add expression and effects to musical notes. It's excellent that you've identified that only the commented-out section was causing silence, and the others were simply not producing the desired effect. This is a common learning point in MIDI programming!
Let's break down each section line by line, explain what the iterations do, why the effects work (or don't work as intended), and then explore better ways to implement these effects to span the entire duration of notes.
Understanding MIDI Control Changes (CCs)
Before we dive into your code, let's clarify what MIDI Control Change (CC) messages are. Imagine a physical synthesizer with various knobs, sliders, and wheels. When you turn a knob, it changes a parameter of the sound (like volume, brightness, or vibrato speed). MIDI CCs are the digital equivalent of these physical controls.
- Each CC has a number (0-127) that identifies the parameter it controls (e.g., CC 7 is Volume, CC 11 is Expression, CC 1 is Modulation).
- Each CC has a value (0-127) that indicates the intensity or level of that parameter.
The effectiveness of a CC depends on how the specific MIDI instrument or sound module (the thing that actually makes the sound) is programmed to respond to it.
1. Expression (CC 11) - Crescendo and Decrescendo (The "Silencing" Section)
This section aims to create a dynamic change in volume, specifically a crescendo (gradual increase in volume) followed by a decrescendo (gradual decrease in volume). This is achieved using CC 11, the Expression controller. Expression acts as a scaling factor for the overall volume of an instrument on a specific MIDI channel. A value of 0 means the instrument is completely muted, and 127 means it's at its full expressive volume.
//////for (int i = 0; i <= 127; i += 8)
//////{
////// collection
////// .AddEvent
////// (new
////// ControlChangeEvent
////// (
////// absoluteTime___start___midstksunits + i * 2 // Calculate the absolute time for this specific event.
////// ,
////// ChannelNumber // The MIDI channel (0-15) to which this control change applies.
////// , MidiController.Expression // This specifies that we are controlling MIDI CC 11 (Expression).
////// ,
////// i // The value for the Expression controller, which will increase from 0 to 127.
////// )
////// ,
////// TrackNumber // The MIDI track where this event will be placed.
////// );
//////}//for (int i = 0; i <= 127; i += 8)
for (int i = 0; i <= 127; i += 8)
: Thisfor
loop is designed to create the crescendo.int i = 0
: Starts thei
variable (which will be our CC value) at 0, representing silence.i <= 127
: The loop continues as long asi
is less than or equal to 127 (full volume).i += 8
: In each iteration,i
increases by 8. This means the volume will step up in increments of 8, creating a relatively smooth ramp.absoluteTime___start___midstksunits + i * 2
: This calculates the absolute time (in MIDI ticks) when thisControlChangeEvent
should occur within the MIDI sequence.absoluteTime___start___midstksunits
: This is a base starting time for this sequence of events.i * 2
: This adds a time offset that increases withi
. Asi
goes from 0 to 127, this offset grows, spreading out the volume changes over time. The* 2
determines the speed of the crescendo; a larger multiplier would make the crescendo slower, while a smaller one would make it faster.MidiController.Expression
: This is an enumeration (or constant) that maps to MIDI Control Change number 11. When a MIDI player receives this, it knows to adjust the instrument's expression.i
: This is the actual value (0-127) that is sent for the Expression controller. Asi
increases, the volume gradually increases.
//////for (int i = 127; i >= 0; i -= 8)
//////{
////// collection
////// .AddEvent
////// (
////// new
////// ControlChangeEvent
////// (
////// // 256 + (127 - i) * 2
////// absoluteTime___start___midstksunits + 256 + (127 - i) * 2 // Calculate the absolute time for this event.
////// ,
////// ChannelNumber
////// , MidiController.Expression // Still controlling MIDI CC 11 (Expression).
////// ,
////// i // The value for the Expression controller, now decreasing from 127 to 0.
////// )
////// ,
////// TrackNumber
////// );
//////}//for (int i = 127; i >= 0; i -= 8)
for (int i = 127; i >= 0; i -= 8)
: Thisfor
loop is designed to create the decrescendo.int i = 127
: Startsi
at 127 (full volume).i >= 0
: The loop continues as long asi
is greater than or equal to 0 (silence).i -= 8
: In each iteration,i
decreases by 8, creating a gradual fade-out.absoluteTime___start___midstksunits + 256 + (127 - i) * 2
: This calculates the absolute time for the decrescendo events.absoluteTime___start___midstksunits + 256
: The256
is an additional offset, ensuring that this decrescendo sequence starts after the crescendo sequence has completed.(127 - i) * 2
: Asi
decreases (from 127 down to 0), the term(127 - i)
increases (from 0 up to 127). This effectively creates a progressive time offset for the decreasing volume steps, ensuring the fade-out is smooth.MidiController.Expression
: Again, targets CC 11.i
: The value sent for Expression, which decreases from 127 to 0.
Why this section caused silencing (when active): The crucial point here is that the last event generated by the second loop sets the Expression value to 0
. If this code was active and generated a MIDI file, that Expression = 0
event would be embedded in the file. When a MIDI player encounters this event, it effectively mutes the instrument on that channel. Even if you then comment out the code, the generated MIDI file would still contain that silencing event, causing subsequent notes to be unheard. To fix this, you'd need to regenerate the MIDI file without that final Expression = 0
or ensure a CC 11
event with a value greater than 0
is sent later.
Better Way to Implement Crescendo/Decrescendo Over Note Duration
To apply a crescendo or decrescendo precisely over the duration of a specific note (or a section of notes), you need to tie the timing of these CC events to the Note On
and Note Off
times.
Let's assume you have a noteStartTime
and noteDuration
(in MIDI ticks).
// Example: Crescendo over the first half of a note, then decrescendo over the second half
long noteStartTime =
/* your note's absolute start time */;
long noteDuration =
/* your note's duration in MIDI ticks */;
long noteEndTime = noteStartTime + noteDuration;
// Define the duration for the crescendo and decrescendo phases
long crescendoDuration = noteDuration /
2;
// First half of the note
long decrescendoDuration = noteDuration - crescendoDuration;
// Remaining duration
// --- Crescendo (first half of the note) ---
// Loop through possible CC values (0 to 127)
for (
int i =
0; i <=
127; i +=
8)
{
// Calculate the time for this specific CC event, proportional to the crescendo duration
// This maps the 'i' value (0-127) smoothly across the 'crescendoDuration'
long time = noteStartTime + (
long)((
double)i /
127.0 * crescendoDuration);
collection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.Expression, i),
TrackNumber
);
}
// --- Decrescendo (second half of the note) ---
// Loop through possible CC values (127 down to 0)
for (
int i =
127; i >=
0; i -=
8)
{
// Calculate the time for this specific CC event, proportional to the decrescendo duration
// (127 - i) maps the decreasing 'i' to an increasing offset for time calculation
long time = (noteStartTime + crescendoDuration) + (
long)(((
double)(
127 - i)) /
127.0 * decrescendoDuration);
collection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.Expression, i),
TrackNumber
);
}
// IMPORTANT: If you have subsequent notes, ensure Expression is set back to an audible level!
// For example, if you want the next note to play at full volume:
// collection.AddEvent(new ControlChangeEvent(noteEndTime + 10, ChannelNumber, MidiController.Expression, 127), TrackNumber);
Explanation of the Better Way:
noteStartTime
,noteDuration
,noteEndTime
: These variables are crucial for anchoring the effects to the actual note.- Proportional Time Calculation: The key is
(long)((double)i / 127.0 * duration_of_phase)
. This formula takes the currenti
value (0-127) and scales it to fit perfectly within thecrescendoDuration
ordecrescendoDuration
. This ensures the fade is smooth and lasts exactly as long as intended. noteStartTime + crescendoDuration
: This correctly sets the starting point for the decrescendo phase, right after the crescendo ends.- Resetting Expression: The comment about resetting Expression is vital. If you fade out a note to 0, and then another note starts, it will be silent unless you send another
CC 11
event with a higher value.
2. Vibrato (CC 21) - Oscillating Values (Ineffective)
This section attempts to create a vibrato effect. Vibrato is a periodic, slight variation in pitch. It's usually achieved by rapidly oscillating a pitch-related parameter. Your code uses CC 21, which is a General Purpose Controller (GPC 5). The effect of GPCs is entirely dependent on how the specific MIDI instrument or sound module is programmed. While it can be used for vibrato, it's not a standard assignment like CC 1 (Modulation Wheel).
for (
int i =
0; i <
3; i++)
{
SAANSMIDSEVENTScollection.AddEvent
(
new ControlChangeEvent
(
// 600 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
120
// Absolute time for the first part of the vibrato oscillation.
, ChannelNumber
,
// (MidiController)21 // THIS ALSO WORKS
MidiController.SAANS_VIBRATO
// This targets MIDI CC 21. 'SAANS_VIBRATO' is likely a custom name for this CC.
//THIS ALSO WORKS MidiController.SAANS_VIBRATO
,
64
// Sets the value of CC 21 to 64 (mid-range).
)
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
//////////////////
SAANSMIDSEVENTScollection.AddEvent
(
new
ControlChangeEvent
(
//660 + i * 120
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
120
// Absolute time for the second part of the vibrato oscillation.
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
// (MidiController)21 THIS WAS WORKING
MidiController.SAANS_VIBRATO
// Still targeting MIDI CC 21.
,
0
// Sets the value of CC 21 to 0 (minimum).
)
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
// for (int i = 0; i < 3; i++)
for (int i = 0; i < 3; i++)
: This loop runs 3 times, attempting to create 3 "cycles" of vibrato.- First
ControlChangeEvent
: LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
: Calculates the time for the "on" part of the vibrato. Each cycle starts 120 MIDI ticks after the previous one.MidiController.SAANS_VIBRATO
(CC 21): The controller being targeted., 64
: Sets the vibrato intensity to a mid-range value.- Second
ControlChangeEvent
: LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 120
: This is the critical issue. It uses the exact same absolute time as the first event within the same iteration., 0
: Sets the vibrato intensity to 0.
Why this section was ineffective: Because both the 64
value and the 0
value for CC 21 are sent at the identical absolute time within each loop iteration, a MIDI player will process them almost simultaneously. The 0
value will immediately overwrite the 64
value. This means the vibrato is effectively turned "on" and then instantly "off," resulting in no audible vibrato effect or only a tiny, imperceptible flicker. To create an oscillation, you need a time delay between the "on" and "off" states.
Better Way to Implement Vibrato Over Note Duration
To create a continuous vibrato, you need to oscillate the CC value between two points (e.g., a minimum and maximum intensity) over time. This involves sending many small, rapid control changes.
// Example: Vibrato over the entire duration of a note
long noteStartTime =
/* your note's absolute start time */;
long noteDuration =
/* your note's duration in MIDI ticks */;
long noteEndTime = noteStartTime + noteDuration;
int vibratoPeak =
96;
// Maximum vibrato intensity (e.g., 75% of full range)
int vibratoTrough =
32;
// Minimum vibrato intensity (e.g., 25% of full range)
int vibratoSpeedTicks =
10;
// How many MIDI ticks for one *half-cycle* of the vibrato wave (e.g., 10 ticks for peak to trough)
// Generate vibrato events across the note's duration
for (
long time = noteStartTime; time < noteEndTime; time += (vibratoSpeedTicks *
2))
// Step by a full cycle duration
{
// Send the "peak" value
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.SAANS_VIBRATO, vibratoPeak),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
// Send the "trough" value slightly later (half a cycle later)
long troughTime = time + vibratoSpeedTicks;
if (troughTime < noteEndTime)
// Ensure we don't go past the note end
{
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(troughTime, ChannelNumber, MidiController.SAANS_VIBRATO, vibratoTrough),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
}
// Optional: Set vibrato to 0 at the very end of the note if you want it to stop abruptly
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(noteEndTime, ChannelNumber, MidiController.SAANS_VIBRATO,
0),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
Explanation of the Better Way:
vibratoPeak
,vibratoTrough
: Define the range of the vibrato.vibratoSpeedTicks
: This is crucial. It defines the time duration for half of a vibrato cycle (e.g., from peak to trough, or trough to peak). A smaller value means faster vibrato.- Looping by
vibratoSpeedTicks * 2
: The loop advances by a full vibrato cycle each time. - Time Offset for Trough: Inside the loop, the
vibratoTrough
value is sent attime + vibratoSpeedTicks
. This creates the necessary time delay between the high and low values, allowing the MIDI player to interpret it as an oscillation. - Ending Vibrato: It's good practice to send a
CC 21, 0
event at the end of the note to ensure the vibrato stops cleanly.
3. Modulation (CC 1) - Sweep (Effective, but check instrument)
This section creates a sweep effect using CC 1, the Modulation Wheel controller. This is a very common and widely recognized CC. It's typically used for vibrato (pitch modulation), tremolo (volume modulation), filter sweeps (timbre modulation), or other continuous changes, depending on how the instrument is programmed.
for (
int i =
0; i <=
127; i +=
10)
{
SAANSMIDSEVENTScollection
.AddEvent
(
new ControlChangeEvent
(
// 1000 + i * 2
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i *
2
// Absolute time for each step of the sweep.
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_CHANNEL_NUMBER_0_TO_15
,
MidiController.Modulation
// This specifies MIDI CC 1 (Modulation Wheel).
,
i
// The value for the Modulation controller, increasing from 0 to 127.
)
,
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
//for (int i = 0; i <= 127; i += 10)
for (int i = 0; i <= 127; i += 10)
: Thisfor
loop creates a modulation sweep.int i = 0
: Startsi
at 0 (minimum modulation).i <= 127
: Loop continues untili
reaches 127 (maximum modulation).i += 10
:i
increases by 10 in each step, creating a gradual increase in the modulation effect.LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS + i * 2
: This calculates the absolute time for each step of the sweep.i * 2
adds a time offset, spreading out the modulation changes over time, making the sweep gradual.MidiController.Modulation
: This maps to MIDI Control Change number 1.i
: The value sent for the Modulation controller, increasing from 0 to 127.
Why this section might not produce a noticeable effect: The code for the modulation sweep is correctly implemented for a sweep. The reason you might not hear a strong effect is primarily due to:
- Instrument Mapping: The specific MIDI instrument or soundfont you are using might have CC 1 mapped to a subtle parameter (e.g., a very slow vibrato, or a filter that doesn't change much over its range).
- Lack of Note Context: This sweep starts at
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
. If no notes are playing during this sweep, or if the notes are very short, you won't hear the effect.
Better Way to Implement Modulation Sweep Over Note Duration
This implementation is already good for a sweep. To ensure it spans the whole note, you'd integrate it with the note's timing, similar to the crescendo example.
// Example: Modulate from 0 to 127 over the entire duration of a note
long noteStartTime =
/* your note's absolute start time */;
long noteDuration =
/* your note's duration in MIDI ticks */;
long noteEndTime = noteStartTime + noteDuration;
// Loop through possible CC values (0 to 127)
for (
int i =
0; i <=
127; i +=
5)
// Use a smaller step (e.g., 5) for a smoother sweep
{
// Calculate the time for this specific CC event, proportional to the note's duration
// This maps the 'i' value (0-127) smoothly across the 'noteDuration'
long time = noteStartTime + (
long)((
double)i /
127.0 * noteDuration);
SAANSMIDSEVENTScollection.AddEvent(
new ControlChangeEvent(time, ChannelNumber, MidiController.Modulation, i),
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
);
}
// Optional: Set modulation to 0 at the very end of the note if you want it to reset
// SAANSMIDSEVENTScollection.AddEvent(
// new ControlChangeEvent(noteEndTime, ChannelNumber, MidiController.Modulation, 0),
// Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS.PUBLIC_INT_TRACK_NUMBER_0_TO_ANY_NUMBER
// );
Explanation of the Better Way:
- The
time
calculation(long)((double)i / 127.0 * noteDuration)
is key. It ensures that the modulation sweep's steps are distributed evenly across thenoteDuration
, making the effect directly tied to the length of the note. - Using a smaller step size (e.g.,
i += 5
instead ofi += 10
) will result in more CC events and a smoother, more continuous sweep.
4. Text Event (Informational)
This final section adds a MIDI Text Event to your collection. Text events are a type of meta-event in MIDI files. They don't produce any sound or affect the instrument's parameters directly. Instead, they store textual information within the MIDI file, which can be read by MIDI editors or sequencers.
SAANSMIDSEVENTScollection
.AddEvent
(
new SAANAUDS.Midi.TextEvent
(
(
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_LYR_FOUND
// Retrieves a string, likely containing lyrics.
+
"_"+
// Concatenates it with an underscore.
Object_of_PUBLIC_CLASS_TO_LOAD_FOR_PRELISTENS_SINGLE_ROWS_NOTE_DATA_DETAILS
.PUBLIC_STRING_THE_INDINOTE_FOUND
// Retrieves another string, likely containing an Indian note name or similar musical notation.
).Replace(
",",
"_")
// Replaces any commas within the combined string with underscores.
,
SAANAUDS.Midi.MetaEventType.TextEvent
// Specifies that this is a MIDI Text Event.
,
LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
// The absolute time when this text event will appear in the MIDI file.
)
,
0
// Places this text event on MIDI track 0.
);
new SAANAUDS.Midi.TextEvent(...)
: This creates a new instance of aTextEvent
object.- Text String Construction: The first argument to the
TextEvent
constructor is the actual text string. It's built by concatenating two public string properties (PUBLIC_STRING_THE_LYR_FOUND
andPUBLIC_STRING_THE_INDINOTE_FOUND
) with an underscore, and then replacing any commas in the resulting string with underscores. This is purely for storing human-readable information. SAANAUDS.Midi.MetaEventType.TextEvent
: This is a standard MIDI meta-event type that tells a MIDI parser that the accompanying data is a text string.LONG_OVERALL_CUMULATIVE_START_TIMES_ABSOLUTE_TIMER_CALCULATIONS
: This sets the timestamp for the text event. It indicates at what point in the musical timeline this text is relevant.0
: This specifies that the text event should be placed on MIDI track 0.
Why this doesn't affect sound: This event is purely for informational purposes. It's akin to adding a comment or a lyric sheet to a musical score. It does not send any commands to the sound-generating part of a MIDI instrument, so it has no direct impact on whether your MIDI file plays sound or how it sounds.
Conclusion and Key Takeaways for Better Effects
You're on the right track with using CCs for expressive control! The main lessons for achieving better and more reliable effects are:
- Master Expression (CC 11): Always ensure that CC 11 is at an audible level (e.g., 100-127) when you want notes to be heard. If you use fades, remember to bring the expression back up for subsequent notes if you want them to be audible.
- Precise Timing: For effects that span a note's duration, calculate the absolute times for your CC events proportionally to the
noteStartTime
andnoteDuration
. This ensures the effect starts and ends precisely with the note. - Oscillation Requires Time: For vibrato or tremolo, you must introduce a time delay between the high and low values of the controller to create a true, audible oscillation. Sending them at the same time will result in no effect.
- Instrument Mapping Matters: For General Purpose Controllers (like CC 21) and even standard controllers like CC 1 (Modulation), the actual audible effect depends entirely on how the specific virtual instrument or sound module you are using is programmed. If you're not hearing an effect, try a different instrument or consult its MIDI implementation chart.
- Smoothness vs. Step Size: The step size in your
for
loops (e.g.,+= 8
,+= 10
,+= 5
) determines the smoothness of the effect. Smaller step sizes (e.g.,+= 1
or+= 2
) will generate more CC events and result in a very smooth, continuous change, but will also make your MIDI file larger.
No comments:
Post a Comment