France Hardware : Forums de discussion - Découvrez notre nouveau comparateur d'offres Internet
Retrouvez les prix près de chez vous :  
Index du forum | Liste des membres | Liste des groupes | Inscription | F-A-Q | Recherche
Pseudo :    Password :     
29 521 membres enregistrés - 2 069 420 posts - 122 057 topics
Index des forums FH  | Index des forums DegroupNews
      Programmation
           Sujets divers
                [Algo/Maths/C++] Mon topic synthèse sonore/DSP
144 connectés(record : 2799 le 29 May 2016 - 15 h 34)

Vous devez vous connecter pour répondre au topic.
1,2 | Suivant
[Algo/Maths/C++] Mon topic synthèse sonore/DSP

Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 14 August 2005 - 21 h 12 m 40 s
Bonjour les enfants !

Bon, alors pour vous mettre dans le bain : je suis en train de faire une bibliothèque (en C++) de synthèse sonore/traitement du signal, pour mon plaisir et me faire un peu la main.
Je suis en train de travailler sur ma classe de synthèse de sinusoïde, et pour des questions de performance, je suis à la recherche d'autres solutions que l'utilisation de la fonction sin() ou de coder la fonction transcendante correspondante.
L'idée : utiliser le fait que le sinus est cyclique, et donc le calculer par "récursivité" (principe des séries) : j'utilise la valeur précédente pour calculer la valeur courante.

1. Synthèse récursive bête et méchante - FINI

En partant des définitions
- sin(a+b) = sin(a)cos(b) + cos(a)sin(b) et
- cos(a+b) = cos(a)cos(b) - sin(a)sin(b),

et en posant :
- sin(0) = 0, cos(0) = 1
- step étant la différence d'angle entre deux échantillons
- sample_t représentant un flottant
- toute valeur devant être comprise dans [-1, 1] (j'aimerais bien [-1, 1[ mais je ne sais pas comment faire...)
- baseFrequency est la fréquence du signal à générer

j'en suis arrivé à :

    Code c    
 1. // fouette cocher
 2. WaveBuffer & RecursiveSineWaveGenerator::doIt( WaveBuffer & wbuffer ) const {
 3.     sample_t currentCos = 1.;
 4.     sample_t currentSin = 0.;
 5.     if(m_seed != 0)
 6.     {
 7.         currentCos = cos(m_seed);
 8.         currentSin = sin(m_seed);
 9.     }
10.     sample_t step = 1.0f / wbuffer.getSamplingRate() * m_baseFrequency * M_2PI;
11.     sample_t stepSin = sin(step);
12.     sample_t stepCos = cos(step);
13.     sample_t * buffer = wbuffer.getDataPointer();
14.     size_t bufferSize = wbuffer.getSize();
15. 
16.     *buffer++ = currentSin;
17. 
18.     for( size_t i = 1; i < bufferSize; ++i )
19.     {
20.         // f(x+1) = sin(x + step) = sin(x)cos(step) + cos(x)sin(step)
21.         currentSin = currentSin * stepCos + currentCos * stepSin;
22.         currentCos = currentCos * stepCos - currentSin * stepSin;
23.         *buffer++ = currentSin;
24.     }
25. 
26.     return wbuffer;
27. }
Le problème, c'est que quelque part, un truc foire, et l'amplitude diminue de plus en plus. C'est génial à voir, mais ce n'est pas ce que je cherche. En images pour mieux voir (signal de 50 ms échantilloné à 44100 kHz) (désolé, mon interpolation est un peu bourrine) : Y a-t-il une correction ou un changement dans l'algorithme que je puisse apporter ? 2. Synthèse récursive approximée et plus rapide Bon, cette méthode est déjà environ 5 ou 6 fois plus rapide même sans aucune optimisation (profilage à l'appui). Mais je voulais plus, encore plus ! En me baladant sur Internet, j'ai vu une idée qui exploitait les limites le fait que step est très petit. Cette idée disait : - lim cos(step) quand step-&#620; = 1 - lim sin(step) quand step-&#620; = step L'algorithme résultant est le suivant (ne hurlez pas sur les appels de fonction dans le for(), c'est juste pour le principe ;) ) :
    Code c    
 1. // sirop d'érable
 2. WaveBuffer & OptimizedRecursiveSineWaveGenerator::doIt( WaveBuffer & wbuffer ) const {
 3.     sample_t currentCos = 1.;
 4.     sample_t currentSin = 0.;
 5. 
 6.     sample_t step = 1.0f / wbuffer.getSamplingRate() * m_baseFrequency * M_2PI;
 7.     sample_t stepSin = sin(step);
 8.     sample_t stepCos = cos(step);
 9.     sample_t * buffer = wbuffer.getDataPointer();
10.     size_t buffer_size = wbuffer.getSize();
11. 
12.     *buffer++ = currentSin;
13. 
14.     for( size_t i = 1; i < wbuffer.getSize(); ++i )
15.     {
16.         currentSin += step * currentCos;
17.         currentCos -= step * currentSin;
18.         *buffer++ = currentSin;
19.     }
20. 
21.     return wbuffer;
22. }


Ce code marche très bien :


Le problème, cette fois, c'est que les valeurs sortent (juste un peu) des bornes. J'aimerais bien les ramener dans [-1, 1] sans normaliser (en attendant, j'ai simplement ramené les valeurs extrèmes à -1 ou 1).


Message édité 5 fois, la dernière par Petit_PimoOosE le 15 August 2005 - 20 h 02.

Huile de fraise.

iraysyvalo
-

Messages : 9 647
Inscrit le 19/11/02
Ville : Lyon
Non connecté
  Posté le 14 August 2005 - 22 h 34 m 00 s

Pour cette nuit, juste une question un peu off, tu fais comment pour visualiser tes fonctions la ? Ce que tu mets en image la, c'est la sortie de wbuffer ? Qu'y as-tu mis en entree ?

Decris un peu mieux ce que SineWaveGenerator est sensee faire ..




Pour un ban rapide et garanti sur ce forum, argumentez vos posts, dites simplement la verite, parlez de la realite et les leche-culs d'un cote et les maniaques du ban de l'autre se feront un plaisir de vous envoyer au purgatoire aussi sec.


Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 15 August 2005 - 00 h 58 m 17 s
Bon, alors kha m'a donné une piste de réflexion, je vous livre ça un peu plus tard.

Pour visualiser mes fonctions, j'ai fait un objet qui dessine le contenu d'un WaveBuffer sur une surface SDL.

Enfin, le SineWaveGenerator comprend en membre sa fréquence d'oscillation. Sa fonction doIt prend argument un buffer d'un certain nombre d'échantillons (de type point flottant, la précision ne change rien dans ce cas) et d'une certaine fréquence d'échantillonnage (membres du WaveBuffer), et écrit une sinusoïde de période 1/fréquence dans le tampon.

edit : désolé, je suis arrivé un peu tard pour te donner la matière :rougir:


Message édité 2 fois, la dernière par Petit_PimoOosE le 15 August 2005 - 03 h 09.

Huile de fraise.

Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 15 August 2005 - 03 h 12 m 15 s
Bon, voilà, ma faute était assez stupide : j'utilisais, pour le calcul du nouveau cosinus, la valeur du nouveau sinus... Alors qu'il fallait celle de l'ancien.

La boucle de calcul devient :
    Code c    
 1. // coincoin
 2. for( size_t i = 1; i < bufferSize; ++i )
 3. {
 4.     // f(x+1) = sin(x + step) = sin(x)cos(step) + cos(x)sin(step)
 5.     sample_t oldSin = currentSin;
 6.     sample_t oldCos = currentCos;
 7.     currentSin = oldSin * stepCos + oldCos * stepSin;
 8.     currentCos = oldCos * stepCos - oldSin * stepSin;
 9.     *buffer++ = currentSin;
10. }


C'est sûr que je peux faire sauter oldCos, mais comme ça, ça a le mérite d'être plus clair.



Si vous avez d'autres techniques (utilisant des tables en autres), je suis ouvert.

edit : et bientôt, des questions sur la FM !


Message édité 2 fois, la dernière par Petit_PimoOosE le 15 August 2005 - 06 h 24.

Huile de fraise.

iraysyvalo
-

Messages : 9 647
Inscrit le 19/11/02
Ville : Lyon
Non connecté
  Posté le 15 August 2005 - 11 h 05 m 03 s

J'ai toujours pas capte :(

Tu veux sin(seed+k dt) , c'est ca ?? Et le wbuffer ne te sert qu'a calculer dt (d'ailleurs pourquoi dt est comme ca ?) ?

Si t'as les trucs ou tu t'interfaces avec SDL et un tuto dessus, je veux bien :jap:




Pour un ban rapide et garanti sur ce forum, argumentez vos posts, dites simplement la verite, parlez de la realite et les leche-culs d'un cote et les maniaques du ban de l'autre se feront un plaisir de vous envoyer au purgatoire aussi sec.


Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 15 August 2005 - 17 h 21 m 26 s
Ah m**de, j'ai laissé traîner un seed que je ne voulais pas voir. À la base, ça devait être le décalage de phase initial, mais je me demande si je vais le laisser.

Sinon, je reformule :
considérons le SineWaveGenerator comme un oscillateur possédant une fréquence propre et qui laisse sa trace dans un WaveBuffer possédant une certaine fréquence d'échantillonnage et une certaine taille.
Ainsi, pour chaque échantillon (case du WaveBuffer), on récupère la valeur de l'oscillateur correspondante.

Pour le dessin par SDL, c'est tout simple (même si j'ai galéré :D). En gros, le code, c'est ça (les commentaires en français sont ceux que je viens de rentrer ;) ) :
    Code c    
  1. // initialisation
  2. 
  3.     // initialize SDL Video subsystem
  4.     if(SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
  5.         if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
  6.             std::cout << SDL_GetError() << std::endl;
  7.             throw "erreur sdl_init";
  8.         }
  9.     }
 10. 
 11.     int videoFlags = 0;
 12.     if(m_fullscreen)
 13.         videoFlags |= SDL_FULLSCREEN;
 14. 
 15.     // create a surface with no flag, 32-bit deep
 16.     m_surface = SDL_SetVideoMode(m_width, m_height, 32, videoFlags);
 17.     if(m_surface == 0) {
 18.         std::cout << SDL_GetError() << std::endl;
 19.         throw "erreur setvideomode";
 20. 
 21. 
 22. // dessin du buffer
 23. 
 24.     // create background and dot colors
 25.     Uint32 bgColor= SDL_MapRGB(m_surface->format, 0xFF, 0xFF, 0xA0);
 26.     Uint32 fgColor= SDL_MapRGB(m_surface->format, 0x80, 0, 0);
 27.     
 28.     // fill background with background color
 29.     SDL_Rect fullFrameRect = {0, 0, m_width, m_height};
 30.     SDL_FillRect(m_surface, &fullFrameRect, couleurFond);
 31. 
 32.     sample_t half_height = m_height / 2;
 33. 
 34.     // lock surface if it has to be locked
 35.     if(SDL_MUSTLOCK(m_surface))
 36.         SDL_LockSurface(m_surface);
 37. 
 38.     const sample_t * sample = wb.getDataPointer();
 39. 
 40.     const size_t bufferSize = wb.getSize();
 41.     const sample_t bufferSizeInv = 1. / (sample_t)wb.getSize();
 42.     const sample_t screenWidth = (sample_t)m_width;
 43. 
 44.     int oldY = 0;
 45. 
 46.     // draw a dot for each sample
 47.     for(int i=0; i < bufferSize; ++i) {
 48.         // give sample a position on the surface according to its position in the buffer
 49.         int x = int((sample_t)i * bufferSizeInv * screenWidth);
 50.         int y = int(*sample * half_height + half_height);
 51.         
 52.         // clip out of range samples 
 53.         if(y => m_height)
 54.             y = m_height - 1;
 55. 
 56.         // drow dot on surface
 57.         WaveBufferViewer::putPixel(m_surface, x, y, couleurPx);
 58.         sample++;
 59. 
 60.     // unlock surface if it has been locked
 61.     if(SDL_MUSTLOCK(m_surface))
 62.         SDL_UnlockSurface(m_surface);
 63.         
 64.     // redraw entire surface
 65.     SDL_UpdateRect(m_surface, 0, 0, 0, 0);
 66. 
 67. 
 68. // fermeture
 69. 
 70. 
 71.     // destroy and free SDL surface
 72.     SDL_FreeSurface(m_surface);
 73.     
 74.     // initiate SDL cleanup
 75.     SDL_Quit();
 76. 
 77. 
 78. // procédure proposée par la doc SDL que j'ai gardée
 79. /*
 80.  * Set the pixel at (x, y) to the given value
 81.  * NOTE: The surface must be locked before calling this!
 82.  */
 83. void WaveBufferViewer::putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
 84. {
 85.     int bpp = surface->format->BytesPerPixel;
 86.     /* Here p is the address to the pixel we want to set */
 87.     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
 88. 
 89.     switch(bpp) {
 90.     case 1:
 91.         *p = pixel;
 92.         break;
 93. 
 94.     case 2:
 95.         *(Uint16 *)p = pixel;
 96.         break;
 97. 
 98.     case 3:
 99.         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
100.             p[0] = (pixel >> 16) & 0xff;
101.             p[1] = (pixel >> 8) & 0xff;
102.             p[2] = pixel & 0xff;
103.         } else {
104.             p[0] = pixel & 0xff;
105.             p[1] = (pixel >> 8) & 0xff;
106.             p[2] = (pixel >> 16) & 0xff;
107.         }
108.         break;
109. 
110.     case 4:
111.         *(Uint32 *)p = pixel;
112.         break;
113.     }
114. }


Je pense que je vais créer un projet SourceForge pour profiter du CVS si ça t'intéresse...
Et puis je galère avec la synchro multi-thread et les événements de SDL, donc je vais vous faire travailler ;)


Message édité 1 fois, la dernière par Petit_PimoOosE le 15 August 2005 - 17 h 23.

Huile de fraise.

iraysyvalo
-

Messages : 9 647
Inscrit le 19/11/02
Ville : Lyon
Non connecté
  Posté le 15 August 2005 - 17 h 35 m 34 s

Ok pour le cvs ..

SinWaveGen rend donc en fait l'echantillonnage d'un sin a la meme frequence que le wavebuffer d'origine. Tu ressors avec un nouveau wavebuffer de la meme taille apres.




Pour un ban rapide et garanti sur ce forum, argumentez vos posts, dites simplement la verite, parlez de la realite et les leche-culs d'un cote et les maniaques du ban de l'autre se feront un plaisir de vous envoyer au purgatoire aussi sec.


Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 15 August 2005 - 17 h 45 m 47 s
Non non, j'ai oublié de préciser que l'objet WaveBuffer de sortie est le même que celui en entrée. Son contenu est effacé par le générateur.

Et tu ne confondrais pas fréquence du générateur et fréquence d'échantillonnage du buffer ?
En clair : le générateur oscille à une certaine fréquence, c'est-à-dire qu'il répond selon une fonction cyclique (sinus en l'occurence).
Le WaveBuffer dispose d'une fréquence d'échantillonnage, c'est-à-dire qu'il découpe le temps en échantillons : mettons, si ma fréquence d'échantillonnage est de 1000Hz, alors je vais récupérer la valeur de sortie de l'oscillateur toutes les millisecondes.

En pratique, l'oscillateur va boucler sur tout le buffer. Pour chaque échantillon, il va déterminer combien vaut le sinus pour telle position d'échantillon à telle fréquence d'échantillonage pour telle fréquence d'oscillation.

edit : euh pour le CVS, il va falloir que je mette un peu d'ordre dans mon projet :rougir:


Message édité 2 fois, la dernière par Petit_PimoOosE le 15 August 2005 - 18 h 11.

Huile de fraise.

tempo
Zen

Messages : 2 178
Inscrit le 14/09/02
Ville : Grenoble (Echi)
Non connecté
  Posté le 15 August 2005 - 19 h 19 m 19 s


Je suis en train de travailler sur ma classe de synthèse de sinusoïde, et pour des questions de performance, je suis à la recherche d'autres solutions que l'utilisation de la fonction sin() ou de coder la fonction transcendante correspondante.


bon, j'ai pas tout suivi mais si c'est pour une histoire de perf, un grand classique est de rester dans le domaine discret sans s'amuser a refaire des calculs trigos sans arret:
=> a l'initialisation de la lib, tu generes un tableau [n elements] dans lequel tu stockes toutes les valeurs (double) d'un sinus, en faisant correspondre a chaque element k un angle (2*PI*k/n). Apres, tu ne devrais pas avoir trop de difficulté a utiliser ce sinus echantillonné...




tempo
Zen

Messages : 2 178
Inscrit le 14/09/02
Ville : Grenoble (Echi)
Non connecté
  Posté le 15 August 2005 - 19 h 21 m 05 s


Je suis en train de travailler sur ma classe de synthèse de sinusoïde, et pour des questions de performance, je suis à la recherche d'autres solutions que l'utilisation de la fonction sin() ou de coder la fonction transcendante correspondante.


bon, j'ai pas tout suivi mais si c'est pour une histoire de perf, un grand classique est de rester dans le domaine discret sans s'amuser a refaire des calculs trigos sans arret:
=> a l'initialisation de la lib, tu generes un tableau [n elements] dans lequel tu stockes toutes les valeurs (double) d'un sinus, en faisant correspondre a chaque element k un angle (2*PI*k/n). Apres, tu ne devrais pas avoir trop de difficulté a utiliser ce sinus echantillonné...




Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 15 August 2005 - 20 h 00 m 11 s
En effet, j'ai pensé à la table de valeurs, mais pour l'instant, j'ai du mal à m'imaginer comment faire les correspondances pour les différentes fréquences de son et d'échantillonnage sans faire 36 tables. J'imagine aussi que ce sera mieux si elles sont de taille 2^x, et il va falloir que je fasse de l'interpolation... Si je la veux cubique, va falloir réviser mes formules :unhappy:

edit: enfin merci, tu me motives à me pencher là-dessus :)


Message édité 1 fois, la dernière par Petit_PimoOosE le 15 August 2005 - 20 h 00.

Huile de fraise.

iraysyvalo
-

Messages : 9 647
Inscrit le 19/11/02
Ville : Lyon
Non connecté
  Posté le 15 August 2005 - 20 h 04 m 26 s
PiMoOose : pour le cvs c'est pas urgent ..
Dans ton code, tu fais un calcul de step (= temps ecoule entre deux echantilllons non ?) ... ou est la frequence de ton signal (sinus en l'occurrence) ?

EDIT : Ok, apres reflexion, c'est m_baseFrequency et step, c'est pas le temps entre deux echantillons :)

Tempo : ok, tu precalcules n valeurs. Mais comment tu les reappliques simplement a une frequence et un taux d'echantillonage donne ?


Message édité 1 fois, la dernière par iraysyvalo le 15 August 2005 - 20 h 27.


Pour un ban rapide et garanti sur ce forum, argumentez vos posts, dites simplement la verite, parlez de la realite et les leche-culs d'un cote et les maniaques du ban de l'autre se feront un plaisir de vous envoyer au purgatoire aussi sec.


tempo
Zen

Messages : 2 178
Inscrit le 14/09/02
Ville : Grenoble (Echi)
Non connecté
  Posté le 15 August 2005 - 21 h 22 m 32 s


Tempo : ok, tu precalcules n valeurs. Mais comment tu les reappliques simplement a une frequence et un taux d'echantillonage donne ?


Me faire faire de la trigo +echantillonnage en sortie de WE (et surtout depuis le temps que j'en fais plus...), c'est pas tres gentil :non:

bon, si:
Fe = frequence d'echantillonnage
Fs = frequence du signal a synthetiser
W = pulsation du signal a synthetiser (= 2*PI*Fs)
pour l'echantillon k dans le buffer S de sortie:
t(k) (temps discret dans buffer de sortie) = k/Fe
soit
S(k) = sin (Wt(k)) = sin (2*PI*(Fs/Fe)*k)
comme dans notre domaine discret on a n ~ 2*PI
(c'est a l'arrache, je sais plus comment on note ça...)

=> pour l'echantillon k du buffer de sortie,
l'index i dans le tableau de sinus est (Fs*k/Fe) modulo n
(en calcul sur des int...)

bon, c'est a la louche, y'a pas d'interpolation et j'espere ne pas m'etre gourré...
c'est aussi tres ciblé sur l'utilisation des int et faut faire gaffe a pas depasser les tailles limites sur les types (prendre des long int, voire des long long... vive les cpus 64 bits)

Qui fait la petite appli numerique avec Fe=48Khz et Fs=1Kz sur un buffer de 2 secondes (96000 echantillons...) ?

PS: si n est de la forme 2^p, le modulo doit pouvoir se faire via un simple 'ET', non ?




Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 17 August 2005 - 19 h 53 m 35 s
Merci pour l'analyse :) je m'y attelle dès que possible !



Huile de fraise.

tempo
Zen

Messages : 2 178
Inscrit le 14/09/02
Ville : Grenoble (Echi)
Non connecté
  Posté le 19 August 2005 - 21 h 27 m 08 s
bon, ben y'avait petit gourage dans ma petite formule :D ...


=> pour l'echantillon k du buffer de sortie,
l'index i dans le tableau de sinus est (Fs*k/Fe) modulo n
(en calcul sur des int...)


donc, en fait c'est:
=> pour l'echantillon k du buffer de sortie,
l'index i dans le tableau de sinus est (Fs*k*n/Fe) modulo n


Allez, un petit exemple: Fs=10Hz, Fe=200Hz, sortie de 200 echantillons (1 seconde)
La table de sinus comprend 256 valeurs


Et puis encore un:
Fs=1Hz, toujours 200H pour Fe et 200 echantillons et 256 valeurs:


et pour les plus téméraire, un petit bout de C :love: avec pas beaucoup de commentaires :
    Code     
 1. #include <stdlib.h>
 2. #include <stdio.h>
 3. #include <math.h>
 4. 
 5. #define SINTABSIZE      0x100
 6. #define SINTABMOD       0x0FF
 7. 
 8. double sintab[SINTABSIZE];
 9. 
10. void initSinTab(){
11.   int k;
12.   double angle;
13. 
14.   for(k=0;k<SINTABSIZE;k++){
15.         angle = M_PI*2*(double)k/(double)SINTABSIZE;
16.         sintab[k] = sin(angle);
17.   }
18. }
19. 
20. void compute(unsigned int bufferSize,double* buffer, unsigned int Fs, unsigned int Fe){
21.   unsigned int k;
22.   unsigned int i;
23. 
24.   for (k=0;k<bufferSize;k++){
25.         i = (Fs * k * SINTABSIZE) / Fe;
26.         /* Waouhh , le modulo !!! */
27.         i = i & SINTABMOD;
28.         if(i>SINTABSIZE){
29.                printf("Erreur index i=%u\n",i);
30.                exit(1);
31.         }
32.         buffer[k] = sintab[i];
33.   }
34. }
35. 
36. 
37. void display(unsigned int bufferSize, double* buffer){
38.   unsigned int k;
39. 
40.   for(k=0;k<bufferSize;k++){
41.         printf("%ut%fn",k,buffer[k]);
42.   }
43. }
44. 
45. 
46. int main(int argc, char** argv){
47.   unsigned int bufferSize;
48.   double* buffer;
49.   unsigned int Fe;
50.   unsigned int Fs;
51. 
52.   initSinTab();
53. 
54.   bufferSize = 200;
55.   Fe = 200;
56.   Fs = 50;
57. 
58.   buffer = malloc(sizeof(double)*bufferSize);
59.   if(buffer == NULL){
60.         printf("erreur allocation buffern");
61.         exit(1);
62.   }
63. 
64. 
65.   compute(bufferSize,buffer,Fs,Fe);
66.   display(bufferSize,buffer);
67. 
68.   return 0;
69. }


(heu, pour les graphiques ??? gnuplot !!! :jap: )




iraysyvalo
-

Messages : 9 647
Inscrit le 19/11/02
Ville : Lyon
Non connecté
  Posté le 20 August 2005 - 12 h 02 m 23 s
Tain le modulo !! C'est space !!! Si je change TABSIZE, faut aussi changer le masque non ?? !!

Ah ouais, faut encore que je prenne du papier et un crayon pour verifier ton algo :P

EDIT : ton cast automatique pour i est un peu dangereux non ?


Message édité 1 fois, la dernière par iraysyvalo le 20 August 2005 - 12 h 03.


Pour un ban rapide et garanti sur ce forum, argumentez vos posts, dites simplement la verite, parlez de la realite et les leche-culs d'un cote et les maniaques du ban de l'autre se feront un plaisir de vous envoyer au purgatoire aussi sec.


tempo
Zen

Messages : 2 178
Inscrit le 14/09/02
Ville : Grenoble (Echi)
Non connecté
  Posté le 20 August 2005 - 15 h 31 m 17 s


Le 20 août 2005 - 12 h 02, iraysyvalo a écrit :
Tain le modulo !! C'est space !!! Si je change TABSIZE, faut aussi changer le masque non ?? !!


c'est pas du joli et de l'efficace comme calcul de modulo, ca ?!? :D
(on utilise ce genre de truc pour faire des buffers circulaires DMA, etc...)

sinon, si tu changes le TABSIZE il faut bien sur changer le masque...
bon, ce masque peut aussi se calculer d'apres le TABSIZE
et pour etre certain que le TABSIZE soit en 2^p, on peut aussi faire plus propre dans le define:

    Code     
 1. 
 2. /* taille du tableau de valeurs: 2^16 */
 3. #define SINTABSIZE      (0x1&#6016;)
 4. 
 5. ...
 6. 
 7. /* calcule le masque pour modulo d'apres la taille du tableau */
 8. unsigned int modmask(unsigned int size){
 9.         unsigned int s;
10.         unsigned int mask;
11. 
12.         mask = 1;
13. 
14.         while(size&#622;){
15.                 size>>=1;
16.                 mask<<=1;
17.                 mask++;
18.         }
19. 
20.         return mask;
21. }


EDIT: apres (longue...) reflexion, c'est plus facile de faire:
mask = size-1
:D



Ah ouais, faut encore que je prenne du papier et un crayon pour verifier ton algo :P


y'en a qui sont vraiment de mauvaise foi. :Grrrr:
pour verifier l'algo, moi j'ai pris mon vi et mon gcc :lol:



EDIT : ton cast automatique pour i est un peu dangereux non ?

Heu, y'a pas de cast (meme caché) sur i... tout est en unsigned int...
le gros probleme est en cas de depassement du produit...

=> c'est vrai que si on utilise un TABSIZE en 2^16 (comme ci dessus...) le produit k*TABSIZE est deja aux limites d'un unsigned int (2^32) quand k=0xFFFF et que le produit avec Fs risque de provoquer un depassement...

Il faut donc limiter certaines valeurs, selon l'application:
Pour une appli type "sortie sur carte Audio", avec un echantillonage a 96KHz (elles font toutes ca, les cartes audio, de nos jours ???):
- Fe sur 17bits (on a une marge... 128KHz)
- Fs&#602;*Fe (Shannon...) donc Fs sur 16 bits (en audio... un signal a 64KHz !!!)
ca nous laisse 16bits pour le produit k*TABSIZE, donc un TABSIZE de 2^8 (256 echantillons...elle sont pas jolies les sinusoides generées avec ma table de 256 valeurs ???).

et si ca ne passe pas en unsigned int, il faut alors passer en long long, ce qui te permettra de justifier l'achat un nouveau PC avec un Athlon FX53(tiens, ca me fait penser que je suis en train d'essayer de faire un Linux From Scratch sur ma O2 en 'full 64bits'... sympa d'avoir une machine 64bits a la maison, meme si elle date de 1996...)

Et si on veut encore optimiser, il faut pas oublier que multiplier par 2, c'est faire un decalage d'un bit a gauche - tres rapide en terme CPU...- (et reciproquement diviser par 2, faire un shift right, la encore tres rapide...) donc on peut aussi envisager differement la multiplication par TABSIZE :jap: , voire meme utiliser une Fe de la forme 2^n ...

Tiens, si tu veux vraiment sortir ton papier et ton crayon, tu pourras aussi calculer la DHT (Distorsion Harmonique Totale) liée a l'utilisation de la table de valeurs :D


Message édité 2 fois, la dernière par tempo le 20 August 2005 - 15 h 40.


Petit_PimoOosE
rsqrtps & pshufb

Messages : 4 617
Inscrit le 15/06/03
Ville : Montréal
Non connecté
  Posté le 20 August 2005 - 16 h 23 m 54 s
Rha, merci tempo, c'est génial !

Sans procrastiner, je mets tout ça à l'oeuvre demain ou lundi.

Mais d'ores et déjà, puisque tu fais péter le modulo, moi je remplacerais toutes les divisions avec une constante en diviseur par des multiplications par l'inverse de ces constantes !



Huile de fraise.

tempo
Zen

Messages : 2 178
Inscrit le 14/09/02
Ville : Grenoble (Echi)
Non connecté
  Posté le 20 August 2005 - 19 h 03 m 03 s


Mais d'ores et déjà, puisque tu fais péter le modulo, moi je remplacerais toutes les divisions avec une constante en diviseur par des multiplications par l'inverse de ces constantes !


pas si vite !!!
Si tu veux calculer l'inverse d'un unsigned int, tu vas etre obligé de trimballer des float ou des doubles (donc passer par la FPU du processeur) dans tes multiplications...
Par contre si tu divise un unsigned int par un unsigned int, le CPU fait ca tout seul dans ses propres registres dans le domaine entier (meme un proco 8 bits sait faire des divisions entieres...) et c'est tres rapide.

Et comme je le disais precedement, vu que c'est parti pour travailler sur une table de valeurs de taille 2^p, la division peut se faire par un simple decalage a droite de p bits, encore bien plus rapide pour le CPU qu'une division entiere...

PS: en relisant le code que j'ai posté, je vois qu'il y a toujours des probleme dans les balises de code avec slash, anti-slash (pour les saut de ligne dans les printf) et la definition de la taille du buffer (il faut lire "1 decalé a gauche de 16 bits")




iraysyvalo
-

Messages : 9 647
Inscrit le 19/11/02
Ville : Lyon
Non connecté
  Posté le 20 August 2005 - 22 h 36 m 58 s

Je suis sceptique sur un point :

i = (Fs * k * SINTABSIZE) / Fe;

T'es pas forcement sur que c'est un int ... :chepa:




Pour un ban rapide et garanti sur ce forum, argumentez vos posts, dites simplement la verite, parlez de la realite et les leche-culs d'un cote et les maniaques du ban de l'autre se feront un plaisir de vous envoyer au purgatoire aussi sec.


1,2 | Suivant
Page genérée en 0.7583 secondes par RahForum 2.0 | Gzip off |  Stats |  Metaforums |  RSS
© 2004 Cerbere Systems.
Prix Matériel Informatique | Informatique Lyon | Informatique Grenoble | Informatique Annecy | Informatique Marseille | Informatique Bordeaux | Forum Informatique
ADSL | Actualité ADSL | Deligo | Appareil photo | Commande Au Volant
Creative Commons
Message Boards and Forums Directory