GÉNÉRER UN SON À LA VOLÉE

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 23 juin 2010 à 06:08
sokoban Messages postés 32 Date d'inscription mardi 4 novembre 2003 Statut Membre Dernière intervention 4 novembre 2006 - 24 juin 2010 à 21:30
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/51940-generer-un-son-a-la-volee

sokoban Messages postés 32 Date d'inscription mardi 4 novembre 2003 Statut Membre Dernière intervention 4 novembre 2006
24 juin 2010 à 21:30
Salut à tous !

Merci pour vos commentaires. Cela est très motivant, même si je manque cruellement de temps pour prendre en compte ces remarques.

A bientôt,
Sokoban
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
24 juin 2010 à 11:35
Salut,

tout d'abords merci d'avoir réagit aussi vite et favorablement à la demande de Bacterius au sujet du Zip.
C'est vrai que c'est plus pratique ...

suggestions:

ton code ne fonctionne plus à partir de Delphi 2009 à cause de l'unicode ... la solution est toute simple il suffit de remplacer tes constantes "string" en "AnsiString" et le code fonctionnera dans toutes les versions.
const
Mono: Word = $0001;
SampleRate: Integer = 44100;
RiffId: AnsiString = 'RIFF';
WaveId: AnsiString = 'WAVE';
FmtId: AnsiString = 'fmt ';
DataId: AnsiString = 'data';

Quand on crée un composant que l'on libère dans la même procédure "MS: TMemoryStream", il est vivement conseillé d'utiliser un block "try finally end;" afin d'encadrer son utilisation mais surtout de garantir sa libération quoi qu'il arrive au cour du traitement.

et dans ton programme on pourrait même se passer de la déclaration de variable "MS: TMemoryStream":

//MS := TMemoryStream.Create;

with TMemoryStream.Create do
try
DataCount := (Duration * SampleRate) div 1000;
RiffCount := Length(WaveId) + Length(FmtId) + SizeOf(DWORD) +
SizeOf(TWaveFormatEx) + Length(DataId) + SizeOf(DWORD) + DataCount;

Write(RiffId[1], 4);
Write(RiffCount, SizeOf(DWORD));
Write(WaveId[1], Length(WaveId));
Write(FmtId[1], Length(FmtId));

TempInt := SizeOf(TWaveFormatEx);

Write(TempInt, SizeOf(DWORD));
Write(WaveFormatEx, SizeOf(TWaveFormatEx));
Write(DataId[1], Length(DataId));
Write(DataCount, SizeOf(DWORD));

for i := 0 to DataCount - 1 do
begin
t := (i * Frequency / SampleRate);

//sinusoide
if (Waveform = 1) then SoundValue := 127 + trunc(Volume * sin(2 * pi * t));
//carre
if (Waveform = 2) then SoundValue := 127 + trunc(Volume * sign(sin(2 * pi * t)));
//triangle
if (Waveform = 3) then SoundValue := 127 + trunc(Volume * (2 * abs(2 * t - 2 * floor(t) - 1 ) - 1));
//dent de scie
if (Waveform = 4) then SoundValue := 127 + trunc(Volume * (2 * (t - floor(t + 0.5))));

Write(SoundValue, SizeOf(Byte));
end;

sndPlaySound(Memory, SND_MEMORY or SND_SYNC);
finally
Free;
end;

@++
sokoban Messages postés 32 Date d'inscription mardi 4 novembre 2003 Statut Membre Dernière intervention 4 novembre 2006
23 juin 2010 à 21:59
Salut Bacterius !

Merci pour tes remarques.

Dans la partie code source, la fonction MakeSound a été améliorée. Un paramètre Waveform a été ajouté, qui permet de ne plus être dépendant des composants visuels. Par contre, pas eu le temps de mettre la fonction dans une unité à part, ni de rendre le son asynchrone. Ce sera pour plus tard !

A bientôt,
Sokoban
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
23 juin 2010 à 06:08
Salut Sokoban,
intéressant, j'ai deux-trois remarques :
- pourrais-tu poster un zip contenant la source ? Car sinon, pour compiler, nous on doit créer un nouveau projet, renommer plein de trucs et déposer les composants nous-mêmes sans même connaître le libellé des radiobutton par exemple. Sinon, ça marche bien sous Vista en tout cas !
- l'application freeze pendant le son, et c'est bien normal, pour contourner ça je te conseille d'appeller la fonction qui produit le son depuis un thread séparé du thread principal, ou alors appeller PlaySound avec le flag SND_ASYNC qui permettra à l'application de continuer à fonctionner pendant que le son tourne :)
- la prochaine étape pourrait d'être de créer une petite unité permettant d'appeller la fonction MakeSound dans n'importe-quel projet, en passant à la fonction les caractéristiques du son à émettre (si c'est une onde carrée, sinuosidale ou triangle par exemple), dans une unité "Waves.pas", qu'on aurait plus qu'à ajouter aux projets facilement !

Bonne source pour comprendre un peu mieux comment fonctionnent les flux de données, avec une application intéressante aux formes sinuosidales (format WAV).

Je ne note pas encore, j'attends d'avoir le zip pour pouvoir télécharger la source telle qu'elle doit être exécutée et pouvoir la garder dans mon dossier favoris !

Cordialement, Bacterius !
Rejoignez-nous