key signature আধুনিক confusion RPN pirchbend
আধুনিকতার কনফিউশন
ব্ল্যাকবোর্ড এ পাওয়ারপয়েন্ট প্রেজেন্টেশন দেওয়ার মতন আধুনিক সমস্যা
Automated স্টেজ এর আলো গুলোকে ফোয়ারা গুলোকে নাচাতে না চাইলে এখন আর key সিগনেচার এর দরকার হয়না তেমন। স্টাফ নোটেশন গুলো অটোমেট করতে না চাইলে তো আরো দরকার হয়না key সিগনেচার গুলোর। আমরা যারা milisecond হিসেব করে নোট গুলো place করি cad এর মতন করে calculate করে করে milusecond এর নিক্তি মেপে মেপে boq তৈরি করে করে নোট গুলোকে পরিমাপ করে করে ওজন দিই সেগুলোতে তাদের জন্য key সিগনেচার এর কোন তেমন প্রয়োজন হয় না।
MIDI প্রোগ্রামিং এ Key Signature মূলত একটি "musical meta data" এটি বলছে কোন scale বা raga অনুযায়ী composition লেখা হয়েছে, কিন্তু এটি অডিও প্লে আউটপুট বা actual sound কে সরাসরি প্রভাবিত করে না।
Key Signature কী?
Key Signature হল একটি MIDI Meta Message (type 0x59), যা এই তথ্য দেয়।হাতে করে স্টাফ নোটেশন লিখলে সাহায্য হয় তাতে।
Composition কোন key তে আছে (যেমন C Major, A Minor, etc.)
কতটি sharp বা flat আছে
Major নাকি Minor
MIDI-l তে Key Signature এর ব্যবহার
NAudio দিয়ে Key Signature Add করা যায় কিভাবে?
var metaEvent = new MetaEvent(MetaEventType.KeySignature, 2, absoluteTime);
metaEvent.Data = new byte[] { 0, 0 }; // C major
midiEventCollection.AddEvent(metaEvent, track);
{ 0, 0 } = 0 sharps, 0 flats = C major
{ -3, 1 } = 3 flats, minor scale
Key Signature "sound" নয়, "musical context" বোঝায়।Playback, pitch, velocity এগুলো key signature দ্বারা প্রভাবিত হয় না।Indian Ragas এর context এ এটা শুধুই informational, functional নয়।
অভিজ্ঞতা থেকে যখন আমরা কিছু জিনিস বুঝতে পারি আর পণ্ডিত দের কাছে শিখতে গিয়ে যখন প্রাচীন পদ্ধতি তে আটকে যেতে বাধ্য হইতখন খুবই ক্লান্ত লাগে। স্বাভাবিক ভাবেই আমাদের দৈনন্দিন হাই টেক পরীক্ষা নিরীক্ষার সাথে তত্ত্ব গুলো মেলে না অনেক ক্ষেত্রে।Audacity তে মিডি প্লে করলে আমরা টেম্পো bpm পরিবর্তিত করে প্লে করতে পারি vlc তে মিডি ফাইল এর tempo আর মিডি ফাইল এর time সিগিগনেচার গুলোই নেয়। কত বার প্রশ্ন আসে মনে মিডি ফাইল এর Time সিগনেচার পরিবর্তন করলে vlc তে প্লে করলে তাল বদলে যাবে নাকি সুর বদলে যাবে??????
MIDI ফাইলের Time Signature পরিবর্তন করলে VLC তে সুর (pitch বা scale) বদলায় না, কিন্তু খাতায় নোটেশন গুলো লিখতে গেলে তাল (rhythm, meter) সংক্রান্ত তথ্য বদলাতে পারে তবে সেটা শুধু visual বা theoretical, actual playback এ তেমন পরিবর্তন হয় না।
Time Signature MIDI-তে কী?
Time Signature হচ্ছে একটি MIDI Meta Event (0x58), যেটা এই তথ্য দেয় যাতে খাতায় লেখা নোটেশন গুলো কে মিলিয়ে দেখা যায়। তাছাড়া কোন তফাৎ হয় না প্লে হওয়ার সময়।
Numerator
প্রতি measure এ কতটা beat আছে (উপরের সংখ্যা)
Denominator
কোন নোট ভ্যালু হচ্ছে 1 beat (নিচের সংখ্যা)
উদাহরণ খাতায় লিখতে সহজ হয় সিভিল ইঞ্জিনিয়ার দের গ্রিড এর মতন। যারা ডিসটেন্স মেপে কাজ করে তাদের গ্রিড না তৈরি করলেও একই আউটপুট আসে।
4/4 মানে প্রতি বারবিএ ৪টি beat, প্রতিটি beat হল quarter note
6/8 মানে প্রতি বার এ ৬টি beat, প্রতিটি beat হল eighth note লিখতে হবে খাতায়।vlc পাত্তাও দেবে না সেই নোটেশন গুলোকে।
Time Signature Playback এ কীভাবে কাজ করে?
যদি VLC তে MIDI বাজে
Time Signature = শুধুই তাল/beat count এর ভিজুয়াল রিপোর্ট এর ছবি টা বোঝায়, pitch বা সুর প্লে হওয়ার ক্ষেত্রে কোন কিছুই একেবারেই বদলায় না।এবং 4/4 থেকে 3/4 করে শুনে কোন তফাৎ পাই না তখন নিজের কান কে অবিশ্বাস হয় , VLC তাতে সুর ঠিক থাকবে, তাল বা বীট গণনা VLC বুঝেও কাজ করবে না, কারণ VLC শুধু raw MIDI events বাজায়, time signature এর সাথে sync করে না
// 3/4 time signature: 3 beats per bar, quarter note gets 1 beat
var timeSignature = new TimeSignatureEvent(0, 3, 2, 24, 8);
track.Add(timeSignature);
3 = beats per bar
2 = log2(note value), 2 means quarter note
24 = MIDI clocks per metronome click
8 = number of 1/32 notes per 24 MIDI clocks
Time Signature শুধুই musical structure বোঝায়।VLC playback স্রেফ নোট বাজায়, beat structure অনুযায়ী তাল রাখে না।সুর বা pitch একেবারেই পরিবর্তন হয় না।Tempo (BPM) আলাদা Meta Event, tempo বদলালে playback speed পরিবর্তন হয়, কিন্তু time signature বদলালে প্লে করার ক্ষেত্রে কোন এফেক্ট হয় না।
স্বাভাবিক ভাবেই প্রোগ্রাম লেখার সময় মাথায় ঘোরে একটা মিডি ফাইল এ কতবার টেম্পো পরিবর্তন করা যায়??? কেনো করা হয়??? টেম্পো কি track এর জন্য প্রয়োগ হয় নাকি চ্যানেল এর জন্য???
প্রশ্ন ১ একটা MIDI ফাইলে কতবার Tempo পরিবর্তন করা যায়?
উত্তর
একটি MIDI ফাইলে অসীম সংখ্যক বার Tempo পরিবর্তন করা যায়।এটি একটি Meta Event (SetTempo) যা টাইমলাইনের যেকোনো স্থানে রাখা যায়। এটা প্লে করার সময় তফাত দেখায়।ফলে, তুমি চাইলে প্রতিটি beat বা measure এর আগেও tempo বদলাতে পারো।
প্রশ্ন ২ কেনো Tempo পরিবর্তন করা হয়?
কারণসমূহ
1. Expressiveness ভারতীয় বা পশ্চিমা শাস্ত্রীয় সংগীতে কোথাও দ্রুত, কোথাও ধীরে এটা “tempo rubato” বা expressive timing। তারপর আলাপ জোর হয়ে ঝালা পর্যন্ত 3 বার তো টেম্পো পরিবর্তন হয় সাধারণত। তবে সঞ্জয় নাথ গাণিতিক ভাবেই নোট এর ডিউরেশন গুলো বদলে বদলে একই এফেক্ট আনে।
2. Section Changes গানের verse, chorus, alap, jhala ইত্যাদিতে আলাদা tempo দরকার হয়।
3. Composition Structure নাটকীয় পরিবর্তন (dramatic buildup or slowdown) দিতে।
4. Realistic Playback মানুষের মত tempo-তে variation আনতে, robotic না শোনানোর জন্য।
প্রশ্ন ৩ Tempo কি track এর জন্য প্রয়োগ হয় নাকি চ্যানেল এর জন্য?
Tempo হচ্ছে গোটা MIDI ফাইল বা Sequence-এর জন্য বৈধ
track বা channel ভিত্তিক নয়।
SetTempo একটি Meta Event, যা শুধুমাত্র MIDI ফিলেবএর ১ নম্বর track (usually the Conductor track) এ থাকে। লিরিক্স গুলো আমি সেখানেই রাখি।
যখন tempo change করা হয়, সেটা সব track ও সব channel এ প্রভাব ফেলে।
এটা যেমন “গোটা orchestra র জন্য একজন conductor কতটা দ্রুত beat দিচ্ছে” সেইরকম।
Extra Info: Tempo কিভাবে নির্ধারিত হয় MIDI-তে?
Tempo set করা হয় “microseconds per quarter note” দিয়ে।
উদাহরণ একটা অংক
int bpm = 120;
int tempo = 60000000 / bpm;
var tempoEvent = new TempoEvent(tempo, 0); // tick 0
track.Add(tempoEvent);
60000000 / bpm = microseconds per quarter note
উদাহরণস্বরূপ, 120 bpm হলে 500000 microseconds per quarter note
Tempo Events বিভিন্ন সময়ে যুক্ত করা যায়
// শুরুতে 100 BPM
track.Add(new TempoEvent(60000000 / 100, 0));
// 10th second এ 140 BPM
track.Add(new TempoEvent(60000000 / 140, midiTimeConverter.SecondsToTicks(10)));
// 20th second এ আবার 90 BPM
track.Add(new TempoEvent(60000000 / 90, midiTimeConverter.SecondsToTicks(20)));
MIDI ফাইলের মধ্যে কোন কোন Control Change (CC) গুলো VLC এর FluidSynth soundfont প্লেব্যাকে প্রভাব ফেলে?
FluidSynth (যেটা VLC ব্যবহার করে MIDI বাজানোর জন্য) GM (General MIDI) standard অনুযায়ী অনেকগুলো Control Change message বুঝে এবং সেগুলোতে সাড়া দেয়। নিচে সেই Control Change গুলো উল্লেখ করা হলো যেগুলো বাস্তবে সাউন্ড প্রভাবিত করে FluidSynth প্লেব্যাকে
প্রধান Control Change Messages (CC) যা FluidSynth বা VLC তে প্রভাব ফেলে
যে Control Change গুলো VLC / FluidSynth এ প্রায় কোনো প্রভাব ফেলে না বা নির্ভর করে SoundFont এর capability এর উপর
FluidSynth-Specific বিষয়
FluidSynth এর কার্যকারিতা অনেকটা তার SoundFont ফাইলের উপর নির্ভর করে। যদি কোনো high quality SoundFont (যেমন FluidR3_GM.sf2) ব্যবহার হলে, তাহলে Reverb/Chorus/Modulation বেশ ভালো সাড়া দেয়।
VLC বা FluidSynth MIDI playback এ নিচের CC গুলো সবচেয়ে কার্যকরী
CC 1 (Modulation)
CC 7 (Volume)
CC 10 (Pan)
CC 11 (Expression)
CC 64 (Sustain Pedal)
CC 91 (Reverb)
CC 93 (Chorus)
Strict note
সঞ্জয় নাথ যেহেতু CADএর মত millisecond নিক্তি দিয়ে MIDI গঠন করে এতে CC 11 (Expression) আর CC 64 (Sustain) কে সময় অনুযায়ী Automate করলে খুব চমৎকার dynamics তৈরি করা যায়।
VLC বা FluidSynth এ যেসব MIDI Control Change (CC) নম্বর সরাসরি শব্দে প্রভাব ফেলে
Vlc তে কাজ করে এমন CC নম্বর ও কী করে তা
1. CC 1 – Modulation Wheel হালকা vibrato বা tremolo যোগ করে। কিছু ইন্সট্রুমেন্টে স্পষ্ট শোনা যায়।
2. CC 7 – Channel Volume প্রতিটি চ্যানেলের শব্দের প্রধান গেইন নিয়ন্ত্রণ করে।
3. CC 10 – Pan সাউন্ডকে বাম বা ডান দিকে সরায় (Stereo position)।
4. CC 11 – Expression Dynamic volume control — CC 7-এর উপর ভিত্তি করে ভলিউম নিয়ন্ত্রণ করে (soft/loud)।
5. CC 64 – Sustain Pedal: নোট ছাড়ার পরেও বাজতে থাকে, sustain যোগ করে। Piano বা Violin-এর মতো ইফেক্ট দিতে ব্যবহৃত হয়।
6. CC 91 – Reverb Send Level: রিভার্ব যোগ করে, SoundFont সাপোর্ট করলে শোনা যায়।
7. CC 93 – Chorus Send Level: Chorus বা echo টাইপ ইফেক্ট যোগ করে, কিন্তু সব ইন্সট্রুমেন্টে কাজ নাও করতে পারে।
যেগুলো কাজ করে না বা সাউন্ডে প্রভাব ফেলে না (FluidSynth/VLC-তে)
CC 2, 4, 5, 68 কাজ করে না বা শুধুই কিছু synthesizer এ।
CC 120 127 এগুলো সাউন্ড বন্ধ করে, রিসেট করে; কিন্তু কোনো নতুন শব্দ তৈরি করে না।
Pitch Bend Sensitivity RPN (Registered Parameter Number) MIDI তে এমন একটি বিশেষ মেসেজ যা বলে দেয়, Pitch Bend Wheel কতটা সেমিটোন পর্যন্ত কাজ করবে।
কী কাজ করে Pitch Bend Sensitivity RPN?
Pitch Bend সাধারনত ±8192 মানে ±2 সেমিটোন পর্যন্ত bend করে।
RPN 0 (Pitch Bend Sensitivity) সেট করে এই সীমা
দরকার হলে ±1, ±3, এমনকি ±12 (এক octave) সেমিটোন করতে পারে উচিত।
ব্যবহার করার পদ্ধতি (CC মেসেজ দিয়ে):
Step 1 RPN নির্বাচন করো (RPN 0 = Pitch Bend Sensitivity):
CC 101 (RPN MSB) = 0
CC 100 (RPN LSB) = 0
Step 2 Sensitivity মান সেট করতে হয় (CC 6 = MSB, CC 38 = LSB):
উদাহরণ
যদি 0 থেকে 16384 অবধি ±12 সেমিটোন দরকার হয়
CC 6 = 12 (MSB = 12 semitones)
CC 38 = 0 (LSB = 0 cents)
Step 3 (Optional) RPN deselect (reset):
CC 101 = 127
CC 100 = 127
RPN 0 = Pitch Bend Sensitivity
CC 6 দিয়ে সেমিটোন সংখ্যা সেট করে
Pitch Bend Wheel এখন ওই পরিমাণ পর্যন্ত bend করবে
FluidSynth বা VLC তে rpn এটা কি কাজ করে?
FluidSynth: হ্যাঁ, সঠিকভাবে RPN সেট করলে Pitch Bend sensitivity পরিবর্তন করে।VLC তে সঞ্জয় নাথ চেষ্টা করে পারেনি আগে।সাধারণভাবে না, VLC অনেক সময় এগুলো ইগনোর করে বা ঠিকঠাক ব্যাখ্যা করে না।
ভারতীয় রা
গ সঙ্গীত এর জন্য প্রোগ্রামিং
MIDI তে Key Pressure বলতে দুই ধরনের ডেটা বোঝানো হতে পারে, এবং এগুলো অনেক সময় গুলিয়ে ফেলা হয়
1. Channel Aftertouch (বা Channel Pressure)
এটি পুরো চ্যানেলের উপর ভিত্তি করে একটি মাত্র প্রেসার ভ্যালু পাঠায়।
অর্থাৎ, আপনি যদি একটি চ্যানেলে একাধিক কী বাজান, তবে এই টাইপের aftertouch সবগুলো নোটের জন্য একই প্রেসার ভ্যালু প্রয়োগ করে।
MIDI Message Format
Status byte: 0xD0 + channel
Data byte 1 প্রেসার ভ্যালু (0–127)
2. Polyphonic Aftertouch (বা Key Pressure)
এটি প্রতি কী আলাদাভাবে প্রেসার সেন্স করে — অর্থাৎ কোন কী-তে কতটা চাপ দেওয়া হচ্ছে সেটা আলাদাভাবে জানায়।
অনেক উন্নত কীবোর্ড/সিন্থে এই ফিচার থাকে।
MIDI Message Format
Status byte: 0xA0 + channel
Data byte 1 note number (0–127)
Data byte 2 প্রেসার ভ্যালু (0–127)
এর কাজ কী?
Key Pressure (Aftertouch) ব্যবহার করে নিম্নলিখিত জিনিসগুলো করা যায়
Vibrato নিয়ন্ত্রণ
Filter cutoff modulation
Volume বা expression modulation
Modulation wheel এর মত control কিন্তু finger pressure দিয়ে
উদাহরণ
যদি কোনো কীবোর্ডে Aftertouch support করে এবং আপনি কোনো key টিপে ধরে রাখেন এবং চাপ বাড়ান, তাহলে সেই চাপ অনুযায়ী vibrato বা tone color পরিবর্তন হতে পারে।
বাস্তব ব্যবহারে
সব MIDI কীবোর্ড বা সফটওয়্যার Polyphonic Aftertouch সাপোর্ট করে না।
অনেক ডিভাইস শুধু Channel Pressure সাপোর্ট করে।
DAW গুলোতে যেমন Ableton, Logic, FL Studio সেখানে Aftertouch automation করা যায়।
সংক্ষেপে
Key Pressure = Polyphonic Aftertouch প্রতি কী র আলাদা চাপ বোঝায়
Channel Pressure = Channel Aftertouch পুরো চ্যানেলের জন্য একটাই চাপ মান
NAudio ব্যবহার করে C# এ MIDI ফাইল তৈরি করলে এবং Key Pressure (Aftertouch) বা Channel Pressure যুক্ত করতে হলে NAudio এবং MIDI তে Aftertouch ব্যবহারের মূল ধারণা
NAudio তে MIDI বার্তা তৈরি করতে হয় MidiEvent দিয়ে। দুই ধরনের প্রেশার থাকে
1. Channel Pressure (Channel Aftertouch)
var time = 0; // tick position
var channel = 0; // MIDI Channel 1
var pressureValue = 100; // 0–127
var channelPressureEvent = new ChannelAfterTouchEvent(time, channel, pressureValue);
2. Polyphonic Aftertouch (Key Pressure)
var time = 0; // tick position
var channel = 0;
var noteNumber = 60; // Middle C
var pressureValue = 80;
var polyPressureEvent = new PolyAfterTouchEvent(time, channel, noteNumber, pressureValue);
একটি উদাহরণ যেখানে Aftertouch ব্যবহার হচ্ছে
using NAudio.Midi;
class Program
{
static void Main()
{
var midiEventCollection = new MidiEventCollection(1, 480);
int channel = 0;
int note = 60; // Middle C
int velocity = 100;
int duration = 240;
// Note On
midiEventCollection.AddEvent(new NoteOnEvent(0, channel, note, velocity, duration), 0);
// Polyphonic Aftertouch (Key Pressure)
midiEventCollection.AddEvent(new PolyAfterTouchEvent(120, channel, note, 80), 0);
// Note Off
midiEventCollection.AddEvent(new NoteEvent(240, channel, MidiCommandCode.NoteOff, note, 0), 0);
// End of Track
midiEventCollection.PrepareForExport();
MidiFile.Export("aftertouch_test.mid", midiEventCollection);
}
}
কিছু গুরুত্বপূর্ণ বিষয়
PolyAfterTouchEvent ও ChannelAfterTouchEvent দুটোই MidiEvent থেকে তৈরি হয়।সব সফটওয়্যার বা হার্ডওয়্যার Polyphonic Aftertouch পড়তে বা রেন্ডার করতে পারে না। সেটা নির্ভর করে যে DAW বা Synth ব্যবহার করছো তার ওপর।
Export() করলে .mid ফাইল তৈরি হবে, যেটা DAW বা MIDI প্লেয়ার দিয়ে বাজানো যাবে।
ভারতীয় শাস্ত্রীয় সঙ্গীতের MIDI রেন্ডারিংয়ের ক্ষেত্রে খুব গুরুত্বপূর্ণ। নিচে আমি ধাপে ধাপে ব্যাখ্যা করছি C# + NAudio + MIDI Pitch Bend ব্যবহার করে কীভাবে n-6 থেকে n+6 পর্যন্ত meend/murki/gamaka style glide করা যায়।
1. Pitch Bend এর রেঞ্জ (MIDI Spec)
MIDI তে Pitch Bend ভ্যালু হয় 0 থেকে 16383 (14-bit)।
8192 = center (no bend)
0 = সর্বোচ্চ নিচে (maximum pitch down)
16383 = সর্বোচ্চ উপরে (maximum pitch up)
Default pitch bend range note -/+ 6 হবে না ডিফল্ট। সেই ক্ষেত্রে সেনসিটিভিটি কম করতে হবে।RPN send করে। ডিফল্ট ±2 semitone (unless synth config is changed)
2. n - 6 থেকে n + 6 পর্যন্ত glide করতে চাইলে
কিন্তু এই ক্ষেত্রে আমরা চাই 12 semitone bend
MIDI synth বা DAW কে জানাতে হবে যে pitch bend range ±12 semitone
কিন্তু NAudio দিয়ে .mid ফাইল বানালে daw synth configuration পাঠাতে হবে না unless
RPN 0 (Pitch Bend Sensitivity) বার্তা দিতে হবে।
তা না হলে default daw synth ডিফল্ট 2 semitone ধরে নিচ্ছে।
3. NAudio দিয়ে Pitch Bend Event যুক্ত করার ধরন
// Pitch bend value: 14-bit (0 to 16383), 8192 is center (no bend)
int bendValue = 8192 + delta;
// delta = pitch offset in 14-bit units
// Pitch Bend Event
var pitchBendEvent = new PitchWheelChangeEvent(ticks, channel, bendValue);
// Pitch bend value: 14-bit (0 to 16383), 8192 is center (no bend)
int bendValue = 8192 + delta;
// delta = pitch offset in 14-bit units
// Pitch Bend Event
var pitchBendEvent = new PitchWheelChangeEvent(ticks, channel, bendValue);
4. 12 সেমিটোনের Mapping (assuming ±12 semitone range):
Pitch bend sensitivity ±12 হলে
প্রতি সেমিটোনে ≈ (16384 / 24) = 682.66 units
অর্থাৎ
একটার পর একটা PitchWheelChangeEvent দিয়ে Meend তৈরি করা যায়।
5. উদাহরণ (C# + NAudio) Meend Effect
using NAudio.Midi;
class Program
{
static void Main()
{
var midiEvents = new MidiEventCollection(1, 480);
int channel = 0;
int note = 60;
int velocity = 100;
// Note On
midiEvents.AddEvent(new NoteOnEvent(0, channel, note, velocity, 0), 0);
// Pitch bend values to glide from -6 to +6 over time
for (int i = 0; i <= 12; i++)
{
int semitoneOffset = i - 6;
int bendValue = 8192 + (int)(semitoneOffset * (16384.0 / 24));
int tick = i * 20;
midiEvents.AddEvent(new PitchWheelChangeEvent(tick, channel, bendValue), 0);
}
// Note Off after meend
midiEvents.AddEvent(new NoteEvent(300, channel, MidiCommandCode.NoteOff, note, 0), 0);
midiEvents.PrepareForExport();
MidiFile.Export("meend.mid", midiEvents);
}
}
6. কীকরে “Indian meend” এর মত শোনাবে?
সব DAW বা synth pitch bend sensitivity ±2 ধরে নেয়। যদি ±12 করতে দরকার, তাহলে .mid ফাইলের শুরুতে RPN message পাঠাতে হবে ।সব ইনস্ট্রুমেন্ট বা MIDI channel pitch bend সাপোর্ট করে না। Mono synth sounds (violin, bansuri, etc) তে এটা সবচেয়ে ভালো কাজ করে।যদি পরপর glide effect দরকার তাহলে বেশ কিছু মিলিসেকোন্ড মিডিটিক এ পর পর PitchWheelChangeEvent টাইমিং সহ send করতে হবে।RPN এর অংশ টা বেশ কঠিন তবে আমি vlc তে fluidsynth sf2 use করে মিডি প্লে করি চালাই এবং audacity তে মিডি চালাই RPN কীকরে use করে note number n এর জন্য n -k থেকে n+r অবধি pitch bend range fit করবো সেইটা অনেক ক্যালকুলেশন এর দরকার।
সাধারণত NAudio দিয়ে .mid ফাইল তৈরি করি এবং সেটা VLC বা Audacity (যেখানে FluidSynth .sf2 ব্যবহার করে) এ প্লে করি, pitch bend range মানে ±2 semitone ডিফল্ট থাকে।
আমরা যদি Note n এর জন্য n - k থেকে n + r অবধি pitch bend ব্যবহার করতে চাই (যেমন n - 6 থেকে n + 6), তাহলে প্রথমেই .mid ফাইলের শুরুতে সেই pitch bend sensitivity সেট করতে হবে RPN মেসেজ দিয়ে।
1. তাহলে কীভাবে RPN দিয়ে Pitch Bend Sensitivity সেট করবো? কারণ শাস্ত্রীয় সঙ্গীত এর ক্ষেত্রে এটা করতেই হয়। কেবল 2 সেমিটোন নিয়ে ভারতীয় রাগ সঙ্গীত তো হবে না।
MIDI তে Pitch Bend Sensitivity = RPN #0
RPN Message পাঠাতে হয় এইভাবে
Controller 101 (0x65)
RPN MSB (value = 0 for pitch bend sensitivity)
Controller 100 (0x64)
RPN LSB (value = 0)
Controller 6 (0x06)
Data Entry MSB (value = number of semitones bend allowed)
Controller 38 (0x26): Data Entry LSB (value = cents, usually 0)
2. NAudio দিয়ে কোড
n - 6 থেকে n + 6 bend করার উপযোগী .mid ফাইল
using NAudio.Midi;
class Program
{
static void Main()
{
int channel = 0;
int baseNote = 60; // e.g., Middle C
int velocity = 100;
int pitchBendRange = 12; // semitone range: -6 to +6 = total 12
int ticksPerQuarterNote = 480;
var midiEvents = new MidiEventCollection(1, ticksPerQuarterNote);
// 0 ticks = Start
int absoluteTime = 0;
// 1. Set RPN 0
//Pitch Bend Sensitivity to ±12 semitones
midiEvents.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.RpnMsb, 0), 0); // 101 → MSB
midiEvents.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.RpnLsb, 0), 0); // 100 → LSB
midiEvents.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.DataEntryMsb, pitchBendRange), 0); // 6
midiEvents.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.DataEntryLsb, 0), 0); // 38
// Optional: Reset RPN (to avoid accidental edits)
midiEvents.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.RpnMsb, 127), 0);
midiEvents.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.RpnLsb, 127), 0);
// --- 2. Note On ---
midiEvents.AddEvent(new NoteOnEvent(absoluteTime, channel, baseNote, velocity, 0), 0);
// --- 3. Add Pitch Bend Meend from -6 to +6 over time ---
for (int semitone = -6; semitone <= 6; semitone++)
{
int bendValue = 8192 + (int)(semitone * (8192.0 / pitchBendRange)); // linear scale
int tick = absoluteTime + (semitone + 6) * 30; // every 30 ticks (adjust as needed)
midiEvents.AddEvent(new PitchWheelChangeEvent(tick, channel, bendValue), 0);
}
// --- 4. Note Off after full bend cycle ---
midiEvents.AddEvent(new NoteEvent(absoluteTime + 400, channel, MidiCommandCode.NoteOff, baseNote, 0), 0);
// --- 5. Export to file ---
midiEvents.PrepareForExport();
MidiFile.Export("pitchbend_meend_rpn.mid", midiEvents);
}
}
3. এই কোড কী করে?
MIDI ফাইলের শুরুতে RPN দিয়ে ±12 semitone bend sensitivity সেট করে
তারপর একটি note on করে
তারপর -6 থেকে +6 পর্যন্ত meend দেয় pitch bend দিয়ে
শেষে note off করে
4. VLC/FluidSynth এবং Audacity তে কীভাবে এটা কাজ করবে?
যদি .sf2 ফাইলের synth RPN 0 সাপোর্ট করে, তাহলে তুমি পুরো ±12 semitone bend পাবে।Audacity বা VLC যদি RPN 0 ইগনোর করে, তাহলে pitch bend range ±2 থাকবে।
এই অবস্থায় -6 semitone মানে হবে out-of-range, ফলে bend কাটা যাবে।
.sf2 ফাইল বা FluidSynth config চেক করতে হবে pitch_bend_range সাপোর্ট করে কিনা।
5. Bonus
n-k থেকে n+r bend কাস্টমাইজড করতে চাইলে
k = 3, r = 5 তাহলে total = 3 + 5 = 8 semitone
তাহলে
int pitchBendRange = 8;
int bendStart = -3;
int bendEnd = +5;
bendValue হিসাব করবে এই স্কেলে
int bendValue = 8192 + (int)(semitone * (8192.0 / pitchBendRange));
একটি Generalized C# Function চেষ্টা করা যেতে পারে যেখানে noteNumber (n), lowerBendSemitones (k), upperBendSemitones (r) ইনপুট দিয়ে .mid ফাইল বানাতে হলে যেটাতে pitch bend sensitivity k + r অনুযায়ী সেট হবে এবং note n এর চারপাশে meend (glide effect) তৈরি হবে।
Generalized C# Function (NAudio দিয়ে MIDI ফাইল)
using NAudio.Midi;
using System;
class MidiMeendGenerator
{
public static void CreateMeendMidiFile(string outputFilePath, int noteNumber, int lowerBendSemitones, int upperBendSemitones)
{
int totalBendRange = lowerBendSemitones + upperBendSemitones;
int ticksPerQuarterNote = 480;
int channel = 0;
int velocity = 100;
int startTime = 0;
var midiEvents = new MidiEventCollection(1, ticksPerQuarterNote);
// Step 1: Set RPN 0 to configure Pitch Bend Sensitivity
midiEvents.AddEvent(new ControlChangeEvent(startTime, channel, MidiController.RpnMsb, 0), 0);
midiEvents.AddEvent(new ControlChangeEvent(startTime, channel, MidiController.RpnLsb, 0), 0);
midiEvents.AddEvent(new ControlChangeEvent(startTime, channel, MidiController.DataEntryMsb, totalBendRange), 0);
midiEvents.AddEvent(new ControlChangeEvent(startTime, channel, MidiController.DataEntryLsb, 0), 0);
// Optional: Reset RPN
midiEvents.AddEvent(new ControlChangeEvent(startTime, channel, MidiController.RpnMsb, 127), 0);
midiEvents.AddEvent(new ControlChangeEvent(startTime, channel, MidiController.RpnLsb, 127), 0);
// Step 2: Note On
midiEvents.AddEvent(new NoteOnEvent(startTime, channel, noteNumber, velocity, 0), 0);
// Step 3: Pitch Bend Meend from -k to +r
int totalSteps = totalBendRange * 2; // smoother meend = more steps
for (int i = 0; i <= totalSteps; i++)
{
double position = i / (double)totalSteps;
double semitone = -lowerBendSemitones + position * totalBendRange;
int bendValue = 8192 + (int)(semitone * (8192.0 / totalBendRange));
int tick = startTime + i * 20; // smooth motion
midiEvents.AddEvent(new PitchWheelChangeEvent(tick, channel, bendValue), 0);
}
// Step 4: Note Off after full cycle
int endTick = startTime + (totalSteps + 10) * 20;
midiEvents.AddEvent(new NoteEvent(endTick, channel, MidiCommandCode.NoteOff, noteNumber, 0), 0);
// Step 5: Export
midiEvents.PrepareForExport();
MidiFile.Export(outputFilePath, midiEvents);
}
}
ব্যবহার করার উদাহরণ
MidiMeendGenerator.CreateMeendMidiFile("meend_output.mid", 62, 5, 7);
// note = D4 (62), bend from -5 to +7 semitones
VLC বা Audacity দিয়ে কিছুটা এফেক্ট তো টের পাই।
যদি FluidSynth RPN 0 সাপোর্ট করে (প্রায় সব .sf2 synth করে), তাহলে পুরো ±bend কাজ করবে।
Note 62 নিচে 5 semitone 57 পর্যন্ত (A3) bend
Note 62 উপর 7 semitone 69 পর্যন্ত (A4) bend
মোট 12 semitone bend, মানে octave level meend
Extra Features যোগ করতে হবে
durationMilliseconds ইনপুট নিলে কত সময় ধরে glide হবে তা কাস্টমাইজ করা যায়।Strumming effect, multiple notes, pitch curves (logarithmic, sinusoidal), velocity variation ইত্যাদি future enhancement করা যায়। note চলাকালীন তার ভেলোসিটি পরিবর্তন করা যায় না সরাসরি, কারণ MIDI NoteOn ইভেন্টে একবারই velocity সেট হয়, এবং সেটা change করা যায় না যতক্ষণ না note আবার NoteOff হয়ে যায়।ওই "volume automation" বা "expression control" ব্যবহার করে note চলার সময় ভলিউম বাড়ানো বা কমানো করতে হয় অবশ্যই এই কাজ MIDI Control Change (CC) message দিয়ে করা হয়।
"Pitch bend কমলে ভলিউম বাড়বে, আর pitch bend বাড়লে ভলিউম কমবে" এই ধরনের সম্পর্ক তৈরি করতে হলে Pitch Bend এর মানের সাথে সাথে CC#11 (Expression Controller) বা CC#7 (Main Volume) message পাঠাতে হবে।
NAudio দিয়ে কোড (Pitch Bend এর সঙ্গে Volume Automation)
int pitchBendRange = lowerSemis + upperSemis;
int totalSteps = pitchBendRange * 2;
for (int i = 0; i <= totalSteps; i++)
{
double position = i / (double)totalSteps;
double semitone = -lowerSemis + position * pitchBendRange;
int bendValue = 8192 + (int)(semitone * (8192.0 / pitchBendRange));
int tick = startTime + i * 20;
// Pitch bend
midiEvents.AddEvent(new PitchWheelChangeEvent(tick, channel, bendValue), 0);
// Volume automation (inverse relation: more pitch -> less volume)
// Value between 30 to 127 depending on bend position
int volume = 127 - (int)(Math.Abs(semitone) / pitchBendRange * 97);
volume = Math.Max(30, Math.Min(127, volume));
// Send expression controller (CC #11)
midiEvents.AddEvent(new ControlChangeEvent(tick, channel, MidiController.Expression, volume), 0);
}
ধারনা
যখন bend নিচে যাচ্ছে (negative semitone), তখন volume বাড়ছে।যখন bend উপরে যাচ্ছে (positive semitone), তখন volume কমছে।এর ফলে, শাস্ত্রীয় সঙ্গীত এর Meend এখন স্বর অনুযায়ী ভলিউমে অনুভবযোগ্য পরিবর্তন আনবে, যেটা ভারতীয় সঙ্গীতের dynamics capture করতে সাহায্য করবে।
কী ব্যবহৃত হলো এখানে?
ControlChangeEvent দিয়ে CC messages পাঠানো
CC #11 (Expression) = finer volume control (বেশিরভাগ synth এটি ভালো সাপোর্ট করে)।বিকল্প CC #7 (Main Volume) কিন্তু এটা অনেক synth এ abrupt হয়Pitch অনুযায়ী volume বাড়া/কমা sinusoidal বা logarithmic করে নিতে হবে।Velocity র মতো behave করাতে হলে expression + velocity shaping একসাথে করতে হবে। এই কোড গুলো NAudio ব্যবহার করে একটি .mid ফাইল তৈরি করে। এই ফাংশনটি নিচের কাজগুলো করে
একটি নির্দিষ্ট noteNumber চালায় অর্থাৎ স্টার্ট করে
k সেমিটোন নিচে এবং r সেমিটোন উপরে পর্যন্ত pitch bend করে কারণ অনেক রাগ এ এটা দরকার।
pitch bend চলাকালীন volume পরিবর্তন হয় (inverse relationship) যত বেশি pitch bend, তত কম ভলিউম, যত কম bend তত বেশি ভলিউম
কোড (NAudio MIDI Generator with Meend and Dynamic Volume)
using NAudio.Midi;
using System;
using System.IO;
public class MidiMeendGenerator
{
public static void CreateMeendMidi(int noteNumber, int k, int r, string filePath)
{
int channel = 0;
int velocity = 100;
int durationPerStep = 30; // ms per step
int ticksPerQuarterNote = 480;
var midiEventCollection = new MidiEventCollection(1, ticksPerQuarterNote);
int absoluteTime = 0;
// Note On
midiEventCollection.AddEvent(new NoteOnEvent(absoluteTime, channel, noteNumber, velocity, 0), 0);
// Pitch bend + expression automation
int totalSteps = (k + r) * 2;
for (int i = 0; i <= totalSteps; i++)
{
double position = i / (double)totalSteps;
double semitone = -k + position * (k + r);
int bendValue = 8192 + (int)(semitone * (8192.0 / (k + r)));
bendValue = Math.Max(0, Math.Min(16383, bendValue));
// Inverse volume logic
int volume = 127 - (int)(Math.Abs(semitone) / (k + r) * 97);
volume = Math.Max(30, Math.Min(127, volume));
// Add pitch bend event
midiEventCollection.AddEvent(new PitchWheelChangeEvent(absoluteTime, channel, bendValue), 0);
// Add expression controller (CC 11)
midiEventCollection.AddEvent(new ControlChangeEvent(absoluteTime, channel, MidiController.Expression, volume), 0);
absoluteTime += durationPerStep;
}
// Note Off
midiEventCollection.AddEvent(new NoteEvent(absoluteTime + 100, channel, MidiCommandCode.NoteOff, noteNumber, 0), 0);
// End of track
midiEventCollection.PrepareForExport();
MidiFile.Export(filePath, midiEventCollection);
Console.WriteLine("MIDI file saved at: " + Path.GetFullPath(filePath));
}
}
ভারতীয় শাস্ত্রীয় সঙ্গীত এ ব্যবহার
MidiMeendGenerator.CreateMeendMidi(noteNumber: 60, k: 6, r: 6, filePath: "meend_output.mid");
এটি C note (MIDI 60) থেকে শুরু করে -6 থেকে +6 সেমিটোন পর্যন্ত মীর (meend) সহ একটি MIDI তৈরি করবে যেখানে pitchbend অনুযায়ী volume পরিবর্তন হবে।
প্রয়োজনীয় Info
VLC/FluidSynth/sf2 সাপোর্ট করে PitchWheelChangeEvent ও Expression Controller
Volume automation এখানে done via CC 11
ভারতীয় রাগ সঙ্গীত এর জন্য .mid ফাইলটি Audacity বা অন্য DAW এ টেস্ট করতে হবে। এটাকে আরো পরিমার্জিত করে sinusoidal বা logarithmic dynamic volume দিয়েও করতে হবে।
Comments
Post a Comment