Vous êtes sur la bonne voie.
Reprenons votre exemple :
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(256 * Math.Sin(i));
OK, vous avez 11025 échantillons par seconde. Vous avez 60 secondes d'échantillons. Chaque échantillon est un nombre compris entre 0 et 255 qui représente un petit changement dans pression de l'air en un point de l'espace à un moment donné.
Attendez une minute, le sinus va de -1 à 1, donc les échantillons vont de -256 à +256, et c'est plus grand que la gamme d'un octet, donc quelque chose de bizarre se passe ici. Retravaillons votre code pour que l'échantillon soit dans la bonne plage.
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(128 + 127 * Math.Sin(i));
Nous avons maintenant des données à variation douce qui vont de 1 à 255, nous sommes donc dans la gamme d'un octet.
Essayez-le et voyez ce que ça donne. Il devrait être beaucoup plus "fluide".
L'oreille humaine détecte des changements incroyablement minuscules de la pression atmosphérique. Si ces changements forment un motif répétitif alors le fréquence à laquelle le motif se répète est interprétée par la cochlée de votre oreille comme un son particulier. Le site taille du changement de pression est interprété comme le volume .
Votre forme d'onde dure soixante secondes. Le changement va du plus petit changement, 1, au plus grand changement, 255. Où sont les pics ? C'est-à-dire, où l'échantillon atteint-il une valeur de 255, ou proche de celle-ci ?
Eh bien, le sinus est égal à 1 pour /2 , 5/2, 9/2, 13/2, et ainsi de suite. Donc les pics sont atteints lorsque i est proche de l'un d'entre eux. C'est-à-dire, à 2, 8, 14, 20,...
A quelle distance dans le temps sont-elles ? Chaque échantillon représente 1/11025e de seconde, donc les pics sont espacés d'environ 2/11025 = environ 570 microsecondes. Combien de pics y a-t-il par seconde ? 11025/2 = 1755 Hz. (Le Hertz est la mesure de la fréquence ; combien de pics par seconde). 1760 Hz correspond à deux octaves au-dessus du la 440, il s'agit donc d'un ton la légèrement bémolisé.
Comment fonctionnent les accords ? Sont-ils la moyenne des hauteurs ?
Non. Un accord qui est A440 et une octave au-dessus, A880 n'est pas équivalent à 660 Hz. Vous n'avez pas moyennement le site terrain . Vous somme le site forme d'onde .
Pensez à la pression de l'air. Si vous avez une source vibrante qui fait monter et descendre la pression 440 fois par seconde, et une autre qui fait monter et descendre la pression 880 fois par seconde, le résultat net n'est pas le même qu'une vibration à 660 fois par seconde. Elle est égale à la somme des pressions à un moment donné. Rappelez-vous, c'est tout ce qu'est un fichier WAV : une grande liste de changements de pression d'air .
Supposons que vous vouliez faire une octave en dessous de votre échantillon. Quelle est la fréquence ? Deux fois moins. Donc faisons en sorte que ça arrive deux fois moins souvent :
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(128 + 127 * Math.Sin(i/2.0));
Notez que la valeur doit être 2.0, et non 2. Nous ne voulons pas arrondir les nombres entiers ! Le 2.0 indique au compilateur que vous voulez le résultat en virgule flottante, pas en entier.
Si vous faites cela, vous obtiendrez des pics deux fois moins souvent : à i = 4, 16, 28... et donc la tonalité sera une octave complète plus basse. (Chaque octave vers le bas moitiés la fréquence ; chaque octave vers le haut doubles le.)
Essayez cela et voyez si vous obtenez le même son, une octave plus bas.
Maintenant, ajoutez-les ensemble.
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(128 + 127 * Math.Sin(i)) +
(byte)(128 + 127 * Math.Sin(i/2.0));
Ça a probablement sonné comme de la merde. Que s'est-il passé ? Nous avons débordé à nouveau la somme était supérieure à 256 à de nombreux endroits. Divisez par deux le volume des deux vagues :
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(128 + (63 * Math.Sin(i/2.0) + 63 * Math.Sin(i)));
Mieux. "63 sin x + 63 sin y" est compris entre -126 et +126, donc cela ne peut pas dépasser un octet.
(Alors là es une moyenne : nous prenons essentiellement la moyenne de la contribution à la pression de chaque ton et non la moyenne des fréquences .)
Si vous jouez cela, vous devriez obtenir les deux tons en même temps, l'un une octave plus haut que l'autre.
Cette dernière expression est compliquée et difficile à lire. Nous allons la décomposer en un code plus facile à lire. Mais d'abord, résumons l'histoire jusqu'à présent :
- 128 est à mi-chemin entre la basse pression (0) et la haute pression (255).
- le volume du ton est la pression maximale atteinte par l'onde
- un ton est une onde sinusoïdale d'une fréquence donnée
- la fréquence en Hz est la fréquence de l'échantillon (11025) divisée par 2
Alors, mettons tout ça ensemble :
double sampleFrequency = 11025.0;
double multiplier = 2.0 * Math.PI / sampleFrequency;
int volume = 20;
// initialize the data to "flat", no change in pressure, in the middle:
for(int i = 0; i < data.Length; i++)
data[i] = 128;
// Add on a change in pressure equal to A440:
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(data[i] + volume * Math.Sin(i * multiplier * 440.0)));
// Add on a change in pressure equal to A880:
for(int i = 0; i < data.Length; i++)
data[i] = (byte)(data[i] + volume * Math.Sin(i * multiplier * 880.0)));
Et voilà, vous pouvez maintenant générer n'importe quel son, de n'importe quelle fréquence et volume. Pour faire un accord, ajoutez-les ensemble, en veillant à ne pas aller trop fort et à ne pas dépasser l'octet.
Comment connaître la fréquence d'une note autre que A220, A440, A880, etc ? Chaque demi-ton supérieur multiplie la fréquence précédente par la 12ème racine de 2. Calculez donc la 12ème racine de 2, multipliez-la par 440, et vous obtenez A#. Multipliez A# par la 12ème racine de 2, vous obtenez B. B multiplié par la 12ème racine de 2 donne C, puis C#, et ainsi de suite. Faites-le 12 fois et, comme il s'agit de la 12ème racine de 2, vous obtiendrez 880, soit le double de ce que vous aviez au départ.
Comment la durée de lecture de chaque note est-elle spécifiée, lorsque le contenu du fichier wav est une forme d'onde ?
Il suffit de remplir l'espace de l'échantillon où le son est émis. Supposons que vous vouliez jouer A440 pendant 30 secondes, puis A880 pendant 30 secondes :
// initialize the data to "flat", no change in pressure, in the middle:
for(int i = 0; i < data.Length; i++)
data[i] = 128;
// Add on a change in pressure equal to A440 for 30 seconds:
for(int i = 0; i < data.Length / 2; i++)
data[i] = (data[i] + volume * Math.Sin(i * multiplier * 440.0)));
// Add on a change in pressure equal to A880 for the other 30 seconds:
for(int i = data.Length / 2; i < data.Length; i++)
data[i] = (byte)(data[i] + volume * Math.Sin(i * multiplier * 880.0)));
comment le résultat de la FFT inverse de plusieurs notes est-il converti en un tableau d'octets, qui constituent les données d'un fichier wav ?
La FFT inverse construit simplement les ondes sinusoïdales et les additionne, comme nous le faisons ici. C'est tout ce que c'est !
toute autre information pertinente à ce sujet ?
Voir mes articles sur le sujet.
http://blogs.msdn.com/b/ericlippert/archive/tags/music/
Les parties un à trois expliquent pourquoi les pianos ont douze notes par octave.
La quatrième partie est pertinente pour votre question ; c'est là que nous construisons un fichier WAV à partir de zéro.
Notez que dans mon exemple, j'utilise 44100 échantillons par seconde, et non 11025, et que j'utilise des échantillons 16 bits allant de -16000 à +16000 au lieu d'échantillons 8 bits allant de 0 à 255. Mais à part ces détails, c'est fondamentalement le même que le vôtre.
Je vous recommande d'opter pour un débit binaire plus élevé si vous souhaitez réaliser des formes d'onde complexes ; 8 bits à 11K échantillons par seconde ne conviendront pas pour des formes d'onde complexes. 16 bits par échantillon avec 44K échantillons par seconde est une qualité CD.
Et franchement, il est beaucoup plus facile de faire les bons calculs si vous les faites en shorts signés plutôt qu'en octets non signés.
La cinquième partie donne un exemple intéressant d'illusion auditive.
Essayez également de regarder vos formes d'onde avec la visualisation "scope" dans Windows Media Player. Cela vous donnera une bonne idée de ce qui se passe réellement.
UPDATE :
J'ai remarqué que lorsque l'on ajoute deux notes l'une à l'autre, on peut se retrouver avec un bruit sec, en raison d'une transition trop nette entre les deux formes d'onde (par exemple, la fin de l'une et le début de la suivante). Comment résoudre ce problème ?
Excellente question de suivi.
Il s'agit essentiellement d'un passage instantané de la haute pression à la basse pression, qui se traduit par un "pop". Il y a plusieurs façons de gérer ce phénomène.
Technique 1 : Déplacement de phase
Une façon de procéder serait de "déphaser" le son suivant d'une petite quantité telle que la différence entre la valeur initiale du son suivant et la valeur finale du son précédent. Vous pouvez ajouter un terme de déphasage comme ceci :
data[i] = (data[i] + volume * Math.Sin(phaseshift + i * multiplier * 440.0)));
Si le déphasage est nul, il n'y a évidemment pas de changement. Un déphasage de 2 (ou de tout multiple pair de ) n'est pas non plus un changement, puisque le sinus a une période de 2. Chaque valeur entre 0 et 2 déplace l'endroit où le son "commence" un peu plus loin sur l'onde.
Déterminer exactement quel est le bon déphasage peut être un peu délicat. Si vous lisez mes articles sur la génération d'un son d'illusion Shepard "descendant en continu", vous verrez que j'ai utilisé quelques calculs simples pour m'assurer que tout changeait en continu sans aucun pop. Vous pouvez utiliser des techniques similaires pour déterminer quel est le bon décalage pour faire disparaître le pop.
J'essaie de trouver comment générer la valeur du déphasage. Est-ce que "ArcSin(((premier échantillon de données de la nouvelle note) - (dernier échantillon de données de la note précédente))/noteVolume)" est correct ?
Eh bien, la première chose à réaliser est qu'il n'y a peut-être pas être une "bonne valeur". Si la note de fin est très forte et se termine sur un pic, et que la note de départ est très calme, il se peut que le nouveau son ne corresponde pas à la valeur de l'ancien son.
En supposant qu'il existe une solution, quelle est-elle ? Vous avez un échantillon final, appelé y, et vous voulez trouver le déphasage x tel que
y = v * sin(x + i * freq)
lorsque i est égal à zéro. Donc, c'est
x = arcsin(y / v)
Cependant c'est peut-être pas tout à fait ça ! Supposons que vous ayez
et vous voulez ajouter
Il y a deux déphasages possibles :
y
Devinez laquelle des deux sonne le mieux :-)
Il n'est pas toujours facile de savoir si l'on se trouve dans le sens ascendant ou descendant de la vague. Si vous ne voulez pas faire de véritables calculs, vous pouvez utiliser des méthodes heuristiques simples, comme "le signe de la différence entre les points de données successifs a-t-il changé à la transition ?".
Technique 2 : enveloppe ADSR
Si vous modélisez quelque chose qui est censé sonner comme un véritable instrument, vous pouvez obtenir de bons résultats en modifiant le volume comme suit.
Ce que vous voulez faire, c'est avoir quatre sections différentes pour chaque note, appelées attaque, déclin, maintien et relâchement. Le volume d'une note jouée sur un instrument peut être modélisé comme suit :
/\
/ \__________
/ \
/ \
A D S R
Le volume commence à zéro. Puis l'attaque se produit : le son monte rapidement jusqu'à son volume maximal. Puis il diminue légèrement jusqu'à son niveau de maintien. Il reste ensuite à ce niveau, en diminuant peut-être lentement pendant que la note est jouée, puis il redescend à zéro.
Si vous faites cela, il n'y a pas de pop car le début et la fin de chaque note sont à zéro volume. C'est ce que garantit le release.
Des instruments différents ont des "enveloppes" différentes. Un orgue à tuyaux, par exemple, a une attaque, un déclin et un relâchement incroyablement courts ; il n'y a que du sustain, et le sustain est infini. Votre code existant est comme un orgue à tuyaux. Comparez avec, disons, un piano. Là encore, l'attaque, la décroissance et le relâchement sont courts, mais le son devient progressivement plus faible pendant le maintien.
Les sections d'attaque, de décroissance et de relâchement peuvent être très courtes, trop courtes pour être entendues mais suffisamment longues pour éviter le pop. Essayez de modifier le volume pendant que la note est jouée et voyez ce qui se passe.
0 votes
P.S., je comprends que la réponse ne sera pas triviale, donc même un lien vers un endroit expliquant cela serait utile.
0 votes
Vous pourriez trouver quelque chose ici sonicspot.com/guide/files d'ondes.html
0 votes
Commencez par les sox. Ensuite, si vous ressentez le besoin de "rouler votre propre", vous avez une bonne base de référence connue.