upto try 18 midi ragas

Try 1

  নিচের C# কোডটা NAudio দিয়ে চালালে এবং Behag রাগ + তবলা সহ MIDI ফাইল বানাতে হলে 
আধুনিক পদ্ধতি তে গাণিতিক ভাবে ও NAudio C# Code (Behag + Tabla with Strumming and natural Effects) তৈরি করে দেখতে শুনতে হলে 

using NAudio.Midi;

class BehagWithTabla
{
    static void Main()
    {
        var midiEventCollection = new MidiEventCollection(1, 480);

        int flutePatch = 73;  // Flute
        int tablaChannel = 9; // Percussion
        int tablaNote1 = 60;  // Dha
        int tablaNote2 = 63;  // Tin

        // Assign Flute to channels 0–5
        for (int ch = 0; ch < 6; ch++)
        {
            midiEventCollection.AddEvent(new PatchChangeEvent(0, ch, flutePatch), 0);
        }

        // Define Behag notes (MIDI numbers)
        int[] notes = { 60, 64, 65, 67, 69, 67, 65, 64, 62, 60 };
        int[] durations = { 480, 240, 240, 480, 480, 240, 240, 480, 240, 480 };

        int absoluteTime = 0;

        // Add flute on multiple channels with effects
        for (int i = 0; i < notes.Length; i++)
        {
            for (int ch = 0; ch < 6; ch++)
            {
                int delay = ch * 10; // slight strum delay
                int time = absoluteTime + delay;
                midiEventCollection.AddEvent(new NoteOnEvent(time, ch, notes[i], 80, durations[i]), 0);
                midiEventCollection.AddEvent(new ChannelAfterTouchEvent(time + durations[i] / 3, ch, 60), 0);
                midiEventCollection.AddEvent(new PitchWheelChangeEvent(time + (2 * durations[i]) / 3, ch, 8192 + 300), 0);
                midiEventCollection.AddEvent(new NoteEvent(time + durations[i], ch, MidiCommandCode.NoteOff, notes[i], 64), 0);
            }

            absoluteTime += durations[i];
        }

        // Add tabla (loop pattern)
        int tablaTime = 0;
        while (tablaTime < 3 * 60 * 480) // approx 3 minutes
        {
            midiEventCollection.AddEvent(new NoteOnEvent(tablaTime, tablaChannel, tablaNote1, 100, 240), 1);
            tablaTime += 240;
            midiEventCollection.AddEvent(new NoteOnEvent(tablaTime, tablaChannel, tablaNote2, 100, 240), 1);
            tablaTime += 240;
            midiEventCollection.AddEvent(new NoteOnEvent(tablaTime, tablaChannel, tablaNote2, 100, 240), 1);
            tablaTime += 240;
            midiEventCollection.AddEvent(new NoteOnEvent(tablaTime, tablaChannel, tablaNote1, 100, 240), 1);
            tablaTime += 240;
        }

        // Save MIDI
        var midiFile = new MidiFile(1, midiEventCollection.DeltaTicksPerQuarterNote);
        MidiFile.Export("BehagWithTablaAndFlute.mid", midiEventCollection);
    }
}
এখানে কিছু প্রয়োজনীয় প্রোগ্রামিং এর প্রশ্নগুলোর উত্তর একত্রিত করা হচ্ছে 
Channel Pressure যতবার খুশি apply করা যায়, note on এর পর যে কোনো সময় add করা যায়।
Pitch Bend প্রতি চ্যানেলে প্রতিটি টিকেও করা যায়। কিন্তু flute ও সেইক্ষেত্রে ড্রাম বিট এর মতন লাগবে।
Breathe Control Channel Pressure দিয়েই simulate করা যায়, frequency high হলেই বেশি চাপ।
Minimum Duration: Flute এ realistic শুনতে হলে 200ms বা তার বেশি রাখতে হয় সাধারণত। একসাথে অনেক নোট হলে 100ms রাখা যায়।

__________________

Try 2

তবলার ক্ষেত্রে General MIDI (GM) সিস্টেমে Drum sounds এর জন্য আলাদা কোনো "patch number" (Program Change) দিতে হয় না। কারণ

Drum / Percussion চ্যানেল (Channel 10 বা index 9):

Channel 10 (MIDI channel index 9) হচ্ছে GM Standard Drum Channel।

এই চ্যানেলে instrument patch change প্রযোজ্য না — কারণ প্রতিটি note number নিজে নিজেই একটি specific percussion sound বোঝায়।
তবলা related drum sounds

তবলা GM drum bank এ সরাসরি নেই, তবে নিম্নোক্ত note numbers ব্যবহারে তবলার কাছাকাছি ইফেক্ট পাওয়া যায়
 অনেক sound module বা VST plugin (যেমন: Indian Percussion VSTs) তবলার জন্য আলাদা patch বা kit রাখে, কিন্তু standard MIDI file এর মধ্যে এসব ড্রাম চ্যানেলেই বেজে থাকে।

NAudio-তে কোনো patch দরকার নেই এই জন্যে

// Channel 9 is drum channel, no patch change needed
midiEvents.AddEvent(new NoteOnEvent(tick, 9, 60, 90, 120), 1); // Dha

তবলা বাজাতে চাইলে Channel 9 (i.e., MIDI channel 10) ব্যবহার করো।

Program Change ইভেন্ট একেবারেই দরকার নেই ড্রাম চ্যানেলে।কোনো Indian VST instrument ব্যবহার করে তবলা সাউন্ড আরও রিচ করতে পারি কিন্তু সেটা MIDI standard এর বাইরে।

_____________

Try 3

 এখন আমরা Behag রাগের জন্য যে MIDI ফাইল তৈরি করছিলাম, তাতে একটি প্রোফেশনাল তবলা লুপ যোগ করব, যাতে পুরো কম্পোজিশন আরও প্রাণবন্ত ও ভারতীয় শাস্ত্রীয় সংগীতধর্মী হয়ে ওঠে।
মিডি প্রোগ্রামিং এ তবলা Loop সংযুক্ত করা 
 Overview
আমরা 1টি নতুন চ্যানেল (Channel 9 অর্থাৎ Standard Drum Channel in GM MIDI) ব্যবহার করব।

আমরা একটি সাধারণ Teentaal (16-beat) বা Keharwa (8-beat) এর প্যাটার্ন ব্যবহার করব Behag-এর mood অনুযায়ী।

GM MIDI তে তবলার জন্য কিছু percussive sound ব্যবহৃত হবে, যেমন

Tabla Dayan → MIDI note 60

Tabla Bayan → MIDI note 59

Muted Slap / Na / Tin / Tun → MIDI notes 61-67 (approx)
Behag + Guitar + Tabla (NAudio C# code snippet)
 আগের Behag কোডে শুধু নিচের অংশটা যোগ করবো এবার 

// Channel 9 (Drums) Tabla Loop - Teentaal/Keharwa style
var tablaTrack = new List<MidiEvent>();
midiEvents.AddTrack(tablaTrack);

int tablaTick = 0;
int tablaTempo = 240; // adjust to sync with melody

int[] tablaPattern = {
    60, 59, 60, 61,  // Dha - Ge - Dha - Tin
    60, 59, 60, 63   // Dha - Ge - Dha - Na
};

for (int i = 0; i < 180; i++)  // approx for 3 min
{
    foreach (int tablaNote in tablaPattern)
    {
        tablaTrack.Add(new NoteOnEvent(tablaTick, 9, tablaNote, 90, tablaTempo / 2));
        tablaTrack.Add(new NoteEvent(tablaTick + tablaTempo / 2, 9, MidiCommandCode.NoteOff, tablaNote, 0));
        tablaTick += tablaTempo;
    }
}

tablaTrack.Add(new MetaEvent(MetaEventType.EndTrack, 0, tablaTick + 100));Tabla tempo বা pattern আরও change করে specific রাগের lay বানাতে চেষ্টা করবো অবশ্যই।Advanced tabla pattern যোগ করার জন্য  MIDI percussion reference দেখে বিভিন্ন note (56–75 range) ব্যবহার করতে পারি হয়তো তবে শুনে দেখতে হবে।
Behag এর mood অনুযায়ী তবলার sound “খুলে” না গিয়ে soft + emotional হওয়াই ভালো।
 Behag এর full updated C# ফাইল (গিটার + তবলা সহ) তোমার জন্য paste করতে চেষ্টা করা উচিত ।
এছাড়াও আমি এর পর Bageshree, Darbari, Desh, Yaman  এগুলোও এভাবে বানিয়ে দেখবো ।

______________

Try 3+

 নিচে আমি Behag রাগের জন্য একটি প্রফেশনাল guitar strumming pattern সহ MIDI জেনারেটর sample code দিচ্ছি C#-এ, যেখানে 6টি চ্যানেলে বিভিন্ন গিটার ধ্বনি বাজবে, কিছু চ্যানেল শুধু strumming করবে, কিছু lead style বাজাবে, এবং সবকিছু tempo অনুযায়ী সাজানো থাকবে।এছাড়াও এই প্রোগ্রাম টি তে আমি Modulation, Pitch Bend, Velocity Variation, Proper Note Duration, এবং Program Change দিয়ে realistic effect এনেছি। চেষ্টা করছি অন্তত।
Behag Guitar Strumming MIDI Generator (NAudio + C#)

using NAudio.Midi;
using System;
using System.Collections.Generic;
using System .IO;

class BehagGuitarStrumming
{
    static List<int> scaleNotes = new List<int> {
        60, 62, 64, 65, 67, 69, 71, 72, // Ascending
        71, 69, 67, 65, 64, 62, 60       // Descending
    };

    static Dictionary<int, int> noteDurations = new Dictionary<int, int>
    {
        { 60, 500 }, { 62, 450 }, { 64, 400 },
        { 65, 500 }, { 67, 420 }, { 69, 400 },
        { 71, 430 }, { 72, 550 }
    };

    static int GetVelocity(int note)
    {
        Random rand = new Random();
        return Math.Clamp(105 - ((note - 60) * 2) + rand.Next(-8, 8), 70, 127);
    }

    static void Main()
    {
        var midiEvents = new MidiEventCollection(1, 480);
        var rand = new Random();

        int[] guitarPrograms = { 24, 25, 26, 27, 25, 26 }; // Nylon, Steel, Jazz, Clean

        for (int ch = 0; ch < 6; ch++)
        {
            var track = new List<MidiEvent>();
            midiEvents.AddTrack(track);

            int tick = 0;
            track.Add(new PatchChangeEvent(0, ch, guitarPrograms[ch]));

            if (ch < 2)
            {
                // Strumming channel
                for (int i = 0; i < 60; i++)
                {
                    int baseNote = scaleNotes[rand.Next(scaleNotes.Count)];
                    int[] chord = { baseNote, baseNote + 4, baseNote + 7 }; // Major chord
                    int vel = GetVelocity(baseNote);

                    foreach (int n in chord)
                    {
                        track.Add(new NoteOnEvent(tick, ch, n, vel, 120));
                        track.Add(new NoteEvent(tick + 120, ch, MidiCommandCode.NoteOff, n, 0));
                    }

                    tick += 240; // 1 beat strum
                }
            }
            else if (ch < 5)
            {
                // Lead melody channel
                for (int i = 0; i < scaleNotes.Count; i++)
                {
                    int note = scaleNotes[i];
                    int vel = GetVelocity(note);
                    int duration = noteDurations[note] + rand.Next(-20, 50);
                    int ticks = (int)(duration / 2.5);

                    track.Add(new ControlChangeEvent(tick, ch, MidiController.Modulation, rand.Next(40, 90)));
                    track.Add(new PitchWheelChangeEvent(tick, ch, rand.Next(3000, 9000)));

                    track.Add(new NoteOnEvent(tick, ch, note, vel, ticks));
                    track.Add(new NoteEvent(tick + ticks, ch, MidiCommandCode.NoteOff, note, 0));

                    tick += ticks + rand.Next(20, 80);
                }
            }
            else
            {
                // Bass channel or rhythm filler
                for (int i = 0; i < 40; i++)
                {
                    int note = scaleNotes[rand.Next(3)]; // lower notes only
                    int vel = GetVelocity(note) - 10;
                    int ticks = 160;

                    track.Add(new NoteOnEvent(tick, ch, note - 12, vel, ticks));
                    track.Add(new NoteEvent(tick + ticks, ch, MidiCommandCode.NoteOff, note - 12, 0));
                    tick += 320;
                }
            }

            track.Add(new MetaEvent(MetaEventType.EndTrack, 0, tick + 200));
        }

        string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Behag_Guitar_Strumming.mid");
        MidiFile.Export(fileName, midiEvents);
        Console.WriteLine("Behag Guitar MIDI with Strumming saved to: " + fileName);
    }
}

তৈরি হওয়া এই MIDI ফাইলটি

Behag রাগের স্বাদ বজায় রেখে melodic & harmonic parts গঠিত
6টি চ্যানেলে প্লে হবে
2টা Strumming Guitar (Nylon, Steel)
2টা Lead Guitar (Jazz, Clean)
1টা Bass Guitar
1টা Fill/String Guitar
Chords
Basic major chord progression (optional behag flavoring)
Effects
 Channel modulation, pitch wheel, varying velocity
পরবর্তী ধাপ এর চেষ্টা।
 আমি এই MIDI ফাইলে tabla/percussion loop যোগ করেও দেখতে হবে ।অথবা Behag-এর আরেকটা pure classical version চেষ্টা করতে পারি (no chords, just melody)

_________

Try 3++

 যদি Behag বা যেকোনো রাগ guitar এ 6টি চ্যানেলে বাজাতে চাই, তাহলে প্রোগ্রাম টি তে কিছু পরিবর্তন দরকার হবে

কী কী পরিবর্তন দরকার?

1. Instrument Patch (Program Change)

Flute এর জন্য আমরা 73 ব্যবহার করেছিলাম (MIDI Program 73 = Flute)

Guitar এর জন্য patch number এ এগুলো ব্যবহার করতে পারি 
24: Nylon Guitar
25: Steel Guitar
26: Jazz Guitar
27: Clean Electric Guitar
(একাধিক চ্যানেলে আলাদা গিটার tone দিতে পারো)

2. Velocity ও Duration Tuning

Guitar এর pluck effect তুলনামূলক দ্রুত decay হয় flute এর তুলনায়
Velocity একটু বেশি হলে ভালো লাগে (80-120 range)
Duration তুলনামূলক ছোট রাখতে হবে (150ms - 800ms)
3. Breath Controller (CC2) বাদ দিতে হবে
Breath guitar এর জন্য applicable না

4. Channel Pressure রাখা যেতে পারে, but optionally
Guitar expression এর জন্য অনেকসময় Modulation (CC1) ও Expression (CC11) ব্যবহার হয়

এই নতুন চেষ্টায় পরিবর্তিত C# NAudio Code (Behag on 6-Channel Guitar)

using NAudio.Midi;
using System;
using System.Collections.Generic;
using System.IO;

class BehagGuitarMidiGenerator
{
    static Dictionary<int, int> behagNoteDurations = new Dictionary<int, int>
    {
        { 60, 500 },  // Sa
        { 62, 400 },  // Re
        { 64, 350 },  // Ga
        { 65, 500 },  // Ma
        { 67, 450 },  // Pa
        { 69, 400 },  // Dha
        { 71, 420 },  // Ni
        { 72, 500 }   // Sa (higher)
    };

    static List<int> behagNotes = new List<int>
    {
        60, 62, 64, 65, 67, 69, 71, 72,
        71, 69, 67, 65, 64, 62, 60
    };

    static int GetVelocity(int noteNumber)
    {
        Random rand = new Random();
        int baseVelocity = 110 - ((noteNumber - 60) * 2);
        return Math.Clamp(baseVelocity + rand.Next(-10, 10), 70, 127);
    }

    static void Main()
    {
        var midiEventCollection = new MidiEventCollection(1, 480);
        int[] guitarPatches = { 24, 25, 26, 27, 24, 25 }; // Nylon, Steel, Jazz, Clean etc.
        var rand = new Random();

        for (int channel = 0; channel < 6; channel++)
        {
            var track = new List<MidiEvent>();
            midiEventCollection.AddTrack(track);

            track.Add(new PatchChangeEvent(0, channel, guitarPatches[channel]));

            int tick = 0;

            for (int i = 0; i < 14; i++)
            {
                int note = behagNotes[rand.Next(behagNotes.Count)];
                int durationMs = behagNoteDurations[note] + rand.Next(-30, 60);
                int velocity = GetVelocity(note);
                int durationTicks = (int)(durationMs / 2.5);

                // Optional: Use Modulation instead of Breath
                track.Add(new ControlChangeEvent(tick, channel, MidiController.Modulation, rand.Next(20, 80)));

                // Pitch Bend
                track.Add(new PitchWheelChangeEvent(tick, channel, rand.Next(4000, 9000)));

                // Note On
                track.Add(new NoteOnEvent(tick, channel, note, velocity, durationTicks));

                // Note Off
                track.Add(new NoteEvent(tick + durationTicks, channel, MidiCommandCode.NoteOff, note, 0));

                tick += durationTicks + rand.Next(20, 100);
            }

            // End Track
            track.Add(new MetaEvent(MetaEventType.EndTrack, 0, tick + 120));
        }

        string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Behag_Guitar_6_Channel.mid");
        MidiFile.Export(filePath, midiEventCollection);
        Console.WriteLine($"Saved Behag Guitar MIDI: {filePath}");
    }
}

chord ধরার জন্য কিছু চ্যানেল এ একসাথে multiple notes বাজাতে চেষ্টা করেছি try 3+ এ(strumming effect) এবং আরও depth আনতে চাইলে আমি "slide", "hammer-on", "string bend" effect simulate করেও চেষ্টা করতে পারি (MIDI CC ব্যবহার করে)।এইবার আমি Behag রাগের rhythmic guitar strumming with tabla loop MIDI বানিয়েও দেখবো try 3+ এ।

_______________

Try 6

নিচে Behag রাগ এর জন্য C# এবং NAudio ব্যবহার করে MIDI ফাইল জেনারেট করার সম্পূর্ণ কোড দিচ্ছি। এতে চেষ্টা করছি 
Behag স্কেল অনুযায়ী সঠিক নোট সিকোয়েন্স
6টি চ্যানেল ব্যবহার
Pitch Bend, Channel Pressure, Breath Control
Variation in note duration and velocity
MIDI ফাইল হিসেবে সেভ হবে
Behag Raga Flute MIDI Generator (6-Channel, Expressive)

using NAudio.Midi;
using System;
using System.Collections.Generic;
using System.IO;

class BehagFluteMidiGenerator
{
    static Dictionary<int, int> behagNoteDurations = new Dictionary<int, int>
    {
        { 60, 1000 },  // Sa
        { 62, 600 },   // Re
        { 64, 500 },   // Ga
        { 65, 1000 },  // Ma
        { 67, 900 },   // Pa
        { 69, 600 },   // Dha
        { 71, 700 },   // Ni
        { 72, 1000 }   // Sa (higher)
    };

    static List<int> behagNotes = new List<int>
    {
        60, 62, 64, 65, 67, 69, 71, 72,
        71, 69, 67, 65, 64, 62, 60
    };

    static int GetVelocity(int noteNumber)
    {
        Random rand = new Random();
        int baseVelocity = 100 - ((noteNumber - 60) * 2);
        return Math.Clamp(baseVelocity + rand.Next(-10, 10), 60, 127);
    }

    static void Main()
    {
        var midiEventCollection = new MidiEventCollection(1, 480); // Format 1
        int channelCount = 6;
        var rand = new Random();

        for (int channel = 0; channel < channelCount; channel++)
        {
            var track = new List<MidiEvent>();
            midiEventCollection.AddTrack(track);

            track.Add(new PatchChangeEvent(0, channel, 73)); // Flute

            int tick = 0;

            for (int i = 0; i < 12; i++)
            {
                int note = behagNotes[rand.Next(behagNotes.Count)];
                int durationMs = behagNoteDurations[note] + rand.Next(-50, 70);
                int velocity = GetVelocity(note);
                int pitchBend = rand.Next(3000, 10000);
                int durationTicks = (int)(durationMs / 2.5); // Rough

                // Channel Pressure (Breath feel)
                track.Add(new ChannelAfterTouchEvent(tick, channel, (byte)rand.Next(60, 100)));

                // Pitch Bend
                track.Add(new PitchWheelChangeEvent(tick, channel, pitchBend));

                // Note On
                track.Add(new NoteOnEvent(tick, channel, note, velocity, durationTicks));

                // Breath Control (CC 2)
                track.Add(new ControlChangeEvent(tick + 10, channel, MidiController.BreathController, rand.Next(60, 110)));

                // Note Off
                track.Add(new NoteEvent(tick + durationTicks, channel, MidiCommandCode.NoteOff, note, 0));

                tick += durationTicks + rand.Next(30, 120);
            }

            // End of track
            track.Add(new MetaEvent(MetaEventType.EndTrack, 0, tick + 120));
        }

        string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Behag_Flute_6_Channel.mid");
        MidiFile.Export(filePath, midiEventCollection);

        Console.WriteLine($"Saved Behag MIDI on: {filePath}");
    }
}

Behag স্কেল সম্পর্কে সংক্ষেপে
Behag রাগ সাধারণত ব্যবহার করে:
Aroha: Ni Sa Ga Ma Pa Ni Sa (no Re)
Avaroha: Sa Ni Dha Pa Ma Ga Re Sa
চলতি ফিচারস

6 Channel Flute
Randomized expressive velocity & duration
Breath Control (CC2) & Channel Pressure
Human feel pitch bends

প্রোগ্রাম টা চালানোর জন্য
1. Visual Studio তে একটি Console Project তৈরি কর 
2. NuGet থেকে NAudio ইনস্টল করা 
Install-Package NAudio
3. এই কোডটি Program.cs এ বসাও ও রান করো

MIDI ফাইল Behag_Flute_6_Channel.mid নামে Desktop এ পাওয়া যাবে।আরও ঠাট বা রাগ ওথবা Behag-এ আরও depth (Jhala, Sargam, Meend),  বানিয়ে দেখতে হবে।Behag-এর জন্য খুব ধীরে Alaap বা ঝিম সুরেও চেষ্টা করা যেতে পারে 

_______________

Try 6+
এইবার ভৈরবী ঠাট অনুযায়ী flute এর জন্য একটি সম্পূর্ণ C# কোড লিখে চেষ্টা করছি যাতে সেই প্রোগ্রাম টা 

NAudio ব্যবহার করে
6টি চ্যানেলে চালায়
Velocity ও Duration human-like expressive করে
Channel Pressure, Pitch Bend, Breath Control ইত্যাদি যোগ করে
প্রোগ্রাম টা একটি MIDI ফাইলে save করে

NAudio MIDI
 Bhairavi Raga Flute Performance (6-Channel, Expressive)

using NAudio.Midi;
using System;
using System.Collections.Generic;
using System.IO;

class BhairaviFluteMidiGenerator
{
    static Dictionary<int, int> bhairaviNoteDurations = new Dictionary<int, int>
    {
        { 60, 900 },  // Sa
        { 61, 300 },  // Komal Re
        { 63, 350 },  // Komal Ga
        { 65, 800 },  // Ma
        { 67, 900 },  // Pa
        { 68, 350 },  // Komal Dha
        { 70, 400 },  // Komal Ni
    };

    static int GetVelocity(int noteNumber)
    {
        // Expressive dynamic based on pitch: higher pitch, softer velocity
        Random rand = new Random();
        int baseVelocity = 100 - ((noteNumber - 60) * 3);
        return Math.Clamp(baseVelocity + rand.Next(-10, 10), 50, 127);
    }

    static void Main()
    {
        var midiEventCollection = new MidiEventCollection(1, 480); // Format 1, 480 ticks per beat
        int channelCount = 6;
        int trackIndex = 0;

        var random = new Random();
        var notes = new List<int> { 60, 61, 63, 65, 67, 68, 70 }; // Bhairavi scale
        int currentTick = 0;

        for (int channel = 0; channel < channelCount; channel++)
        {
            var track = new List<MidiEvent>();
            midiEventCollection.AddTrack(track);

            track.Add(new PatchChangeEvent(0, channel, 73)); // Flute instrument

            int tick = 0;

            for (int i = 0; i < 20; i++)
            {
                int note = notes[random.Next(notes.Count)];
                int durationMs = bhairaviNoteDurations[note] + random.Next(-50, 50);
                int velocity = GetVelocity(note);
                int pitchBend = random.Next(2000, 10000);
                int durationTicks = (int)(durationMs / 2.5); // Approximation

                // Channel pressure (Breath control effect)
                track.Add(new ChannelAfterTouchEvent(tick, channel, (byte)random.Next(50, 100)));

                // Pitch bend (expressive glide)
                track.Add(new PitchWheelChangeEvent(tick, channel, pitchBend));

                // Note On
                track.Add(new NoteOnEvent(tick, channel, note, velocity, durationTicks));

                // Breath Control (CC 2)
                track.Add(new ControlChangeEvent(tick + 10, channel, MidiController.BreathController, random.Next(40, 100)));

                // Note Off
                track.Add(new NoteEvent(tick + durationTicks, channel, MidiCommandCode.NoteOff, note, 0));

                tick += durationTicks + random.Next(20, 80); // Add rest
            }

            // End of track
            track.Add(new MetaEvent(MetaEventType.EndTrack, 0, tick + 120));
        }

        string outputPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Bhairavi_Flute_6_Channel.mid");
        MidiFile.Export(outputPath, midiEventCollection);

        Console.WriteLine($"MIDI file saved to: {outputPath}");
    }
}

মিডি তে Programming Features Explained

Channel Pressure
ChannelAfterTouchEvent simulates breathing effort
Pitch Bend
 Gives flute-style natural bends
Breath Control (CC2)
 Simulates breath intensity (only some synths respond)
Velocity
 Soft/hard note hit simulation
6 Channels
 Can be routed to 6 flute layers with slight variation for realism
Duration
Controlled by real Bhairavi aesthetics + randomness
Run Instructions
1. Install NAudio via NuGet
Install Package NAudio
2. Compile and run the code. It will save Bhairavi_Flute_6_Channel.mid on your Desktop.
Next Step
আমি এই কোডটাকে extend করে Behag বা অন্য ঠাটে নিয়ে যাবো এবং আরও প্রোগ্রামিং করে করে রাগিক অভিব্যক্তি (gamaka, meend, staccato vs sustain) যোগ করে চেষ্টা করবো আরো।

________________

Try 8

অবশ্যই! এখন আমি তোমাকে MIDI note duration নির্ণয় করার নিয়মগুলো ব্যাখ্যা করব এবং তার জন্য প্রয়োজনীয় durationRules ডিকশনারি ও কোড দিয়ে দেব। এতে করে তুমি ভিন্ন ঠাটে বা রাগে, ভিন্ন note-এর জন্য সময় (মিলিসেকেন্ড) কত হবে সেটা নির্ধারণ করতে পারবে।

---

১. Duration Calculation মূল ধারণা:

MIDI note duration (মিলিসেকেন্ডে) বিভিন্ন বিষয়ের উপর নির্ভর করে:

রাগের mood বা tempo (ধীর/মধ্য/দ্রুত)

note-এর position (Sa, Re, Ga... কোনটা কতটা গুরুত্ব পায়)

phrase structure (sustain, ornamentation, glide ইত্যাদি)

human playability (flute-এ কত ক্ষণ একটা note ধরা সম্ভব)

আমরা এই জন্য একটি সাধারণ রেঞ্জ ধরতে পারি:

Main Notes (Vadi/Samvadi): 600–1000 ms

Passing Notes (Alpatva): 200–400 ms

Grace/Ornamental Notes (Kan Swar): 100–200 ms

Rest or Deliberate Silence: 300–800 ms

---

২. C# Dictionary: Note Duration Map (Per Thaat or Raga)

উদাহরণ: ভৈরবী ঠাট এর জন্য duration mapping

var bhairaviDurationMap = new Dictionary<int, int>
{
    { 60, 900 },  // Sa
    { 61, 300 },  // Komal Re
    { 63, 350 },  // Komal Ga
    { 65, 800 },  // Ma
    { 67, 900 },  // Pa
    { 68, 350 },  // Komal Dha
    { 70, 400 },  // Komal Ni
};

---

উদাহরণ: বিলাওল ঠাট

var bilawalDurationMap = new Dictionary<int, int>
{
    { 60, 800 },  // Sa
    { 62, 700 },  // Re
    { 64, 700 },  // Ga
    { 65, 750 },  // Ma
    { 67, 800 },  // Pa
    { 69, 750 },  // Dha
    { 71, 700 }   // Ni
};

---

৩. একত্রিত সব ঠাটের জন্য master dictionary:

var thaatDurationMap = new Dictionary<string, Dictionary<int, int>>
{
    { "Bhairavi", bhairaviDurationMap },
    { "Bilawal", bilawalDurationMap },
    // Add more thaats as you define
};

---

৪. Helper Function:

int GetNoteDuration(string thaatName, int midiNote)
{
    if (thaatDurationMap.TryGetValue(thaatName, out var durationMap))
    {
        if (durationMap.TryGetValue(midiNote, out var duration))
        {
            return duration;
        }
    }

    return 400; // Default fallback duration in ms
}

---

৫. Example Usage (MIDI Event Timing):

int note = 60; // C (Sa)
int velocity = GetVelocity("Bhairavi", note);
int duration = GetNoteDuration("Bhairavi", note);

// Add to MIDI track
track.AddNoteOnEvent(channel, note, velocity, currentTime);
track.AddNoteOffEvent(channel, note, 0, currentTime + duration);

---

৬. চাইলেই Human-like Fluctuation যোগ করতে পারো:

Random rand = new Random();
int fluctuation = rand.Next(-50, 50); // Slight tempo variation
duration += fluctuation;
velocity += rand.Next(-10, 10); // Slight volume variation

, আমি বাকি ঠাট গুলোর duration dictionary ও লিখে চেষ্টা করতে হবে।তারপর তুমি এগুলো দিয়ে full expressive MIDI বানাতে হবে। এইবার আমি ভৈরবী ঠাট এর পুরো MIDI  কোড এ integrate করে  updated velocity + duration সহ, professional articulation সহ চেষ্টা করবো আর ও।

_______________

Try 9

অবশ্যই! নিচে আমি প্রতিটি ঠাটের জন্য একটি C# Dictionary<int, int> দিয়ে উদাহরণ দিচ্ছি, যেখানে key হচ্ছে MIDI note number (যেমন 60 = Middle C), এবং value হচ্ছে velocity।
তুমি একে একে সব ঠাট এর dictionary বানিয়ে রাখতে পারো এবং প্রয়োজনমতো access করতে পারো।

---

১. ভৈরবী ঠাট (Bhairavi Thaat) Velocity Map:

var bhairaviThaatVelocityMap = new Dictionary<int, int>
{
    // S, r (komal), g (komal), M, P, d (komal), n (komal)
    { 60, 80 },  // Sa (C)
    { 61, 70 },  // Komal Re (C#)
    { 63, 75 },  // Komal Ga (D#)
    { 65, 85 },  // Ma (F)
    { 67, 90 },  // Pa (G)
    { 68, 75 },  // Komal Dha (G#)
    { 70, 78 },  // Komal Ni (A#)
};

---

২. কাল্যাণ ঠাট (Kalyan Thaat) Velocity Map:

var kalyanThaatVelocityMap = new Dictionary<int, int>
{
    { 60, 85 },  // Sa
    { 62, 90 },  // Re
    { 64, 95 },  // Ga
    { 66, 110 }, // Tivra Ma
    { 67, 90 },  // Pa
    { 69, 95 },  // Dha
    { 71, 100 }  // Ni
};

---

৩. মারওয়া ঠাট (Marwa Thaat) Velocity Map:

var marwaThaatVelocityMap = new Dictionary<int, int>
{
    { 60, 75 },  // Sa
    { 61, 65 },  // Komal Re
    { 64, 85 },  // Ga
    { 66, 100 }, // Tivra Ma
    { 67, 85 },  // Pa
    { 69, 90 },  // Dha
    { 71, 95 }   // Ni
};

---

৪. বিলাওল ঠাট (Bilawal Thaat) Velocity Map:

var bilawalThaatVelocityMap = new Dictionary<int, int>
{
    { 60, 85 },  // Sa
    { 62, 88 },  // Re
    { 64, 90 },  // Ga
    { 65, 95 },  // Ma
    { 67, 100 }, // Pa
    { 69, 95 },  // Dha
    { 71, 90 }   // Ni
};

---

৫. খাম্বাজ ঠাট (Khamaj Thaat) Velocity Map:

var khamajThaatVelocityMap = new Dictionary<int, int>
{
    { 60, 85 },  // Sa
    { 62, 88 },  // Re
    { 64, 90 },  // Ga
    { 65, 95 },  // Ma
    { 67, 98 },  // Pa
    { 69, 95 },  // Dha
    { 70, 80 }   // Komal Ni
};

---

তুমি যদি এভাবে প্রতিটি ঠাটের জন্য আলাদা Dictionary<int, int> বানিয়ে নাও, তাহলে কোডে সেগুলাকে একটা Dictionary<string, Dictionary<int, int>> হিসেবে একত্র করতে পারো:

var thaatVelocityMap = new Dictionary<string, Dictionary<int, int>>
{
    { "Bhairavi", bhairaviThaatVelocityMap },
    { "Kalyan", kalyanThaatVelocityMap },
    { "Marwa", marwaThaatVelocityMap },
    { "Bilawal", bilawalThaatVelocityMap },
    { "Khamaj", khamajThaatVelocityMap },
    // ... add more
};

---

Helper Function:

int GetVelocity(string thaatName, int midiNote)
{
    if (thaatVelocityMap.TryGetValue(thaatName, out var noteMap))
    {
        if (noteMap.TryGetValue(midiNote, out var velocity))
        {
            return velocity;
        }
    }

    return 80; // Default fallback velocity
}

বাকি ৫টা ঠাট এর mapওলিখতে হবেই।
এই structure দিয়ে এখন  pernote accurate velocity assign করতে  MIDI generationএরeffect দেখা যাবে।
 duration rules-এর guide টাও এখন লিখে দেখবো।

____________

Try 9+

এখন আমি তোমাকে বিভিন্ন ঠাটের জন্য Velocity Calculation এর নিয়মগুলো কোন নোটে কী রকম ভেলোসিটি দেওয়া যায়, সেটার একটা লিখিত ফর্মে ধারাবাহিক গাইডলাইন হিসেবে দিচ্ছি (টেবিল নয়)। এতে প্রতিটি ঠাটের মুড ও চরিত্র অনুযায়ী কোন নোটে কতটা শক্তি/তীব্রতা দেওয়া উচিত, সেটা বোঝা যাবে।

1. ভৈরবী ঠাট (Bhairavi)

ভাব: করুণ, কোমল, বিষণ্ন

Sa (Tonic): 75–85 (stable)
Komal Re, Komal Dha: 65–75 (soft, gliding)
Komal Ga, Komal Ni: 70–80 (gentle, emotional)
Ma, Pa: 80–90 (stable, but expressive)
Tivra Ma (if used rarely): 85–95 (sharp but brief emphasis)

2. কাল্যাণ ঠাট (Kalyan)

ভাব: দেবতা, ঐশ্বরিকতা, ভক্তি
Sa: 80–90
Re, Ga, Dha, Ni: 85–100 (shining)
Tivra Ma: 100–115 (high emphasis; centerpiece of the scale)
Pa: 85–95 (stability)

3. মারওয়া ঠাট (Marwa)
ভাব: রহস্যময়, উদ্বেগ, গোধূলি
Sa: 70–80 (uncertain, floating)
Re (Komal): 60–70 (tension, soft but haunting)
Ga, Dha: 75–85 (sharp entry)
Tivra Ma: 90–105 (directional)
Ni: 85–95

4. বিলাওল ঠাট (Bilawal)
ভাব: উদারতা, সরলতা, পবিত্রতা
Sa: 80–90 (clean base)
Re, Ga, Dha, Ni: 85–95 (happy energy)
Ma, Pa: 90–100 (uplifting)
5. খাম্বাজ ঠাট (Khamaj)
ভাব: প্রেম, নরম, অলংকারপূর্ণ
Sa: 80–90
Re, Ga: 85–95 (playful)
Komal Ni: 75–85 (soft landing)
Ma, Pa: 90–100
6. আসাবারি ঠাট (Asavari)
ভাব: উদাসীনতা, কষ্ট, কোমল অনুভব
Sa: 70–80
Komal Ga, Dha, Ni: 60–75 (deep expression)
Ma, Pa: 80–90
7. পুরবী ঠাট (Purvi)
ভাব: অলৌকিক, সন্ধ্যা-রহস্য, উচ্চ অনুভব
Sa: 75–85
Komal Re, Dha: 70–80
Tivra Ma: 100–110
Ga, Ni: 85–95
8. ভৈরব ঠাট (Bhairav)
ভাব: গম্ভীরতা, ভক্তি, ভয়-ভীতি
Sa: 80–90
Komal Re, Dha: 65–75
Ma, Pa, Ni: 85–95
9. তোড়ি ঠাট (Todi)
ভাব: পরিশীলিত, রহস্যময়, তীব্র অভিব্যক্তি
Sa: 70–80
Komal Re, Ga, Dha, Ni: 60–75
Tivra Ma: 100–115
10. কফি ঠাট (Kafi)
ভাব: নরম, মৃদু প্রেম, দোলপূর্ণ
Sa: 80–90
Komal Ga, Ni: 65–75
Ma, Pa, Dha: 85–95
ভারতীয় দের পছন্দ non perfections ফলে Extra random ধরনের additional Notes দরকার হয়।
Velocity এর মধ্যে variation রাখা natural human expression এর simulation এর জন্য ভালো।যদি একটু random ±10 range দেওয়া হয়, তাহলে সেই human imperfection আসে। এই ইনফারফেকশন টা ভারতীয় দের খুব পছন্দ। গাণিতিক ভাবে বোকা বোকা।

NAudio-তে velocity = GetVelocityForThaatAndNote(thaat, midiNote) এইরকম function করে রাখলে  কোড টা modular হয়। প্রতিটা ঠাটের জন্য একটা Dictionary<string, int> বানিয়ে দেখতে শুনতে পারি যেটা নোট নাম্বার অনুযায়ী velocity return করবে।

____________

Try 11

 Velocity এবং Note Duration (in milliseconds) নির্ধারণ করা রাগ বাজানোর সময় খুবই গুরুত্বপূর্ণ—এগুলো ঠিকঠাক না হলে sound কৃত্রিম বা unmusical শোনায়।
1. Velocity Calculation Rule (MIDI)

MIDI Velocity Range

0 – 127:
0 = no sound
127 = maximum force/loudness
Behag বা Bhairavi র মতো soft রাগে সাধারণত
Velocity Range: 60 – 110
Soft expressive parts → 60–80
Bold or emphasized parts (like high Sa or Pa) → 90–110
Velocity Calculation Heuristic
velocity = (int)(baseVelocity + (durationMs / 10) + (pitch / 3)) % 127;

Example

Higher pitched notes naturally sound louder, so we increase velocity slightly.
Longer notes usually played more expressively → slightly more velocity.
Or, we can add randomness with bounds

int velocity = rnd.Next(70, 110);

If you want more control:

int pitch = 72; // C5
int durationMs = 600;

int velocity = 70 + (durationMs / 20) + ((pitch - 60) / 2); // You can tune the constants
if (velocity > 127) velocity = 127;

2. Note Duration Calculation Rule (ms)
MIDI তে duration হিসাব হয়
ticksPerQuarterNote = 480 (standard)

Then,use

durationTicks = (int)((durationMs / 1000.0) * bpm * ticksPerQuarterNote / 60);

Example:

int bpm = 90;
int durationMs = 600;

int durationTicks = (int)((600 / 1000.0) * 90 * 480 / 60);
// = (0.6) * 90 * 8
// = ~432 ticks

Duration Based on Raga Feeling
Restful Notes (Sa, Pa) → Longer: 600ms–1000ms
Moving Notes (Re, Ga, Dha) → Shorter: 250ms–500ms
Gamaka or fast transition → Very short: 120–200ms
General Heuristic Code Example

int note = 72;
bool isRestNote = (note % 12 == 0 || note % 12 == 7); // Sa or Pa
int durationMs = isRestNote ? rnd.Next(600, 900) : rnd.Next(300, 600);

একটি auto calculated velocity & duration helper class তৈরি করে দেখা টা রিসার্চ, যেটা automated raga MIDI generator এ ব্যবহার করতে চেষ্টা করছি।

______________

Try 11+

প্রোগ্রামিং করার জন্য NAudio C# দিয়ে রাগ বেহাগ (Behag) এর ৩ মিনিটের একটি প্রোফেশনাল MIDI ফাইল তৈরির কোড তৈরি করব 

৬টি চ্যানেল ব্যবহার করে
Pure Flute sound (MIDI Program 73)
Pitch Bend, Channel Pressure, Breath Control, Volume Fade, Strumming, Panning সহ সম্পূর্ণ effect দেয়
সুন্দর Stereo Imaging তৈরি করে
শুনলে প্রফেশনাল লাইভ ফ্লুট রেন্ডিশনের মত শোনাবে
Behag Raga MIDI Generator (NAudio C# Pro Version)

using System;
using System.IO;
using NAudio.Midi;

class BehagMidiFlutePro
{
    static void Main()
    {
        string outputPath = "BehagFlute_Effect.mid";
        var midiEventCollection = new MidiEventCollection(1, 480);

        int bpm = 95;
        int ticksPerBeat = 480;

        // Raga Behag (approx. notes used)
        // Aroha: S G M P N S’
        // Avaroha: S’ N D P M G R S
        // Behag uses both shuddha and teevra notes depending on the phrasing
        int[] behagNotes = { 60, 64, 65, 67, 71, 72, 74, 69, 68, 65, 64, 62, 60 };

        Random rnd = new Random();

        for (int channel = 0; channel < 6; channel++)
        {
            midiEventCollection.AddTrack();
            midiEventCollection[channel].Add(new PatchChangeEvent(0, channel, 73)); // Flute

            int currentTime = 0;

            for (int i = 0; i < 150; i++) // approx 3 minutes of music
            {
                int note = behagNotes[rnd.Next(behagNotes.Length)];
                int velocity = rnd.Next(70, 110);
                int duration = rnd.Next(300, 800); // between 300ms to 800ms
                int strumDelay = channel * 15;

                // Pitch bend (±1500)
                int pitchBend = 8192 + rnd.Next(-1500, 1500);
                midiEventCollection[channel].Add(new PitchWheelChangeEvent(currentTime, channel, pitchBend));

                // Channel Pressure
                midiEventCollection[channel].Add(new ChannelAfterTouchEvent(currentTime, channel, rnd.Next(50, 120)));

                // Breath Control (CC 2)
                midiEventCollection[channel].Add(new ControlChangeEvent(currentTime, channel, MidiController.BreathController, rnd.Next(60, 120)));

                // Volume fade (CC 7)
                int volume = 100 - (i % 15);
                midiEventCollection[channel].Add(new ControlChangeEvent(currentTime, channel, MidiController.MainVolume, volume));

                // Panning (CC 10)
                int pan = 30 + channel * 14;
                midiEventCollection[channel].Add(new ControlChangeEvent(currentTime, channel, MidiController.Pan, pan));

                // Note On
                midiEventCollection[channel].Add(new NoteOnEvent(currentTime + strumDelay, channel, note, velocity, duration));

                // Note Off
                midiEventCollection[channel].Add(new NoteEvent(currentTime + duration + strumDelay, channel, MidiCommandCode.NoteOff, note, 0));

                currentTime += duration;
            }
        }

        MidiFile.Export(outputPath, midiEventCollection);
        Console.WriteLine("Behag MIDI file generated: " + outputPath);
    }
}

_________

Try 11++

এইবার sample রূপে নিচে দেওয়া হলো পূর্ণাঙ্গ NAudio C# কোড, যেটি

ভৈরবী রাগ এর ৩ মিনিটের MIDI ফাইল তৈরি করে
Flute (Program 73) 6টি চ্যানেলে বাজায়
Pitch bend, Channel Pressure, Breath Control (CC 2)
Strumming effect (slight delay between simultaneous notes)
Volume fading (CC 7)
Panning (CC 10)
পুরো ফাইলটি সুন্দরভাবে ব্যালেন্সড করে

Full Pro Level C# Code: Bhairavi MIDI (With Effects)

using System;
using System.IO;
using NAudio.Midi;

class BhairaviMidiProFlute
{
    static void Main()
    {
        string outputPath = "BhairaviFlute_Effect.mid";
        var midiEventCollection = new MidiEventCollection(1, 480);

        int bpm = 90;
        int ticksPerBeat = 480;
        int msPerTick = (60000 / bpm) / ticksPerBeat;

        // Bhairavi Notes (Sa, Komal Re, Komal Ga, Ma, Pa, Komal Dha, Komal Ni, Sa)
        int[] bhairaviNotes = { 60, 61, 63, 65, 67, 68, 70, 72 };

        Random rnd = new Random();

        for (int channel = 0; channel < 6; channel++)
        {
            int track = channel;
            midiEventCollection.AddTrack();

            // Set Instrument - Flute (73)
            midiEventCollection[track].Add(new PatchChangeEvent(0, channel, 73));

            int currentTime = 0;

            for (int i = 0; i < 150; i++) // ~150 notes x avg 1.2s = ~3 min
            {
                int noteIndex = rnd.Next(bhairaviNotes.Length);
                int note = bhairaviNotes[noteIndex];
                int velocity = rnd.Next(70, 120);
                int duration = rnd.Next(240, 960); // variable durations

                // Pitch bend (±2000 random)
                int pitch = 8192 + rnd.Next(-2000, 2000);
                midiEventCollection[track].Add(new PitchWheelChangeEvent(currentTime, channel, pitch));

                // Channel Pressure
                midiEventCollection[track].Add(new ChannelAfterTouchEvent(currentTime, channel, rnd.Next(40, 127)));

                // Breath Control (CC 2)
                midiEventCollection[track].Add(new ControlChangeEvent(currentTime, channel, MidiController.BreathController, rnd.Next(50, 127)));

                // Volume Fade (CC 7)
                int volume = 100 - (i % 20); // fade out effect
                midiEventCollection[track].Add(new ControlChangeEvent(currentTime, channel, MidiController.MainVolume, volume));

                // Panning (CC 10)
                int pan = 32 + (channel * 12); // stereo separation
                midiEventCollection[track].Add(new ControlChangeEvent(currentTime, channel, MidiController.Pan, pan));

                // Strumming delay (each channel slightly delayed)
                int strumDelay = channel * 20;

                // Note On
                midiEventCollection[track].Add(new NoteOnEvent(currentTime + strumDelay, channel, note, velocity, duration));

                // Note Off
                currentTime += duration;
                midiEventCollection[track].Add(new NoteEvent(currentTime + strumDelay, channel, MidiCommandCode.NoteOff, note, 0));
            }
        }

        MidiFile.Export(outputPath, midiEventCollection);
        Console.WriteLine("MIDI file generated: " + outputPath);
    }
}

______________

Try 11+++

এইবার নিচে ৩ মিনিটের জন্য একটি ভৈরবী রাগ MIDI ফাইল তৈরি করার সম্পূর্ণ C# কোড দিচ্ছি, যেটা

C sharp এর NAudio ব্যবহার করে
6 টি চ্যানেলে flute এর ভিন্ন ভিন্ন নোট বাজায়
প্রতিটি নোটে ভিন্ন duration, pitch bend, channel pressure ও breath control (CC #2) প্রয়োগ করে
MIDI instrument: Flute (Program 73)
Total duration: 3 minutes
Output: .mid ফাইল হিসেবে save হবে
এই C# কোড (NAudio দিয়ে MIDI ফাইল তৈরি)

using System;
using System.IO;
using NAudio.Midi;

class BhairaviMidiGenerator
{
    static void Main()
    {
        string outputPath = "BhairaviFlute.mid";
        var midiEventCollection = new MidiEventCollection(1, 480);

        // Bhairavi raga notes (Sa, Komal Re, Komal Ga, Ma, Pa, Komal Dha, Komal Ni, Sa)
        int[] bhairaviNotes = { 60, 61, 63, 65, 67, 68, 70, 72 };

        int bpm = 90;
        int ticksPerBeat = 480;
        int msPerTick = (60000 / bpm) / ticksPerBeat;

        Random rnd = new Random();

        for (int channel = 0; channel < 6; channel++)
        {
            int track = channel;
            midiEventCollection.AddTrack();

            // Set Instrument to Flute (Program Number 73)
            midiEventCollection[track].Add(new PatchChangeEvent(0, channel, 73));
            
            int currentTime = 0;

            for (int i = 0; i < bhairaviNotes.Length * 20; i++)
            {
                int noteIndex = i % bhairaviNotes.Length;
                int noteNumber = bhairaviNotes[noteIndex];
                int velocity = rnd.Next(70, 110);
                int durationTicks = rnd.Next(240, 960); // Varying durations (0.5 to 2 beats)
                
                // Optional Pitch Bend (centered ±2000)
                int pitchBend = 8192 + rnd.Next(-2000, 2000);
                midiEventCollection[track].Add(new PitchWheelChangeEvent(currentTime, channel, pitchBend));

                // Channel Pressure
                midiEventCollection[track].Add(new ChannelAfterTouchEvent(currentTime, channel, rnd.Next(50, 120)));

                // Breath Control (CC 2)
                midiEventCollection[track].Add(new ControlChangeEvent(currentTime, channel, MidiController.BreathController, rnd.Next(40, 127)));

                // Note On
                midiEventCollection[track].Add(new NoteOnEvent(currentTime, channel, noteNumber, velocity, durationTicks));

                // Note Off
                currentTime += durationTicks;
                midiEventCollection[track].Add(new NoteEvent(currentTime, channel, MidiCommandCode.NoteOff, noteNumber, 0));
            }
        }

        MidiFile.Export(outputPath, midiEventCollection);
        Console.WriteLine($"MIDI file generated: {outputPath}");
    }
}

এগুলো চেষ্টা করার আগে
Visual Studio Console App তৈরি করুন
NuGet দিয়ে NAudio ইনস্টল করুন
Install-Package NAudio
BhairaviFlute.mid নামে ৩ মিনিটের MIDI ফাইল তৈরি হবে
এই কোডে delay effect, strumming simulation, volume fading, বা panning ও যোগ করে চেষ্টা করা উচিত 

______
Try 15

এখানে ভৈরবী রাগের MIDI তথ্য নিচে দেওয়া হলো (Pure Flute এর জন্য)
ভৈরবী রাগের স্বর (মধ্য সপ্তক)
Sa (C4) – MIDI: 60 – Frequency: 261.63 Hz
komal Re (C#4) – MIDI: 61 – Frequency: 277.18 Hz
komal Ga (D#4) – MIDI: 63 – Frequency: 311.13 Hz
Ma (F4) – MIDI: 65 – Frequency: 349.23 Hz
Pa (G4) – MIDI: 67 – Frequency: 392.00 Hz
komal Dha (G#4) – MIDI: 68 – Frequency: 415.30 Hz
komal Ni (A#4) – MIDI: 70 – Frequency: 466.16 Hz
Sa (C5) – MIDI: 72 – Frequency: 523.25 Hz
আমি NAudio ব্যবহার করে ভৈরবী রাগের একটি C# প্রোগ্রাম লিখেছি 

6টি channel ব্যবহার করে
প্রতিটি নোটে ভিন্ন duration
Pitch Bend, Channel Pressure ও Breath Control (CC #2) সহ শুধুমাত্র flute instrument (MIDI Program Number: 73)
এগুলো MIDI ফাইলে অবশ্যই সংরক্ষিত করতে হবে কারণ direct প্লে তে অনেক effect computer এ পাবেন না।

_________

Try 15+

 নিচে 10টি প্রধান ঠাট (Thaat) অনুযায়ী প্রত্যেকটি স্বরের MIDI Note Number এবং Frequency in Hertz (Hz) সহ একটি তালিকা তৈরি করে দেবো পরে। ধরে নিচ্ছি Sa = C4 (MIDI note 60 = 261.63 Hz) হিসাবে।

প্রত্যেক ঠাটে Sa, Re, Ga, Ma, Pa, Dha, Ni এই সাতটি স্বর থাকে এদের মধ্যেই কোনটা কোমল (♭) বা তীব্র (♯) সেটা বদলায়। 20 cent থেকে 100 cent পর্যন্ত।
Frequency & MIDI Note Reference Table তৈরি করছি। সময় লাগবে।(Hertz গুলো সমান তাপমাত্রা ও standard tuning A4=440Hz অনুযায়ী)
10 Principal Thaats with MIDI Note Numbers and Frequencies গুলো আলোচনা করতে হবে।

প্রতিটি ঠাটের MIDI ফাইল জেনারেট করে ও দেখতে পারি।
আলাদা আলাদা চ্যানেল এ ভিন্ন ঠাট বাজাতে পারি।
নির্দিষ্ট রাগ বা ঠাটের emotional expression অনুযায়ী pitch bend, velocity, pressure যোগ করতে পারি।

_________

Try 17

ভৈরবী রাগ (Bhairavi Raga) একটি মিষ্টি, মেলানকোলিক এবং devotional ধরণের রাগ। MIDI দিয়ে এটি রেন্ডার করতে চাইলে আমাদের কিছু জিনিস মাথায় রাখতে হবে
ভৈরবী রাগ  স্কেল (MIDI Note Numbers সহ)
NAudio দিয়ে MIDI File
 ভৈরবী রাগ Pure Flute (C# Code)

using NAudio.Midi;
using System;
using System.IO;
using System.Collections.Generic;

class BhairaviRagaMidi
{
    static void Main()
    {
        string filePath = "bhairavi_flute.mid";
        var midiEvents = new MidiEventCollection(1, 480);

        var trackEvents = new List<MidiEvent>();
        int channel = 0;
        int velocity = 90;
        int tick = 0;
        int noteLength = 480; // 1 beat at 120 BPM

        // Bhairavi Raga notes ascending & descending
        int[] bhairaviNotes = {
            60, 61, 63, 65, 67, 68, 70, 72, // Arohan
            72, 70, 68, 67, 65, 63, 61, 60  // Avarohan
        };

        foreach (int note in bhairaviNotes)
        {
            // Add pitch bend for vibrato feel (optional)
            trackEvents.Add(new PitchWheelChangeEvent(tick + 10, channel, 8192 + 300));
            trackEvents.Add(new PitchWheelChangeEvent(tick + 30, channel, 8192 - 300));
            trackEvents.Add(new PitchWheelChangeEvent(tick + 50, channel, 8192));

            // Breath Control for expression
            trackEvents.Add(new ControlChangeEvent(tick, channel, MidiController.BreathController, 100));

            // Channel Pressure
            trackEvents.Add(new ChannelAfterTouchEvent(tick + 5, channel, 70));

            // Note On
            trackEvents.Add(new NoteOnEvent(tick, channel, note, velocity, noteLength));
            // Note Off
            trackEvents.Add(new NoteEvent(tick + noteLength, channel, MidiCommandCode.NoteOff, note, 0));

            tick += noteLength + 30; // spacing between notes
        }

        // Add End of Track
        trackEvents.Add(new MetaEvent(MetaEventType.EndTrack, 0, tick + 100));

        // Add to MIDI collection
        midiEvents.AddTrack(trackEvents);

        // Export
        MidiFile.Export(filePath, midiEvents);
        Console.WriteLine("MIDI File saved: " + Path.GetFullPath(filePath));
    }
}

এই কোডে যা থাকছে

ভৈরবী রাগের আরোহ ও অবরোহ অনুযায়ী নোট প্লে করা হচ্ছে।প্রতি নোটে Pitch Bend, Channel Pressure ও Breath Controller যুক্ত করা হয়েছে।Pure Flute tone পেতে DAW এ General MIDI Channel 74 বা কোনো Flute VSTi সেট করা যাবে। এখানে noteLength parametrically permuted করে করে পরিবর্তন করে slow/fast ভৈরবী বানাতে হবে।

Vibrato আরও expressive করতে হবে ফলে PitchWheelChange আরও smooth করে চেষ্টা করছি। আমি MIDI তে alaap style বা রাগের মতো phrasing করে generate করবো পরে।  কী ধরনের emotion বা structure হবে তার vector রূপ ডিজাইন করতে হবে আগে।
_________
Try 18
এইবার তাহলে আমরা নিচের কাজগুলো করব

1. ৬টি চ্যানেলে ভিন্ন ভিন্ন ফ্লুট নোট প্লে করব ভিন্ন duration ও expression সহ।
2. Channel Pressure, Breath Control, Pitch Bend — এগুলো apply করব।
3. MIDI ফাইল তৈরি করব .mid format-এ NAudio দিয়ে।
NAudio দিয়ে MIDI ফাইল তৈরি করার সম্পূর্ণ C# কোড দেওয়া হচ্ছে 

using NAudio.Midi;
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "flute_expression_layered.mid";
        var midiEventCollection = new MidiEventCollection(1, 480); // format 1, 480 ticks per quarter

        int[] channels = { 0, 1, 2, 3, 4, 5 };
        int[] notes = { 72, 74, 76, 77, 79, 81 }; // C5 → A5
        int[] velocities = { 100, 90, 110, 80, 105, 95 };
        int[] durations = { 300, 500, 700, 400, 600, 800 }; // in ms
        int tickPerMs = 480 / 500; // Assuming 120 BPM = 500 ms per quarter note

        for (int i = 0; i < channels.Length; i++)
        {
            int channel = channels[i];
            int note = notes[i];
            int velocity = velocities[i];
            int duration = durations[i];
            int startTick = 0;
            int endTick = duration * tickPerMs;

            var trackEvents = new TrackEventCollection();

            // Add Note On
            trackEvents.Add(new NoteOnEvent(startTick, channel, note, velocity, 0));

            // Add Breath Control (CC2)
            trackEvents.Add(new ControlChangeEvent(startTick, channel, MidiController.BreathController, 80));
            trackEvents.Add(new ControlChangeEvent(startTick + 20 * tickPerMs, channel, MidiController.BreathController, 100));

            // Add Channel Pressure
            trackEvents.Add(new ChannelAfterTouchEvent(startTick + 10 * tickPerMs, channel, 70));
            trackEvents.Add(new ChannelAfterTouchEvent(startTick + 30 * tickPerMs, channel, 90));

            // Add Pitch Bend (Vibrato)
            trackEvents.Add(new PitchWheelChangeEvent(startTick + 5 * tickPerMs, channel, 8192 + 512));
            trackEvents.Add(new PitchWheelChangeEvent(startTick + 15 * tickPerMs, channel, 8192 - 512));
            trackEvents.Add(new PitchWheelChangeEvent(startTick + 25 * tickPerMs, channel, 8192));

            // Add Note Off
            trackEvents.Add(new NoteEvent(endTick, channel, MidiCommandCode.NoteOff, note, 0));

            // Add End of Track
            trackEvents.Add(new MetaEvent(MetaEventType.EndTrack, 0, endTick + 100));

            // Add to master collection
            midiEventCollection.AddTrack(trackEvents);
        }

        MidiFile.Export(filePath, midiEventCollection);
        Console.WriteLine("MIDI file saved to: " + Path.GetFullPath(filePath));
    }
}
এই কোডে যা হচ্ছে
প্রতি চ্যানেলে একটি নোট প্লে হচ্ছে ভিন্ন duration সহ।
Breath Control (CC2), Channel Pressure, ও Pitch Bend পরিবর্তন হচ্ছে।
MIDI ফাইল flute_expression_layered.mid হিসেবে সেভ হচ্ছে।
 .mid ফাইলটা DAW (audacity,FL Studio, Reaper, etc.) তে ওপেন করে শুনতে পারি।

Flute sound পেতে DAW এ একটা ভাল VSTi বা GM Flute Instrument সেট করতে হয় আগেই প্রতিটা চ্যানেলে।Pitch bend range DAW এ 2 semitone করে রাখতে হয়, নাহলে pitch bend কাজ করবে না।
এইবার যদি parametrically auto generated permuted Indian ragas বা parametric emotional expression যুক্ত করতে চেষ্টা করি,  সেটাও MIDI প্রোগ্রাম করে চেষ্টা করতে পারি। 

_________
Try 19

  Memory overflow হচ্ছে post এর

Comments

  1. https://drinkussions.blogspot.com/2025/04/saan-programming-for-ragas.html

    ReplyDelete

Post a Comment

Popular posts from this blog

SANJOYNATHSMANIMMOVIES___SCENE.PY

GTTERMS_FORMALIZATION_GEOMETRIFYING_TRIGONOMETRY

why_set_theory_needed