Question

Je suis en train d’écrire un synthétiseur logiciel et j’ai besoin de générer des formes d’ondes sans alias, à bande limitée, en temps réel à une fréquence d’échantillonnage de 44,1 kHz. La forme d'onde en dents de scie suffirait pour le moment, car je peux générer une onde pulsée en mélangeant deux dents de scie, l'une inversée et déphasée.

Jusqu'à présent, j'ai essayé les approches suivantes:

  1. Précalculez au premier démarrage des échantillons de forme d'onde parfaitement limités en bande à un cycle à différentes fréquences, puis reproduisez les deux échantillons les plus proches mélangés. Fonctionne bien je suppose, mais ne me sens pas très élégant. Il faut beaucoup d’échantillons ou les "lacunes". entre eux seront entendus. L’interpolation et le mixage demandent également beaucoup de ressources processeur.

  2. Intégration d'un train d'impulsions sincères compensées en courant continu pour obtenir une onde en dents de scie. Ça a l'air génial, sauf que la vague s'éloigne de zéro si vous n'obtenez pas la compensation DC exactement comme il faut (ce que j'ai trouvé très difficile). Le problème de courant continu peut être réduit en ajoutant un peu de fuite à l'intégrateur, mais vous perdez alors les basses fréquences.

Donc, ma question est la suivante: quelle est la manière habituelle de procéder? Toute solution suggérée doit être efficace en termes de CPU, car elle doit être faite en temps réel, pour plusieurs voix à la fois.

Était-ce utile?

La solution

Il existe de nombreuses façons d’approcher la génération de formes d’ondes à bande limitée. Vous finirez par échanger vos coûts de calcul contre la qualité, comme d'habitude.

Je vous suggère de consulter ce site ici:

http://www.musicdsp.org/

Découvrez les archives! C'est plein de bon matériel. Je viens de faire une recherche sur le mot clé " bandlimited " ;. Le matériel qui apparaît devrait vous occuper pendant au moins une semaine.

Btw - Je ne sais pas si c'est ce que vous cherchez, mais j’ai fait alias une génération de formes d’ondes réduite (par exemple, pas vraiment limitée au niveau de la bande) il ya quelques années. Je viens de calculer l'intégrale entre le dernier et la position actuelle de l'échantillon. Pour les formes d'onde de synthé traditionnelles, vous pouvez le faire assez facilement si vous divisez votre intervalle d'intégration aux singularités (par exemple, lorsque la dent de scie récupère sa réinitialisation). La charge du processeur était faible et la qualité acceptable pour mes besoins.

J'ai eu les mêmes problèmes de dérive, mais l'application d'un passe-haut avec une fréquence de coupure très basse sur l'intégrale a éliminé cet effet. Le vrai synthé analogique n’entre de toute façon pas dans la région subhertz, vous ne manquerez donc pas grand chose.

Autres conseils

Un moyen rapide de générer des formes d'onde à bande limitée consiste à utiliser des étapes à bande limitée (BLEP). Vous générez l’étape limitée au groupe proprement dit:

entrer la description de l'image ici

et stockez-le dans une table d'ondes, puis remplacez chaque transition par une étape limitée par une bande, afin de créer des formes d'onde ressemblant à ceci:

entrer la description de l'image ici

Voir la visite guidée à la Synthèse sonore avec bande limitée .

Etant donné que ce BLEP n’est pas causal (c’est-à-dire qu’il s'étend dans le futur), il est préférable d’utiliser l’étape limite de bande à phase minimale, appelée MinBLEP , qui a le même spectre de fréquences, mais ne s'étend que dans le passé:

  

Les minBLEP poussent l’idée plus loin et   prendre un sinc fenêtre, effectuer un   reconstruction de phase minimale puis   intégrer le résultat et le stocker dans un   table. Maintenant pour faire un oscillateur vous   il suffit d'insérer un MinBLEP à chaque   discontinuité dans la forme d'onde. Donc pour   une onde carrée vous insérez un MinBLEP   où la forme d'onde inverse, pour la scie   agiter vous insérez un MinBLEP où le   la valeur inverse, mais vous générez la   rampe comme d'habitude.

C’est ce que j’ai proposé, inspiré par les idées de Nils. En le collant ici au cas où il serait utile à quelqu'un d'autre. Je filtre simplement une onde en dents de scie de manière analytique en utilisant le changement de phase du dernier échantillon comme taille de noyau (ou seuil). Cela fonctionne assez bien, il y a un certain aliasing aux notes les plus hautes, mais pour une utilisation normale, ça sonne bien.

Pour réduire encore plus le crénelage, la taille du noyau peut être légèrement augmentée, ce qui donne 2 * phaseChange, par exemple, sonne bien aussi, même si vous perdez un peu des fréquences les plus hautes.

Voici également une autre bonne ressource DSP trouvée lors de la recherche de sujets similaires dans le SP: Le Kit de synthèse en C ++ (STK) . C'est une bibliothèque de classes qui contient de nombreux outils DSP utiles. Il est même prêt à utiliser des générateurs de signaux à bande limitée. La méthode qu'ils utilisent est d'intégrer sinc comme je l'ai décrit dans mon premier post (même si je suppose qu'ils le font mieux que moi ...).

float getSaw(float phaseChange)
{
    static float phase = 0.0f;
    phase = fmod(phase + phaseChange, 1.0f);
    return getBoxFilteredSaw(phase, phaseChange);
}

float getPulse(float phaseChange, float pulseWidth)
{
    static float phase = 0.0f;
    phase = fmod(phase + phaseChange, 1.0f);
    return getBoxFilteredSaw(phase, phaseChange) - getBoxFilteredSaw(fmod(phase + pulseWidth, 1.0f), phaseChange);
}

float getBoxFilteredSaw(float phase, float kernelSize)
{
    float a, b;

    // Check if kernel is longer that one cycle
    if (kernelSize >= 1.0f) {
        return 0.0f;
    }

    // Remap phase and kernelSize from [0.0, 1.0] to [-1.0, 1.0]
    kernelSize *= 2.0f;
    phase = phase * 2.0f - 1.0f;

    if (phase + kernelSize > 1.0f)
    {
        // Kernel wraps around edge of [-1.0, 1.0]
        a = phase;
        b = phase + kernelSize - 2.0f;
    }
    else
    {
        // Kernel fits nicely in [-1.0, 1.0]
        a = phase;
        b = phase + kernelSize;
    }

    // Integrate and divide with kernelSize
    return (b * b - a * a) / (2.0f * kernelSize);
}

Le décalage CC d'un bloc - peut être réduit avec un simple filtre passe-haut! - un peu comme un vrai circuit analogique où ils utilisent un capuchon de blocage CC!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top