Concatenation de fichiers wav

Soyez le premier à donner votre avis sur cette source.

Vue 14 422 fois - Téléchargée 628 fois

Description

Une unité offrant une fonction "Concatener", qui permet d'assembler en un seul fichier WAV plusieurs fichiers WAV donnés... J'ai fait ça pour une personne qui me l'a demandé, mais je pense que ça peut servir à d'autres !!

Dans le ZIP, y a une petite "démo" pour voir comment utiliser la fonction... Vous verrez, c'est on ne peut plus simple !!

MISE A JOUR :
Après le comentaire de bgK, fallait bien que je modifie un peu mon source :
Les fichiers qui ne sont pas des fichiers WAVE PCM sont ignorés, ainsi que ceux qui n'ont pas le même format audio que le premier fichier enregistré

Source / Exemple :


Voici le nouveau contenu de l'unité uConcatWAV :
unit uConcatWAV;

interface
uses SysUtils, Classes, Dialogs;

//Déclaration des différents headers contenus dans un fichier WAV...
//Allez faire une recherche sur www.wotsit.org pour des informations précises
//sur le format WAV ! (ou sur google : "WAVE File Format specification" !)
type
  THeaderRIFF = Packed Record
    ID    : Array[1..4]Of Char;
    Taille: Cardinal;
    Format: Array[1..4]Of Char;
  end;

  THeaderFormat = Packed Record
    ID    : Array[1..4]Of Char;
    Taille: Cardinal;
    Format: WORD;
    Mode  : WORD;
    SRate : Cardinal; //=Sample Rate
    BRate : Cardinal; //=Byte Rate
    Align : WORD;
    BPS   : WORD;     //Bits Per Sample
  //FACULTATIF (INEXISTANT POUR LE FORMAT PCM)\\
  //TailleExtra: WORD;\\
  //Extras: Array Of Byte;\\
  end;

  THeaderData = Packed Record
    ID    : Array[1..4]Of Char;
    Taille: Cardinal;
//Inutile ici Datas: Array Of Byte;
  end;

  TWAVE = Packed Record //Ajouté pour avoir un format de référence servant
    RIFF: THeaderRIFF;  //à ignorer les fichiers dont le format diffère
    Fmt : THeaderFormat;
    Data: THeaderData;
  end;

function Concatener(Liste: PAnsiChar; Sortie: String): String;

implementation

function WAV_Valid(Fichier: String): Boolean;
var WAV: TFileStream;
    RIFF: Array[1..4]Of Char;
    WAVEfmt: Array[1..8]Of Char;
    PCM: WORD;
begin

  Result := False;

  Try
    WAV := TFileStream.Create(Fichier, fmOpenRead);

    WAV.Read(RIFF, 4);
    If RIFF <> 'RIFF' then Exit;

    WAV.Seek(8, soFromBeginning);
    WAV.Read(WAVEfmt, 8); //Lecture de "WAVE" et "fmt " en même temps
    If WAVEfmt <> 'WAVEfmt ' then
      begin
        WAV.Free;
        Exit;
      end;

    WAV.Seek(20, soFromBeginning);
    WAV.Read(PCM, 2);
    If PCM <> 1 then
      begin
        WAV.Free;
        Exit;
      end;

  except
    On Exception do Exit;
  end;

  WAV.Free;

  Result := True;

end;

function FormatOK(Ref, Fich: TWAVE): Boolean;
begin

  Result := (Ref.Fmt.Format = Fich.Fmt.Format) and (Ref.Fmt.Mode  = Fich.Fmt.Mode ) and
            (Ref.Fmt.SRate  = Fich.Fmt.SRate ) and (Ref.Fmt.BRate = Fich.Fmt.BRate) and
            (Ref.Fmt.Align  = Fich.Fmt.Align ) and (Ref.Fmt.BPS   = Fich.Fmt.BPS  );

end;

function Concatener(Liste: PAnsiChar; Sortie: String): String;
var Lst: TStringList;
    Source, Dest: TFileStream;
    Temp: TMemoryStream;
    i: Integer;
    Fichier, Ref: TWAVE;
begin

  Result := Sortie;

  Try
    Try
      Lst := TStringList.Create;
      Lst.SetText(Liste);

      Temp := TMemoryStream.Create;
      Dest := TFileStream.Create(Sortie, fmCreate);

      for i := 0 to Lst.Count - 1 do
       If WAV_Valid(Lst[i]) then
        begin
          Try
            Source := TFileStream.Create(Lst[i], fmOpenRead);

            Source.Read(Fichier.RIFF, SizeOf(THeaderRIFF));
            Source.Read(Fichier.Fmt, SizeOf(THeaderFormat));
            Source.Read(Fichier.Data, SizeOf(THeaderData));

            if i = 0 then
              begin
                Ref.RIFF := Fichier.RIFF;
                Ref.Fmt  := Fichier.Fmt;
                Ref.Data := Fichier.Data;
              end;

            If FormatOK(Ref, Fichier) then
              Temp.CopyFrom(Source, Fichier.Data.Taille);

          finally
            Source.Free;
          end;
        end;

      Ref.RIFF.Taille := 36 + Temp.Size;
      Ref.Data.Taille := Temp.Size;

      Dest.Write(Ref.RIFF, SizeOf(Ref.RIFF));
      Dest.Write(Ref.Fmt, SizeOf(Ref.Fmt));
      Dest.Write(Ref.Data, SizeOf(Ref.Data));
      Dest.CopyFrom(Temp, 0);

    except
      On Exception Do
        begin
          Result := 'Erreur';
          Exit;
        end;
    end;
  finally
    Lst.Free;
    temp.Free;
    Dest.Free;
  end;

end;

end.

Conclusion :


Je crois que c'est tout, à part une petite limitation :
sachant que je ne sais pas faire de "resampling", il faut que tous les fichiers choisis soient au même format audio (par exemple : PCM, 22050Hz, Stéréo, 16 bits par sample) pour que le fichier de sortie soit correct !

Bonne prog' à tous !

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
71
Date d'inscription
mercredi 8 janvier 2003
Statut
Membre
Dernière intervention
24 février 2012

Salut! Bestio: Si tu veux, tu peux ajouter des fonctionalités intérressantes à ton projet, comme convertir la fréquence ou le format d'un sample avant la fusion... Le savais-tu: Pour que les samples se fusionnent correctement, il faut qu'il est la même valeur d'amplitude à l'endroit de la fusion, sinon, on peut obtienir un craquement à l'écoute de cet position... Une solution est d'ajouter fade-out à la fin du sample et fade-in au début... Si tu es intérressé, contacte-moi! Autre chose, j'ai découvert une erreur dans mon tuto -(merci Steph!). Il sagit de la fonction de conversion 16bits non-signés -> signés. Voici la correction (il manquait le signe = dans la condition):

donnee:=donnee+32768;
IF(donnee>=65536)THEN donnee:=donnee-65536;

à+
Messages postés
833
Date d'inscription
dimanche 6 janvier 2002
Statut
Membre
Dernière intervention
3 novembre 2005
1
delphifan a eu la gentillesse de m'envoyer un message expliquant notre petite discussion sur la taille du header !! Voici son message qui explique le pourquoi du moment ! ;o)

"la valeur 36 est juste, et c'est pas etonnant, car si on regarde bien la définition de bloc RIff
on trouve que ce dèrnier contient les informations suivantes:
- 4 octets pour les caractères ascii "riff".ensuite vient les 4octets qui détermine la longueur totale en octet de la suite de du fichier et non pas la taille total du fichier
càd riff.taille= la taille total de fichier -8 octets(4octets pour les caractères "riff"+4octets pour la taille )
autrement dit,c'est la taille de fichier apartir de l'octet numéro 8jusqu'à la fin du ficchier d'ou 44-8=36.
donc riff.taille =36+taille de données est juste.rien ne vient de hasard."

Vala vala... Merci Delphifan ! =0)
Et bonne prog' à tous !
Bestiol.
Messages postés
6
Date d'inscription
lundi 22 mars 2004
Statut
Membre
Dernière intervention
15 mai 2004

tout d'abord merci pour les efforts que vous avez fait pour faire réussir ce programme ,ton idée ma beaucoup apprécier,elle est simple et au même temps avantageuse sauf que vous avez travaillez
que sur les formats pcm sans prendre en compte le cas
ou data ="fact" .
comme les autres commentaires ,bien que le header est sur 44 alors que ça marche sur 36,c'est ettonant n'est ce pas !j'ai essaie ce programme avec C++builder mais il m'a poser une exception de violation d'adresse au niveau de l'instruction :Temp->CopyFrom(Source, Fichier.Data.Taille);voulez vous bien m'aider pour résoudre ce problème réponder moi le plutot possible,et merci.
Messages postés
71
Date d'inscription
mercredi 8 janvier 2003
Statut
Membre
Dernière intervention
24 février 2012

Merci! Ben, c'est bien parti là! J'ai déjà le ripper au point!
Il manque plus que le MP3 (encodage direct de l'extraction).
Toutes les sources seront dans mon tuto! C'est cadeau! à+
Messages postés
833
Date d'inscription
dimanche 6 janvier 2002
Statut
Membre
Dernière intervention
3 novembre 2005
1
Salut Sub0 !!

Pour le Header, j'ai vérifié, c'est bien 44 octets !! Ce qui est bizarre, c'est que ça marche également avec 36 dans mon programme !!

Bonne chance pour ton projet de prog' !
Afficher les 13 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.