Forum Liberty Basic France

Général » Générateur BF Ou qui tente de l'être
Le 22/12/2015 à 16h22

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Reprise du message précédent

Je dis que c'est une entourloupe par rapport au fonctionnement d'un oscillo
Si par exemple tu mets 1 s par div, je doute que tu vois le balayage sans signal.
Citation:
convertir en audio ce qui était affiché à l'écran,

Lol ! Ah oui, c'était mal barré. il ne faut travailler que sur le code de notre ami l'inconnu.

Sur qu'un signal numérisé, c'est que des rondelles; si fines soient-elles; mais bon, une droite c'est aussi que des points; vaste débat
La visu n'est qu'une visu et n'a rien à voir avec l'usine à gaz de l"inconnu"
On va peut-être laisser aussi de côté la visu par échantillonnage, hein.

Le tout est de comprendre comment l"inconnu" a additionnées (en fait mixées) ses fréquences, il """"suffira"""" de piloter les paramètres par le réglage des fréquence actuel (en parallèle ou séparément, la visu ne sera qu'une "relation" de ce qu'a pondu l'usine à gaz)
Le déphasage à la visu pour le fun (une seule puisque c'est relatif)

Le gros morceau, c'est l'usine à gaz, et là, comme visu, y a que la mainwin ; d'ici qu'il faille faire un programme pour décortiquer la flopée de données qu'elle sort, y a pas loin
____________________
Roro

   
Le 22/12/2015 à 23h53

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Roland, tu planes...

Par "convertir en audio ce qui était affiché à l'écran", je pensais "utiliser les données du tableau traçant la courbe de la somme pour en faire un wav". Mais comme on l'a vu, une mauvais choix de la fréquence d'échantillonnage (donc du nombre de millisecondes par pixel horizontal) entraîne de sévères aberrations.

La solution est effectivement d'abandonner la visu par échantillonnage. En travaillant directement à une fréquence d'échantillonnage classique pour un wav, on ne devrait plus avoir de surprises dans le domaine audio, et si on le désire, on en déduit un graphe du signal obtenu. Il va y avoir une refonte en profondeur du programme

Pour le déphasage, on peut avoir deux fréquences identiques, mais qui ne "démarrent" pas en même temps, et voir l'effet de ce déphasage sur la somme. Le déphasage est obtenu par décalage volontaire de l'index d'un des tableaux

Point d'"usine-à-gaz", notre illustre inconnu s'est simplement contenté d'additionner les courbes, comme nous :
Code VB :
 
sample=amp/4*sin(omega1*t)+amp/4*sin(omega2*t)+amp/3*sin(omega3*t) 
 


Voilivoilà
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 23/12/2015 à 10h47

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Pour planer, c'est sûr que je plane
Pour te dire, j'ai virée toute la trainée de décimales de delta; avec: 0.00009 et basta ça a l'air de marcher aussi bien
C'est pas orthodoxe ?
Ce que j'ai du mal à piger, c'est pourquoi ce bazar d'origine est en deux parties avec un beau "else" au milieu
(entre autres, parce que je n'ai pas encore mis le nez dans les fonctions de la mort).
Code VB :
 
    for t = 0 to 2 step delta
        if (t>.125  and t<.750) then
            sample=amp/4*sin(omega1*t)+amp/4*sin(omega2*t)+amp/4*sin(omega3*t)+amp/4*sin(omega4*t+t)  'all
        else
            sample=amp/4*sin(omega1*t)+amp/4*sin(omega2*t)+amp/4*sin(omega3*t)  '1, 2 and 3
        end if
        x=DisplayWidth*t
        y=sample*offset
        print sample, y+offset
        data$=data$;chr$(int(y+offset))
        #g "goto ";x;" ";y+offset
    next t
 
____________________
Roro

   
Le 23/12/2015 à 15h25

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
En passant delta à 0.00009, la fréquence d'échantillonnage est passée de 11025 à 11111 Hz. Par contre dans l'en-tête du fichier wav, la fréquence d'échantillonnage est toujours 11025, donc ton fichier est lu plus lentement dans le player (à vue de nez, 0.75 %).

voici les instructions qui formatent la fréquence d'échantillonnage en vue de son intégration dans l'en-tête du wav
Code VB :
 
    SampleRate$=makeAsciiNumber$(11025,4)
    ByteRate$=makeAsciiNumber$(11025,4)
 


la fonction makeAsciiNumber$ renvoie dans le bon ordre l'équivalent de 11025 codé sur 4 caractères, tel qu'attendu pour un fichier wav.

Il me faut encore travailler cette section, c'est là que je la trouve "usine à gaz"

Citation:

Ce que j'ai du mal à piger, c'est pourquoi ce bazar d'origine est en deux parties avec un beau "else" au milieu

La boucle que tu cites dure deux secondes au pas de "delta", qui est la durée entre deux échantillons successifs
lorsque t > 0.125s et t< 0.750s il y a 4 fréquences jouées simultanément, sinon il n'y en a que 3.

Sans être hors sujet puisqu'on parle sinusoides, un détail que je viens de remarquer sur la 4ème fréquence :
sample=amp/4*sin(omega1*t)+amp/4*sin(omega2*t)+amp/4*sin(omega3*t)+amp/4*sin(omega4*t+t)

quel besoin a-t-il eu d'aller ajouter un "t" dans sin(omega4*t+t) ?

omega4 vaut 2*pi*freq4
dans son prog, freq1 = 261, et freq4 = freq1*1.68179 donc freq4 = 438,9759

donc omega4 = 2*3.14*439 = 2757
si on fait omega4*t avec t variant de 0 à 2, on obtiendra 0 < omega4*t < 5514

quelle est donc l'influence d'un "t" variant de 0 à 2 sur une variable qui va simultanément de 0 à 5514 ?


de même, pourquoi amp/4*sin(omega*t) ? (amp/4)*sin(omega*t) m'aurait semblé plus naturel : amp/4 est le volume, sin(omega*t) la sinusoïde.

c'est un truc bricolé à la va-vite, un test de faisabilité ou un petit défi entre gens de forums. Le prog semble fonctionner, alors il ne s'est pas penché sur d'éventuelles erreurs.
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 23/12/2015 à 16h26

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Citation:
pourquoi amp/4*sin(omega*t) ? (amp/4)*sin(omega*t)

Produit et quotient sont commutatifs => les parenthèses sont supperflues

Pour la boucle, ce que je comprends:
Entre 0 et .125 C'est le else qui est exécuté
Entre .125 et .750; c'est le if
Et entre .750 et 2; c'est à nouveau le else
J'ai bon, là ?
Je te dis pas les essais de ouf que je fais
Le "+t" pourrait bien être aussi un essai de ouf du concepteur (que je continue de chercher chez les english speakers)
____________________
Roro

   
Le 24/12/2015 à 14h00

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
ok pour le produit et le quotient. J'avais juste peur que jb considère 4*sin(omega*t) comme le dénominateur. Il fait bien la division amp/4, et seulement après la multiplication par sin(omega*t)

Doit normalement donner 0 :
Code VB :
 
t=2:omega=3000:amp=0.75
print amp/4*sin(omega*t) - (amp/4)*sin(omega*t)
 


(il y a longtemps que je n'avais pas entendu parler de commutativité)

Citation:
J'ai bon, là ?

C'est comme ça que je l'entends. De là à dire que j'ai bon, c'est une autre histoire, mais je pense que oui quand même.

Bonnes Fêtes
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 03/01/2016 à 22h44

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
On a repris le taf.

C'est une histoire de périodes, inverses de la fréquences, et dont le produit donne une nouvelle période parfaitement prévisible, qu'on numérisera.

Comme toujours il y a un truc qui me chiffonne, mais je verrais plus tard.

Vous pouvez dire aussi que je me torture l'esprit pour pas grand chose, ou que je suis complètement à côté de la plaque^^

on aboutit au prog ci-dessous, lequel calcule aussi le nombre d'échantillons qui dimensionnera le tableau recevant la nouvelle forme d'onde, et le remplit avec la somme des signaux des générateurs.

(de petites valeurs comme 1 ou 2 Hz donnent, avec une fréquence d'échantillonnage de 44100 Hz, une période résultante de... 117 000 secondes, hormis grosse erreur de raisonnement de ma part, le générateur aura une limite basse, ou on abaissera la fréquence d'échantillonnage dans ces cas-là)

Code VB :
 
 
 
'fréquences générateurs et échantillonnage, en Herz
    F1=440
    F2=800
    Fech=22050
    print F1;" ";F2;" ";Fech
 
'périodes correspondantes
    T1=1/F1
    T2=1/F2
    Tech=1/Fech
    print T1;" ";T2;" ";Tech
 
'période la plus petite devient comprise entre 1 et 9, et on garde la proportion avec
'   les autres périodes
'   (parce que 10*5=50 ms alors que 0,01*0,005=0,00005s, et on en arrive à 50 ms=50µs, alors que c'est
'   strictement la même chose
'   il y a donc un truc que je sais pas faire, c'est pour ça que je passe par cette étape)

    'Tmini prendra la plus faible valeur des trois périodes
    Tmini=10
    if T1<Tmini then Tmini=T1
    if T2<Tmini then Tmini=T2
    if Tech<Tmini then Tmini=Tech
    print "Tmin=";Tmin;" secondes"
 
    'on calcule la puissance de 10 nécessaire pour avoir la plus faible valeur >1
    while Tmini<1
        Tmini=Tmini*10
        exposant=exposant+1
    wend
    print "exposant : ";exposant
 
    'qu'on applique à toutes les périodes
    T1=T1*10^exposant
    T2=T2*10^exposant
    Tech=Tech*10^exposant
 
    'au final, on fait notre produit de périodes, et on les remet dans le système d'unité initial
    Tmult=T1*T2*Tech*10^(0-exposant)
 
    print "Période mini = ";Tmult;" secondes"
    'Tmult est la période minimale permettant de retrouver touts les résultats des sommes

    pi=3.14159265
 
    deltaT=1/Fech           'écart entre deux échantillons, secondes
    NbEch=int(Tmult/deltaT) 'nombre d'échantillons dans la période minimale
    print "nombre d'échantillons :";NbEch
    Ech=0   'échantillon courant
    dim sortie(NbEch)
 
    omega1=2*pi*F1
    omega2=2*pi*F2
 
    print "calcul en cours"
    for a=0 to Tmult step deltaT
 
        echF1=sin(omega1*a)
        echF2=sin(omega2*a)
        sortie(Ech)=echF1+echF2
        Ech=Ech+1
 
    next
    print "fin des calculs"
 
 
 
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 04/01/2016 à 00h39

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Moi, ce que je ne capte pas, c'est où (dans le code) se fait le découpage
Pour la fréquence d'échantillonnage, en prenant trois fréquences à la louche pour trois bandes de fréquences (et donc de périodes) à découper, il me semble que ça devrait passer sans trop se prendre la tête
Parce qu'il me semble aussi qu'avec le 44100 tout passe sans se soucier du rapport période/freqech (sous réserve des limitations de JB)
Je me suis amusé à faire un essai (empirique), et bizarrement il me joue 11 fois la séquence
J'ai tout mis en tableaux
Code VB :
 
    dim freq(15): freq$="262 262 262 294 330 294 262 330 294 294 262"
    dim dur(15):  dur$="0.5 0.5 0.5 1 1 1 0.5 0.5 0.5 0.5 1"
    dim omega(15)
    for a=1 to 11
       dur(a)= val(word$(dur$,a))
       freq(a)= val(word$(freq$,a))
       omega(a)=2*pi*freq(a)
    next a
 

Et j'ai fait la boucle qui devrait générer les 11 notes avec leurs temps respectifs (et pas plus)
Sans me soucier de ton histoire d'échantillonnage (Lol !)
Code VB :
 
  for a=1 to 11
    dur=dur(a): omega=omega(a) ' Dans le doute qu'il ne veuille pas du tableau dans la "for t"; 
                                                              ' c'est con, mais le doute, c'est le doute
    for t = 0 to dur step delta
            sample=amp/4*sin(omega*t)
        x=DisplayWidth*t
        y=sample*offset
        print sample, y+offset
        data1$=data1$;chr$(int(y+offset))
        #g "goto ";x;" ";y+offset ' Là, je n'ai pas effacé donc ça sur-impressionne; normal
    next t
    data$=data$+data1$
  next a
 

[
____________________
Roro

   
Le 04/01/2016 à 21h25

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Hello Roland,

Je suppose que tu as modifié le programme du notre inconnu.

Citation:
Moi, ce que je ne capte pas, c'est où (dans le code) se fait le découpage


Normalement, dans ta boucle "for t=0 to dur step delta", tous les "delta" seconde, on calcule un échantillon, une tranche du signal. Ou si tu parlais de mon code dans le post au dessus, dans la boucle "for a=0 to Tmult step deltaT"

Citation:
Parce qu'il me semble aussi qu'avec le 44100 tout passe sans se soucier du rapport période/freqech (sous réserve des limitations de JB)


En effet, pour une fréquence d'une centaine de Hz, il ne devrait pas y avoir énormément de différence entre deux échantillons successifs, ça devient moins vrai quand on monte en fréquence : à 22 kHz il n'y aurait plus que deux échantillons pour caractériser la sinusoïde. C'est là que je vois que j'ai encore des choses à apprendre, puisqu'un théorème célèbre dit qu'il n'y a pas de perte d'information si la fréquence de numérisation est le double de la fréquence à numériser. Il va falloir que je me cultivationne, pas moyen d'y échapper... jusqu'à présent j'ai fait "à l'estime".

Citation:
Je me suis amusé à faire un essai (empirique), et bizarrement il me joue 11 fois la séquence


La boucle serait-elle imbriquée dans une autre boucle "for a=1 to 11" oubliée suite à un essai?

A+, il est tard :)
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 04/01/2016 à 22h48

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Citation:
, tous les "delta" seconde, on calcule un échantillon,

Ah ben ouais, ça crevait les yeux.

Et non pas de double boucle, mais j'ai lu la wav dans un séquenceur, et c'est encore plus bizarre que le lecteur Windows;
Possible que JB n'aime pas trop les tranches fines, parce que là, on est quand même à 10^-5
ça doit faire comme avec le jambon, quand les tranches sont trop fines y a des problèmes
____________________
Roro

   
Le 12/01/2016 à 14h32

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Il devrait pourtant savoir gérer les fines tranches. Je vais voir si on peut trouver un "le fichier WAV pour les nuls" ;) parce que moi aussi je ne suis pas très satisfait des résultats. En cause, peut-être l'instruction INT qui tronque à la partie entière alors qu'il faudrait arrondir à l'entier le plus proche...

Au fait, 256 niveaux suffisent à coder de l'audio de qualité alors qu'on voit tout de suite une photo affichée en 256 couleurs, notre ouïe serait donc si loin d'être à la hauteur de notre vue ???

Autrement, des nouvelles du front :

J'ai renoncé à :
  • une présentation façon "appareil de labo", pour revenir à une interface classiquement informatique.
  • calculer une période multiple qu'on numériserait une fois et qu'on reproduirait autant de fois que nécessaire : trop de limitations dans ce que je sais faire (nombre de générateurs, fréquences avec décimales ou proches, etc...)
  • la fenêtre de visualisation : les données audio sont directement intégrées dans la chaîne de caractères qui sera transférée dans le fichier final, il n'y a donc plus de tableau, si commode pour dessiner des courbes. On peut peut-être le faire à partir d'une chaine en extrayant caractère par caractère (Pas prévu pour le moment).


Dans l'actuel code Il n'y a aucune création ou lecture de fichier.

L'estimation du temps de codage qui s'affiche est monumentalement buggée, j'ai dû rater quelque chose, car le temps de codage effectif est nettement plus long que le temps estimé, et il faudra y ajouter le temps de transfert dans le fichier wav final. Je suppose que la chaîne de caractère utilisée devient énorme, et que le temps d'ajout d'un caractère le devient en conséquence, alors que le test de rapidité est fait sur une chaine courte... ça pourrait être une explication, qui me ferait revenir au tableau.

Pourquoi estimer un temps de codage ? parce qu'il est pertinent de savoir si on a le temps de se préparer un café quand on a appuyé sur "générer" ^^

Je suis toujours à la recherche de la fonction qui détecterait l'entrée de données dans une textbox sans qu'on ait à cliquer sur un bouton...

Voici l'intermédiaire code, pour les ceusses que ça intéresse :
Code VB :
 
'GénéBF 2 fréquences,
'pas opérationnel, seuls les calculs fonctionnent, pas la création du fichier
'il n'y a pas non plus de controle des données entrées
'on ne sait pas ce que donnera une entrée hors-normes

    nomainwin
 
    NomWav$="pardefaut.wav"
    CheminWav$=DefaultDir$
 
    'estimation des temps et poids du fichier généré
    tpsEstime$="<inconnue>"  'temps estimé de génération de fichier wav
    tailEstime$="<inconnue>"'taille estimée du fichier wav apres génération

    'dimensions de la fenêtre
    WindowWidth = 415
    WindowHeight = 475
 
    'formats d'affichage
    fonteGlobale$="font ms_sans_serif 0 16"
    fonteTitre$="!font ms_sans_serif 0 16 bold"
 
    'valeurs par défaut
    pi=3.1415926536
    freq1=880
    vol1=70
    freq2=440
    vol2=70
    volSortie=100
    duree=3
    indexFech=1
    FreqEch$(1)="11025"
    FreqEch$(2)="22050"
    FreqEch$(3)="44100"
 
    'création de l'interface utilisateur
    statictext #1.titreGen, "Générateurs :", 15, 15, 100, 20
 
    statictext #1.frequences, "Fréquence, Hz", 85, 40, 100, 20
    statictext #1.volumes, "Volume, 0 à 100", 195, 40, 100, 20
 
    statictext #1.gen1, "Gen. 1", 30, 65, 40, 20
    textbox #1.freq1, 80, 60, 100, 25
    textbox #1.vol1, 190, 60, 100, 25
 
    statictext #1.gen2, "Gen. 2", 30, 95, 40, 20
    textbox #1.freq2, 80, 90, 100, 25
    textbox #1.vol2, 190, 90, 100, 25
 
    statictext #1.sortie, "Fichier de sortie :", 15, 140, 125, 20
    statictext #1.nomWav, NomWav$, 140, 140, 390, 20
    button #1.changeDest, "Emplacement et nom du fichier", [changeDestination], UL, 30, 165, 350, 25
    statictext #1.cheminWav, CheminWav$, 30, 195, 300, 40
 
    statictext #1.param, "Paramètres du fichier Wave :", 15, 245, 200, 20
    statictext #1.fech, "Fréqu. éch., kHz", 30, 270, 110, 20
    statictext #1.volWav, "Volume, 0 à 100", 150, 270, 110, 20
    statictext #1.dureeWav, "Durée, s", 270, 270, 110, 20
 
 
 
    combobox #1.comboEch, FreqEch$(), [frequences_ech], 30, 290, 110, 100
    textbox #1.bxVolWav, 150, 290, 110, 25
    textbox #1.bxDureeWav, 270, 290, 110, 25
 
    statictext #1.estimDuree, "Durée de calcul estimée : "+tpsEstime$, 30, 325, 400, 20
    statictext #1.estimTaille, "Taille estimée : "+tailEstime$, 30, 345, 400, 20
 
    statictext #1.avanti, "En avant !", 15, 375, 270, 20
    button #1.genWav, "Générer", [transfere_wav], UL, 30, 400, 80, 25
    button #1.annulCalc, "Annuler", [annule_calcul], UL, 120, 400, 80, 25
    button #1.quit, "Quitter", [quitter], UL, 300, 400, 80, 25
 
    'ouverture fenêtre d'interface utilisateur
    open "Géné. BF" for window as #1
 
        'fonte global
        print #1, fonteGlobale$
 
        'fonte titres
        print #1.titreGen, fonteTitre$
        print #1.sortie, fonteTitre$
        print #1.param, fonteTitre$
        print #1.avanti, fonteTitre$
        print #1.titreGen, fonteTitre$
 
        'données pré-réglées
        print #1.freq1, freq1
        print #1.vol1, vol1
        print #1.freq2, freq2
        print #1.vol2, vol2
        print #1.comboEch,"selectindex ";indexFech
        print #1.bxVolWav, volSortie
        print #1.bxDureeWav, duree
 
        'estimations durée et poids du fichier wav
        fEchant=val(FreqEch$(indexFech))    'récupère la fréquence d'échantillonnage
        echantillons=1000   'nbre d'échantillons dont on va simuler la création
        gosub [estimations]
 
        print #1.freq1, "!setfocus"
        print #1, "trapclose [quitter]"
 
    wait
 
end
'***************sous-programmes********************

[quitter]
    'quitte le programme
    close #1
    end
 
[annule_calcul]
    'pas encore créé

    'on annule la création en cours (temps trop long, ou erreur de saisie
    'et vouloir relancer avant la fin réelle du traitement, ...)
    wait
 
[changeDestination]
    filedialog "Save to, entrer un nom pour le fichier :","*.wav",chemin$
    if chemin$<>"" then
        numCar=0
        antislash=0
 
        while antislash=0
            a$=mid$(chemin$,len(chemin$)-numCar,1)
            if a$="\" or numCar>len(chemin$) then antislash=1
            numCar=numCar+1
        wend
 
        NomWav$=right$(chemin$,numCar-1)
        CheminWav$=left$(chemin$,len(chemin$)-numCar+1)
 
        print #1.cheminWav, CheminWav$
        print #1.nomWav, NomWav$
    end if
    wait
 
 
[estimations]
    'calcul "à blanc" pour approcher la durée nécessaire aux calculs des données audio
    'et la taille du fichier wav résultant

    'lancé à la première exécution, et à chaque changement des valeurs
    '   fréquence d'échantillonnage et durée
    '(question toujours d'actualité : comment dire au programme de prendre la valeur
    'qui vient d'être entrée dans la textbox "durée" sans aller cliquer sur un bouton ?)

    '(reste à faire) ouverture fichier test

    'début du test de durée
    topdebut=time$("ms")
 
    gosub [genere_wav]
 
    'fin du test de durée
    topfin=time$("ms")
 
    '(reste à faire) fermeture et effacement fichier test

    'temps par échantillon
    tpsEch=(topfin-topdebut)/echantillons
 
    'nombre d'échantillons à calculer : freq échantillonnage*durée
    nbEchantFinal=fEchant*duree
 
    'durée finale estimée
    tpsSec=int((nbEchantFinal*tpsEch)/1000) '(parce que tpsEch est exprimé en millisecondes)
    if tpsSec=0 then
        tpsEstime$="moins d'une seconde"
    else
        hrs=int(tpsSec/3600):tpsSec=tpsSec-hrs*3600
        min=int(tpsSec/60):tpsSec=tpsSec-min*60
        sec=tpsSec
        tpsEstime$=str$(hrs)+"h "+str$(min)+"min"+str$(sec)+"s"
    end if
 
    print #1.estimDuree, "Durée de calcul estimée : "+tpsEstime$
 
    'taille du fichier
    taille$=str$(nbEchantFinal*8)
    tailEstime$=""
 
    compteur=0
    for a=len(taille$) to 1 step -1
        compteur=compteur+1
        b$=mid$(taille$,a,1)
        if int(compteur/3)=compteur/3 and compteur>1 then b$=" "+b$
        tailEstime$=b$+tailEstime$
    next
 
    tailEstime$=tailEstime$+" octets"
    print #1.estimTaille, "Taille estimée : "+tailEstime$
 
    return
 
[frequences_ech]
 
    'lecture valeur combobox
    print #1.comboEch,"selectionindex? indexFech"
    fEchant=val(FreqEch$(indexFech))
 
    'lecture durée
    #1.bxDureeWav, "!contents? duree$"
    duree=val(duree$)
 
    gosub [estimations]
    wait
 
 
[duree_wav]
    'dès que je saurais détecter l'appui sur la touche "enter" pour prendre
    'en compte la durée que je viens d'entrer dans la textbox

    'ce sous-programme sera très similaire à [frequences_ech]
    'en fait on lance l'estimation à chaque fois que la fréquence d'échantillonnage
    'OU la durée souhaitée du fichier wav, est modifiée
    wait
 
 
[genere_wav]
    'récupération fréquences et volumes des générateurs
    print #1.freq1, "!contents? a$":freq1=val(a$)
    print #1.vol1, "!contents? a$":vol1=val(a$)
    print #1.freq2, "!contents? a$":freq2=val(a$)
    print #1.vol2, "!contents? a$":vol2=val(a$)
 
    'calcul pulsations
    omega1=2*pi*freq1
    omega2=2*pi*freq2
 
    'récupération volume final
    print #1.bxVolWav, "!contents? a$":volSortie=val(a$)
 
 
    amplitudeMax=2*vol1+2*vol2
    deltaT=1/fEchant
    chaine$=""
    t=0
    for a=1 to echantillons
        'il faut ramener un signal d'amplitude -n*100 à +n*100,
        'n=nombre de générateurs, 100=maxi de la valeur sin*volume, sin allant de 0 à 1
        'à un signal d'amplitude 0 à 255, pour pouvoir coder chaque valeur sur un octet
        somme=127+(vol1*sin(omega1*t)+vol2*sin(omega2*t))*(256/amplitudeMax)*(volSortie/100)
        'print somme
        t=t+deltaT
        chaine$=chaine$+chr$(int(somme))
        'le recours à INT n'est pas génial : int(9.9)=9 alors que le plus proche entier est 10

    next
 
    '(reste à faire)
    'transfert de la chaîne dans le fichier actif
    'en fait il peut y en avoir deux : le fichier test, ou le fichier final
    return
 
 
[transfere_wav]
 
    echantillons=fEchant*duree
    '(reste à faire) ouvrir le fichier NomWav$ dans le dossier CheminWav$ 
    gosub [genere_wav]
    '(reste à faire) fermer le fichier NomWav$ dans le dossier CheminWav$
    'play CheminWav$\NomWav
    wait
 
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 12/01/2016 à 16h14

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Oh ! L'arnaque ! Il y a beaucoup de "reste à faire".
Et oui, c'est bien la création de la chaîne qui pose soucis, je m'en suis bien rendu compte en voulant faire une séquence, sans parler des silences que j'ai tenté d'intégrer et qui ont donnés des gros "clacs"
Pour le temps, une simple règle de trois en fonction de la longueur de la chaîne devrait faire l'affaire
____________________
Roro

   
Le 12/01/2016 à 19h17

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Oh, arnaque, arnaque, hein, faut relativiser. C'est normal qu'il en manque la moitié, c'est in-for-ma-tique. A-t-on déjà vu un jeu vidéo qui affiche les parties cachées d'une scène ? une carte son qui reproduit le signal entre deux échantillons au lieu de le déduire ? On nous vend du vent, ça fait quarante ans que ça dure et tout le monde trouve ça normal, quelle époque !

Nan mais allo, quoi ! (c) ;)

Si tu as fait l'essai avec la chaîne générée par mon prog, c'est que je suis pas trop loin de la vérité. Pour le cloc, le zéro n'est pas à la bonne place, ou la transition est trop brutale, avec passage direct d'un volume à 70 ou 80 % à zéro en moins d'une période qu'il n'en faut pour le dire. Je présume.

Les choses sérieuses commencent : I am reading this, avec les liens associés.

C'était trop compliqué de commencer par là... Au moins j'aurais appris justbasic.
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 12/01/2016 à 21h13

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Ouais, ton lien, j'y été allé, y a que des généralités.
Pour le temps, on ne peut que le déduire des paramètres de génération (durée, échantillonnage)
J'ai fait un truc avec la longueur de la chaîne pour m'apercevoir que pour en connaître la longueur de la chaîne, et ben il fallait d'abord la créer, et que c'est justement ça qui prends du temps; et donc, on a le résultat quand on n'en a plus besoin.
Mais on l'a... ça commence à 11 000 caractères pour 1 s à bas prix.
____________________
Roro

   
Le 13/01/2016 à 10h37

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Petite précision relative à une incrédule constatation sur la qualité audio, en attendant de reprendre le fil de la discussion :

Christophe:
Au fait, 256 niveaux suffisent à coder de l'audio de qualité alors qu'on voit tout de suite une photo affichée en 256 couleurs, notre ouïe serait donc si loin d'être à la hauteur de notre vue ???


Bah non, 8bits + int() ça donne un truc pas terrible. La qualité CD c'est du 16 bits, soit 65536 niveaux, pas du 8bits, allons, à quoi pensais-je ?! ,

Donc chaque échantillon sera codé sur 2 octets, il suffira de multiplier par 2 la durée estimée

Apluche, je retourne au marché, le cours du caractère s'effondre^^
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 19/02/2016 à 20h43

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Bon, c'est pas encore le générateur, mais j'ai drastiquement revu à la baisse mes prétentions car je ne m'en sortais pas.

Il n'y a donc plus qu'une seule liste de paramètres, in English, il n'y a plus de page de paramétrage et l'interface est bien grisounette, mais c'est juste un outil pour se faire une petite collection d'en-têtes de fichiers wave classiques, toujours bonne à avoir sous la main à des fins de comparaison avec les wav fournis par le générateur.

Le bouton "archiver l'en-tête" stocke les données affichées dans le fichier "entetes_wave.txt" dans le dossier par défaut, donc celui qui contient le programme.

Si les textes dépassent le cadre de la fenêtre, c'est parce que j'utilise Wine sous Linux car je ne peux plus voir le rendu sous un vrai windows. Au cas où, Une petite capture d'écran serait sympa

Je peux reprendre le générateur^^

(dans ce post, un "end" se trouve en bas de la fenêtre de code. Ce n'est pas la vraie fin. Si on exécute le programme visible seulement dans la fenêtre, on ne pourra plus l'arrêter autrement qu'avec un ctrl-alt-suppr)

(edit 05 mars : remplacé la ligne print #principale.affichage, "!font courier 0 16" par print #principale.affichage, "!font courier 0 12", les données de l'en-tête apparaissent maintenant en entier)

Code VB :
 
'lecture et affichage de l'en-tête d'un fichier wave
'affichage dans un statictext

 
nomainwin
'
'chemins
'   fichier wav à ouvrir
    cheminWav$=DefaultDir$
 
'   fichier txt à générer et à mettre à jour (contiendra les en-tetes des fichiers wav)
    cheminArchive$=DefaultDir$
    nomArchive$="entetes_wave.txt"
 
'fenêtre principale
    'dimensions de la fenêtre
    WindowWidth = 700
    WindowHeight = 370
 
    'équipement de la fenêtre en boutons et contrôles
    button #principale.fichier,"Ouvrir un fichier",[ChoixFichierAOuvrir], UL, 15,10,150,25
    button #principale.archiver,"Archiver l'en-tête",[Archiver], UL, 185,10,150,25
    button #principale.quitter,"Quitter",[quitter], UL, 525,10,150,25
    statictext #principale.affichage, "",15, 70, 650, 300
 
 
    'ouverture
    open "Lecture de l'en-tête de fichiers wav" for window as #principale
 
    print #principale.affichage, "!font courier 0 12"
    print #principale, "trapclose [quitter]"
    wait
 
'assure-vous de tout copier ! si vous ne copiez que jusqu'ici vous ne pourrez pas
'quitter le programme sans un ctrl-alt-suppr

 
 
 
 
 
end
 
'**************** zone des sous-programmes ******************

[AnalyseFichier]
    gosub [ListeDesChamps]
 
    'lecture du fichier et copie de l'en-tête dans la chaine entete$
    open fichier$ for input as #lecture
 
    'si le fichier est plus petit que la dimension attendue de l'en-tête
    '***    hem, pas testé !!!   ****
    if lof(#lecture)<nbOcts then
        print "le fichier est trop court ou si c'est un wav, y'a un problème"
        print "il sera lu malgré tout"
        nbOcts=lof(#lecture)
    end if
 
    entete$=input$(#lecture,nbOcts)
 
    'fermeture du fichier, on va dorénavant travailler sur la chaine entete$
    close #lecture
 
    'lecture de l'en-tête
    Donnee$=""
    numdonnee=0
    debut=1
 
    'pour chacun des paramètres listés dans [datas]
    for tour = 1 to nldat 'nldat=Nombre de Lignes de DATas, voir [ListeDesChamps])

        chaine$=mid$(entete$,debut,longueur(numdonnee))
        fin=debut+longueur(numdonnee)-1
 
        'position de la donnée dans le fichier : octet de début, octet de fin
        Donnee$ = "Octets " + right$("  "+str$(debut),2) + " à " + right$("  "+str$(fin),2)+" : "
 
        'nom de la donnée
        Donnee$ = Donnee$ + left$(descript$(numdonnee) + space$(30),30)+" : "
 
        'extraction des octets
        nombre=0    'future donnée
        exposant=0  'pour conversion octet->décimal
        octets$=""  'pour présentation du résultat
        nombre$=""
        chaine$=""
 
        'calcul des nombres en little endianess
        for a=debut to fin
            b=asc(mid$(entete$,a,1))
            nombre = nombre + b*256^exposant
            exposant = exposant+1
            octets$ = octets$ + right$("   "+str$(b),3)+" "
            chaine$ = chaine$ + chr$(b)
        next
 
        'la donnée est-elle nombre ou texte
        Donnee$ = Donnee$ + left$(octets$ + space$(16),16)+" : "
        if type(numdonnee)=0 then Donnee$ = Donnee$ + str$(nombre)
        if type(numdonnee)=1 then Donnee$ = Donnee$ + chaine$
 
        'préparation du tour suivant
        debut=debut+longueur(numdonnee)
        numdonnee=numdonnee+1
 
        'ligne vide pour séparer la déclaration du fichier wav de son organisation
        if tour = 4 then
            afficheDonnee$ = afficheDonnee$ + chr$(10) + chr$(10) + Donnee$
        else
            afficheDonnee$ = afficheDonnee$ + chr$(10) + Donnee$
        end if
 
    next
 
    'on a fait le tour des données de l'en-tête, on l'affiche
    afficheDonnee$ = afficheDonnee$ + chr$(10)
    print #principale.affichage, afficheDonnee$
    return
 
 
[Archiver]
    'stocke l'en-tête dans un fichier texte, tel qu'il est affiché dans la fenêtre
    'y ajoute un horodatage
    'stocke l'en-tête au dessus des en-tetes déjà enregistrés

    'créer l'horodatage :
    horodatage$="Le "+Date$()+" à "+Time$()+" :"+chr$(10)
 
    'on vérifie que le fichier existe : fichier nomArchive$ (normalement : "entetes_wave.txt")
    Archive$ = cheminArchive$ + "\" + nomArchive$
    dim info$(10, 10)
    files cheminArchive$, nomArchive$, info$()
 
    if val(info$(0, 0))<>0 then 'le fichier existe

        'renommer le fichier en "provisoire.txt"
        Provisoire$ = cheminArchive$ + "\provisoire.txt"
        name Archive$ as Provisoire$
 
        'recréer "entetes_wave.txt" en y transférant afficheDonnee$
        open Archive$ for output as #text
        print #text, horodatage$+afficheDonnee$+chr$(10)+chr$(10)
        close #text
 
        'y ajouter le contenu de "provisoire.txt"
        open Provisoire$ for input as #prov
        open Archive$ for append as #text
        print #text, input$(#prov, lof(#prov));
        close #text
        close #prov
 
        'effacer "provisoire.txt"
        kill Provisoire$
 
    else 'le fichier n'existe pas, on va le créer et y transférer afficheDonnee$

        open Archive$ for output as #text
        print #text, horodatage$+afficheDonnee$
        close #text
 
    end if
 
    wait
 
 
[ChoixFichierAOuvrir]
    'choisir le fichier wav à analyser
    filedialog "Quel fichier doit-on lire ?", "*.wav", fichier$
    print "fichier choisi = ";fichier$
    if fichier$<>"" then 'récupération du nom de fichier

        numCar=0
        antislash=0
 
        while antislash=0
            a$=mid$(fichier$,len(fichier$)-numCar,1)
            if a$="\" or numCar>len(fichier$) then antislash=1
            numCar=numCar+1
        wend
 
        NomWav$="Nom du fichier : " + right$(fichier$,numCar-1)
        CheminWav$="Chemin : "+ left$(fichier$,len(fichier$)-numCar+1)
 
        'intégration dans la chaîne qui sera affichée
        afficheDonnee$=NomWav$+chr$(10)+CheminWav$+chr$(10)
 
        gosub [AnalyseFichier]
    end if
 
    wait
 
 
[ListeDesChamps]
    'à l'affichage, le nom des champs sera devant les données du fichier

    afficheDonnee$=afficheDonnee$+"Décodage en-tête selon WAVE_FORMAT_PCM"+chr$(10)
 
    nldat=13    'nombre total de lignes de data
    nbOcts=0    'nombre d'octets attendus, défini après analyse de la liste

    'prépa tableaux
    dim longueur(nldat),type(nldat),nom$(nldat),descript$(nldat)
 
    'mise en tableau des datas
    restore [datas]
    for a=0 to nldat-1
        read lng, type, nm$, desc$
        longueur(a)=lng
        type(a)=type
        nom$(a)=nm$
        descript$(a)=desc$
        nbOcts=nbOcts+lng 'nombre total d'octets
    next
 
    return
 
 
[quitter]
    confirm "quitter le programme ?";rep$
    if rep$="no" then wait
    close #principale
    end
 
end
 
 
 
[datas] 'longueur champ en octets, type du champ (0=nombre, 1=texte),nom, signification
'en cas d'ajout, mettre à jour <nldat> dans [ListeDesChamps]
    data 4,1,"ckID","chunk identification (RIFF)"
    data 4,0,"ckSize","chunk size (file size)"
    data 4,1,"WAVEID","WAVE ID (WAVE)"
    data 4,1,"ckID","chunk identification (fmt )"
    data 4,0,"cksize","chunk size"
    data 2,0,"wFormatTag","format code (1=PCM)"
    data 2,0,"nChannels","number of channels"
    data 4,0,"nSamplePerSec","blocs per sec"
    data 4,0,"nAvgBytesPerSec","average data rate"
    data 2,0,"nBlockAlign","data block size"
    data 2,0,"wBitsPerSample","bits per sample"
    data 4,1,"ckID","chunk ID (data)"
    data 4,0,"ckSize","chunk size"
 
 




Edité par Christophe Le 05/03/2016 à 15h20
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 19/02/2016 à 21h20

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
Mais saperlipopette...Tu t'amuse comme un petit fou.
Je vais regarder ton délire
Et surtout, essayer de comprendre à quoi ça peut servir.
Certes, à l'instar de la tête de veau vinaigrette, on pourra faire de l'entête de code au vin blanc.
Mais what else ...?
____________________
Roro

   
Le 20/02/2016 à 15h28

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Comme un fou je me suis amusé, c'est vrai. Et ce n'était pas le générateur, mais bien un programme indépendant juste pour lire des en-têtes de fichier wav, qui devrait pouvoir m'aider dans la validation du sous-programme de génération de wav

Il y a sûrement 36 petits programmes sur internet qui font la même chose en bien mieux, mais là j'ai la satisfaction de le faire comme je le souhaite. j' suis content :)
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 05/03/2016 à 15h51

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Ce qu'il y a de bien avec l'oscilloscope, c'est qu'on voit tout de suite si ça oscille ;)

Le géné avance vers sa moûture finale, mais l'onde obtenue ne sonnait toujours pas comme je m'y attendais. J'ai ouvert le wav dans audacity : il y a un échantillon de trop à chaque période. -> en cours d'investigation.

Les données affichées par audacity sont conformes sauf pour le 32-bit : c'est du 8 bits ! -> j'investigationne aussi

____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Le 05/03/2016 à 20h41

Administrateur

Groupe: Administrateur

Inscrit le: 04/03/2012
Messages: 2253
bah, il faut que l'échantillonnage soit un sous multiple entier de la période
Mais alors pourquoi le 44100 marche avec toutes les périodes ?
____________________
Roro

   
Le 06/03/2016 à 09h18

Modérateur

Groupe: Modérateur

Inscrit le: 09/02/2015
Messages: 612
Je ne suis pas certain qu'il marche vraiment : l'intervalle de temps entre échantillons est plus petit, il y a moins d'écart d'amplitude à fréquence échantillonnée égale, et ça passe peut-être plus inaperçu à l'oreille...

J'ai laissé tomber les multiples car un ppcm ne peut être calculé qu'avec des entiers, et les périodes en 1/F sont très rarement entières. A la place je lance une série de calculs qui ne s'arrêtent que lorsque les signaux passent simultanément par zéro en montant, et quand ça arrive j'ai ma période globale, celle qui sera numérisée et reproduite autant de fois que nécessaire pour arriver à la durée souhaitée.

Sauf que, le dernier calcul donne 0, qui est le début de la période suivante, et si je base mon nombre d'échantillons sur ce calcul j'en ai un de trop. Et si je me trompe de signe, du genre +1 au lieu de -1, j'enregistre aussi l'échantillon suivant de la période d'après. Et lorsque je fais la concaténation, je me retrouve avec le petit pic qui dépasse 0, comme entouré sur l'image.

J'ai maintenant un autre souci : théoriquement j'efface le fichier wav à chaque fois que je clique sur "générer". Ca marche au premier lancement du programme : si le fichier wav existe alors il est effacé, et on génère le nouveau fichier. Par contre, si le programme est déjà lanceé, et que j'appuie une nouvelle fois sur "générer", le fichier n'est pas effaçé, mais les nouvelles données sont écrites après les données existantes. A un moment donné le transfert donne n'importe quoi...

Si c'est pas clair, voici le prog, si tu veux voir par toi-même (il n'y a que la génération 8 bits mono qui fonctionne):
Code VB :
 
'Géné BF 2 fréquences
'pour le moment, seule la génération 8bits mono fonctionne
'elle fonctionne mal puisqu'il semble que le fichier wav n'est pas effacé avant l'essai suivant
'reste à faire : barre de progression (_2.bas)
'                générateur morse (_3.bas) 'clin d'oeil à pmp^^

 
    'nomainwin

    NomWav$="pardefaut.wav"
    CheminWav$=DefaultDir$
 
    'dimensions de la fenêtre
    WindowWidth = 415
    WindowHeight = 495
 
    'formats d'affichage
    fonteGlobale$="font ms_sans_serif 0 16"
    fonteTitre$="!font ms_sans_serif 0 16 bold"
 
    'valeurs par défaut
    pi=3.1415926536
    freq1=880
    vol1=70
    freq2=440
    vol2=70
 
    duree=1
 
    'fréquences échantillonnage, Hz
    indexFech=1 'élément qui sera affiché dans la combobox
    FreqEch$(1)="11025"
    FreqEch$(2)="22050"
    FreqEch$(3)="44100"
 
    'résolution échantillonnage, bits
    indexRes=1
    WaveRes$(1)="8"
    WaveRes$(2)="16"
 
    'nombre de voies
    indexVoies=1
    WaveNbvoies$(1)="1-Mono"
    WaveNbvoies$(2)="2-Stereo"
 
    'création de l'interface utilisateur
    statictext #1.titreGen, "Générateurs :", 15, 15, 100, 20
 
    statictext #1.frequences, "Fréquence, Hz", 85, 40, 100, 20
    statictext #1.volumes, "Volume, 0 à 100", 195, 40, 100, 20
 
    statictext #1.gen1, "Gen. 1", 30, 65, 40, 20
    textbox #1.freq1, 80, 60, 100, 25
    textbox #1.vol1, 190, 60, 100, 25
 
    statictext #1.gen2, "Gen. 2", 30, 95, 40, 20
    textbox #1.freq2, 80, 90, 100, 25
    textbox #1.vol2, 190, 90, 100, 25
 
    statictext #1.sortie, "Fichier de sortie :", 15, 140, 125, 20
    statictext #1.nomWav, NomWav$, 140, 140, 390, 20
    button #1.changeDest, "Emplacement et nom du fichier", [changeDestination], UL, 30, 165, 350, 25
    statictext #1.cheminWav, CheminWav$, 30, 195, 300, 40
 
    statictext #1.param, "Paramètres du fichier Wave :", 15, 245, 200, 20
 
    statictext #1.fech, "Freq. échantillonnage, Hz", 30, 270, 170, 20
    combobox #1.comboEch, FreqEch$(), [f_echantillonnage], 210, 268, 75, 20
 
    statictext #1.fech, "Résolution, bits", 30, 300, 170, 20
    combobox #1.comboRes, WaveRes$(), [Wav_resolution], 210, 297, 75, 20
 
    statictext #1.fech, "Nombre de voies", 30, 330, 170, 20
    combobox #1.comboVoi, WaveNbvoies$(), [Wav_nombre_voies], 210, 328, 75, 20
 
    statictext #1.dureeWav, "Durée, s", 30, 360, 170, 20
    textbox #1.bxDureeWav, 210, 358, 75, 25
    'button #1.okDuree, "OK", [valide_duree], UL, 290, 360, 25, 25

    statictext #1.avanti, "En avant !", 15, 400, 270, 20
    button #1.genWav, "Générer", [genere_wav], UL, 30, 425, 80, 25
    button #1.annulCalc, "Annuler", [annule_calcul], UL, 120, 425, 80, 25
    button #1.quit, "Quitter", [quitter], UL, 300, 425, 80, 25
 
    'ouverture fenêtre d'interface utilisateur
    open "Géné. BF" for window as #1
 
        'fonte global
        print #1, fonteGlobale$
 
        'fonte titres
        print #1.titreGen, fonteTitre$
        print #1.sortie, fonteTitre$
        print #1.param, fonteTitre$
        print #1.avanti, fonteTitre$
        print #1.titreGen, fonteTitre$
 
        'données pré-réglées
        print #1.freq1, freq1
        print #1.vol1, vol1
        print #1.freq2, freq2
        print #1.vol2, vol2
 
        print #1.comboEch,"selectindex ";indexFech
        fEchant=val(FreqEch$(indexFech))
 
        print #1.comboRes,"selectindex ";indexRes
        resolution=val(WaveRes$(indexRes))
 
        print #1.comboVoi,"selectindex ";indexVoies
        voies=val(WaveNbvoies$(indexVoies))
 
        print #1.bxDureeWav, duree
        print #1.annulCalc, "!disable"
        print #1.freq1, "!setfocus"
        print #1, "trapclose [quitter]"
 
    wait
 
end
'***************sous-programmes********************

[quitter]
    'quitte le programme
    close #1
    end
 
[annule_calcul]
    'pas encore créé

    'on annule la création en cours (temps trop long, ou erreur de saisie
    'et vouloir relancer avant la fin réelle du traitement, ...)
    wait
 
[changeDestination]
    print "[changeDestination]"
    filedialog "Save to, entrer un nom pour le fichier :","*.wav",chemin$
    if chemin$<>"" then
        numCar=0
        antislash=0
 
        while antislash=0
            a$=mid$(chemin$,len(chemin$)-numCar,1)
            if a$="\" or numCar>len(chemin$) then antislash=1
            numCar=numCar+1
        wend
 
        NomWav$=right$(chemin$,numCar-1)
        CheminWav$=left$(chemin$,len(chemin$)-numCar+1)
 
        print #1.cheminWav, CheminWav$
        print #1.nomWav, NomWav$
 
    end if
    wait
 
 
[chercher_periode_somme]
    print "[chercher_periode_somme]"
    tour=0
    t=0
    gen1zm=0
    gen2zm=0
    trouve=0
    limitetemps=10*fEchant  '(10 fois la fréquence d'échantillonnage, soit 10 secondes)

    while trouve=0
 
        anciengen1=gen1
        anciengen2=gen2
 
        gen1=vol1*sin(omega1*t)
        gen2=vol2*sin(omega2*t)
 
        print gen1;"       ";gen2
 
        'détecte le passage par zéro en montant
        if anciengen1<0 and gen1>=0 then gen1zm=1:print "generateur1 passe 0 en montant"
        if anciengen2<0 and gen2>=0 then gen2zm=1:print "generateur2 passe 0 en montant"
 
        if gen1zm=1 and gen2zm=1 then
            trouve=1
            tours=tour-1 '  (on retire 1 parce que on vient de trouver le premier
            '               point de la période suivante)
            print "*** trouvé au ";tour;"ème calcul ! ***"
        end if
 
        gen1zm=0
        gen2zm=0
 
        tour=tour+1
        t=t+tEchant
        if t>limitetemps then trouve=1:tempsdepasse=1:tours=tour:print "!!! pas trouvé !!!"
 
    wend
 
    if tempsdepasse then
        repetitions=1
    else
        repetitions=int(duree/(tours*tEchant)+1)
    end if
    print "il y aura ";repetitions;" fois la période de la somme"
    '(période finale = période décrivant totalement la forme d'onde de la somme)
    'on arrondi à l'entier supérieur, et on obtient le nombre de fois qu'il faudra
    'répéter la période finale pour aboutir à la durée souhaitée
return
 
 
[f_echantillonnage]
    print "[f_echantillonnage]"
 
    'lecture valeur combobox
    print #1.comboEch,"selectionindex? indexFech"
    fEchant=val(FreqEch$(indexFech))
 
    wait
 
 
[genere_wav]
    print "[genere_wav]"
    'récupération fréquences et volumes des générateurs
    print #1.freq1, "!contents? a$":freq1=val(a$)
    print #1.vol1, "!contents? a$":vol1=val(a$)
    print #1.freq2, "!contents? a$":freq2=val(a$)
    print #1.vol2, "!contents? a$":vol2=val(a$)
 
    'calcul pulsations
    omega1=2*pi*freq1
    omega2=2*pi*freq2
 
    'récupération paramètres wav
    print #1.bxDureeWav, "!contents? a$":duree=val(a$)
 
    'déterminer la période décrivant complètement la somme des deux fréquences
    tEchant=1/fEchant
    gosub [chercher_periode_somme]
 
    'en fonction de la résolution et du nombre de voies on détermine le codage
    'pour la durée d'une "période somme"
    amplitudemax=400
    t=0
    if resolution=8 then
        if voies=1 then gosub [fichier_8bits_mono]
        if voies=2 then gosub [fichier_8bits_stereo]
    end if
 
    if resolution=16 then
        if voies=1 then gosub [fichier_16bits_mono]
        if voies=2 then gosub [fichier_16bits_stereo]
    end if
 
    'on prépare les données pour la durée finale souhaitée
    for a=1 to repetitions
        audio$=audio$+periodesomme$
        'audio$=audio$+left$(periodesomme$,len(periodesomme$)-1)
    next
 
    'On prépare l'en-tête du fichier
    longueurAudio=len(audio$)
    nbOctet=resolution/8    'nombre d'octets par échantillon pour une voie
    fluxDonnees=nbOctet*voies*fEchant'débit en nombre d'octets par seconde

    'données du programme
    et$="RIFF"                              'toujours RIFF
    et$=et$+littleEndian$(36+longueurAudio,4)'taille fichier (devrait être 44+nbre d'octets audio ???)
    et$=et$+"WAVE"                          'toujours WAVE
    et$=et$+"fmt "                          'toujours "fmt "
    et$=et$+littleEndian$(16,4)              '16, 18 ou 40
    et$=et$+littleEndian$(1,2)               '1=PCM, Pulse Code Modulation, classique pour un wave ordinaire
    et$=et$+littleEndian$(voies,2)           'nombre de canaux interlacés (1=mono, 2=stéréo,...)
    et$=et$+littleEndian$(fEchant,4)         'fréquence échantillonnage
    et$=et$+littleEndian$(fluxDonnees,4)     'nombre moyen d'octets par seconde
    et$=et$+littleEndian$(nbOctet,2)         'taille du bloc de donnees
    et$=et$+littleEndian$(resolution,2)      'bits par échantillon (pour une voie)
    et$=et$+"data"                          'toujours "data", annonce les données audio
    et$=et$+littleEndian$(longueurAudio,4)   'longueur en octets des données audio

    'le futur fichier audio est complètement contenu dans la chaine wav$
     wav$=et$+audio$
 
    'on transfère wav$ dans le fichier
    Fichier$=CheminWav$+"\"+NomWav$ '
    dim info$(10, 10)
    files CheminWav$, NomWav$, info$()
 
    if val(info$(0, 0))<>0 then 'le fichier existe, le supprimer
        print "kill Fichier$ : ";Fichier$
        kill Fichier$
    end if
 
    print Fichier$
    open Fichier$ for output as #audio
        print #audio,wav$
    close #audio
 
    'contrôle (prévoir un arrêt prématuré
    playwave Fichier$
 
    wait 'return provisoire 'ce serait-y pas un wait, des fois ?

 
[fichier_8bits_mono]
    print "[fichier_8bits_mono]"
 
    maxoct=0:minoct=256 '(c'est inversé, c'est normal ici)

    for a=0 to tours
        'calcul échantillon
        somme=vol1*sin(omega1*t)+vol2*sin(omega2*t)
        echantillon=int(128+somme*256/amplitudemax)   'échantillons

        'arrondir
        entiere=int(echantillon)
        decimale=somme-int(echantillon)
        if decimales>=0.5 then echantillon=entiere+1 else echantillon=entiere
 
        'stoker l'échantillon en chaine
        periodesomme$=periodesomme$+chr$(echantillon)
 
        'if valeurmaxoctet<echantillon then valeurmaxoctet=echantillon
        'if valeurminoctet>echantillon then valeurminoctet=echantillon
        print "somme = ";somme;", échantillon = ";echantillon
 
        'prépare pour échantillon suivant
        t=t+tEchant
    next
    periodesomme$=left$(periodesomme$,len(periodesomme$)-1)
    return
 
 
[fichier_8bits_stereo]
    print "[fichier_8bits_stereo]"
 
    for a=0 to tours
 
        'voie gauche
        'calcul échantillon
        somme=vol1*sin(omega1*t)+vol2*sin(omega2*t)
        echantillon=int(128+somme*256/amplitudemax)   'échantillons

        'arrondir
        entiere=int(echantillon)
        decimale=somme-int(echantillon)
        if decimales>=0.5 then echantillon=entiere+1 else echantillon=entiere
 
        'stoker l'échantillon en chaine
        periodesomme$=periodesomme$+chr$(echantillon)
 
 
        'voie droite
        'calcul échantillon
        somme=vol1*sin(omega1*t)+vol2*sin(omega2*t)
        echantillon=int(128+somme*256/amplitudemax)   'échantillons
        'arrondir
        entiere=int(echantillon)
        decimale=somme-int(echantillon)
        if decimales>=0.5 then echantillon=entiere+1 else echantillon=entiere
 
        'stoker l'échantillon en chaine
        periodesomme$=periodesomme$+chr$(echantillon)
 
        t=t+tEchant
    next
    periodesomme$=left$(periodesomme$,len(periodesomme$)-1)
return
 
 
[fichier_16bits_mono]
    print "[fichier_16bits_mono]"
    for a=0 to tours
 
        'calcul échantillon
        somme=vol1*sin(omega1*t)+vol2*sin(omega2*t)
        echantillon=int(somme*65536/amplitudemax)   'échantillons

        'arrondir
        entiere=int(echantillon)
        decimale=somme-int(echantillon)
        if decimales>=0.5 then echantillon=entiere+1 else echantillon=entiere
 
        octetFort=int(echantillon/256)
        octetFaible=int(echantillon)-octetFort*256
        periodesomme$=periodesomme$+chr$(octetFaible)+chr$(octetFort)
 
        t=t+tEchant
    next
 
return
 
 
[fichier_16bits_stereo]
        print "[fichier_16bits_mono]"
    for a=0 to tours
 
        'voie gauche
        'calcul échantillon
        somme=vol1*sin(omega1*t)+vol2*sin(omega2*t)
        echantillon=int(somme*65536/amplitudemax)   'échantillons

        'arrondir
        entiere=int(echantillon)
        decimale=somme-int(echantillon)
        if decimales>=0.5 then echantillon=entiere+1 else echantillon=entiere
 
        octetFort=int(echantillon/256)
        octetFaible=int(echantillon)-octetFort*256
        periodesomme$=periodesomme$+chr$(octetFaible)+chr$(octetFort)
 
        'voie droite
        'calcul échantillon
        somme=vol1*sin(omega1*t)+vol2*sin(omega2*t)
        echantillon=int(somme*65536/amplitudemax)   'échantillons

        'arrondir
        entiere=int(echantillon)
        decimale=somme-int(echantillon)
        if decimales>=0.5 then echantillon=entiere+1 else echantillon=entiere
        octetFort=int(echantillon/256)
        octetFaible=int(echantillon)-octetFort*256
        periodesomme$=periodesomme$+chr$(octetFaible)+chr$(octetFort)
 
        t=t+tEchant
    next
 
    return
 
[Wav_nombre_voies]
    print "[Wav_nombre_voies]"
    print #1.comboVoi,"selectionindex? indexVoies"
    voies=val(WaveNbvoies$(indexVoies))
 
    wait
 
[Wav_resolution]
    print "[Wav_resolution]"
    print #1.comboRes,"selectionindex? indexRes"
    resolution=val(WaveRes$(indexRes))
 
    wait
 
'************** fonctions ***************

function littleEndian$(nombre,longueur)
    print
    print "function littleEndian$ ";
    print "nombre=";nombre;"  longueur=";longueur
    code$="":reste=nombre
 
    for a=longueur-1 to 1 step -1
 
        octet=int(nombre/256^a)
        code$=chr$(octet)+code$
 
        reste=nombre-octet*256^a
 
        nombre=reste
 
        print "boucle=";a;" octet=";octet;"  nombre=";nombre;"  code$=";code$
    next
 
    code$=chr$(reste)+code$
    littleEndian$=code$
 
    'vérification
    for a=1 to longueur
        print asc(mid$(code$,a,1));" ";
    next
    print
end function
 
 
 
____________________
Just BASIC v2.0 :
  • utilisation courante avec GNU/Linux Mageia6 + Wine (Pas trouvé d'incohérences ou de bug de compilation à ce jour)
  • utilisation occasionnelle ou vérification/débugage difficile avec Windows XP sur un petit eeepc

   
Général » Générateur BF Ou qui tente de l'être  

 |  |

2 Utilisateurs en ligne : 0 Administrateur, 0 Modérateur, 0 Membre et 2 Visiteurs
Utilisateurs en ligne : Aucun membre connecté
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie