Comment boucler une section d'une chanson correctement?

8

Je programme un petit moteur de musique pour mon jeu en C # et XNA, et un aspect en est la possibilité de boucler une section d'une chanson. Par exemple, ma chanson a un intropart, et lorsque la chanson a atteint la fin (ou tout autre point spécifique), elle saute là où l'intropart est juste terminée. (A - B - B - B ...)

Maintenant, j'utilise IrrKlank, qui fonctionne parfaitement, sans aucune lacune, mais j'ai un problème:

Le point où revenir en arrière est un peu inexact. Voici un exemple de code:

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

Maintenant, le problème est que la chanson passe les 10 secondes, mais joue quelques millisecondes jusqu'à 10.1f environ, puis passe à 5 secondes. Ce n'est pas si dramatique, mais très incorrect pour mes besoins. J'ai essayé de le réparer comme ça:

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

(dt est le temps delta, le temps écoulé depuis la dernière image)

Mais je ne pense pas que ce soit une bonne solution pour cela.

J'espère que vous pouvez comprendre mon problème (et mon anglais, yay / o /) et m'aider :)

Teflo
la source
Pouvez-vous choisir entre diffuser le son ou le charger en une seule fois?
tesselode
Je pense que c'est possible. En ce moment, je charge la chanson complète, parce que je pensais que sauter dans la chanson serait plus rapide. J'essaie le multithreading pour résoudre ce problème, mais je n'ai toujours pas de chance: /
Teflo
Essayez de diffuser le son à la place. Après tout, il devrait être capable de charger un petit morceau de la chanson presque instantanément.
tesselode
Comment votre chanson est-elle encodée?
michael.bartnett
Peut-être qu'au lieu d'utiliser "passé", vous pourriez ajouter des ques (comme des événements) qui font une fonction de rappel. Je ne sais pas comment tu gères ton temps. Mais ne pourriez-vous pas utiliser la quantité d'octets lus jusqu'à présent et la comparer à la quantité totale d'octets et la traduire en une heure précise? Vous devriez pouvoir calculer la quantité de données lues en une seconde. Je ne sais pas à quelle vitesse cela irait cependant. Mais peut-être alors pourriez-vous lire l'heure plus précisément.
Sidar

Réponses:

3

À mon avis, une solution plus simple et plus courante consiste à avoir deux pistes différentes: une section d'intro et une section de boucle. Ensuite, le seul problème est de détecter la fin de l'intro (assez facile, mais pas parfaitement précis si vous utilisez 30 ips). Ensuite, la deuxième piste peut être lue avec le bouclage activé.

Ainsi, vous réduisez les erreurs de reproduction à un léger retard lors du premier démarrage de la boucle, au lieu de chaque fois que la section de boucle doit être rembobinée.

Elideb
la source
0

La solution idéale serait de savoir à l'avance quelles parties du morceau doivent être chargées ensuite dans le tampon. Chaque «section» A - B - C aurait une heure de début et de fin, et ce serait votre système de streaming de niveau inférieur qui chargerait les bonnes parties du fichier dans le bon ordre. Vous devrez cependant avoir un débit fixe pour que cela fonctionne, et il pourrait être assez difficile de trouver où dans le fichier vous devez passer.

J'ai jeté un coup d'œil au site irrKlang et ils se vantent de la possibilité d'écrire vos propres lecteurs / décodeurs de format de fichier pour étendre le moteur avec, donc vous voudrez peut-être essayer.

Il y a aussi un tutoriel ici pour remplacer l'accès au fichier - vous pouvez donner une idée à mon idée originale, ou vous pouvez la mélanger avec plusieurs sons comme Elideb l'a dit. Vous pouvez étendre votre classe CMyReadFile pour avoir accès à plusieurs fichiers (comme PartA.wav, PartB.wav, PartC.wav), et vous pouvez remplacer la méthode de lecture, plutôt que simplement:

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

Vous pourriez faire quelque chose comme:

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

Ce qui signifie que la chanson changerait de section de façon transparente sans avoir à synchroniser les jeux et les arrêts.

Jonathan Connell
la source