eXma » Diskutieren » Computer und Technik
Startseite - Veranstaltungen - Mitglieder - Suche
Vollständige Version anzeigen: Java byte array manipulation
sn3ek
hi,

ich kriege irgendwie seit Tagen keinen klaren Kopf bei dem ganzen Audiozeuch - folgendes:

Ich habe eine WAV Datei, erzeuge einen audiostream und trenne die beiden Kanäle (Stereo file) in jeweils ein byte array. Soweit so gut funktioniert auch super. Nun will ich die einzelnen Bytes manipulieren, was ja auch kein Problem darstellt. Nur bekomme ich dabei ein Rauschen.

Ein Sample besteht ja nun aus 4 Byte - 2 Byte für Links und 2 Byte für rechts.

L L R R

und ich will auf die 2 Byte des Linken kanals ein Gain (Lautstärke) multiplizieren und auf den rechten - was aber unterschiedliche Verstärkungsfaktoren sind. Mir wurde nun gesagt ich müsse die 2 Bytes aus dem Kanal in ein Short überführen, es manipulieren und wieder in die 2 Bytes packen. Nur funktioniert das nicht so richtig.

Details auf der StackOverflow Seite


wicked
Warum nimmst du nicht irgendeinen Wrapper der dir gleich short/int/whatever für die jeweiligen samples liefert und dir das ins korrekte format zurückschreibt?
sn3ek
Zitat(wicked @ 03 Sep 2009, 16:06)
Warum nimmst du nicht irgendeinen Wrapper der dir gleich short/int/whatever für die jeweiligen samples liefert und dir das ins korrekte format zurückschreibt?
*


Hast du Vorschläge für mich? Ich bin nämlich mit meinem Latein am Ende.
JanLo
Beachte das Java kein unsigned kennt, also byte geht von -127 bis +128, short von -32767 bis 32768 das Nervt immer wenn man mit byte-arrays was machen will.
wicked
Sowas mal angeguckt (von wegen signed/unsigned problematik + beispielcode)?

Bin sonst in c++, nicht in java, unterwegs - deswegen kann ich nur vermuten das es unter java sicher genug bibliotheken für multimedia-zeug gibt.
sn3ek
Zitat(JanL. @ 03 Sep 2009, 16:15)
Beachte das Java kein unsigned kennt, also byte geht von -127 bis +128, short von -32767 bis 32768 das Nervt immer wenn man mit byte-arrays was machen will.
*


Jap das hab ich schon mit beachtet. Aber da ich ja z.b. bei gain von 0.5 die Amplituden jedes einzelnen Bytes verringere und somit NIE über den Bereich drüber kommen würde, ist das auch nicht der Fall. Habe das schon probiert.
stth
mit c wäre das nicht passiert smile.gif

ne mal im ernst...

CODE
byte arr[] = getTheDataSonstewoHer();
int i = 0;
while(i*4 < arr.length)
{
 // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
 // L
 int gegaehnt = ((((int)arr[i * 4 + 1]) << 8) | arr[i*4] ) * gaehn;
 arr[i*4] = (byte)(gegaehnt & 0xff);
 arr[i*4 +1] = (byte)((gegaehnt & 0xff00) >> 8);
 
 // R
 gegaehnt = ((((int)arr[i * 4 + 3]) << 8) + arr[i*4 + 2] ) * gaehn;
 arr[i*4 +2] = (byte)(gegaehnt & 0xff);
 arr[i*4 +3] = (byte)((gegaehnt & 0xff00) >> 8);

 i++;
}


denk bitte dran, dass du nur ganzzahlige verstärkungen machen kannst. ansonsten hilft dir nur der weg über byte -> int -> float -> rechnen -> int -> byte

€ paar klammern geeckt und verschoben
€2: auf solaris gehört
solaris
Zitat(stth @ 03 Sep 2009, 18:30)
mit c wäre das nicht passiert smile.gif

ne mal im ernst...

CODE
byte arr = getTheDataSonstewoHer();
int i = 0;
while(i*4 < arr.length())
{
 // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
 // L
 int gegaehnt = (((int)arr[i * 4 + 1]) << 8 | arr[i*4] ) * gaehn;
 arr[i*4] = (byte)(gegaehnt & 0xff);
 arr[i*4 +1] = (byte)((gegaehnt & 0xff00) >> 8);
 
 // R
 gegaehnt = (((int)arr[i * 4 + 3]) << 8 + arr[i*4 + 2] ) * gaehn;
 arr[i*4 +2] = (byte)(gegaehnt & 0xff);
 arr[i*4 +3] = (byte)((gegaehnt & 0xff00) >> 8);
}


denk bitte dran, dass du nur ganzzahlige verstärkungen machen kannst. ansonsten hilft dir nur der weg über byte -> int -> float -> rechnen -> int -> byte
*


Ich kann mich irren, aber hast Du in dem Code vergessen, das i zu inkrementieren?
stth
Zitat(solaris @ 03 Sep 2009, 18:34)
Ich kann mich irren, aber hast Du in dem Code vergessen, das i zu inkrementieren?
*
jep... aber in foren geposteter quelltext ist grundsätzlich im browser geschrieben und hat noch nie nen compiler von innen gesehen.... syntaxfehler sind also sicher auch noch drinne
stth
achduscheiße... der macht bei der umwandlung ja mist

mal probieren, wie man java zum bitmanipulator macht....
sn3ek
Zitat(stth @ 03 Sep 2009, 18:30)
mit c wäre das nicht passiert smile.gif

ne mal im ernst...

CODE
byte arr[] = getTheDataSonstewoHer();
int i = 0;
while(i*4 < arr.length)
{
 // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
 // L
 int gegaehnt = ((((int)arr[i * 4 + 1]) << 8) | arr[i*4] ) * gaehn;
 arr[i*4] = (byte)(gegaehnt & 0xff);
 arr[i*4 +1] = (byte)((gegaehnt & 0xff00) >> 8);
 
 // R
 gegaehnt = ((((int)arr[i * 4 + 3]) << 8) + arr[i*4 + 2] ) * gaehn;
 arr[i*4 +2] = (byte)(gegaehnt & 0xff);
 arr[i*4 +3] = (byte)((gegaehnt & 0xff00) >> 8);

 i++;
}


denk bitte dran, dass du nur ganzzahlige verstärkungen machen kannst. ansonsten hilft dir nur der weg über byte -> int -> float -> rechnen -> int -> byte

€ paar klammern geeckt und verschoben
€2: auf solaris gehört
*



Mein Gain Control liegt zwischen 0 und irgendwas --> hängt vom Delay ab und das ist double demzufolge brauch ich die umwandlung byte--> int -> float --> rechnen --> int --> byte

hast du vllt noch nen herz für mich und kannst mir das an nem codesnippet zeigen? bin irgendwie nach 2 wochen durchweg coden nicht mehr wirklich allein dazu fähig.. aber am montag muss das programm stehen... bin also für jede hilfe dankbar!!! smile.gif
sn3ek
So ich hab jetzt den code in mein Programm umgesetzt und es funktioniert nicht. Ich habe zwar den Sound der normal ist und zusätzlich das doofe rauschen oder zischen oder wie auch immer. Und das hatte ich auch schon vorher. Das ist auch wenn ich es mit 1 multipliziere wie hier zu sehen:

CODE
int z = 0;
 while(z*4 < Constants.getBufferlength())
 {
  // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
  // L
  int gegaehnt = ((((int)arrayLeft[z * 4 + 1]) << 8) | arrayLeft[z*4] ) * 1;
  arrayLeft[z*4 +0] = (byte)(gegaehnt & 0xff);
  arrayLeft[z*4 +1] = (byte)((gegaehnt & 0xff00) >> 8);
 
  // R
  gegaehnt = ((((int)arrayRight[z * 4 + 3]) << 8) + arrayRight[z*4 + 2] ) * 0;
  arrayRight[z*4 +2] = (byte)(gegaehnt & 0xff);
  arrayRight[z*4 +3] = (byte)((gegaehnt & 0xff00) >> 8);

  z++;
 }
stth
CODE
 byte arr[] = {
   1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, -50, 1, -50, 1, 0, 0, 0, 0};
 int i = 0;
 double gaehn = 1.5;
 while (i * 4 < arr.length)
 {
  // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
  // L
  int gegaehnt = (((((int) arr[i * 4 + 1]) << 8) & 0xFF00) | ((int) (arr[i * 4]) & 0xFF));
  gegaehnt = (int)((double)gegaehnt * gaehn);
  arr[i * 4] = (byte)(gegaehnt | ((gegaehnt | 0x80) > 0 ? 0xffffff00 : 0));
  arr[i * 4 + 1] = (byte)((gegaehnt >> 8) | ((gegaehnt | 0x8000) > 0 ? 0xffffff00 : 0));

  // R
  gegaehnt = (((((int) arr[i * 4 + 3]) << 8) & 0xFF00) | ((int) (arr[i * 4 + 2]) & 0xFF));
  gegaehnt = (int)((double)gegaehnt * gaehn);
  arr[i * 4 + 2] = (byte)(gegaehnt | ((gegaehnt | 0x80) > 0 ? 0xffffff00 : 0));
  arr[i * 4 + 3] = (byte)((gegaehnt >> 8) | ((gegaehnt | 0x8000) > 0 ? 0xffffff00 : 0));

  i++;
 }


auf den ersten blick geht das. es sind ein paar unnecessary casts drinne und die rückwandlung geht u.u. einfacher. teste aber erstmal, obs tut in allen lebenslagen wink.gif
stth
Zitat(sn3ek @ 03 Sep 2009, 19:14)
So ich hab jetzt den code in mein Programm umgesetzt und es funktioniert nicht. Ich habe zwar den Sound der normal ist und zusätzlich das doofe rauschen oder zischen oder wie auch immer. Und das hatte ich auch schon vorher. Das ist auch wenn ich es mit 1 multipliziere wie hier zu sehen:

CODE
int z = 0;
 while(z*4 < Constants.getBufferlength())
 {
  // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
  // L
  int gegaehnt = ((((int)arrayLeft[z * 4 + 1]) << 8) | arrayLeft[z*4] ) * 1;
  arrayLeft[z*4 +0] = (byte)(gegaehnt & 0xff);
  arrayLeft[z*4 +1] = (byte)((gegaehnt & 0xff00) >> 8);
 
  // R
  gegaehnt = ((((int)arrayRight[z * 4 + 3]) << 8) + arrayRight[z*4 + 2] ) * 0;
  arrayRight[z*4 +2] = (byte)(gegaehnt & 0xff);
  arrayRight[z*4 +3] = (byte)((gegaehnt & 0xff00) >> 8);

  z++;
 }

*



du hast da zwo arrays. dann wird das sicherlich nicht passen mit den indizes. ich hatte mich an die
LLRRLLRRLLRRLLRR - codierung in einem array aus dem ersten post gehalten
sn3ek
ja das hab ich jetzt angepasst also habs dorthin geschoben wo Left and Right wieder zurückgeschrieben werden ins Complete Array. ich teste das mal

//edit nein es geht nicht. jetzt höre ich nichtmal mehr ton. nur noch solches geflattertes knistern und zwar sehr laut. Sowohl Big als auch Little Endian

CODE
float gaehn = 0.5f;
 int q =0;
  while (q * 4 < Constants.getBufferlength())
  {
   // annahme little endian, für big muss +0 und +1 sowie +2 und +3 getauscht werden
   // L
   int gegaehnt = (((((int) arrayComplete[q * 4 + 1]) << 8) & 0xFF00) | ((int) (arrayComplete[q * 4]) & 0xFF));
   gegaehnt = (int)((double)gegaehnt * gaehn);
   arrayComplete[q * 4] = (byte)(gegaehnt | ((gegaehnt | 0x80) > 0 ? 0xffffff00 : 0));
   arrayComplete[q * 4 + 1] = (byte)((gegaehnt >> 8) | ((gegaehnt | 0x8000) > 0 ? 0xffffff00 : 0));

   // R
   gegaehnt = (((((int) arrayComplete[q * 4 + 3]) << 8) & 0xFF00) | ((int) (arrayComplete[q * 4 + 2]) & 0xFF));
   gegaehnt = (int)((double)gegaehnt * gaehn);
   arrayComplete[q * 4 + 2] = (byte)(gegaehnt | ((gegaehnt | 0x80) > 0 ? 0xffffff00 : 0));
   arrayComplete[q * 4 + 3] = (byte)((gegaehnt >> 8) | ((gegaehnt | 0x8000) > 0 ? 0xffffff00 : 0));

   q++;
  }


Wofür das?

gegaehnt = (int)((double)gegaehnt * gaehn);
stth
schlecht...

letzeres ist die verstärkung... akt. wert in double, malnehmen, zurück nach int
wenn float gain = 0.5f
gegaehnt = (int)((float)gegaehnt * gaehn);

€: hast du da ne möglichkeit den signalgang mal anzuzeigen? damit du sehen kannst, was da passiert? also so wie als bild malen?
sn3ek
Zitat(stth @ 03 Sep 2009, 19:36)
schlecht...

letzeres ist die verstärkung...  akt. wert in double, malnehmen, zurück nach int
wenn float gain = 0.5f
gegaehnt = (int)((float)gegaehnt * gaehn);
*


Also vllt kams ja falsch an: ich will lediglich die lautstärke der einzelnen kanäle manipulieren. Auf das gesamte ist das kein Problem, dafür gibts die Gain control in der API. Aber wie ich das auf die einzelnen kanäle abwälzen soll ist mir unklar...
stth
Zitat(sn3ek @ 03 Sep 2009, 19:38)
Aber wie ich das auf die einzelnen kanäle abwälzen soll ist mir unklar...
*

na linksgaehn und rechtsgaehn statt gaehn verwenden wink.gif

mich verwirrt noch, dass du da keinen graden ton mehr rausbekommst


€: grade nochmal nachgerechnet... meinen zahlen nach kommts binär richtig raus. frage ist, ob die vllt anders codieren, um es leichter rechnen zu können das würde die verfälschung/rauschen
sn3ek
Zitat(stth @ 03 Sep 2009, 19:55)
na linksgaehn und rechtsgaehn statt gaehn verwenden wink.gif

mich verwirrt noch, dass du da keinen graden ton mehr rausbekommst
€: grade nochmal nachgerechnet... meinen zahlen nach kommts binär richtig raus. frage ist, ob die vllt anders codieren, um es leichter rechnen zu können das würde die verfälschung/rauschen
*


Ich hab keine Ahnung, ich kann mir das rauschen auch nicht erklären.
stth
Zitat(sn3ek @ 04 Sep 2009, 00:52)
Ich hab keine Ahnung, ich kann mir das rauschen auch nicht erklären.
*

heißt das rauschen eigentlich, dass nur rauschen ist, oder einfach nur ein rauschen drunter liegt?

fall 2teres: da kanns daran liegen, dass die signal-quantisierung logaritmisch ist und wir das signal linear verstärken. das geht natürlich schief. müsste man mal die wav-spec lesen.

fall1teres: was sagt denn das java doc der gain control api über die codierung? €: hast du da mal in den code geguckt, wenn der offen ist?
sn3ek
Zitat(stth @ 04 Sep 2009, 07:45)
heißt das rauschen eigentlich, dass nur rauschen ist, oder einfach nur ein rauschen drunter liegt?

fall 2teres: da kanns daran liegen, dass die signal-quantisierung logaritmisch ist und wir das signal linear verstärken. das geht natürlich schief. müsste man mal die wav-spec lesen.

fall1teres: was sagt denn das java doc der gain control api über die codierung? €: hast du da mal in den code geguckt, wenn der offen ist?
*



es liegt ein rauschen drunter.

ich hab mir die openjdk heruntergeladen aber keine sound api gefunden (die da mit drin sein müsste). das gain control wird jedenfalls logarithmisch angesteuert. die gain control für die komplette line liegt zwischen -79 und +6 db. Aber wie sollte ich das denn auf den kanal umwelzen?ä
sn3ek
Wow geil es funktioniert hab jetzt das gemacht - also Rauschunterdrückung ist jetzt drin, ist noch nicht komplett weg. Aber da muss ich noch bisschen herumspielen vllt krieg ich das noch hin.

CODE
for(int c=0; c<Constants.getBufferlength()-4; c+=4) {
  arrayLeft[c] = (byte) Math.min(Math.max((arrayLeft[c]*(Math.exp(leftGain*2)-1)/(Math.E-1)), -128), 127);
  arrayLeft[c+1] = (byte) Math.min(Math.max((arrayLeft[c+1]*(Math.exp(leftGain*2)-1)/(Math.E-1)), -128), 127);
 
  arrayRight[c+2] = (byte) Math.min(Math.max((arrayRight[c+2]*(Math.exp(leftGain*2)-1)/(Math.E-1)),-128),127);
  arrayRight[c+3] = (byte) Math.min(Math.max((arrayRight[c+3]*(Math.exp(rightGain*2)-1)/(Math.E-1)), -128), 127);
 }
sn3ek
Zitat(sn3ek @ 04 Sep 2009, 10:34)
Wow geil es funktioniert hab jetzt das gemacht - also Rauschunterdrückung ist jetzt drin, ist noch nicht komplett weg. Aber da muss ich noch bisschen herumspielen vllt krieg ich das noch hin.

CODE
for(int c=0; c<Constants.getBufferlength()-4; c+=4) {
  arrayLeft[c] = (byte) Math.min(Math.max((arrayLeft[c]*(Math.exp(leftGain*2)-1)/(Math.E-1)), -128), 127);
  arrayLeft[c+1] = (byte) Math.min(Math.max((arrayLeft[c+1]*(Math.exp(leftGain*2)-1)/(Math.E-1)), -128), 127);
 
  arrayRight[c+2] = (byte) Math.min(Math.max((arrayRight[c+2]*(Math.exp(leftGain*2)-1)/(Math.E-1)),-128),127);
  arrayRight[c+3] = (byte) Math.min(Math.max((arrayRight[c+3]*(Math.exp(rightGain*2)-1)/(Math.E-1)), -128), 127);
 }

*


// edit

mein chef meint dass das falsch wäre die pegelanpassung mit logarithmischen werten zu füttern. WTF?! ich seh echt nicht mehr durch

Polygon
Zitat(sn3ek @ 04 Sep 2009, 12:14)
// edit

mein chef meint dass das falsch wäre die pegelanpassung mit logarithmischen werten zu füttern. WTF?! ich seh echt nicht mehr durch
*


Und was soll richtig sein? Is doch ansich piepegal ob man das linear oder logarithmisch macht, kommt doch aufs gleiche raus.
sn3ek
Zitat(Polygon @ 04 Sep 2009, 12:57)
Und was soll richtig sein? Is doch ansich piepegal ob man das linear oder logarithmisch macht, kommt doch aufs gleiche raus.
*


Ich kanns mir nicht erklären aber kann es sein dass java ein problem damit hat dass man die signed bytes nicht einfach bearbeiten kann? oder woran liegt das dass es bei einem unsigned char aka byte in c++ funktioniert mit pegelanpassung?
Polygon
Zitat(sn3ek @ 04 Sep 2009, 15:07)
Ich kanns mir nicht erklären aber kann es sein dass java ein problem damit hat dass man die signed bytes nicht einfach bearbeiten kann? oder woran liegt das dass es bei einem unsigned char aka byte in c++ funktioniert mit pegelanpassung?
*

Hast du nicht gerade gesagt, dass es funktioniert? Und was soll die obige Aussage mit logarithmisch und nicht logarithmisch zu tun haben?
sn3ek
Ich hab nicht gesagt das es funktioniert ich habe gesagt dass das rauschen leicht unterdrückt wird. Die aussage kommt von meinem chef und nicht von mir.