|
|
|
|
Bonjour,
Pour un projet, j'ai dans une grande chaine de caractère des données brutes d'un son Wave.
L'avantage de le mettre dans une chaine de caractère est que 1 ou 2 caractère (ou plus) donnent une note (8bits per sample ou 16bits per sample - un caractère fait 8 bits). Pour traiter ce son (en l'occurence, faire un effet d'echo), je dois prendre les valeurs, les atenuer, les sommer et les remettre en format caractère.
Je cherche donc comment utiliser les fonctions existantes ou quelle fonction ecrire pour passer de 1 ou 2 caractères à une valeur entière : en fait relire les bits mais au format entier et non caractère... Un cast suffit-il ?
Je dois faire cela sachant que les données à récupérer sont signées (-127 a 127 en 8 bits).
Je vous remercie... dites moi si il manque des détails pour répondre.
Colin
Configuration: Windows Vista Firefox 3.0.1
Répondre à fiddy
|
Bonjour
|
J'essaye de lire attentivement le message, j'oublie le titre...
|
Bonjour,
Colin, le samedi 17 janvier 2009 à 21:54:19 Un cast suffit-il ? Selon moi, oui. Un point devient flou au fur et à meusure des posts : Prenons un échantillon 8 bit signé, donc entre -128 et 127 : Je pense que cet échantillon n'est pas écrit en texte dans ta chaîne de caractères mais bien en données binaires. Une précision est nécessaire : L'échantillon de valeur 127 est-il écrit dans ta chaîne de caractère avec le caractère '1' puis le caractère '2' puis le '7', donc trois caractères et au format texte ou est-il codé sur un seul caractère dont la valeur est 127 ? (Comme dans un fichier .wav par exemple) 1) Format binaire : Il n'existe pas de base un type numérique codé sur 8 bits (peut-être le short short int, je n'en suis même pas sûr) Il est donc courant d'utiliser le type char comme un nombre en lui retirant toute sa valeur de caractère.
// On simplifie en définissant deux formats
typedef signed char Sample8; // type 8 bits pour la définition du Sample8
typedef signed short Sample16; // type 16 bits pour la définition du Sample16
// (éventuellement, lorsque que le code sera compilé sur un ordinateur ayant des tailles différentes pour les types de base, seuls ces deux typedef seront à changer.)
// Les échantillons : (Au format binaire)
char *pData; // Je suppose qu'il sont dedans, je ne sais pas comment ils sont obtenus.
// 8 bits par échantillon
if ( bitsPerSample == 8 )
{
// variable locale et temporaire pour éviter de mettre des casts partout
Sample8 *pSamples = (Sample8 *) pData; // Je change l'interprétation des données
unsigned int numSamples = dataSize / sizeof( Sample8 );
// Traitement
...
pSamples[i] = ...;
...
}
// 16 bits par échantillon
else if ( bitsPerSample == 16 )
{
Sample16 *pSamples = (Sample16 *) pData;
unsigned int numSamples = dataSize / sizeof( Sample16 ); // 2 octets par échantillons
...
pSamples[i] = ...;
...
}
L'usage de templates serait une très bonne idée Le type char est souvent utilisé parce qu'il fait 8 bits, l'ordinateur ne fait pas de différence entre un nombre et le caractère qu'il représente. (c'est d'ailleurs pour cela que l'on a 'A' - 32 == 'a' et que l'ordi le comprend très bien) 2) Format texte Si les échantillons sont au format texte, il manque une précision : admettons que j'ai la chaîne de caractères suivante "127127127", je peux très bien avoir entre 3 et 9 échantillons, comment le sait-on ? Pour repasser du format numérique au format texte il y a sprintf. Merci donc de préciser le format que tu as en entrée, binaire ou texte. Si tes données sont en Big Endian et que ton ordinateur ne l'est pas, oui il faudra transformer. M.
|
Oui, le passage en nombre flottant n'est forcément pas nécessaire.
|
Toi seul sais si les échantillons 8 bits qui te sont fournis sont signés ou non.
|
Ok, l'erreur vient du traitement en 8bits qui est non signé. L'attenuation se porte sur l'echelle 0 - 255 et non pas sur -127 - 127. Il faut donc que je traite le 8 bits specialement comme cela :
if ( projectFormat.wBitsPerSample == 8 )
{
// local temporary variable to avoid cast everywhere
Sample8 *pSamples = (Sample8 *) echoWaveData; // change data interpretation
// Traitment
// take care of 8 bits format
for(unsigned int i=0; i<DataSize+dp; i++)
pSamples[i] = (Sample8)((((int)pSamples[i]-127) * ap) + 127);
}
On calcule la valeur en soustrayant 127 et on la re-range en rajoutant les 17 (après traitement) |
C'est bon, j'ai trouvé ce qu'il me faut : voici la fonction qui ajoute de l'echo sur un son Wave stocké dans une chaîne de caractères :
void Echo(float ap_float_user, int dp_bytes_user)
{
// parameter attenuation : "ap"
// parameter delay : "dp"
if(projectFormat.wBitsPerSample!=8 && projectFormat.wBitsPerSample!=16)
{
ShowMessage("Sorry, format not supported for echo effect");
return;
}
float ap;
int dp;
ap = ap_float_user; // atenuation parameter
dp = dp_bytes_user * projectFormat.nChannels;
// delay in bytes, multiple of 2
// this value has to be multiple of nbChannels, here 2 or 1
char* echoWaveData = new char[DataSize+dp];
char* effectWaveData = new char[DataSize+dp];
// copy WaveData into echoWaveData with decalage
for(unsigned int i=0; i<DataSize+dp; i++)
{
if(i<(unsigned int)dp && projectFormat.wBitsPerSample == 8)
echoWaveData[i]= (Sample8)128; // silent 128
else
if(i<(unsigned int)dp && projectFormat.wBitsPerSample == 16)
echoWaveData[i]=(Sample16)0;
else
echoWaveData[i]= WaveData[i-dp];
}
// end of copy with decalage // OK 16bits, OK 8bits
// attenuation of echoWaveData
// 8 bits per sample
if ( projectFormat.wBitsPerSample == 8 )
{
// local temporary variable to avoid cast everywhere
Sample8 *pSamples = (Sample8 *) echoWaveData; // change data interpretation
// Traitment
// take care of 8 bits format
for(unsigned int i=0; i<DataSize+dp; i++)
pSamples[i] = (Sample8)((((int)pSamples[i]-127) * ap) + 127);
}
// 16 bits per sample
else
if ( projectFormat.wBitsPerSample == 16 )
{
Sample16 *pSamples = (Sample16 *) echoWaveData;
unsigned int numSamples = (DataSize+dp) / 2; // 2 bytes per sample
for(unsigned int i=0; i<numSamples; i++)
pSamples[i] = (Sample16)((float)pSamples[i] * ap);
}
// end attenuation // OK 16bits, OK 8bits
// addition of two signals
if ( projectFormat.wBitsPerSample == 8 )
{
// local variable to change interpretation
Sample8 *pSamplesOri = (Sample8 *) WaveData;
Sample8 *pSamplesEco = (Sample8 *) echoWaveData;
Sample8 *pSamplesEffect = (Sample8 *) effectWaveData;
// Traitement
// have to treat case of sum > 127
// we will add wave divide by 2
// and multiply it by 2 at the end
for(unsigned int i=0; i<DataSize+dp; i++)
{
// do not copy data from WaveDatz[DataSize_or_more]
// no existing data here
if(i>=DataSize)
{
pSamplesEffect[i] = (Sample8)((int)64 + (int)pSamplesEco[i]/2); // because we divide all by 2
}
else
{
pSamplesEffect[i] = (Sample8)((int)pSamplesOri[i]/2 + (int)pSamplesEco[i]/2);
}
}
// Now, amplification of signal by 1.5
// take care of 8 bits format
for(unsigned int i=0; i<DataSize+dp; i++)
pSamplesEffect[i] = (Sample8)((((int)pSamplesEffect[i]-127) * 1.4) + 127);
}
// 16 bits per sample
else
if ( projectFormat.wBitsPerSample == 16 )
{
Sample16 *pSamplesOri = (Sample16 *) WaveData;
Sample16 *pSamplesEco = (Sample16 *) echoWaveData;
Sample16 *pSamplesEffect = (Sample16 *) effectWaveData;
unsigned int numSamples = (DataSize+dp) / 2; // 2 octets par échantillons
for(unsigned int i=0; i<numSamples; i++)
{
// do not copy data from WaveDatz[DataSize_or_more]
// no existing data here
if(i>=DataSize/2)
pSamplesEffect[i] = (Sample16)((int)0 + (int)pSamplesEco[i]/2);
else
pSamplesEffect[i] = (Sample16)((int)pSamplesOri[i]/2 + (int)pSamplesEco[i]/2);
}
for(unsigned int i=0; i<numSamples; i++)
pSamplesEffect[i] = (Sample16)((float)pSamplesEffect[i] * 1.4);
}
// end addition of two signals
// 16 bits : OK
// 8 bits : not at all, data more than +/-127
// copying result into WaveData
if(WaveData)
delete[] WaveData;
WaveData = new char[DataSize+dp];
for(unsigned int i=0; i<DataSize+dp; i++)
WaveData[i] = effectWaveData[i];
// end copying
// destroying buffer
delete[] echoWaveData;
delete[] effectWaveData;
// reconfigure DataSize
DataSize = DataSize + dp;
}
Merci pour votre aide, ça m'a bien servi ! |