Bagaimana cara mengulang bagian dari lagu dengan benar?

8

Saya memprogram Mesin Musik kecil untuk permainan saya di C # dan XNA, dan satu aspek darinya adalah kemungkinan untuk mengulang bagian dari sebuah lagu. Sebagai contoh, lagu saya memiliki intropart, dan ketika lagu mencapai akhir (atau titik spesifik lainnya), ia melompat kembali ke tempat intropart baru saja berakhir. (A - B - B - B ...)

Sekarang saya menggunakan IrrKlank, yang berfungsi dengan baik, tanpa celah, tapi saya punya masalah:

Titik untuk melompat kembali sedikit tidak akurat. Berikut beberapa contoh kode:

public bool Passed(float time)
    {
        if ( PlayPosition >= time )
            return true;
        return false;
    }
//somewhere else
if( song.Passed( 10.0f ) )
   song.JumpTo( 5.0f );

Sekarang masalahnya adalah, lagunya melewati 10 detik, tetapi mainkan beberapa milidetik hingga 10.1f atau lebih, dan kemudian lompat ke 5 detik. Ini tidak sedramatis itu, tetapi sangat salah untuk kebutuhan saya. Saya mencoba memperbaikinya seperti itu:

public bool Passed( float time )
{
      if( PlayPosition + 3 * dt >= time && PlayPosition <= time )
             return true;
      return false;
}

(dt adalah waktu delta, waktu yang berlalu sejak frame terakhir)

Tapi saya tidak berpikir, itu solusi yang bagus untuk itu.

Saya harap, Anda dapat memahami masalah saya (dan bahasa Inggris saya, yay / o /) dan membantu saya :)

Teflo
sumber
Bisakah Anda memilih antara streaming suara atau memuat semuanya sekaligus?
tesselode
Saya pikir itu mungkin. Saat ini saya sedang memuat lagu lengkap, karena saya pikir, melompat-lompat di lagu akan lebih cepat. Saya mencoba Multithreading untuk menyelesaikan masalah ini, tapi saya masih kurang beruntung: /
Teflo
Alih-alih, coba streaming suara. Lagipula, lagu itu seharusnya dapat memuat sebagian kecil lagu tersebut secara instan.
tesselode
Bagaimana lagu Anda dikodekan?
michael.bartnett
Mungkin alih-alih menggunakan "berlalu" Anda bisa menambahkan ques (seperti acara) yang melakukan fungsi panggilan balik. Saya tidak tahu bagaimana Anda mengatur waktu Anda. Tetapi tidak bisakah Anda menggunakan jumlah byte yang telah dibaca sejauh ini dan membandingkannya dengan jumlah total byte yang menerjemahkannya ke waktu yang akurat? Anda harus dapat menghitung berapa banyak data yang dibaca dalam satu detik. Saya tidak tahu seberapa cepat ini akan berjalan. Tapi mungkin Anda bisa membaca waktu dengan lebih tepat.
Sidar

Jawaban:

3

Menurut pendapat saya, solusi yang lebih sederhana dan lebih biasa adalah memiliki dua lagu yang berbeda: bagian intro dan loop. Kemudian, satu-satunya masalah adalah mendeteksi kapan intro berakhir (cukup mudah, meskipun tidak tepat jika menggunakan 30fps). Kemudian trek kedua dapat dimainkan dengan pengulangan diaktifkan.

Dengan demikian, Anda mengurangi kesalahan dalam reproduksi sedikit keterlambatan saat memulai loop untuk pertama kalinya, alih-alih setiap kali bagian loop harus mundur.

Elideb
sumber
0

Solusi yang ideal adalah mengetahui sebelumnya bagian mana dari lagu yang perlu dimuat selanjutnya ke buffer. Setiap 'bagian' A - B - C akan memiliki waktu mulai dan waktu selesai, dan itu akan menjadi sistem streaming level bawah Anda yang akan memuat bagian file yang benar dalam urutan yang benar. Anda harus memiliki bitrate tetap agar ini berfungsi, dan itu bisa sangat sulit menemukan di mana dalam file yang Anda harus lewati untuk selanjutnya.

Saya melihat sekilas situs irrKlang dan mereka membual tentang kemungkinan untuk menulis pembaca / decoder format file Anda sendiri untuk memperpanjang mesinnya, jadi Anda mungkin ingin mencobanya.

Ada juga tutorial di sini untuk mengganti akses file - Anda bisa mencoba ide asli saya, atau Anda bisa mencampurnya dengan beberapa suara seperti kata Elideb. Anda bisa memperluas kelas CMyReadFile Anda untuk memiliki akses ke banyak file (seperti PartA.wav, PartB.wav, PartC.wav), dan Anda bisa mengganti metode baca, jadi daripada hanya:

return (s32)fread(buffer, 1, sizeToRead, File);

Anda dapat melakukan sesuatu seperti:

switch(CurrentSectionToPlay)
{
case A:
    return (s32)fread(buffer, 1, sizeToRead, FileA);
case B:
    return (s32)fread(buffer, 1, sizeToRead, FileB);
}

Yang berarti lagu akan berubah mulus bagian tanpa harus menyinkronkan Drama & Berhenti.

Jonathan Connell
sumber