Yardım Programımda Çözülemeyen Hesaplama Hataları Oluşuyor

KindElephant480

Asistan
Katılım
14 Eylül 2017
Mesajlar
366
Reaksiyon puanı
44
Puanları
28
433167396-5170729c-cd2e-47c6-aa82-3231f732ece9.png

1 yıldan fazla bir süredir NeoBleeper isimli SomethingUnreal kullanıcı adına sahip eski bir YouTuber'ın VB6 kullanarak geliştirdiği ve bilgisayarların anakartlarında bulunan sistem hoparlörü (normalde bilgisayarların sadece bip sesi çıkarması için kullanılan bir çeşit hoparlör) ile melodi çalmayı sağlayan Bleeper Music Maker programının C# dili ile yeniden yazdığım ve yapay zekâ destekli resimdeki yeniden yapımı olan bir program geliştiriyorum ancak listedeki notaları çalma özelliğini çalışır duruma getirdiğimden bu yana aşırı yavaş çalınma gibi çeşitli sorunlar yaşadım, bir süre sonra pencereyi gizleyene kadar aşırı yavaş çalınma sorunlarını çözdüm ancak videodaki gibi notaların uzunluklarının senkronize oynatmada senkronizasyonu bozacak şekilde hatalı hesaplandığını fark ettim ve sorunu System.Threading.Timers.Timer kullanan ve arayüz dondurmayan bekleme metodumdaki Timer'ı Stopwatch ile değiştirerek büyük oranda çözdüm.


Ancak videolardaki gibi iki programı karşılaştırdığımda orijinal Bleeper Music Maker programında notalar daha hızlı çalınırken NeoBleeper programımda orijinal Bleeper Music Maker programına göre daha yavaş çalındığını fark ettim ve bu kodlardaki yöntemler üzerinde sonuçları kesme veya yuvarlama işlemleri ve vuruş uzunluğu hesaplamaları konusunda denemeler yaptım ancak hiçbir sonuca ulaşamıyorum.



C#:
private async void play_music(int startIndex)
        {
            bool nonStopping = false;
            EnableDisableCommonControls(false);

            while (listViewNotes.SelectedItems.Count > 0 && is_music_playing)
            {
                nonStopping = trackBar_note_silence_ratio.Value == 100;

                // Calculating note length and line length based on BPM
                decimal millisecondsPerWholeNote = 0m;
                if (Variables.bpm > 0)
                {
                    // 60,000 ms / BPM = whole note duration in milliseconds / 240,000 ms = whole note duration in milliseconds for 4/4 time signature
                    millisecondsPerWholeNote = 240000m / Variables.bpm;
                }

                // Note length and line length calculators
                int noteLength = note_length_calculator((double)millisecondsPerWholeNote);
                int lineLength = line_length_calculator((double)millisecondsPerWholeNote);

                // Note duration and wait duration calculations should be at least 1 ms
                int calculatedNoteDuration = Math.Max(1, noteLength);
                // Line length should also be at least 1 ms
                int calculatedWaitDuration = Math.Max(calculatedNoteDuration, lineLength);

                // Silence duration calculation
                int silenceDuration = calculatedWaitDuration - calculatedNoteDuration;

                // Play with MIDI output if enabled
                if (Program.MIDIDevices.useMIDIoutput)
                {
                    play_note_in_line_from_MIDIOutput(
                        listViewNotes.SelectedIndices[0],
                        checkBox_play_note1_played.Checked,
                        checkBox_play_note2_played.Checked,
                        checkBox_play_note3_played.Checked,
                        checkBox_play_note4_played.Checked,
                        calculatedNoteDuration
                    );
                }

                // Regular note playing logic
                play_note_in_line(
                    checkBox_play_note1_played.Checked,
                    checkBox_play_note2_played.Checked,
                    checkBox_play_note3_played.Checked,
                    checkBox_play_note4_played.Checked,
                    calculatedNoteDuration,
                    nonStopping
                );

                // Apply the note length to the selected line in the ListView
                if (silenceDuration > 0 && !nonStopping)
                {
                    UpdateLabelVisible(false); // Hide the label
                    NonBlockingSleep.Sleep(silenceDuration);
                }

                // Select the next line in the ListView
                await UpdateListViewSelectionSync(startIndex);
            }

            // Clean up after playing
            if (nonStopping)
            {
                stopAllNotesAfterPlaying();
            }

            EnableDisableCommonControls(true);
        }

private int note_length_calculator(double msPerWholeNote)
        {
            if (listViewNotes.SelectedItems == null || listViewNotes.SelectedItems.Count == 0 ||
                listViewNotes.Items == null || listViewNotes.Items.Count == 0)
            {
                return 0;
            }

            int selectedLine = listViewNotes.SelectedIndices[0];
            string noteType = listViewNotes.Items[selectedLine].SubItems[0].Text;
            string modifier = listViewNotes.Items[selectedLine].SubItems[5].Text;
            string articulation = listViewNotes.Items[selectedLine].SubItems[6].Text;

            // Calculate the basic note length based on the note type
            decimal noteFraction = noteType switch
            {
                "Whole" => 1m,      // Whole note
                "Half" => 0.5m,     // Half note
                "Quarter" => 0.25m, // Quarter note
                "1/8" => 0.125m,    // 1/8 note
                "1/16" => 0.0625m,  // 1/16 note
                "1/32" => 0.03125m, // 1/32 note
                _ => 0.25m,         // Default: Quarter note
            };

            // Modifier factor (Dot, Triplet)
            decimal modifierFactor = 1m;
            if (!string.IsNullOrEmpty(modifier))
            {
                if (modifier.ToLowerInvariant().Contains("dot"))
                    modifierFactor = 1.5m; // Dotted note: 1.5x length
                else if (modifier.ToLowerInvariant().Contains("tri"))
                    modifierFactor = 1m / 3m; // Triplet: 1/3x length
            }

            // Articulation factor - only affects fermata
            decimal articulationFactor = 1m;
            if (!string.IsNullOrEmpty(articulation))
            {
                if (articulation.ToLowerInvariant().Contains("sta"))
                    articulationFactor = 0.5m;    // Staccato: 0.5x length
                else if (articulation.ToLowerInvariant().Contains("spi"))
                    articulationFactor = 0.25m;   // Spiccato: 0.25x length
                else if (articulation.ToLowerInvariant().Contains("fer"))
                    articulationFactor = 2m;      // Fermata: 2x length
            }

            // Note-silence ratio (from trackBar)
            decimal silenceRatio = (decimal)trackBar_note_silence_ratio.Value / 100m;

            // Calculate the total note length
            decimal result = (decimal)msPerWholeNote * noteFraction * modifierFactor * articulationFactor * silenceRatio;

            // Should be at least 1 ms
            return Math.Max(1, (int)Math.Round(result, MidpointRounding.AwayFromZero));
        }

private int line_length_calculator(double msPerWholeNote)
        {
            if (listViewNotes.SelectedItems == null || listViewNotes.SelectedItems.Count == 0 ||
                listViewNotes.Items == null || listViewNotes.Items.Count == 0)
            {
                return 0;
            }

            int selectedLine = listViewNotes.SelectedIndices[0];
            string noteType = listViewNotes.Items[selectedLine].SubItems[0].Text;
            string modifier = listViewNotes.Items[selectedLine].SubItems[5].Text;
            string articulation = listViewNotes.Items[selectedLine].SubItems[6].Text;

            // Calculate the basic note length based on the note type
            decimal noteFraction = noteType switch
            {
                "Whole" => 1m,      // Whole note
                "Half" => 0.5m,     // Half note
                "Quarter" => 0.25m, // Quarter note
                "1/8" => 0.125m,    // 1/8 note
                "1/16" => 0.0625m,  // 1/16 note
                "1/32" => 0.03125m, // 1/32 note
                _ => 0.25m,         // Default: Quarter note
            };

            // Modifier factor (Dot, Triplet)
            decimal modifierFactor = 1m;
            if (!string.IsNullOrEmpty(modifier))
            {
                if (modifier.ToLowerInvariant().Contains("dot"))
                    modifierFactor = 1.5m; // Dotted: 1.5x length
                else if (modifier.ToLowerInvariant().Contains("tri"))
                    modifierFactor = 1m / 3m; // Triplet: 1/3x length
            }

            // Articulation factor - only affects fermata
            decimal articulationFactor = 1m;
            if (!string.IsNullOrEmpty(articulation) && articulation.ToLowerInvariant().Contains("fer"))
            {
                articulationFactor = 2m; // Fermata: 2x length
            }
            // Staccato and Spiccato do not affect line length

            // Calculate the total line length (without note-silence ratio)
            decimal result = (decimal)msPerWholeNote * noteFraction * modifierFactor * articulationFactor;

            // Should be at least 1 ms
            return Math.Max(1, (int)Math.Round(result, MidpointRounding.AwayFromZero));
        }

Sizce bu durumda programımın kodundaki hesaplama hataları hangi kısımlarda neden kaynaklanıyor olabilir?
Merak edenler için programımın GitHub sayfasının bağlantısı: NeoBleeper GitHub sayfası
 
Son düzenleme:

crow88

İçerik Ekibi
İçerik Ekibi
Katılım
1 Aralık 2010
Mesajlar
6,851
Çözümler
1
Reaksiyon puanı
3,345
Puanları
1,358
Yaş
59
merhaba
sadece fikrimi belirtmek istiyorum(1989 90) yıllarında basıc cobol fortran eğitimi aldım,uzman değilim))
1-biliyorsunuz program içinde döngüler var,bu döngülerden bazıları program içinde çakışma yapabilir
2-akış algoritmasında programın çalışmasını engellebilecek kod vardır,buda gözünüzden kaçmış olabilir
biliyorsunuzki belli aşamadan sonra gözleriniz,ufak nokta hatalarınıda görmez oluyor,şöyle söyleyim,program bu ufak hatayı görüyor ama engel olmayıp kabul ediyor,buda hataya sebep olabiliyor.
3-üst yazınızda hesaplama hatalarını bulduğunuzu söylediniz,bence bölüm bölüm yeniden derleme yaparak çalıştırmaniz,hatayı bu şekilde bulma imkanınız olabilir
kolay gelsin
 

Alois Alzheimer

Müdavim
Müdavim
Katılım
18 Ocak 2019
Mesajlar
1,708
Reaksiyon puanı
2,317
Puanları
358
Yaş
31
İyi derecede C++ ve Delphi bilen birisi olarak orijinal uygulamanın ve senin yaptığın uygulamanın arayüzlerini karşılaştırdım.

Sanki yeni sürümünü yapmış gibisin, çok güzel olmuş.
 

KindElephant480

Asistan
Katılım
14 Eylül 2017
Mesajlar
366
Reaksiyon puanı
44
Puanları
28
İyi derecede C++ ve Delphi bilen birisi olarak orijinal uygulamanın ve senin yaptığın uygulamanın arayüzlerini karşılaştırdım.

Sanki yeni sürümünü yapmış gibisin, çok güzel olmuş.
Ancak her ne kadar arayüzü benziyor ve bahsettiğim hesaplama hatası neredeyse fark edilmeyecek kadar çok küçük bir hata olsa da bu hata senkronize oynatmada senkronizasyonu birkaç ölçü bozuyor, Math.Round ile farklı orta nokta yuvarlaması stratejileri (AwayFromZero, ToZero, ToEven gibi), Math.Truncate ve Math.Floor yöntemlerini denesem de sonuç hepsinde neredeyse aynıydı ve orijinal program açık kaynak kodlu olmadığı için kendim yazmak zorunda kaldım (çünkü orijinal program VB6 ile yazılmış ve orijinal programı geri derlediğimde çıkan kodlar Assembly dilinde ya da anlamsız isimlere sahip).
 

Alois Alzheimer

Müdavim
Müdavim
Katılım
18 Ocak 2019
Mesajlar
1,708
Reaksiyon puanı
2,317
Puanları
358
Yaş
31
Ancak her ne kadar arayüzü benziyor ve bahsettiğim hesaplama hatası neredeyse fark edilmeyecek kadar çok küçük bir hata olsa da bu hata senkronize oynatmada senkronizasyonu birkaç ölçü bozuyor, Math.Round ile farklı orta nokta yuvarlaması stratejileri (AwayFromZero, ToZero, ToEven gibi), Math.Truncate ve Math.Floor yöntemlerini denesem de sonuç hepsinde neredeyse aynıydı ve orijinal program açık kaynak kodlu olmadığı için kendim yazmak zorunda kaldım (çünkü orijinal program VB6 ile yazılmış ve orijinal programı geri derlediğimde çıkan kodlar Assembly dilinde ya da anlamsız isimlere sahip).
Managed dillerle yazılmış programlar dnSpy ile çözülebilir diye biliyorum.
 

KindElephant480

Asistan
Katılım
14 Eylül 2017
Mesajlar
366
Reaksiyon puanı
44
Puanları
28
Managed dillerle yazılmış programlar dnSpy ile çözülebilir diye biliyorum.
Ancak dnSpy ile bile çözülemiyor çünkü .NET tabanlı değil, MSCOMCTL.OCX (ActiveX) tabanlı bir program ve bu nedenle tamamen sıfırdan geliştirmek ve bazı ince detaylarda yapay zekadan yardım almak zorunda kaldım.
Mesaj otomatik birleştirildi:

Ayrıca bu şekilde sorunu kısmen çözdüm ancak nota uzunlukları hâlen istediğim gibi değil

C#:
private async void play_music(int startIndex)
        {
            bool nonStopping = false;
            EnableDisableCommonControls(false);

            while (listViewNotes.SelectedItems.Count > 0 && is_music_playing)
            {
                nonStopping = trackBar_note_silence_ratio.Value == 100;

                // Calculating note length and line length based on BPM
                decimal millisecondsPerWholeNote = 0m;
                if (Variables.bpm > 0)
                {
                    // 60,000 ms / BPM = whole note duration in milliseconds / 240,000 ms = whole note duration in milliseconds for 4/4 time signature
                    millisecondsPerWholeNote = Math.Truncate(240000m / Variables.bpm);
                }

                // Note length and line length calculators
                int noteLength = note_length_calculator(millisecondsPerWholeNote);
                int lineLength = line_length_calculator(millisecondsPerWholeNote);

                // Note duration and wait duration calculations should be at least 1 ms
                int calculatedNoteDuration = Math.Max(1, noteLength);
                // Line length should also be at least 1 ms
                int calculatedWaitDuration = Math.Max(calculatedNoteDuration, lineLength);

                // Silence duration calculation
                int silenceDuration = calculatedWaitDuration - calculatedNoteDuration;

                // Play with MIDI output if enabled
                if (Program.MIDIDevices.useMIDIoutput)
                {
                    play_note_in_line_from_MIDIOutput(
                        listViewNotes.SelectedIndices[0],
                        checkBox_play_note1_played.Checked,
                        checkBox_play_note2_played.Checked,
                        checkBox_play_note3_played.Checked,
                        checkBox_play_note4_played.Checked,
                        calculatedNoteDuration
                    );
                }

                // Regular note playing logic
                play_note_in_line(
                    checkBox_play_note1_played.Checked,
                    checkBox_play_note2_played.Checked,
                    checkBox_play_note3_played.Checked,
                    checkBox_play_note4_played.Checked,
                    calculatedNoteDuration,
                    nonStopping
                );

                // Apply the note length to the selected line in the ListView
                if (silenceDuration > 0 && !nonStopping)
                {
                    UpdateLabelVisible(false); // Hide the label
                    NonBlockingSleep.Sleep(silenceDuration);
                }

                // Select the next line in the ListView
                await UpdateListViewSelectionSync(startIndex);
            }

            // Clean up after playing
            if (nonStopping)
            {
                stopAllNotesAfterPlaying();
            }

            EnableDisableCommonControls(true);
        }

private int note_length_calculator(decimal msPerWholeNote)
        {
            if (listViewNotes.SelectedItems == null || listViewNotes.SelectedItems.Count == 0 ||
                listViewNotes.Items == null || listViewNotes.Items.Count == 0)
            {
                return 0;
            }

            int selectedLine = listViewNotes.SelectedIndices[0];
            string noteType = listViewNotes.Items[selectedLine].SubItems[0].Text;
            string modifier = listViewNotes.Items[selectedLine].SubItems[5].Text;
            string articulation = listViewNotes.Items[selectedLine].SubItems[6].Text;

            // Calculate the basic note length based on the note type
            decimal noteFraction = noteType switch
            {
                "Whole" => 1m,      // Whole note
                "Half" => 0.5m,     // Half note
                "Quarter" => 0.25m, // Quarter note
                "1/8" => 0.125m,    // 1/8 note
                "1/16" => 0.0625m,  // 1/16 note
                "1/32" => 0.03125m, // 1/32 note
                _ => 0.25m,         // Default: Quarter note
            };

            // Modifier factor (Dot, Triplet)
            decimal modifierFactor = 1m;
            if (!string.IsNullOrEmpty(modifier))
            {
                if (modifier.ToLowerInvariant().Contains("dot"))
                    modifierFactor = 1.5m; // Dotted note: 1.5x length
                else if (modifier.ToLowerInvariant().Contains("tri"))
                    modifierFactor = 1m / 3m; // Triplet: 1/3x length
            }

            // Articulation factor - only affects fermata
            decimal articulationFactor = 1m;
            if (!string.IsNullOrEmpty(articulation))
            {
                if (articulation.ToLowerInvariant().Contains("sta"))
                    articulationFactor = 0.5m;    // Staccato: 0.5x length
                else if (articulation.ToLowerInvariant().Contains("spi"))
                    articulationFactor = 0.25m;   // Spiccato: 0.25x length
                else if (articulation.ToLowerInvariant().Contains("fer"))
                    articulationFactor = 2m;      // Fermata: 2x length
            }

            // Note-silence ratio (from trackBar)
            decimal silenceRatio = trackBar_note_silence_ratio.Value / 100m;

            // Calculate the total note length
            decimal result = msPerWholeNote;
            result = Math.Truncate(result * noteFraction);
            result = Math.Truncate(result * modifierFactor);
            result = Math.Truncate(result * articulationFactor);
            result = Math.Truncate(result * silenceRatio);

            // Should be at least 1 ms
            return Math.Max(1, (int)result);
        }

private int line_length_calculator(decimal msPerWholeNote)
        {
            if (listViewNotes.SelectedItems == null || listViewNotes.SelectedItems.Count == 0 ||
                listViewNotes.Items == null || listViewNotes.Items.Count == 0)
            {
                return 0;
            }

            int selectedLine = listViewNotes.SelectedIndices[0];
            string noteType = listViewNotes.Items[selectedLine].SubItems[0].Text;
            string modifier = listViewNotes.Items[selectedLine].SubItems[5].Text;
            string articulation = listViewNotes.Items[selectedLine].SubItems[6].Text;

            // Calculate the basic note length based on the note type
            decimal noteFraction = noteType switch
            {
                "Whole" => 1m,      // Whole note
                "Half" => 0.5m,     // Half note
                "Quarter" => 0.25m, // Quarter note
                "1/8" => 0.125m,    // 1/8 note
                "1/16" => 0.0625m,  // 1/16 note
                "1/32" => 0.03125m, // 1/32 note
                _ => 0.25m,         // Default: Quarter note
            };

            // Modifier factor (Dot, Triplet)
            decimal modifierFactor = 1m;
            if (!string.IsNullOrEmpty(modifier))
            {
                if (modifier.ToLowerInvariant().Contains("dot"))
                    modifierFactor = 1.5m; // Dotted: 1.5x length
                else if (modifier.ToLowerInvariant().Contains("tri"))
                    modifierFactor = 1m / 3m; // Triplet: 1/3x length
            }

            // Articulation factor - only affects fermata
            decimal articulationFactor = 1m;
            if (!string.IsNullOrEmpty(articulation) && articulation.ToLowerInvariant().Contains("fer"))
            {
                articulationFactor = 2m; // Fermata: 2x length
            }
            // Staccato and Spiccato do not affect line length

            // Calculate the total line length (without note-silence ratio)
            decimal result = msPerWholeNote;
            result = Math.Truncate(result * noteFraction);
            result = Math.Truncate(result * modifierFactor);
            result = Math.Truncate(result * articulationFactor);

            // Should be at least 1 ms
            return Math.Max(1, (int)result);
        }
 
Son düzenleme:

KindElephant480

Asistan
Katılım
14 Eylül 2017
Mesajlar
366
Reaksiyon puanı
44
Puanları
28
Ayrıca konuyu açmanın üzerinden neredeyse 1 hafta geçmiş olmasına rağmen hâlen nota uzunluğu sorununun çözümünü bulamıyorum.
 

kmurat

Müdavim
Müdavim
Katılım
8 Şubat 2014
Mesajlar
8,834
Çözümler
3
Reaksiyon puanı
3,876
Puanları
1,358
VB6 bildiğim kadar bir script dili. Kaynak kodlarına erişilebilmeli.
 

KindElephant480

Asistan
Katılım
14 Eylül 2017
Mesajlar
366
Reaksiyon puanı
44
Puanları
28
VB6 bildiğim kadar bir script dili. Kaynak kodlarına erişilebilmeli.
Ancak programın kaynak kodlarına erişilemiyor çünkü yalnızca programın derlenmiş hâli bulunuyor ve geri derlediğimde bahsettiğim gibi kullandığım programa göre ya çıktılar Assembly dilinde ya da arg_A, arg_B, arg_C gibi anlaşılmaz isimler ile geliyor. Bu nedenle kendi mantığıma göre yazmak durumunda kaldım.
Mesaj otomatik birleştirildi:

Ayrıca asıl sorun programdaki notaların uzunluklarının orijinal Bleeper Music Maker programına göre uzun olması ve 1 aydır sorunu çözmek için uğraşıyorum.
 

Alois Alzheimer

Müdavim
Müdavim
Katılım
18 Ocak 2019
Mesajlar
1,708
Reaksiyon puanı
2,317
Puanları
358
Yaş
31
VB6 bildiğim kadar bir script dili. Kaynak kodlarına erişilebilmeli.
VB6 bir script dili değildir, yazılan kodlar IL'e dönüştürülür. IL'i de .NET Runtime çalıştırır.

Bahsettiğin dil VBS lakin VBS ve VB farklı şeyler. VBS'yi wscript.exe yani Windows Script Host çalıştırır.

Managed diller her ne kadar Compiled dil kabul edilse de bana göre öyle değil. Bana göre Managed dilleri "JIT" kategorisine koymamız lazım.
 
Son düzenleme:

kmurat

Müdavim
Müdavim
Katılım
8 Şubat 2014
Mesajlar
8,834
Çözümler
3
Reaksiyon puanı
3,876
Puanları
1,358
VB6 bir script dili değildir, yazılan kodlar IL'e, IL'den de makine koduna çevrilir.

Bahsettiğin dil VBS lakin VBS ve VB farklı şeyler.
Senin söz ettiğin VisualBasic.Net. Visual Basc 6'nın NET ile bir ilgisi yok. Uyumluluk ta yok. Orijinal Visual Basic oluyor. VBS ve VBA alt türevleri. Microsoft 2008'de desteğini durdurmuştu.
 

Alois Alzheimer

Müdavim
Müdavim
Katılım
18 Ocak 2019
Mesajlar
1,708
Reaksiyon puanı
2,317
Puanları
358
Yaş
31
Senin söz ettiğin VisualBasic.Net. Visual Basc 6'nın NET ile bir ilgisi yok. Uyumluluk ta yok. Orijinal Visual Basic oluyor. VBS ve VBA alt türevleri. Microsoft 2008'de desteğini durdurmuştu.
Tamamdır, bir an için karıştırmışım, affola.

Lakin BASIC kaldı mı ya? Hangi çağda yaşıyoruz?
 

KindElephant480

Asistan
Katılım
14 Eylül 2017
Mesajlar
366
Reaksiyon puanı
44
Puanları
28
Senin söz ettiğin VisualBasic.Net. Visual Basc 6'nın NET ile bir ilgisi yok. Uyumluluk ta yok. Orijinal Visual Basic oluyor. VBS ve VBA alt türevleri. Microsoft 2008'de desteğini durdurmuştu.
Ayrıca amacım C# kullanarak yıllar önce VB6 ile yazılmış bir programın geliştirilmiş bir yeniden yapımını oluşturmaktı ancak 1-2 aydır bu sinir bozucu hesaplama hatası ile uğraşıyorum.
Mesaj otomatik birleştirildi:

Tamamdır, bir an için karıştırmışım, affola.

Lakin BASIC kaldı mı ya? Hangi çağda yaşıyoruz?
Ayrıca farkındaysanız C# kullanarak VB6 ile geliştirilmiş bir programı yeniden geliştirmeye çalışıyorum.
 
Üst