• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Générez des sons

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Maintenant que votre robot (grâce à la carte Arduino) sait se déplacer et éviter les obstacles, nous allons voir comment lui faire produire des sons.

Je vous arrête tout de suite, votre robot n’aura pas accès à une synthèse vocale perfectionnée, mais il pourra produire des sons simples et de petites mélodies.

Vous allez donc comprendre le principe électrique de production du son, et voir le matériel nécessaire pour le faire avec votre Arduino.

Vous verrez aussi la différence entre son et note, et comment l’on peut programmer une mélodie.

Enfin, si vous êtes sages, je vous fournirai une petite mélodie connue ;).

Créez un son avec un signal carré

Un petit point sur le son...

Le son

Le son est avant tout une onde. C’est-à-dire, une déformation d’un fluide élastique (l’eau ou l’air par exemple),  qui se propage en s’éloignant de sa source. Notre oreille est capable de percevoir des sons.

Pour vous donner une analogie (oui je suis assez friand de ça), imaginez une petite étendue d’eau plate et calme. Vous tapez à la surface de cette eau. La déformation que vous créez à l’endroit du choc, va se répandre en ondes concentriques (qui ont le même centre) sur toute la surface de l’eau. Si vous placez un bouchon avec un capteur de hauteur, vous réussirez à repérer la hauteur de l’onde (sa puissance) et la longueur de l’onde (sa fréquence)
Et bien c’est la même chose pour le son. 

Une corde de guitare qui vibre, va transmettre sa vibration à l’air. Cette vibration va se propager dans l’air jusqu’à vos oreilles (notre tympan est comme le bouchon mesureur) qui vont recevoir la vibration. Notre cerveau analyse le tout pour nous donner une traduction mentale de cette vibration.

Mais comment produire un son avec du matériel électronique ?

Il nous faut un matériel qui va pouvoir vibrer sur commande ! Pour cela on utilise un piezzo ou un petit haut-parleur.

Un petit haut-parleur et un Piezzo
Un petit haut-parleur et un Piezzo

L’un comme l’autre contient une partie vibrante. Quand je dis vibrante, c’est qu’elle peut passer dans une position puis dans l’autre, très vite. On pourrait parler de position haute et basse.

Comme les trains d’impulsion ?

(Dans le mille Cunégonde !) En fait, c’est justement grâce à un train d’impulsions que l’on va créer un son. Si l’on envoie un signal carré à un piezzo (ou à un haut parleur), il va vibrer en correspondance avec ce signal et produire un son.

Nous l’avons vu dans le cours d'initiation : pour qu’un son soit audible, il faut que la vibration se situe entre 20 Hz et 20000 Hz. Nous verrons que pour l’Arduino, nous n’avons pas besoin de telles extrémités de fréquences.

Voyons comment produire un signal carré.

Le signal carré

Nous l’avons dit, il s’agit de placer le piezzo à l’état haut puis à l’état bas en fonction d’une fréquence donnée. 

Prenons la fréquence de 440 Hz. Ça voudrait dire que le piezzo doit faire un aller-retour 440 fois par seconde. Pour calculer la période, c’est-à-dire le temps d’un aller-retour, on utilise la formule suivante :

 

$\(fréquence (Hz) =1/période (s)\)$

 

donc 1/440=0,002272 secondes soit 2272 microsecondes. Ceci pour un aller-retour. Donc un aller ou un retour donne 2272/2=1136 microsecondes.

Le signal carré doit être régulier, donc autant de temps en haut qu’en bas (contrairement à d’autres trains d’impulsions).

Voici comment se connecte un buzzer ou un piezzo sur l'Arduino :

Connexion d'un piezzo ou buzzer sur l'Arduino
Connexion d'un piezzo ou buzzer sur l'Arduino

Nous allons donc écrire un programme qui place le pin connecté au piezzo, à l’état haut pendant 1136 microsecondes et à l’état bas pendant 1136 microsecondes :

void setup() {
  pinMode(3,OUTPUT); //on prépare le pin 3 en mode sortie
}
void loop() {
    digitalWrite(3,0); // état bas
    delayMicroseconds(1136); //on attend 1136 milli-secondes
    digitalWrite(3,1); // état haut
    delayMicroseconds(1136); // on attend 1136 millisecondes
}

Vous devriez entendre un son sortir du piezzo ou du haut-parleur.

Si vous mesurez ce son avec un accordeur (matériel pour musicien qui aime jouer juste), il vous indiquera que votre son vibre à une fréquence de 434,3 Hz. Nous ne sommes pas loin des 440 Hz. La différence s'explique par le temps que chaque fonction met à s'exécuter. En effet, les fonctions  digitalWrite(),  delayMicroseconds() et  loop() prennent un tout petit peu de temps pour s'exécuter, elles ralentissent donc légèrement le processus.

Ce n'est pas grave en soi dans notre cas, la justesse du son n'est pas notre priorité pour le moment.

En musique, plus la fréquence est élévée (donc la période basse), plus le son est aigu. Donc si on fait varier le délai d'attente on obtient des sons plus ou moins aigus.

Voici un programme qui crée un petit son de laser (à l'ancienne) :

int p=10; // on prépare une variable pour la période
void setup() {
  pinMode(3,OUTPUT); //on prépare le pin en mode sortie
}
void loop() {
    p++; // on incémente p à chaque boucle de loop();
    if (p>500){ // teste la limite de p
      p=10; // on le remet à 10
      delay(500); // on attend un peu
    }
    digitalWrite(3,0); // état bas
    delayMicroseconds(p); //on attend p milli-secondes
    digitalWrite(3,1); // état haut
    delayMicroseconds(p); // on attend p millisecondes
}

Le son part d'une fréquence haute (car la période est petite, de 10 micro-secondes) vers une fréquence basse (de période plus grande, de 500 micro-secondes), et enchaîne très rapidement ces sons, d'où l'effet du son du laser (comme on peut l'entendre dans des films ou des jeux).

Exercice : Je vous propose d'essayer par vous-mêmes de créer le son du saut genre Donkey-Kong. Il vous suffit de faire l'inverse, c'est à dire de partir d'une fréquence basse vers une fréquence haute... (le son produit une sorte de "boiiiing" numérique).
Retrouvez la solution dans la partie Annexe du cours ! 

C'est très bien tout ça, mais ça ne nous dit pas comment faire des mélodies ! 

En effet, pour la mélodie, il faut connaître un peu le principe des tons (non Lukas, rien à voir avec la pêche !).

Le ton

Chaque note que joue un musicien est à une fréquence précise. En effet, tout à l'heure,  en produisant un son à 440 Hz, nous avons joué un LA !

La gamme européenne comprend 12 notes. Chacune d'elle est à une fréquence précise. Voici un exemple de tableau des fréquences :

Note

Fréquence

Do

65 Hz

Do# ou Réb

69 Hz

74 Hz

Ré# ou Mib

78 Hz

Mi

83 Hz

Fa

87 Hz

Fa# ou Solb

93 Hz

Sol

98 Hz

Sol# ou Lab

104 Hz

La

110 Hz

La# ou Sib

117 Hz

Si

123 Hz

Le # signifie dièse (et pas hashtag ) et le b signifie bémol. Ce sont des altérations des notes de la gamme de base (Do, Ré, Mi, Fa, Sol, La, Si). Le dièse augmente la fréquence de la note et le bémol la diminue. Ainsi un La # est situé en fréquence entre le La et le Si (ce qui est vérifié par le tableau).

Mais il n'y a pas que 12 notes sur un piano ?!

(Je vois que vous êtes musicienne Cunégonde...). Chaque touche du clavier d'un piano est en effet une note, et il y en a bien plus que 12 ! En fait une fois qu'on a passé toutes les notes, on recommence avec le do, mais sur une fréquence plus élevée (plus aiguë).

Chaque groupe de note (de Do à Si) est appelé une octave. Et il y a un truc facile à retenir, c'est que pour passer une note d'une octave à l'octave supérieure, il suffit de multiplier sa fréquence par 2.

Prenons l'exemple du la : 

  • Octave 0 : La à 110 Hz

  • Octave 1 : La à 220 Hz

  • Octave 2 : La à 440 Hz (on retrouve bien notre La de tout à l'heure !)

Donc pour jouer une note dans une octave supérieure, il nous suffit d'appliquer la formule suivante :

fréquence=(fréquence à l'octave 1) x (2 puissance octave)

Pour trouver notre La 440 Hz on pouvait faire 110x2^2=440.

Retenons donc deux choses :

  • Les fréquences des notes de la gamme sont fixes.

  • Pour passer d'une octave à la supérieure, on multiplie la fréquence par 2.

Mais produire une mélodie ne repose pas que sur la fréquence...

Le rythme

Si vous chantonnez au clair de la lune, vous verrez que le son des 4 première syllabes est dit régulièrement (au/clair/de/la) et que les syllabes de lune sont dites plus longuement (luuuuuuu/neeeeeeee).

Tout simplement parce qu'on tient plus longtemps la note. Si l'on veut faire une mélodie, il nous faut donc pouvoir tenir la fréquence de la note un certain temps, puis passer à la note suivante.

Une mélodie est donc une succession de notes, qui ont une durée (un rythme) et une octave. En programmation,  on s'imagine assez vite un tableau du genre :

int note[3]={ton, rythme, octave};

qui nous permettrait de stocker une note. Et pour en stocker plusieurs, et bien on ferait un tableau à deux dimensions :

int notes[nbMaxNotes][3];

N'oublions pas que pour déclarer un tableau, il faut en connaître les limites (ou au moins en fixer les limites).

Alors pour que notre mélodie ne soit pas totalement illisible, nous allons créer des constantes qui reprennent la valeur des fréquences. On peut utiliser la directive #define TON frequence  ou déclarer avec la forme proposée par l'IDE Arduino : 

const char TON=frequence;

Je choisis la seconde solution et je vous donne le code. Il est à placer au début du programme :

const char DON = 65;
const char DOD = 69;
const char REN = 74;
const char RED = 78;
const char MIN = 83;
const char FAN = 87;
const char FAD = 93;
const char SON = 98;
const char SOD = 104;
const char LAN = 110;
const char LAD = 117;
const char SIN = 123;

J'ai choisi de noter DON le DO Normal pour avoir le même nombre de lettre partout. Donc pour comprendre, on utilise les deux premières lettres de la note et on ajoute N pour normal ou D pour dièse.

Pour la durée, nous pouvons choisir un code simple : 

Si on imagine que le temps (c'est ce qui est mesuré quand vos tapez du pied en écoutant de la musique) est le code 2, on a :

  • code 1 : la note dure la moitié d'un temps (croche en musique)

  • code 2 : la note dure 1 temps (noire en musique) donc 2 croches

  • code 4 : la note dure 2 temps (blanche en musique) donc 4 croches

  • code 8 : la note dure 4 temps (ronde en musique) donc 8 croches

Du coup, voici comment stocker "Au clair de la lune" dans un tableau :

int auClair[11][3]={
    DON, 2, 2,
    DON, 2, 2,
    DON, 2, 2,
    REN, 2, 2,
    MIN, 4, 2,
    REN, 4, 2,
    DON, 2, 2,
    MIN, 2, 2,
    REN, 2, 2,
    REN, 2, 2,
    DON, 8, 2
}

Voilà, notre mélodie est stockée (enfin le début seulement).

Cool, et on en fait quoi maintenant ?

Et bien, il nous faut créer un interpréteur musical. C'est à dire un programme qui va transformer ce tableau en musique !

Pour créer cet interpréteur, il nous faut prévoir le moment auquel la note doit changer !

Alors pour réaliser ceci il vous faut pouvoir gérer le temps ! En effet, comment allez-vous gérer le passage d'une note à l'autre si vous ne savez pas si un temps suffisant est écoulé ?

Alors j'en profite (car c'est surtout fait pour vous apprendre des choses ce cours) pour vous montrer une méthode très pratique pour gérer le temps : les fonctions  millis()  et micros().

Gérez le temps qui passe

Notre carte Arduino est cadencée à 16 MHz, soit 16 000 000 d'actions machine effectuées par seconde. Il existe dans l'Arduino, des variables spéciales qui comptent le temps qui passe. Nous pouvons avoir accès à ces données de plusieurs façons : soit par les fonctions toutes prêtes, soit en allant chercher dans l'utilisation de registres (mais vous n'en êtes pas là).

Nous allons utiliser deux fonctions toutes prêtes :

  • La fonction  millis(), qui ne prend pas d'argument et qui nous retourne le temps écoulé en millisecondes depuis le dernier "reset" de l'Arduino

  • La fonction  micros(), qui ne prend pas d'argument et qui nous retourne le temps écoulé en micro-seconde depuis le dernier "reset" de l'Arduino.

Si vous deviez agir à la microseconde près, la fonction micro() serait un peu trop lente, mais pour la musique, c'est largement suffisant !

Alors l'idée est simple : on compte le temps qui passe. Si le temps écoulé dépasse la durée (le rythme) de la note, on fait changer la note, sinon, on joue la note.

Voici un morceau de code qui affiche un point sur la console toutes les secondes :

unsigned long tempsDebut; // variable pour stocker le temps de départ
unsigned long tempsActuel;// variable pour stocker le le temps qui s'écoule
unsigned long duree;// variable pour stocker la duree d'attente
void setup() {
  Serial.begin(9600);// on initialise la communication série
  tempsDebut = millis(); // on initialise le temps de départ sur le temps Arduino
  duree = 1000; // on initialise la durée d'attente à 1 seconde
}
void loop() {
  tempsActuel = millis(); //on stocke le temps Arduino
  if (tempsActuel - tempsDebut >= duree) { // on teste si la durée est dépassée
    Serial.print("."); // on écrit un point sur la console
    tempsDebut = tempsActuel; //on remet le temps de départ au temps Arduino
  }
}

Mais quel est l'intérêt, vu qu'on peut utiliser la fonctiondelay()  ?!

(Vous me décevez Cunégonde, je pensais que vous devineriez !)

La fonction  delay()  met le programme en pause, donc aucune autre action n'est possible ! En revanche, avec le programme ci-dessus, on peut demander à l'Arduino de faire autre chose en attendant que le moment d'afficher le point arrive. Le test que nous réalisons avec le comptage du temps nous permet donc de libérer le programme tant que le moment n'est pas encore arrivé.

Avec ce code vous avez créé une sorte de timer.

Et pour être encore plus efficaces, voyons la fonction de son créée pour l'Arduino !

La fonction tone()

Nous avons vu tout à l'heure comment générer un signal carré qui produit un son avec un haut-parleur. 

Notre programme fonctionnait bien, certes, mais il lui manquait une chose importante : si je joue un son, je ne peux pas faire autre chose !

Et bien, grâce aux timers dont nous avons parlé à l'instant, les ingénieurs de l'Arduino on créé la fonction tone()

Cette fonction permet de générer un signal carré correspondant à la fréquence voulue. Mais comme ils utilisent un timer (donc une fonction interne à l'Arduino qui compte le temps qui passe) pour faire vibrer à la bonne fréquence, entre chaque état (haut ou bas) du piezzo, l'Arduino est libre d'exécuter une autre tâche.

Donc si on exécute la fonction  tone() dès le début du programme (dans le  setup()  par exemple) nous pourrions ensuite réaliser toutes les actions voulues, avec un son permanent dans nos haut-parleurs (je parle bien d'un son unique, et non de mélodie).

Alors comment utiliser cette fonction ;) ? Et bien là encore, c'est très simple :

  • On doit mettre le pin concerné en mode OUTPUT.

  • On appelle ensuite la fonction soit en utilisant tone(pin, fréquence)  ou  tone(pin, fréquence, durée). La valeur de durée est en millisecondes.

  • Si on ne met pas de durée, le son continue à l'infini. On peut l'arrêter en faisant appel à la fonction noTone(pin) , qui va stopper le son sur le pin concerné.

Je vous laisse modifier les programmes "laser" et  "saut" de tout à l'heure en utilisant la fonction  tone(). En testant un peu les possibles, vous pourrez rapidement avoir une bibliothèque de bruitages à ajouter à votre robot !

Et si nous créions notre interpréteur ?

L'interpréteur de mélodie

"Voici venu le temps des rires et des chants" (Casimir)

Résumons ce que doit contenir notre interpréteur :

  • La liste des fréquences de base ;

  • Un tableau qui stocke la mélodie ;

  • Un moyen d'attendre un moment défini entre chaque note ;

  • Une fonction qui renvoie la bonne fréquence en fonction de la fréquence de base et de l'octave.

Nous allons décider que l'attente entre chaque note est d'une demi-seconde.

Voici tout d'abord le programme "simple" d'interpréteur. Il ne permet pas de réaliser d'autres actions car nous utilisons la fonction delay()  :

// les constantes des fréquences de base
const char DON = 65;
const char DOD = 69;
const char REN = 74;
const char RED = 78;
const char MIN = 83;
const char FAN = 87;
const char FAD = 93;
const char SON = 98;
const char SOD = 104;
const char LAN = 110;
const char LAD = 117;
const char SIN = 123;
//Le tableau pour la mélodie
char auClair[11][3]={
    DON, 2, 2,
    DON, 2, 2,
    DON, 2, 2,
    REN, 2, 2,
    MIN, 4, 2,
    REN, 4, 2,
    DON, 2, 2,
    MIN, 2, 2,
    REN, 2, 2,
    REN, 2, 2,
    DON, 8, 2
};
int dureeBase=500; //on fixe la durée de basse à 500 millisecondes

void setup(){
  pinMode(3,OUTPUT);//on met le pin 3 en mode OUTPUT
}

void loop(){
  for (int n=0;n<11;n++){ // boucle de lecture du tableau
    char note = auClair[n][0]; // on récupère la fréquence de base dans le tableau
    char octave= auClair[n][2]; // on récupère l'octave
    int frequence=freqNote(note,octave); //on calcule la bonne fréquence
    int duree=dureeBase*auClair[n][1];// on multiplie la duree de base par la valeur de duree du tableau
    
    tone (3,frequence); //on joue la note
    delay(duree);
    noTone(3);//on arrete la note
    delay(10);// petite attente pour avoir l'impression d'attaquer la note
  }
}

// fonction de calcul de la fréquence en fonction de l'octave
int freqNote(int fb,int oc){
  return fb*pow(2,oc);
}

Vous noterez au passage l'utilisation de la fonction mathématique :  pow(nombre1, nombre2)  qui renvoie  nombre1  à la puissance  nombre2.

Vous pouvez modifier le nombre mis dansdureeBase , vous verrez que la musique accélère ou ralentit.

Et voici maintenant la même chose mais en mode multitâches :

// les constantes des fréquences de base
const char DON = 65;
const char DOD = 69;
const char REN = 74;
const char RED = 78;
const char MIN = 83;
const char FAN = 87;
const char FAD = 93;
const char SON = 98;
const char SOD = 104;
const char LAN = 110;
const char LAD = 117;
const char SIN = 123;
//Le tableau pour la mélodie
char auClair[11][3]={
    DON, 2, 2,
    DON, 2, 2,
    DON, 2, 2,
    REN, 2, 2,
    MIN, 4, 2,
    REN, 4, 2,
    DON, 2, 2,
    MIN, 2, 2,
    REN, 2, 2,
    REN, 2, 2,
    DON, 8, 2
};
int dureeBase=500; //on fixe la durée de basse à 500 millisecondes
unsigned long tempsDep; // variable pour le temps de départ
unsigned long tempsAct; // variable pour le temps actuel
int duree; //variable pour la durée d'attente de la note en cours
int n=0; // position dans le tableau de mélodie

void setup(){
  pinMode(3,OUTPUT);//on met le pin 3 en mode OUTPUT
  tempsDep=millis(); // on initialise le temps de départ au temps Arduino
  duree=0; //on initialise l'attente à 0
}

void loop(){
  tempsAct=millis(); // on récupère le temps Arduino
  if (tempsAct-tempsDep>=duree){ // on regarde si le temps est écoulé
    noTone(3); // on stoppe le son
    delay(10); // délay pour l'attaque du son
    joueNote(auClair[n][0],auClair[n][2]); // on appelle la fonction qui joue la bonne note
    duree=dureeBase*auClair[n][1]; // on fixe la duree d'attente
    tempsDep=tempsAct; //on initialise le temps de départ
    n++; // on incrémente la position dans le tableau
    if (n>10) // on teste si on dépasse la fin du tableau
      n=0; // on revient au début du tableau
  }
  // on peut placer ici du code à excécuter en attendant
  // il faut bien-sûr ne pas utiliser la fonction delay() ;)
}

// fonction de calcul de la fréquence en fonction de l'octave
void joueNote(int nt,int oc){
  tone(3,nt*pow(2,oc)); //on joue la note à la bonne fréquence
}

Il est tout à fait possible de placer l'ensemble du bloc lié à la mélodie dans une fonction pour plus de clarté dans la boucle  loop()

Voici une petite dédicace à notre ami Lukas. Le programme joue une mélodie (connue ;) ). On peut tout à fait exécuter d'autres actions dans la  loop() pendant ce temps à condition qu'elles n'utilisent pas de  delay().

/*
Petit clin d'oeil mr Lukas
Nanomaître 2015
*/
// constantes de fréquences
#define DON 33
#define REB 35
#define REN 37
#define MIB 39
#define MIN 41
#define FAN 44
#define SOB 46
#define SON 49
#define LAB 52
#define LAN 55
#define SIB 58
#define SIN 62

// tableau pour la mélodie
int part[50][3] = {
  DON, 2, 100,
  DON, 2, 100,
  DON, 2, 100,
  LAB, 1, 75,
  MIB, 2, 25,
  DON, 2, 100,
  LAB, 1, 75,
  MIB, 2, 25,
  DON, 2, 200,
  SON, 2, 100,
  SON, 2, 100,
  SON, 2, 100,
  LAB, 2, 75,
  MIB, 2, 25,
  SIN, 1, 100,
  LAB, 1, 75,
  MIB, 2, 25,
  DON, 2, 200,
  DON, 3, 100,
  DON, 2, 100,
  DON, 3, 25,
  SIN, 2, 25,
  DON, 3, 25,
  0, 0, 75,
  SIN, 2, 50,
  SIB, 2, 100,
  SIB, 1, 100,
  SON, 2, 25,
  SOB, 2, 25,
  SON, 2, 25,
  0, 0, 75,
  SOB, 2, 50,
  FAN, 2, 100,
  SON, 1, 100,
  SIB, 1, 100,
  SON, 1, 75,
  MIB, 2, 25,
  DON, 2, 100,
  LAB, 1, 75,
  MIB, 2, 25,
  DON, 2, 200,
  -1
};
int pinSon = 3; // pin de connection du haut-parleur
int tempo = 120; // variable du tempo
int duree = 0; // variable de durée de note
unsigned long tempsDep; // variable de temps de départ
int p = 0; // variable de position dans le tableau de mélodie
void setup() {
  pinMode(pinSon,OUTPUT); 
  tempsDep = millis(); // initialisation du temps de départ
}

void loop() {
  joue(); // appel de la fonction pour jouer la mélodie
}

//fonction de lecture de la mélodie
void joue() {
  unsigned long tempsAct = millis();
  if (tempsAct - tempsDep >= duree) {
    if (part[p][0] != -1) { // test de fin de tableau
      noTone(pinSon);
      delay(10); // délai pour l'attaque
      // la fréquence est calculée en fonction des fréquences de base
      // et de l'octave définit dans le tableau
      int frequence = part[p][0] * pow(2, part[p][1] + 1);
      // la durée de la note est calculée comme en musique
      duree = 1000 / (tempo / 60) * (float(part[p][2]) / 100);
      if (frequence > 0) {
        tone (pinSon, frequence);
      }
      p++; //incrémentation de la position dans le tableau
    }
    else { 
      noTone(pinSon);
      p=0;// retour au début du tableau
      duree=1000;// attente avant répétition
    }
    tempsDep=tempsAct;
  }
}

J'ai utilisé des  #define pour les constantes, et j'ai pris les valeurs de fréquences plus petites.

Du fait de la complexité de la mélodie, j'ai codé le tempo et les durées de notes sur 100.

J'espère que les fans apprécieront  ;).

En résumé

Vous avez appris dans ce chapitre :

  • À produire des sons avec votre Arduino (bruitages et mélodies) soit en produisant un signal carré, soit en utilisant la fonction tone() 

  • À gérer le défilement du temps en utilisant les compteurs  millis()  et  micros() .

  • À créer un interpréteur musical à l'aide de tableaux de quelques fonctions.

Vous avez maintenant, à l'issue de cette partie, largement de quoi créer un robot mobile, autonome et musical !!!

Si nous passions à des modes de communication avancés ?

Exemple de certificat de réussite
Exemple de certificat de réussite