001package kramann.info.MODULO;
002
003import processing.core.*; 
004import processing.data.*; 
005import processing.event.*; 
006import processing.opengl.*; 
007
008import java.util.Random; 
009import java.util.concurrent.Executors; 
010import java.util.concurrent.ScheduledExecutorService; 
011import java.util.concurrent.TimeUnit; 
012import java.util.concurrent.Executors; 
013import java.util.concurrent.ScheduledExecutorService; 
014import java.util.concurrent.TimeUnit; 
015import android.media.AudioTrack; 
016import android.media.AudioFormat; 
017import android.media.AudioManager; 
018import android.media.AudioRecord; 
019import android.media.MediaRecorder; 
020import processing.core.*; 
021import java.io.*; 
022
023import java.util.HashMap; 
024import java.util.ArrayList; 
025import java.io.File; 
026import java.io.BufferedReader; 
027import java.io.PrintWriter; 
028import java.io.InputStream; 
029import java.io.OutputStream; 
030import java.io.IOException; 
031
032public class MODULO extends PApplet {
033
034/**
035 *  <h4>MODULO_1003_STEREO</h4>
036 *  <br/>
037 *  Copyright (C) 2019 Guido Kramann<br/>
038 *  kramann@th-brandenburg.de<br/>
039 *  http://www.kramann.info<br/>
040 *  <br/>
041 *  <p>  
042 *  This program is free software: you can redistribute it and/or modify
043 *  it under the terms of the GNU General Public License as published by
044 *  the Free Software Foundation, either version 3 of the License, or
045 *  (at your option) any later version.
046 *
047 *  </p>
048 *  <p>
049 *  This program is distributed in the hope that it will be useful,
050 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
051 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
052 *  GNU General Public License for more details.
053 *  </p>
054 *  <p>
055 *  You should have received a copy of the GNU General Public License
056 *  along with this program (gpl.html).  If not, see http://www.gnu.org/licenses/.
057 *  </p>
058 */
059
060float YOFF=0.0f;
061
062int MODUS = 1;
063
064PFont font;
065
066String[] text = {
067    "1234567890",
068    "abc",
069    "#### ####"
070};
071TEXT testtext;
072
073Spieler spieler_schwarz,spieler_weiss;
074
075//Rekorder rekorder = new Rekorder(86,1525);
076//Rekorder rekorder = new Rekorder(86,286);
077
078boolean WARTUNG = false;
079
080//009: rhythmisierte Fassung:
081//Die Dauer eines Zuges wird festgelegt.
082//Der Wechsel erfolgt immer nach einer Periode, wenn gezogen wurde.
083//Wurde nicht gezogen, werden Strafpunkte abgezogen und erst wieder wenn eine weitere Periode voll ist gewechselt.
084long PULSMILLIS = 200;  //... so viele Millisekunden dauert Pulse
085long PULSEPROZUG = 12;  //... so viele Pulse dauert ein Zug (und auch eine gespielte Phrase)
086//int STRAFPUNKTE = 50;
087int STRAFPUNKTE = 0; //ENTSPANNT!
088
089
090
091//FEHLER: Das Entfernen von Steinen wird nicht richtig behandelt!!!!
092
093//Punkte: werden aktualisiert, wenn die Pfade aktualisiert werden!
094int PUNKTE_WEISS = 0;
095int PUNKTE_SCHWARZ = 0;
096
097//rot wenn schwarz dran ist,
098//gr\u00fcn wenn weiss dran ist
099
100//nur gerade Bewegungen auf Feld erlaubt
101//nur eigene Farbe darf bewegt werden, wenn man dran ist
102
103int[] ROT = {255,100,100};
104int[] GRUEN = {100,255,100};
105
106ArrayList<int[]> schwarzerpfad = null;
107ArrayList<int[]> weisserpfad = null;
108
109
110float LINIENDICKE;
111
112String[] kartentypen;
113Karte[] karte;
114Karte quelleweiss;
115Karte quelleschwarz;
116float kantex;
117float kantey;
118Spielfeld spielfeld;
119Spiel spiel;
120Spiel testspiel;  //Derzeit nur zum laden und speichern von Spielzust\u00e4nden
121Spiel testspiel2;  //Zwischenspeichern
122
123Zugkontrolle zugkontrolle;
124
125Karte dragged = null;
126int FELDBREITE = 101;
127int RANDBREITE = (6 + 3)*2;
128
129float X_PUNKTE_WEISS;
130float X_PUNKTE_SCHWARZ;
131float PUNKTE_TEXTSIZE;
132
133Mysoundplayer msp;
134Wav wav;
135
136TEXT OK;
137public void showOK()
138{
139   if(OK!=null)
140   {
141       //OK.show();
142   }
143}
144
145public void setup()
146{
147   orientation(LANDSCAPE);
148   font = createFont("DejaVuSansMono.ttf",32.0f);
149   textFont(font);
150   
151   
152   int[] MIDI = {33,35,37,38,40,42,44,  47,49,  52,54,56,  59,61,63,  66,68,  71,  75,  80,  87};  //Anzahl=21
153   //Sound
154   println("midi min = "+freq2mid(55));
155   println("midi max = "+freq2mid(1760));
156   
157//     msp = new Mysoundplayer(this,2);
158     msp = new Mysoundplayer(this,4);  //Jetzt 4 Kan\u00e4le
159     int midimin = 33;
160//     int midimax = 93;
161     int midimax = 87;
162     int[] skala = new int[midimax-midimin+1];
163     for(int i=midimin;i<=midimax;i++)
164         skala[i-midimin] = i;
165     float laute1 = 0.1f;
166     float laute2 = 0.2f;
167     float pan   = 0.5f;
168//     msp.ladeKanal(0, "/home/fhbstud/system/samples/89_marimbaneu/normal",skala,laute,pan-0.1);       
169//     msp.ladeKanal(0, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up106",MIDI,laute,pan-0.1);
170//     msp.ladeKanal(0, "data/t35",skala,laute,pan-0.1);
171
172     msp.ladeKanalStereo(0, "t35",MIDI,laute1,pan);  //ohne pan, da ja nur ein Satz Soundfiles
173//     msp.ladeKanalStereo(0, "t35",MIDI,laute1,pan-0.1);
174//     msp.ladeKanalStereo(1, "t36",MIDI,laute1,pan-0.1);     
175
176//     msp.saveKanal(int kanal, String pfad, int[] midiskala)     
177//     msp.ladeKanal(0, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up106",skala,5.0,pan);
178//     msp.saveKanal(0, "data/t35", skala);     
179     
180//     msp.ladeKanal(1, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up98",MIDI,laute,pan+0.1);     
181//     msp.ladeKanalStereo(2, "t21",MIDI,laute2,pan+0.1);     
182//     msp.ladeKanalStereo(3, "t22",MIDI,laute2,pan+0.1);     
183
184//     msp.ladeKanal(1, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up98",skala,5.0,pan);     
185//     msp.saveKanal(1, "data/t36", skala);     
186
187
188//     msp.ladeKanal(0, "/home/fhbstud/system/samples/89_marimbaneu/normal",skala,laute,pan-0.1);       
189//     msp.ladeKanal(1, "/home/fhbstud/system/samples/89_marimbaneu/normal",skala,laute,pan+0.1);
190   // ladeMonostimmen(int[] skala, String[] ordner, String prefix)
191   
192//   msp.ladeMonostimmen(MIDI, new String[] {"a7","a8"}, "ton");
193//   msp.ladeMonostimmen(MIDI, new String[] {"a7","t35"}, new float[] {1.0,0.2}, "ton");
194   
195   //Ende Sound
196  
197    float TEILER = 9.0f;
198//    size(1280,720);
199//    size(1100,720);
200//    size(1100,640);
201    //size(640,640);
202//    size(1280,640);
203    
204    testtext = new TEXT(text,800,800);
205    OK = new TEXT(new String[] {"O.K."},width,height/10);
206    
207    LINIENDICKE = height/300.0f;
208    strokeWeight(LINIENDICKE);
209    
210//    float bsoll = 1280.0f;
211//    float hsoll = 720.0f;
212    float bsoll = width;
213    float hsoll = height;
214    float bist  = width;
215    float hist  = height;
216
217    if(width/height < 1280.0f/720.0f)
218    {
219        float XXX = (width/(1280.0f/720.0f))/height;
220        
221        hsoll = height*XXX;
222        hist  = height*XXX;
223    }
224
225    YOFF = (height-hsoll)*0.5f;
226    
227    float height = hsoll;
228/*    
229    if(hist/bist > hsoll/bsoll)
230    {
231         float faktor = (hsoll/bsoll) / (hist/bist);
232         
233         float bb = width;
234//         float kx = (5.0f/13.0f)*(height*faktor)/(float)TEILER;                   
235         float kx = (5.0f/13.0f)*(height)/(float)TEILER;                   
236         while((int)floor(bb/kx) < FELDBREITE+RANDBREITE)
237             FELDBREITE-=2;
238                  
239         scale(1.0f,faktor);
240    }
241    else if(hist/bist < hsoll/bsoll)
242    {
243         float faktor = (hsoll/bsoll) / (hist/bist);
244         
245//         float bb = width/faktor;
246         float bb = width;
247         float kx = (5.0f/13.0f)*height/(float)TEILER;                   
248         while((int)floor(bb/kx) < FELDBREITE+RANDBREITE)
249             FELDBREITE-=2;
250
251         scale(1.0f/faktor,1.0);
252         
253    }
254*/
255
256
257    
258    strokeWeight(height*0.002f);
259
260    kantex = (5.0f/13.0f)*height/TEILER;
261println("-A-");    
262while((FELDBREITE+RANDBREITE)*kantex>width)
263    FELDBREITE-=2;
264println(FELDBREITE);
265//int RANDBREITE = (6 + 3)*2;
266println("-B-");    
267
268X_PUNKTE_WEISS = 6.0f*kantex+kantex*0.1f;
269X_PUNKTE_SCHWARZ = width - 9.0f*kantex+kantex*0.3f;
270PUNKTE_TEXTSIZE =3.0f;
271textSize(PUNKTE_TEXTSIZE);
272while(textWidth("999999")<2.8f*kantex)
273{
274    PUNKTE_TEXTSIZE+=0.2f;
275    textSize(PUNKTE_TEXTSIZE);
276}
277while(textWidth("999999")>2.8f*kantex)
278{
279    PUNKTE_TEXTSIZE-=0.2f;
280    textSize(PUNKTE_TEXTSIZE);
281}
282    
283println("-C-");    
284    
285    kantey = height/TEILER;
286    kartentypen = loadStrings("kartentypen.txt");
287println("-D-");    
288    
289    frameRate(30);
290//    spielfeld = new Spielfeld(kantex,kantey,21,9);
291    spielfeld = new Spielfeld(kantex,kantey,FELDBREITE,9);
292println("-E-");    
293    
294    karte = new Karte[9*6*2];
295println("-F-");    
296    
297    for(int i=0;i<karte.length/2;i++)
298    {
299       float x = (i/9)*kantex;
300       float y = (i%9)*kantey;
301       karte[i] = new Karte(true,i%9,1+i/9,x,y,(5.0f/13.0f)*height/TEILER,height/TEILER);
302    }
303println("-G-");    
304    
305    quelleweiss = new Karte(true,9,0,kantex*7,kantey*4,(5.0f/13.0f)*height/TEILER,height/TEILER);
306    quelleschwarz = new Karte(false,9,7,width-kantex*7-kantex,kantey*4,(5.0f/13.0f)*height/TEILER,height/TEILER);
307println("-H-");    
308    
309    for(int i=0;i<karte.length/2;i++)
310    {
311       float x = (i/9)*kantex;
312       float y = (i%9)*kantey;
313       karte[i+karte.length/2] = new Karte(false,i%9,1+i/9,width-x-kantex,height-y-kantey,(5.0f/13.0f)*height/TEILER,height/TEILER);
314    }        
315    
316    spiel = new Spiel(spielfeld,karte,quelleweiss,quelleschwarz);
317    testspiel = new Spiel(spielfeld,karte,quelleweiss,quelleschwarz);
318    testspiel2 = new Spiel(spielfeld,karte,quelleweiss,quelleschwarz);
319    
320    zugkontrolle = new Zugkontrolle(PULSMILLIS,PULSEPROZUG,spielfeld,STRAFPUNKTE);
321
322    
323    //Automatische Spieler starten:
324//AUSKOMMENTIEREN BEI SPIEl ZU ZWEIT:    
325//    spieler_weiss = new Spieler(true,spielfeld,spiel,testspiel,testspiel2);
326//    spieler_schwarz = new Spieler(false,spielfeld,spiel,testspiel,testspiel2);
327}
328
329public void draw()
330{
331    strokeWeight(LINIENDICKE);
332    background(70,70,70);
333
334    if(MODUS==0)
335    {
336         testtext.show(0,0,255,255,255,0,0,0);
337         return;
338    }
339    
340    spielfeld.draw();
341    
342//X_PUNKTE_WEISS = 6.0f*kantex;
343//X_PUNKTE_SCHWARZ = width - 9.0f*kantex;
344//PUNKTE_TEXTSIZE =3.0f;
345    textSize(PUNKTE_TEXTSIZE);
346    fill(255);
347    text(""+PUNKTE_WEISS,X_PUNKTE_WEISS,kantey);
348    fill(0);
349    text(""+PUNKTE_SCHWARZ,X_PUNKTE_SCHWARZ,kantey);
350    text("\u00a9 G.K.",X_PUNKTE_SCHWARZ,height-kantey);
351    
352    for(int i=0;i<karte.length;i++)
353       karte[i].draw(null);
354
355
356    if(spielfeld.WEISS_IST_DRAN && spielfeld.TIMER_WEISS_IST_DRAN)
357        quelleweiss.draw(GRUEN); //Korona
358    else    
359        quelleweiss.draw(null); //Korona
360        
361        
362    if(!spielfeld.WEISS_IST_DRAN && !spielfeld.TIMER_WEISS_IST_DRAN)
363        quelleschwarz.draw(ROT);
364    else
365        quelleschwarz.draw(null);
366    
367    
368    //Pfade zeigen:  (siehe mouseReleased() ganz unten!!!!)
369    //  schwarzerpfad = spiel.findeNaechstenpfadWeiss();
370    //  weisserpfad = spiel.findeNaechstenpfadWeiss();
371    stroke(GRUEN[0],GRUEN[1],GRUEN[2]);
372    if(weisserpfad!=null && weisserpfad.size()>1)
373    {
374         ArrayList<int[]> pfad = weisserpfad;
375         for(int i=0;i<pfad.size()-1;i++)
376         {
377               int ii1 = pfad.get(i)[0];
378               int kk1 = pfad.get(i)[1];
379               int ii2 = pfad.get(i+1)[0];
380               int kk2 = pfad.get(i+1)[1];
381               float x1 = spielfeld.kkoord[ii1][kk1];
382               float y1 = spielfeld.ikoord[ii1][kk1];
383               float x2 = spielfeld.kkoord[ii2][kk2];
384               float y2 = spielfeld.ikoord[ii2][kk2];
385               line(x1,y1,x2,y2);
386         }
387    }
388    
389    stroke(ROT[0],ROT[1],ROT[2]);
390    if(schwarzerpfad!=null && schwarzerpfad.size()>1)
391    {
392         ArrayList<int[]> pfad = schwarzerpfad;
393         for(int i=0;i<pfad.size()-1;i++)
394         {
395               int ii1 = pfad.get(i)[0];
396               int kk1 = pfad.get(i)[1];
397               int ii2 = pfad.get(i+1)[0];
398               int kk2 = pfad.get(i+1)[1];
399               float x1 = spielfeld.kkoord[ii1][kk1]+LINIENDICKE*0.5f;
400               float y1 = spielfeld.ikoord[ii1][kk1]+LINIENDICKE*0.5f;
401               float x2 = spielfeld.kkoord[ii2][kk2]+LINIENDICKE*0.5f;
402               float y2 = spielfeld.ikoord[ii2][kk2]+LINIENDICKE*0.5f;
403               line(x1,y1,x2,y2);
404         }
405    }
406    
407    
408    if(dragged!=null)
409    {
410          dragged.set(mouseX,mouseY);
411          dragged.draw(null);
412    }      
413}
414
415public void mousePressed()
416{
417     if(dragged==null)
418     {
419          //ABBRUCH, wenn falsche Farbe!
420          for(int i=0;i<karte.length;i++)
421              if(karte[i].mausHatEs(mouseX,mouseY) && (spielfeld.WEISS_IST_DRAN==spiel.istWeiss(karte[i].ID) && spielfeld.WEISS_IST_DRAN==spielfeld.TIMER_WEISS_IST_DRAN))
422                  dragged = karte[i];
423          if(quelleweiss.mausHatEs(mouseX,mouseY) && (spielfeld.WEISS_IST_DRAN==true && spielfeld.TIMER_WEISS_IST_DRAN==true))        
424                  dragged = quelleweiss;
425          if(quelleschwarz.mausHatEs(mouseX,mouseY) && (spielfeld.WEISS_IST_DRAN==false && spielfeld.TIMER_WEISS_IST_DRAN==false))        
426                  dragged = quelleschwarz;
427                  
428                  
429          if(dragged!=null)
430              dragged.war_auf_feld = false;
431              
432          if(dragged!=null && spielfeld.istInSpielfeld(dragged))
433          {
434               int kk = spielfeld.getNextXindex(dragged);
435               int ii = spielfeld.getNextYindex(dragged);
436               
437               if(spielfeld.istFrei(ii,kk)==false)
438               {
439                   spielfeld.matrix[ii][kk] = null;
440                   dragged.war_auf_feld = true;
441               }
442          }
443     }
444}
445
446public void updateSpielzustand()
447{
448      //Nur bei erfolgreicher Aktion n\u00f6tig:      
449      //Anzeige der aktuellen Belegung:
450      //*********** Das hier m\u00fc\u00dfte auch bei automatischen Z\u00fcgen ausgef\u00fchrt werden: *******
451      spiel.uebernehmeZustand();
452      if(WARTUNG == true)      
453          spiel.zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld();
454      schwarzerpfad = spiel.findeNaechstenpfadSchwarz();
455      weisserpfad = spiel.findeNaechstenpfadWeiss();
456      //****************      
457      
458      //Punkte aktualisieren:
459      if(spielfeld.WEISS_IST_DRAN)
460          PUNKTE_WEISS += spiel.berechnePunkte(weisserpfad);
461      if(!spielfeld.WEISS_IST_DRAN)
462          PUNKTE_SCHWARZ += spiel.berechnePunkte(schwarzerpfad);
463
464     if(WARTUNG)     
465      println("W:"+PUNKTE_WEISS+" S:"+PUNKTE_SCHWARZ);    
466}
467
468public void mouseReleased()
469{
470      float mx = mouseX;
471      float my = mouseY;
472      if(dragged!=null)
473      {
474          if(spielfeld.istInSpielfeld(dragged)) //wenn Figur auf Spielfeld gezogen wurde
475          {
476               float xx = spielfeld.getNextX(dragged);
477               float yy = spielfeld.getNextY(dragged);
478               int kk = spielfeld.getNextXindex(dragged);
479               int ii = spielfeld.getNextYindex(dragged);
480               
481               if(spielfeld.istFrei(ii,kk)) //Wenn Zielplatz auf Spielfeld frei ist
482               {
483                   //ERFOLGREICHER ZUG!
484                   dragged.setNeu(xx,yy);
485                   spielfeld.matrix[ii][kk] = dragged;
486                   dragged.xspielfeld=xx;
487                   dragged.yspielfeld=yy;
488                   
489                   updateSpielzustand(); //Nur bei erfolgreichen Z\u00fcgen Updtae n\u00f6tig!
490                   
491                   //JETZT IST DER ANDERE DRAN!
492                   spielfeld.WEISS_IST_DRAN = !spielfeld.WEISS_IST_DRAN;
493               }
494               else
495               {
496                  if(dragged.war_auf_feld == true)
497                  {
498                   dragged.x = dragged.xspielfeld;
499                   dragged.y = dragged.yspielfeld;
500                   kk = spielfeld.getNextXindex(dragged);
501                   ii = spielfeld.getNextYindex(dragged);
502                   spielfeld.matrix[ii][kk] = dragged;
503                   
504                   
505                  }
506                  else    //wenn Figur zuvor selbst schon auf Spielfeld war, dann auf alten Platz dort zur\u00fcck setzen
507                  {
508                     dragged.setHome();                     
509                  }  
510               }
511               
512          }
513          else //Spielfigut weg von Spielfeld ziehen
514          {
515                   dragged.setHome();
516                     //Das ist auch ein erfolgreicher Zug, darum hier auch update und Wechsel!!!!:
517                     updateSpielzustand(); //Nur bei erfolgreichen Z\u00fcgen Updtae n\u00f6tig!
518                   
519                     //JETZT IST DER ANDERE DRAN!
520                     spielfeld.WEISS_IST_DRAN = !spielfeld.WEISS_IST_DRAN;
521            
522          }
523          
524          dragged = null;
525      }
526
527      //Nur bei erfolgreicher Aktion n\u00f6tig (s. updateSpielzustand und erfolgreicher Zug!):      
528      //Anzeige der aktuellen Belegung:
529      //*********** Das hier m\u00fc\u00dfte auch bei automatischen Z\u00fcgen ausgef\u00fchrt werden: *******
530      //spiel.uebernehmeZustand();
531      //spiel.zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld();
532      //schwarzerpfad = spiel.findeNaechstenpfadSchwarz();
533      //weisserpfad = spiel.findeNaechstenpfadWeiss();
534      //****************      
535}
536
537public void keyPressed()
538{
539     if(key=='r')
540     {
541          spiel.alleHeimschicken(); //Testweise Zustand auf Start setzen
542          spiel.zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld();
543     }
544     else if(key=='s')  //Zustand in testspiel speichern
545     {
546          testspiel.uebernehmeZustand();
547          println("Spielzustand in Testspiel gemerkt");
548     }
549     else if(key=='l')  //Zustand VON testspiel LADEN
550     {
551          testspiel.schreibeZustand();
552          println("Spielzustand von Testspiel geholt");          
553     }
554     
555     
556     
557     
558}
559  public double midi2Frequency(double midi)
560  {
561        if(midi<1.0f)
562            return 0.0f; //Nullereignisse behandeln
563  
564        double freq69 = Math.pow(2.0f,69.0f/12.0f);
565        return Math.pow(2.0f,midi/12.0f)*440.0f/freq69;
566  }
567
568  public double frequency2Midi(double freq)
569  {
570        if(freq<1.0f)
571             return 0.0f; //Nullereignisse behandeln
572  
573        double freq69 = Math.pow(2.0f,69.0f/12.0f);
574        return 12.0f*Math.log(freq*freq69/440.0f)/Math.log(2.0f);
575  }
576
577  public int freq2mid(int freq)
578  {
579    if(freq==0)
580        return 0;
581    else
582        return (int)Math.round(frequency2Midi((double)freq));
583  }
584
585  public int mid2freq(int mid)
586  {
587      if(mid==0)
588          return 0;
589      else
590          return (int)Math.round(midi2Frequency((double)mid));
591  }
592 
593public class Karte
594{
595     public boolean FLASH = false; 
596     public boolean war_auf_feld = false;
597  
598     int typ;
599     String[] pattern;
600     float kantex; 
601     float kantey;
602     public float h,b,x,y,xhome,yhome,xoff,yoff,xspielfeld,yspielfeld;
603     int farbe;
604     boolean WEISS;
605     
606     public int ID=0;
607     
608     //typ 9 ist Quelle, 0..8== .|..|...|-|--|---|+|++|+++
609     //                         0  1  2  3  4   5 6  7  8
610     public Karte(boolean WEISS,int typ,int farbe,float x, float y, float b, float h)
611     {
612          ID = 99000 + typ*100 + farbe*10;
613          if(WEISS)
614            ID++;
615       
616       
617          this.xoff = 0.0f;
618          this.yoff = 0.0f;
619          this.xspielfeld = 0.0f;
620          this.yspielfeld = 0.0f;
621       
622          this.WEISS = WEISS;
623          this.farbe = farbe;
624          this.typ = typ;
625          pattern = new String[13];
626          for(int i=0;i<pattern.length;i++)
627          {
628               pattern[i] = kartentypen[typ*20+i];
629          }
630          kantex = b/5.0f;
631          kantey = h/13.0f;
632          this.h = h;
633          this.b = b;
634          this.x = x;
635          this.y = y;
636          this.xhome = x;
637          this.yhome = y;
638     }
639     
640     public void draw(int[] randfarbe)
641     {
642         if(FLASH==true)
643         {
644             stroke(255);
645         }
646         else if(randfarbe==null)
647            noStroke();
648         else
649            stroke(randfarbe[0],randfarbe[1],randfarbe[2]);
650         int r = ((7-farbe)/4)%2;
651         int g = ((7-farbe)/2)%2;
652         int b = ((7-farbe)/1)%2;
653         //&&&&
654         if(WEISS)
655         {
656             fill(127+64);
657         }    
658         else
659         {
660             fill(0);
661         }    
662         rect(x,y,this.b,this.h,60);
663         //&&&&
664         if(WEISS)
665         {
666             fill(r*127,g*127,b*127);
667             stroke(r*127,g*127,b*127);
668         }    
669         else
670         {
671             fill(r*127+64,g*127+64,b*127+64);
672             stroke(r*127+64,g*127+64,b*127+64);
673         }    
674         for(int i=0;i<pattern.length;i++)
675         {
676              for(int k=0;k<pattern[i].length();k++)
677              {
678                   if(pattern[i].charAt(k)=='*')
679                      rect(x+kantex*(k+1),y+kantey*(i-1),kantex,kantey,3);
680              }
681         }
682     }
683     
684     public boolean mausHatEs(float mx, float my)
685     {
686          if(mx>x && my>y && mx<x+b && my<y+h)
687          {
688              xoff = x-mx;
689              yoff = y-my;
690            
691              return true;
692          }    
693          else
694              return false;
695     }
696     
697     public void set(float mx, float my)
698     {
699          x = mx+xoff;
700          y = my+yoff;
701     }
702     public void setNeu(float mx, float my)
703     {
704          x = mx;
705          y = my;
706          xoff=0.0f;
707          yoff=0.0f;
708     }
709     
710     public void setHome()
711     {
712          this.x = xhome;
713          this.y = yhome;
714          xoff=0.0f;
715          yoff=0.0f;
716     }
717}
718//Spiel repr\u00e4sentiert den Spielstand / den Spielzustand
719//Mit einer Instanz testspiel, k\u00f6nnen auch nicht aktuelle Spielzust\u00e4nde \u00fcberpr\u00fcft werden (2. Instanz von spiel)
720
721public class Spiel
722{
723    //Nur die NEUEN Punkte, nicht die aku,ulierten.
724    //Die akumulierten stehen im Haupt-Sketch
725    //werden beim Bestimmen der Pfade mit aktualisiert!
726  
727  
728    //Die Parameter werden aus den \u00fcbergerbenen Objekten extrahiert und
729    //die \u00fcbergebenen Parameter hier registriert
730    Spielfeld spielfeld;
731    Karte[] karte;
732    Karte quelleweiss;
733    Karte quelleschwarz;
734    
735    public int[][] matrix;
736    public int[][] distmatrix;
737
738    public void noFlash()
739    {
740         for(int i=0;i<karte.length;i++)
741            karte[i].FLASH = false;
742    }
743
744    public void setFlash(int ID)
745    {
746         for(int i=0;i<karte.length;i++)
747         { 
748             if(karte[i].ID==ID)
749             {
750                  karte[i].FLASH = true;
751                  return;
752             }
753         }
754    }
755
756    public void kopiereAufAnderesSpiel(Spiel testspiel)
757    {
758         for(int i=0;i<matrix.length;i++)
759             for(int k=0;k<matrix[i].length;k++)
760                 testspiel.matrix[i][k] = matrix[i][k];
761         for(int i=0;i<matrix.length;i++)
762             for(int k=0;k<matrix[i].length;k++)
763                 testspiel.distmatrix[i][k] = distmatrix[i][k];
764    }
765    
766    public Spiel(Spielfeld spielfeld,Karte[] karte,Karte quelleweiss,Karte quelleschwarz)
767    {
768         this.spielfeld = spielfeld;
769         this.karte = karte;
770         this.quelleweiss = quelleweiss;
771         this.quelleschwarz = quelleschwarz;
772         
773         this.matrix = new int[spielfeld.matrix.length][spielfeld.matrix[0].length];
774         this.distmatrix = new int[spielfeld.matrix.length][spielfeld.matrix[0].length];
775    }
776    
777    public void uebernehmeZustand()
778    {
779         Karte[][] mat = spielfeld.matrix;
780         
781         for(int i=0;i<matrix.length;i++)
782             for(int k=0;k<matrix[i].length;k++)
783                 if(mat[i][k]!=null)
784                     matrix[i][k] = mat[i][k].ID;
785                 else    
786                     matrix[i][k] = 0;
787    }
788    
789    public void schreibeZustand() //in matrix gespeicherten Zustand auf das Spiel \u00fcbertragen!, praktisch f\u00fcr autom. Spiel!!!!
790    {
791        //1. Alle "heimschicken"
792        alleHeimschicken();
793        //2. aus matrix die IDs lesen und dort die Karten in Spielfeld positionieren.
794        for(int i=0;i<matrix.length;i++)
795        {
796            for(int k=0;k<matrix[i].length;k++)
797            {
798                float xxx = spielfeld.getNextXausK(k);
799                float yyy = spielfeld.getNextYausI(i);
800                int ID = matrix[i][k];
801                if(ID>0)
802                {
803                    if(quelleweiss.ID==ID)
804                    {
805                          spielfeld.matrix[i][k] = quelleweiss;
806                          quelleweiss.setNeu(xxx,yyy);
807                    }
808                    else if(quelleschwarz.ID==ID)
809                    {
810                          spielfeld.matrix[i][k] = quelleschwarz;
811                          quelleschwarz.setNeu(xxx,yyy);
812                    }
813                    else
814                    {
815                          for(int pp=0;pp<karte.length;pp++)
816                          {
817                               if(karte[pp].ID==ID)
818                               {
819                                   spielfeld.matrix[i][k] = karte[pp];
820                                   karte[pp].setNeu(xxx,yyy);
821                                   break;
822                               }
823                          }
824                    }
825                }    
826            }
827        }
828    }
829    
830    public void alleHeimschicken()
831    {
832        for(int i=0;i<karte.length;i++)
833            karte[i].setHome();
834        quelleweiss.setHome();
835        quelleschwarz.setHome();
836        for(int i=0;i<spielfeld.matrix.length;i++)
837            for(int k=0;k<spielfeld.matrix[0].length;k++)
838            spielfeld.matrix[i][k]=null;
839    }
840    
841    //Methoden zur Analyse der ID:
842    public boolean istWeiss(int ID)
843    {
844         if(ID%2==1)
845            return true;
846         else
847            return false;
848    }
849    
850    public int farbeVonID(int ID)
851    {
852         return (ID/10)%10;
853    }
854    
855    public int anzahlVonID(int ID)
856    {
857         return ((ID/100)%10)%3;
858    }
859    
860    public int formVonID(int ID)
861    {
862         return ((ID/100)%10)/3;
863    }
864    
865    public boolean istQuelle(int ID)
866    {
867         if( (ID/100)%10==9 )
868           return true;
869         else
870           return false;
871    }
872
873    public boolean istAufSpielfeld(int ID)
874    {
875          for(int i=0;i<matrix.length;i++)
876                for(int k=0;k<matrix[i].length;k++)
877                    if(ID==matrix[i][k])
878                        return true;
879          return false;              
880    }
881    
882    public void zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld()
883    {
884         println("//Angaben:"); 
885         println("[zeile|spalte]"); 
886         println("// S/W schwarz weiss");
887         println("// QQQ   Quelle");
888         println("// Farbe  1..6");
889         println("// Anzahl 1..3");
890         println("// Form   1..3");
891         for(int i=0;i<matrix.length;i++)
892         {
893               for(int k=0;k<matrix[i].length;k++)
894               {
895                 if(matrix[i][k]>0)
896                 {
897                   print("["+i+"|"+k+"] ");
898                   int ID = matrix[i][k];
899                   if(istWeiss(ID))
900                      print("W ");
901                   else   
902                      print("S ");
903                   if(istQuelle(ID))
904                   {
905                        print("QQQ");
906                   }
907                   else
908                   {
909                       int farbe = farbeVonID(ID);      //OHNE INKR schon richtig!!!
910                       int anzahl = anzahlVonID(ID)+1;  //PLUS 1 !!!
911                       int form   = formVonID(ID)+1;    //PLUS 1 !!!
912                       print(farbe+""+anzahl+""+form+"");
913                   }
914                   print(" # ");
915                 }
916                 else
917                 {
918                     print("["+i+"|"+k+"] ");
919                     print("     ");
920                     print(" # ");
921                 }
922               }
923               println();
924         }
925         println();
926    }
927    
928    
929    //Methoden bereitstellen, die es erlauben die G\u00fcltigkeit von Konstellationen zu untersuchen
930    //um schlie\u00dflich g\u00fcltige Z\u00fcge zu suchen und zu bewerten.
931    
932    //Verboten sind Zyklen.
933    //Wie erkennt man Zyklen?
934    //Es d\u00fcrfen keine Rechtecke auftreten! Reicht das???
935    
936    //Wenn man Kreuzungen verbietet reicht das.
937    //Aber wenn nicht g\u00e4be es z.B. 8-ten als M\u00f6glichkeit von Schleifen, die keine Rechtecke sind.
938    
939    //OBIGES VERWERFEN!!!
940    
941    //Statt dessen N\u00e4chstenpfad OHNE Zyklen/Wdh. bilden.
942    //So braucht es sonst keine Beschr\u00e4nkungen!!!!
943    
944    
945    public ArrayList<int[]> findeNaechstenpfadWeiss()
946    {
947        return findeNaechstenpfad(true);
948    }
949    
950    public ArrayList<int[]> findeNaechstenpfadSchwarz()
951    {
952        return findeNaechstenpfad(false);
953    }
954
955    //Nur die NEUEN Punkte, nicht die aku,ulierten.
956    //Die akumulierten stehen im Haupt-Sketch
957    //werden beim Bestimmen der Pfade mit aktualisiert!
958    
959    //Formel:  Anzahl_versch_farben * Anzahl_versch_formen * Anzahl_versch_Anzahlen * ANZAHLWEGSTATIONEN_OHNE_QUELLE
960    
961    public int berechnePunkte(ArrayList<int[]> sammel_ik)
962    {
963        if(sammel_ik==null || sammel_ik.size()<=1)
964            return 0; //Quelle z\u00e4hlt nicht mit!!!
965        int[][] merker = new int[4][matrix[0].length];  //Zeilen: Farbe, Form, Anzahl,distanzen || Spalten werden inkrementiert, wenn korrespondierende Farbe/Form/Anzahl auftaucht.
966        for(int i=0;i<sammel_ik.size();i++)
967        {
968            int ID = matrix[sammel_ik.get(i)[0]][sammel_ik.get(i)[1]];
969            if(ID>0 && !istQuelle(ID))
970            {
971                  int farbe = farbeVonID(ID);
972                  int form =  formVonID(ID);
973                  int anz  =  anzahlVonID(ID);
974                  int distanz = sammel_ik.get(i)[2];
975                  merker[0][farbe]++;
976                  merker[1][form]++;
977                  merker[2][anz]++;
978                  merker[3][distanz]++;
979            }
980        }
981        
982        int PUNKTE = sammel_ik.size()-1;
983        
984        for(int i=0;i<merker.length;i++)
985        {
986              int summe = 0;
987              for(int k=0;k<merker[i].length;k++)
988              {
989                   if(merker[i][k]>0)
990                      summe++;
991              }
992              PUNKTE*=summe;
993        }
994        return PUNKTE;
995    }
996
997    public boolean warschon(int i,int k,ArrayList<int[]> sammel_ik)
998    {
999        for(int p=0;p<sammel_ik.size();p++)
1000             if(i==sammel_ik.get(p)[0] && k==sammel_ik.get(p)[1])
1001                 return true;
1002        return false;          
1003    }
1004    
1005    public ArrayList<int[]> findeNaechstenpfad(boolean weiss)
1006    {
1007//if(weiss)      
1008//println("Suche weiss");
1009//else
1010//println("Suche schwarz");
1011
1012
1013        ArrayList<int[]> sammel_ik = new ArrayList<int[]>();
1014        
1015        //1. Startpunkt suchen:
1016        println();
1017        for(int i=0;i<matrix.length;i++)
1018        {
1019              for(int k=0;k<matrix[i].length;k++)
1020              {
1021                       
1022                    int ID = matrix[i][k];
1023                    if(WARTUNG)
1024                    {
1025                      if(ID==0)
1026                        print(0);
1027                      else if(istQuelle(ID) && istWeiss(ID))
1028                        print("W");
1029                      else if(istQuelle(ID) && !istWeiss(ID))
1030                        print("S");
1031                      else
1032                        print("x");
1033                    }    
1034                    if(weiss)
1035                    {
1036                        if(ID>0 && istQuelle(ID) && istWeiss(ID))
1037                        {
1038                          sammel_ik.add(new int[] {i,k});
1039                        }
1040                    }
1041                    else
1042                    {                                              
1043                        if(ID>0 && istQuelle(ID) && !istWeiss(ID))
1044                        {
1045                          sammel_ik.add(new int[] {i,k});
1046                        }
1047                    }
1048              }
1049              if(WARTUNG)
1050              println();
1051        }
1052if(WARTUNG)        
1053println("Quellanz="+sammel_ik.size());        
1054        //2. Immer die k\u00fcrzeste Verbindung suchen.
1055        while(sammel_ik.size()>0) //Abbruch, wenn kein neuer gefunden wird.
1056        {
1057            int i_start = sammel_ik.get(sammel_ik.size()-1)[0];
1058            int k_start = sammel_ik.get(sammel_ik.size()-1)[1];
1059            
1060            int[][] merker = new int[4][4]; // i k ID dist, wenn ID 0 == nix gefunden
1061            for(int p=k_start+1;p<matrix[0].length;p++)
1062            {
1063                 int ID = matrix[i_start][p]; 
1064                 if(istQuelle(ID))
1065                     break;  //andere Quelle blockiert weitergehen! 
1066                 if(ID>0 && !istQuelle(ID)  && !warschon(i_start,p,sammel_ik)) //solche, die schon waren \u00fcbergehen!
1067                 {
1068                      merker[0][0] = i_start;
1069                      merker[0][1] = p;
1070                      merker[0][2] = matrix[i_start][p]; //ID
1071                      merker[0][3] = p - k_start; //dist (>0)
1072                      break;
1073                 }
1074                 else if(warschon(i_start,p,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war!
1075                 {
1076                      break;
1077                 }
1078            }
1079            //3 weitere...
1080            for(int p=k_start-1;p>=0;p--)
1081            {
1082                 int ID = matrix[i_start][p]; 
1083                 if(istQuelle(ID))
1084                     break;  //andere Quelle blockiert weitergehen! 
1085                 if(ID>0 && !istQuelle(ID)  && !warschon(i_start,p,sammel_ik)) //solche, die schon waren \u00fcbergehen!
1086                 {
1087                      merker[1][0] = i_start;
1088                      merker[1][1] = p;
1089                      merker[1][2] = matrix[i_start][p]; //ID
1090                      merker[1][3] = k_start - p; //dist (>0)
1091                      break;
1092                 }
1093                 else if(warschon(i_start,p,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war!
1094                 {
1095                      break;
1096                 }
1097            }
1098            for(int p=i_start+1;p<matrix.length;p++)
1099            {
1100                 int ID = matrix[p][k_start]; 
1101                 if(istQuelle(ID))
1102                     break;  //andere Quelle blockiert weitergehen! 
1103                 if(ID>0 && !istQuelle(ID)  && !warschon(p,k_start,sammel_ik)) //solche, die schon waren \u00fcbergehen!
1104                 {
1105                      merker[2][0] = p; // i k ID dist, wenn ID 0 == nix gefunden
1106                      merker[2][1] = k_start;
1107                      merker[2][2] = matrix[p][k_start]; //ID
1108                      merker[2][3] = p - i_start; //dist (>0)
1109                      break;
1110                 }
1111                 else if(warschon(p,k_start,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war!
1112                 {
1113                      break;
1114                 }
1115            }
1116            for(int p=i_start-1;p>=0;p--)
1117            {
1118                 int ID = matrix[p][k_start]; 
1119                 if(istQuelle(ID))
1120                     break;  //andere Quelle blockiert weitergehen! 
1121                 if(ID>0 && !istQuelle(ID)  && !warschon(p,k_start,sammel_ik)) //solche, die schon waren \u00fcbergehen!
1122                 {
1123                      merker[3][0] = p; // i k ID dist, wenn ID 0 == nix gefunden
1124                      merker[3][1] = k_start;
1125                      merker[3][2] = matrix[p][k_start]; //ID
1126                      merker[3][3] = i_start - p; //dist (>0)
1127                      break;
1128                 }
1129                 else if(warschon(p,k_start,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war!
1130                 {
1131                      break;
1132                 }
1133            }            
1134            
1135            //Pr\u00fcfen, ob Nachfolger dabei ist, oder Abbruch n\u00f6tig:
1136            int dist_best = Integer.MAX_VALUE;
1137            int dist_zweitbest = Integer.MAX_VALUE;
1138            int i_best    = -1;
1139            int k_best    = -1;
1140            
1141            for(int i=0;i<merker.length;i++)
1142            {
1143                 int i_test = merker[i][0];
1144                 int k_test = merker[i][1];
1145                 int id_test = merker[i][2];
1146                 int dist_test = merker[i][3];
1147                 
1148                 if(id_test>0 && dist_test<=dist_best)
1149                 {
1150                      dist_zweitbest = dist_best;
1151                      dist_best = dist_test;
1152                      i_best = i_test;
1153                      k_best = k_test;
1154                 }                                  
1155            }
1156            
1157            if(i_best>-1 && k_best>-1 && dist_best<dist_zweitbest && !warschon(i_best,k_best,sammel_ik)) //muss echt n\u00e4chster sein ohne Auswahlm\u00f6glichkeit
1158            {
1159                  sammel_ik.add(new int[] {i_best,k_best,dist_best});                                    
1160            }
1161            else
1162            {
1163                  break;  //wenn keiner mehr gefunden wird, der echt am n\u00e4chsten an dem zuletzt gefundenen liegt ohne wdh.
1164            }
1165        }
1166        
1167        return sammel_ik;
1168    }            
1169}
1170
1171
1172public class Spieler implements Runnable
1173{
1174//     Random zufall = new Random(System.currentTimeMillis());
1175     Random zufall = new Random(0);
1176  
1177     boolean WEISS;
1178     Spielfeld spielfeld;
1179     Spiel spiel;
1180     Spiel testspiel;
1181     Spiel testspiel2;
1182     public Spieler(boolean WEISS, Spielfeld spielfeld, Spiel spiel, Spiel testspiel, Spiel testspiel2)
1183     {
1184         this.WEISS = WEISS;
1185         this.spiel = spiel;
1186         this.testspiel = testspiel;
1187         this.testspiel2 = testspiel2;
1188         this.spielfeld = spielfeld;
1189         
1190         (new Thread(this)).start();         
1191     }
1192     
1193     public void run()
1194     {
1195        while(true)
1196        {
1197          if(spielfeld.WEISS_IST_DRAN == WEISS && spielfeld.TIMER_WEISS_IST_DRAN == WEISS ) //ist dran und darf loslegen
1198          {
1199               //Pr\u00fcfen, ob schon Quelle auf dem Feld ist, wenn nicht diese setzen
1200               Karte quelle = quelleweiss;
1201               if(!WEISS)
1202                   quelle = quelleschwarz;
1203               int ID = quelle.ID;
1204               if(!spiel.istAufSpielfeld(ID))
1205               {
1206//println("Nicht auf Feld");                 
1207                   int i = zufall.nextInt(spiel.matrix.length);
1208                   int k = zufall.nextInt(spiel.matrix[0].length);
1209                   while(spiel.matrix[i][k]>0)
1210                   {
1211                       i = zufall.nextInt(spiel.matrix.length);
1212                       k = zufall.nextInt(spiel.matrix[0].length);
1213                   }
1214//println("setze auf "+i+" "+k);                   
1215                   spiel.matrix[i][k] = ID;
1216               }
1217               else
1218               {
1219                    spiel.kopiereAufAnderesSpiel(testspiel);
1220                    spiel.kopiereAufAnderesSpiel(testspiel2);
1221                    int punkte_best = 0;
1222                    for(int i=0;i<3;i++)
1223                    {
1224                        spiel.kopiereAufAnderesSpiel(testspiel);
1225                        int punkte = zufallszug(testspiel);
1226                        if(punkte>=punkte_best)
1227                        {
1228                             punkte_best = punkte;
1229                             testspiel.kopiereAufAnderesSpiel(testspiel2);
1230                        }
1231                    }    
1232                    testspiel2.kopiereAufAnderesSpiel(spiel);
1233               }
1234               
1235               //abschliessen:
1236               //JETZT IST DER ANDERE DRAN!
1237               spiel.schreibeZustand();
1238               updateSpielzustand();
1239               spielfeld.WEISS_IST_DRAN = !spielfeld.WEISS_IST_DRAN;
1240          
1241               
1242          }
1243       
1244       
1245          try
1246          {
1247              Thread.sleep(1000);
1248          }
1249          catch(Exception e)
1250          {
1251          }
1252        }//while true  
1253     }//run
1254     
1255
1256     public boolean spielfeldVoll(Spiel spiel)
1257     {
1258           for(int i=0;i<spiel.matrix.length;i++)
1259               for(int k=0;k<spiel.matrix[0].length;k++)
1260                    if(spiel.matrix[i][k]==0)
1261                        return false;
1262           return true;             
1263     }
1264     
1265     public int spielfeldProzentVoll(Spiel spiel)
1266     {
1267           int anz = 0;
1268           int sum = spiel.matrix.length*spiel.matrix[0].length;
1269           for(int i=0;i<spiel.matrix.length;i++)
1270               for(int k=0;k<spiel.matrix[0].length;k++)
1271                    if(spiel.matrix[i][k]!=0)
1272                        anz++;
1273           return (anz*100)/sum;             
1274     }
1275     
1276     
1277     public int[] zufalls_ik(Spiel spiel)
1278     {
1279           int i = zufall.nextInt(spiel.matrix.length);
1280           int k = zufall.nextInt(spiel.matrix[0].length);
1281           while(spiel.matrix[i][k]>0)
1282           {
1283               i = zufall.nextInt(spiel.matrix.length);
1284               k = zufall.nextInt(spiel.matrix[0].length);
1285           }
1286           return new int[] {i,k};
1287     }
1288
1289     public int[] zufalls_ik_besetztEigeneFarbe(Spiel spiel) //liefert Platz, der besetrzt ist mit eigener Farbe und nicht Quelle
1290     {
1291           int i = zufall.nextInt(spiel.matrix.length);
1292           int k = zufall.nextInt(spiel.matrix[0].length);
1293           while(spiel.matrix[i][k]==0 || spiel.istWeiss(spiel.matrix[i][k])!=WEISS || spiel.istQuelle(spiel.matrix[i][k]))
1294           {
1295               i = zufall.nextInt(spiel.matrix.length);
1296               k = zufall.nextInt(spiel.matrix[0].length);
1297           }
1298           return new int[] {i,k};
1299     }
1300     
1301     
1302     public void entferneID(int ID,Spiel spiel)
1303     {
1304           for(int i=0;i<spiel.matrix.length;i++)
1305               for(int k=0;k<spiel.matrix[0].length;k++)
1306                    if(spiel.matrix[i][k]==ID)
1307                    {
1308                        spiel.matrix[i][k]=0;
1309                        return;
1310                    }    
1311     }
1312     
1313     public int bestimmePunkte(Spiel spiel, boolean WEISS)
1314     {
1315           if(WEISS)
1316           {
1317                return spiel.berechnePunkte(spiel.findeNaechstenpfadWeiss());
1318           }
1319           else
1320           {
1321                return spiel.berechnePunkte(spiel.findeNaechstenpfadSchwarz());
1322           }
1323     }
1324     
1325     public int zufallszug(Spiel spiel)  //Liefert auch mit dem Zug erreichbare Punkte
1326     {
1327          if(  spielfeldProzentVoll(spiel) > 30 )  //wenn zu 60% voll, dann in jedem Fall etwas entfernen
1328          {
1329              int[] ik = zufalls_ik_besetztEigeneFarbe(spiel); //sucht besetzten Platz eigener Farbe
1330              
1331              spiel.matrix[ik[0]][ik[1]] = 0; 
1332                                        
1333            
1334              //return bestimmePunkte(spiel,WEISS)-bestimmePunkte(spiel,!WEISS);
1335              return bestimmePunkte(spiel,WEISS);
1336          }
1337          else if(  spielfeldProzentVoll(spiel) > 10 && zufall.nextInt(100)<50)  //wenn zu 60% voll, dann in jedem Fall etwas entfernen
1338          {
1339              int[] ik = zufalls_ik_besetztEigeneFarbe(spiel); //sucht besetzten Platz
1340              
1341              spiel.matrix[ik[0]][ik[1]] = 0; 
1342            
1343              //return bestimmePunkte(spiel,WEISS)-bestimmePunkte(spiel,!WEISS);
1344              return bestimmePunkte(spiel,WEISS);
1345          }
1346       
1347          int inx = zufall.nextInt(karte.length);
1348          int ID = karte[inx].ID;
1349          while(spiel.istWeiss(ID)!=WEISS)
1350          {
1351              inx = zufall.nextInt(karte.length);
1352              ID = karte[inx].ID;
1353          }
1354          
1355          if(spiel.istAufSpielfeld(ID))  //dann verschieben
1356          {
1357               entferneID(ID,spiel);
1358               int[] ik = zufalls_ik(spiel);
1359               spiel.matrix[ik[0]][ik[1]] = ID;
1360          }
1361          else  //dann neu setzen
1362          {
1363               int[] ik = zufalls_ik(spiel);
1364               spiel.matrix[ik[0]][ik[1]] = ID;
1365          }
1366          
1367           //return bestimmePunkte(spiel,WEISS)-bestimmePunkte(spiel,!WEISS);
1368           return bestimmePunkte(spiel,WEISS);
1369     }
1370}
1371public class Spielfeld
1372{
1373     public boolean WEISS_IST_DRAN = true;
1374     public boolean TIMER_WEISS_IST_DRAN = true;
1375
1376     public float[][] ikoord; //Koordinaten des Spielfeldes  
1377     public float[][] kkoord; //Koordinaten des Spielfeldes  
1378  
1379     int anzx,anzy;
1380     float kantex,kantey;
1381     float mx;
1382     float my;
1383          
1384     float x;
1385     float y;
1386
1387     float b,h;
1388     
1389     public Karte[][] matrix; //mit belegten Feldern
1390     
1391     public Spielfeld(float kantex, float kantey,int anzx, int anzy)
1392     {
1393          this.anzx=anzx;
1394          this.anzy=anzy;
1395          this.kantex=kantex;
1396          this.kantey=kantey;
1397          this.matrix = new Karte[anzy][anzx+1]; //HACK. anzx mu\u00df ungerade sein, Breite wird dann komischerweise gerade wg. Darstellung
1398          this.mx = width/2.0f;
1399          this.my = height/2.0f - YOFF;
1400          
1401          this.x = mx - kantex*(0.5f*(float)anzx);
1402          this.y = my - kantey*(0.5f*(float)anzy);
1403          this.b = anzx*kantex;
1404          this.h = anzy*kantey;
1405          
1406          ikoord = new float[matrix.length][matrix[0].length];
1407          kkoord = new float[matrix.length][matrix[0].length];
1408          for(int i=0;i<matrix.length;i++)
1409          {
1410                for(int k=0;k<matrix[i].length;k++)
1411                {
1412                    // rect(x+(k+i%2)*kantex-kantex*0.5f,y+i*kantey,kantex,kantey,60);
1413                    float xxx = x+k*kantex-kantex*0.5f;
1414                    float yyy = y+i*kantey;
1415                    ikoord[i][k] = yyy + kantey*0.5f;
1416                    kkoord[i][k] = xxx + kantex*0.5f;
1417                }
1418          }
1419     }
1420     
1421     public void draw()
1422     {
1423          //noFill();
1424          //stroke(95);
1425          noStroke();
1426          fill(127);
1427          for(int i=0;i<anzy;i++)
1428          {
1429                for(int k=0;k<anzx;k+=2)
1430                {
1431                     rect(x+(k+i%2)*kantex-kantex*0.5f,y+i*kantey,kantex,kantey,60);
1432                }
1433          }
1434          
1435          //fill(64);
1436          for(int i=0;i<anzy;i++)
1437          {
1438                for(int k=0;k<anzx;k+=2)
1439                {
1440                     rect(x+(k+(i+1)%2)*kantex-kantex*0.5f,y+i*kantey,kantex,kantey,60);
1441                }
1442          }
1443          
1444     }
1445     
1446     public boolean istInSpielfeld(Karte k)
1447     {
1448          float mausx = k.x - k.xoff;
1449          float mausy = k.y - k.yoff;
1450       
1451          if(mausx>x-kantex*0.4f && mausx<x+b+kantex*0.4f && mausy>y && mausy<y+h)
1452               return true;
1453          else
1454              return false;
1455     }
1456     
1457     public float getNextX(Karte k)
1458     {
1459           float mausx = k.x - k.xoff+kantex*0.5f;
1460           return x + kantex*floor((mausx-x)/kantex)-kantex*0.5f;
1461     }
1462
1463     public float getNextXausK(int kkk)
1464     {
1465           return x + kantex*kkk-kantex*0.5f;
1466     }     
1467     
1468     public float getNextY(Karte k)
1469     {
1470           float mausy = k.y - k.yoff;
1471           return y + kantey*floor((mausy-y)/kantey);
1472     }
1473
1474     public float getNextYausI(int iii)
1475     {
1476           return y + kantey*iii;
1477     }     
1478 
1479 
1480     public int getNextXindex(Karte k)
1481     {
1482           float mausx = k.x - k.xoff+kantex*0.5f;
1483           return (int)floor((mausx-x)/kantex);
1484     }
1485     
1486     public int getNextYindex(Karte k)
1487     {
1488           float mausy = k.y - k.yoff;
1489           return (int)floor((mausy-y)/kantey);
1490     }
1491     
1492     public boolean istFrei(int i, int k)
1493     {
1494          if(matrix[i][k]==null)
1495              return true;
1496          else
1497              return false;
1498     }
1499     
1500     public boolean istAufSpielfeld(Karte karte)
1501     {
1502          for(int i=0;i<matrix.length;i++)
1503              for(int k=0;k<matrix[i].length;k++)
1504                  if(matrix[i][k]!=null && karte!=null && matrix[i][k].ID==karte.ID)
1505                      return true;
1506          return false;            
1507     }
1508}
1509public class TEXT
1510{
1511    float textgroesse = 10.0f;
1512    float tw;
1513    float cw;
1514    float th;
1515    float hh;
1516    float bb;
1517    String[] text;
1518    float maxwidth,maxheight;
1519    public TEXT(String[] text, float maxwidth, float maxheight)
1520    {
1521          this.maxwidth = maxwidth;
1522          this.maxheight = maxheight;
1523          this.text = text;
1524          textSize(textgroesse);
1525          int inx = 0;
1526          int maxanz = 0;
1527          String maxtext = text[0];
1528          for(int i=0;i<text.length;i++)
1529          {
1530               if(text[i].length()>maxanz)
1531               {
1532                   maxtext = text[i];
1533                   maxanz = text[i].length();
1534               }
1535          }
1536          
1537          tw = textWidth(maxtext);
1538          cw = textWidth("#");
1539          th = (cw*8.0f)/5.0f;
1540          hh = th*(float)text.length;
1541          bb = tw;               
1542          
1543          while(hh<maxheight && bb<maxwidth)
1544          {
1545               textgroesse+=0.2f;
1546               textSize(textgroesse);
1547               tw = textWidth(maxtext);
1548               cw = textWidth("#");
1549               th = (cw*8.0f)/5.0f;
1550               hh = th*(float)text.length;
1551               bb = tw;               
1552          }
1553          
1554          
1555          while(hh>maxheight || bb>maxwidth)
1556          {
1557               textgroesse-=0.2f;
1558               textSize(textgroesse);
1559               tw = textWidth(maxtext);
1560               cw = textWidth("#");
1561               th = (cw*8.0f)/5.0f;
1562               hh = th*(float)text.length;
1563               bb = tw;               
1564          }
1565    }
1566    
1567    public void show(float x, float y)
1568    {
1569         for(int i=0;i<text.length;i++)
1570         {
1571              text(text[i],x,y+(float)i*th+th);              
1572         }
1573    }
1574    public void show(float x, float y, int r, int g, int b)
1575    {
1576         fill(r,g,b);
1577         for(int i=0;i<text.length;i++)
1578         {
1579              text(text[i],x,y+(float)i*th+th);              
1580         }
1581    }
1582    
1583    public void show(float x, float y, int r, int g, int b, int rh, int gh, int bh)
1584    {
1585         noStroke();
1586         fill(rh,gh,bh);
1587         rect(x,y,maxwidth,maxheight);
1588         fill(r,g,b);
1589         for(int i=0;i<text.length;i++)
1590         {
1591              text(text[i],x,y+(float)i*th+th);              
1592         }
1593    }
1594    
1595}
1596
1597
1598
1599
1600public class Zugkontrolle implements Runnable
1601{
1602     private long WERT_WEISS = 0;
1603     private long WERT_SCHWARZ = 0;
1604     private long FREQ_WEISS = 0;
1605     private long FREQ_SCHWARZ = 0;
1606     private long MIDI_WEISS = 0;
1607     private long MIDI_SCHWARZ = 0;
1608     
1609     private long FFREQ = 0;
1610     private long MMID = 0;
1611//Basiszahl: 2*2*2*3*3*5*7 == 2520 == 7*360
1612//Faktor:    1
1613//fmin:      55  == KA
1614//fmax:     1760 == a''' 
1615  
1616     private long BASISZAHL = 2520; 
1617     private long FAKTOR = 1; 
1618     private long FMIN = 55; 
1619     private long FMAX = 1760; 
1620  
1621     private ScheduledExecutorService schedExecService; //realtime process     
1622  
1623     private Spielfeld spielfeld;
1624     
1625  
1626     long PULSMILLIS;
1627     long PULSEPROZUG;
1628     long t;
1629     int STRAFPUNKTE;
1630     public Zugkontrolle(long PULSMILLIS, long PULSEPROZUG, Spielfeld spielfeld, int STRAFPUNKTE)
1631     {
1632         
1633         this.STRAFPUNKTE = STRAFPUNKTE;
1634         this.spielfeld = spielfeld;
1635         this.PULSMILLIS = PULSMILLIS;
1636         this.PULSEPROZUG = PULSEPROZUG;
1637         
1638         t=0;
1639         schedExecService = Executors.newSingleThreadScheduledExecutor();
1640//         schedExecService.scheduleAtFixedRate(this, 0, PULSMILLIS, TimeUnit.MILLISECONDS);
1641//FLASH:
1642         schedExecService.scheduleAtFixedRate(this, 0, PULSMILLIS/2, TimeUnit.MILLISECONDS);             
1643         
1644     }
1645  
1646     public long berechneWertAusPfad(long t,ArrayList<int[]> pfad, boolean WEISS)
1647     {
1648          long erg = t;
1649          try
1650          {
1651            for(int i=1;i<pfad.size();i++)
1652            {
1653               int ID = spiel.matrix[pfad.get(i)[0]][pfad.get(i)[1]];
1654               long operand = spiel.farbeVonID(ID); //==farbe 1,2,3,4,5,6
1655               
1656//NEU: dist ber\u00fccksichtigen
1657operand*=pfad.get(i)[2];
1658               
1659               //typ 9 ist Quelle, 0..8== .|..|...|-|--|---|+|++|+++ 
1660               //                         0  1  2  3  4  5  6  7  8
1661               //                         *  / gt  - =   %  +   
1662               int operator = 3*spiel.formVonID(ID) + spiel.anzahlVonID(ID);
1663               switch(operator)
1664               {
1665                   case 0:  // .
1666                      erg *= operand;
1667                   break;
1668                   case 1:  // ..
1669                      erg/=operand;
1670                   break;
1671                   case 2:  // ...  gemeinsame Teiler finden und durch ihre Gesamtprodukt teilen.
1672                      long teiler=1;
1673                      for(int p=2;p<=operand;p++)
1674                          if(operand%p==0 && erg%p==0)
1675                              teiler*=p;
1676                      erg/=teiler;        
1677                   break;
1678                   case 3:  // -
1679                      erg-=operand;
1680                      if(erg<0)
1681                         erg=0;
1682                   break;
1683                   case 4:  // --
1684                      if(erg==operand)
1685                          erg = operand;
1686                      else
1687                          erg = 0;
1688                   break;
1689                   case 5:  // --- Modulo
1690                      if(operand>0)
1691                          erg%=operand;
1692                      else
1693                          erg = erg;
1694                   break;
1695                   case 6:  // +
1696                      erg+=operand;
1697                   break;
1698                   case 7:  // ++ als UNGLEICH behandeln
1699                      if(erg!=operand)
1700                          erg = erg;
1701                      else
1702                          erg = 0;                   
1703                   break;
1704                   case 8:  // +++ , wie ..., aber multiplizieren statt dividieren
1705                      long faktor=1;
1706                      for(int p=2;p<=operand;p++)
1707                          if(operand%p==0 && erg%p==0)
1708                              faktor*=p;
1709                      erg*=faktor;        
1710                   break;
1711               }
1712               
1713               if(erg>0 && BASISZAHL%erg==0)
1714               {
1715             FREQ_WEISS = BASISZAHL/(erg*FAKTOR);
1716             if(FREQ_WEISS<FMIN)
1717                FREQ_WEISS=0;
1718             if(FREQ_WEISS>FMAX)
1719                FREQ_WEISS=0;
1720             if(FREQ_WEISS>0)
1721             {
1722                MIDI_WEISS = freq2mid((int)FREQ_WEISS);
1723                if(MIDI_WEISS>0 && WEISS)
1724                {
1725//                    msp.play(0+i%2,(int)MIDI_WEISS);  //2 M\u00f6gl. je nach Pos. in Kette
1726                    msp.play(0,(int)MIDI_WEISS);  //2 M\u00f6gl. je nach Pos. in Kette
1727                    spiel.setFlash(ID);
1728//                    msp.playMono(0,(int)MIDI_WEISS);
1729                }    
1730                else if(MIDI_WEISS>0 && !WEISS)
1731                {
1732//                    msp.play(2+i%2,(int)MIDI_WEISS);
1733//                    msp.play(2,(int)MIDI_WEISS);
1734                    msp.play(0,(int)MIDI_WEISS);
1735                    spiel.setFlash(ID);
1736//                    msp.play(1,(int)MIDI_WEISS);
1737//                    msp.playMono(1,(int)MIDI_WEISS);
1738                }    
1739             }  
1740                    
1741               }
1742            }
1743          }
1744          catch(Exception e)
1745          {
1746              println(e);
1747              return 0;
1748          }
1749          return erg;
1750     }
1751long ANZ=0; 
1752boolean FFF = true;
1753     public void run()
1754     {       
1755         if(FFF==true)
1756         {
1757              FFF = !FFF;
1758         }
1759         else
1760         {
1761              FFF = !FFF;
1762              spiel.noFlash();
1763              return;
1764         }
1765       
1766         if(t%PULSEPROZUG==0 && t>0)
1767         {
1768              if(spielfeld.WEISS_IST_DRAN != spielfeld.TIMER_WEISS_IST_DRAN)
1769              {
1770                  spielfeld.TIMER_WEISS_IST_DRAN = !spielfeld.TIMER_WEISS_IST_DRAN;
1771              }
1772              else
1773              {
1774                  if(spielfeld.WEISS_IST_DRAN && PUNKTE_WEISS>=STRAFPUNKTE)
1775                      PUNKTE_WEISS-=STRAFPUNKTE;
1776                  else if(spielfeld.WEISS_IST_DRAN && PUNKTE_WEISS<STRAFPUNKTE)
1777                      PUNKTE_WEISS=0;
1778                  else if(!spielfeld.WEISS_IST_DRAN && PUNKTE_SCHWARZ>=STRAFPUNKTE)
1779                      PUNKTE_SCHWARZ-=STRAFPUNKTE;
1780                  else if(!spielfeld.WEISS_IST_DRAN && PUNKTE_SCHWARZ<STRAFPUNKTE)
1781                      PUNKTE_SCHWARZ=0;
1782                  if(WARTUNG)    
1783                     println("Nach Strafpunkten: W:"+PUNKTE_WEISS+" S:"+PUNKTE_SCHWARZ);    
1784              }
1785         }
1786         //Werte aus Pfaden berechnen:
1787         if(weisserpfad!=null && weisserpfad.size()>1)
1788         {
1789             WERT_WEISS = berechneWertAusPfad(t,weisserpfad,true);
1790         }
1791         else
1792         {
1793             WERT_WEISS = 0;
1794         }
1795         if(schwarzerpfad!=null && schwarzerpfad.size()>1)
1796         {
1797             WERT_SCHWARZ = berechneWertAusPfad(t,schwarzerpfad,false);
1798         }
1799         else
1800         {
1801             WERT_SCHWARZ = 0;
1802         }
1803FFREQ=0;
1804         if(WERT_WEISS>0 && BASISZAHL%(WERT_WEISS*FAKTOR)==0)
1805         {
1806             FREQ_WEISS = BASISZAHL/(WERT_WEISS*FAKTOR);
1807             if(FREQ_WEISS<FMIN)
1808                FREQ_WEISS=0;
1809             if(FREQ_WEISS>FMAX)
1810                FREQ_WEISS=0;
1811             if(FREQ_WEISS>0)
1812             {
1813                MIDI_WEISS = freq2mid((int)FREQ_WEISS);
1814                FFREQ += FREQ_WEISS;
1815             }  
1816         }    
1817         else
1818         {
1819             FREQ_WEISS = 0;
1820         }
1821         
1822         if(WERT_SCHWARZ>0 && BASISZAHL%(WERT_SCHWARZ*FAKTOR)==0)
1823         {
1824             FREQ_SCHWARZ = BASISZAHL/(WERT_SCHWARZ*FAKTOR);
1825             if(FREQ_SCHWARZ<FMIN)
1826                FREQ_SCHWARZ=0;
1827             if(FREQ_SCHWARZ>FMAX)
1828                FREQ_SCHWARZ=0;
1829             if(FREQ_SCHWARZ>0)
1830             {
1831                MIDI_SCHWARZ = freq2mid((int)FREQ_SCHWARZ);
1832                FFREQ += FREQ_SCHWARZ;
1833             }  
1834                
1835         }    
1836         else
1837         {
1838             FREQ_WEISS = 0;
1839         }
1840
1841//             if(MIDI_SCHWARZ>0)
1842//                msp.play(1,(int)MIDI_SCHWARZ);
1843//             if(MIDI_WEISS>0)
1844//                msp.play(0,(int)MIDI_WEISS);
1845//         if(FFREQ>0)
1846//         {
1847//              MMID =  freq2mid((int)FFREQ);
1848//              if(MMID>0)
1849//                 msp.play(0,(int)MMID);
1850//         }
1851         
1852         //print(WERT_WEISS+"|"+WERT_SCHWARZ+" ");
1853//         print(MIDI_WEISS+"|"+MIDI_SCHWARZ+" ");
1854       
1855         ANZ++;
1856         if(ANZ>=PULSEPROZUG)
1857         {
1858//              println("###");
1859              ANZ=0;
1860         }
1861       
1862         t++;
1863       
1864     }
1865}
1866
1867
1868
1869
1870
1871
1872//import javax.sound.sampled.*;
1873//import java.nio.ByteBuffer;
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883 
1884
1885public class FastSoundplayer implements Runnable
1886{
1887     int MAXPOLY = 200; //Maximale Anzahl aktuell noch abzuarbeitender Samples
1888     float[][][] sample = new float[MAXPOLY][][]; 
1889     int[] index = new int[MAXPOLY];
1890     float[][] sampleMono = new float[MAXPOLY][]; 
1891     float[][] panMono = new float[MAXPOLY][2];  //wird mit \u00fcbernommen! 
1892     int[] indexMono = new int[MAXPOLY];
1893     //der play-Funktion wird ein Sample \u00fcbergeben und der korrespondierende Index wird auf Null gesetzt, alles, wenn noch
1894     //Platz im Array sample.
1895     //erreicht index die L\u00e4nge des samples wird dieses entfernt und damit der Platz f\u00fcr nachfolgende Samples frei gegeben.
1896     
1897     int sr = 44100;
1898     int buffsize = 512;
1899//TEST:     
1900//     int buffsize = 2048;
1901     int buffsize2 = buffsize*2;
1902     public float[] mikrofon_welle = new float[buffsize2];
1903     float dt = 1.0f/(float)sr;
1904     float dth = 0.5f*dt;
1905     protected ScheduledExecutorService schedExecService;  
1906     short[] puffer = new short[buffsize*2]; //4 Byte pro Sample == 16Bit Stereo  //2 * bei short
1907     float[] fpuffer = new float[buffsize*2]; //4 Byte pro Sample == 16Bit Stereo  //2 * bei short
1908     public float t=0.0f;
1909     
1910     private AudiotrackMic track;
1911     
1912     public void play(float[][] data)
1913     {
1914          for(int i=0;i<sample.length;i++)
1915          {
1916                if(sample[i]==null)
1917                {
1918                      sample[i]=data;
1919                      index[i]=0;
1920                      break;
1921                }
1922          }
1923     }
1924
1925     public void playMono(float[] data)
1926     {
1927          for(int i=0;i<sampleMono.length;i++)
1928          {
1929                if(sampleMono[i]==null)
1930                {
1931                      sampleMono[i]=data;
1932                      indexMono[i]=0;
1933                      panMono[i][0] = 0.1f;  //s\u00e4ter wird von au\u00dfen die Richtung berechnet und mit \u00fcbergeben
1934                      panMono[i][1] = 0.1f;
1935                      break;
1936                }
1937          }
1938     }
1939     
1940     
1941     public FastSoundplayer()
1942     {
1943         
1944         track = new AudiotrackMic(sr,buffsize);
1945         schedExecService = Executors.newSingleThreadScheduledExecutor();
1946         long period = (buffsize*1000)/sr; //Seconds per Beat==60/BPM, die H\u00e4lfte weil 8tel, mal 1000 weil Millisekunden.
1947         schedExecService.scheduleAtFixedRate(this, 0, period, TimeUnit.MILLISECONDS);                
1948     }
1949
1950     public void run()
1951     {
1952         runStereo();
1953//         runMono();
1954     }
1955     
1956     public void runStereo()
1957     {
1958         //Neues Vorgehen:
1959         for(int k=0;k<fpuffer.length;k++)
1960             fpuffer[k]=0.0f;
1961//STEREO:             
1962         for(int i=0;i<sample.length;i++)
1963         {
1964              float[][] data = sample[i]; //Threadsicher machen, indem Referenz erst einmal gemerkt / gesichert wird.
1965              if(data!=null)
1966              {
1967                  for(int k=0;k<puffer.length;k+=2)
1968                  {
1969                      if(index[i]>=data[0].length)
1970                      {
1971                          sample[i]=null;                          
1972                          break;
1973                      }    
1974                      fpuffer[k+0] += data[0][index[i]];
1975                      fpuffer[k+1] += data[1][index[i]];
1976                      index[i]++;
1977                  }
1978              }
1979         }
1980         for(int k=0;k<fpuffer.length;k++)
1981             puffer[k]=(short)(32767.0f*fpuffer[k]+0.5f);
1982                                       
1983         //audioTrack.write(puffer, 0,buffsize2);
1984         mikrofon_welle = track.write(puffer);
1985     }     
1986     
1987     public void runMono()
1988     {
1989         //Neues Vorgehen:
1990         for(int k=0;k<fpuffer.length;k++)
1991             fpuffer[k]=0.0f;
1992//MONO:             
1993         for(int i=0;i<sampleMono.length;i++)
1994         {
1995              float[] dataMono = sampleMono[i]; //Threadsicher machen, indem Referenz erst einmal gemerkt / gesichert wird.
1996              if(dataMono!=null)
1997              {
1998                  for(int k=0;k<puffer.length;k+=2)
1999                  {
2000                      if(indexMono[i]>=dataMono.length)
2001                      {
2002                          sampleMono[i]=null;                          
2003                          break;
2004                      }    
2005                      fpuffer[k+0] += dataMono[indexMono[i]] * panMono[i][0];
2006                      fpuffer[k+1] += dataMono[indexMono[i]] * panMono[i][1];
2007                      indexMono[i]++;
2008                  }
2009              }
2010         }
2011         for(int k=0;k<fpuffer.length;k++)
2012             puffer[k]=(short)(32767.0f*fpuffer[k]+0.5f);
2013                                       
2014         //audioTrack.write(puffer, 0,buffsize2);
2015         mikrofon_welle = track.write(puffer);
2016     }     
2017     
2018}
2019
2020/**
2021 * Interface f\u00fcr Audiostream mit zus\u00e4tzlichem Mikrofonkanal
2022 */
2023public interface iAudiotrackMic
2024{
2025    public abstract float[] write(short[] puffer);
2026}
2027
2028public class AudiotrackMic implements iAudiotrackMic
2029{
2030    // instance variables - replace the example below with your own
2031    private iAudiotrackMic track;
2032    public short[] shortpuffer;
2033    public float[] micpuffer;
2034    protected ScheduledExecutorService schedExecService;  
2035    
2036    public AudiotrackMic(int SAMPLING_RATE, int buffsize)
2037    {
2038          shortpuffer = new short[buffsize*2]; //2* weil Stereo
2039          micpuffer = new float[buffsize*2]; 
2040        
2041              //track = new AudiotrackMicPC(SAMPLING_RATE, buffsize);
2042              track = new AudiotrackAndroid(SAMPLING_RATE, buffsize);
2043              
2044    }
2045
2046    public float[] write(short[] shortpuffer)
2047    {            
2048        return track.write(shortpuffer);
2049    }
2050
2051 
2052}
2053
2054public class AudiotrackAndroid implements iAudiotrackMic
2055{
2056    private int sr=44100; //Sample rate
2057    int BYTEPUFFERGROESSE;
2058    int SAMPLING_RATE;
2059
2060    private AudioTrack audioTrack; //Connection to sound card
2061    
2062    //SourceDataLine line;
2063    //TargetDataLine targetLine;  //Mikrofon
2064    //DataLine.Info info;
2065    //DataLine.Info targetInfo;  //Mikrofon
2066    
2067    AudioFormat format;
2068        
2069     //AudioTrack audioTrack;
2070     //int sr = 11025;
2071     //Versuchen die Qualit\u00e4t zu verbessern:
2072    
2073     //int buffsize = 512;
2074     int buffsize;
2075     int buffsize2;
2076    
2077     byte[] bytepuffer;
2078     byte[] targetData;
2079     float[] targetWelle;
2080    public AudiotrackAndroid(int SAMPLING_RATE, int buffsize)
2081    {
2082        this.sr = SAMPLING_RATE;
2083        this.SAMPLING_RATE = SAMPLING_RATE;
2084        this.buffsize = buffsize;
2085        this.buffsize2 = buffsize*2;
2086        this.BYTEPUFFERGROESSE = buffsize*4;
2087
2088        bytepuffer = new byte[BYTEPUFFERGROESSE];
2089        targetData = new byte[BYTEPUFFERGROESSE];
2090        targetWelle = new float[buffsize2];
2091        for(int i=0;i<bytepuffer.length;i++)
2092            bytepuffer[i]=0;
2093/*        
2094        this.format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,(float)SAMPLING_RATE, 16, 2, 4, (float)SAMPLING_RATE, false);
2095        this.info = new DataLine.Info(SourceDataLine.class, format);
2096        this.targetInfo = new DataLine.Info(TargetDataLine.class, format);
2097        if (!AudioSystem.isLineSupported(info))
2098        {
2099         System.out.println("Line matching " + info + " is not supported.");
2100         //throw new LineUnavailableException();
2101        }
2102        //format = new AudioFormat(SAMPLERATE, 16, 2, true, true);
2103        try
2104        {
2105            this.targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo);
2106            this.targetLine.open(format);
2107            this.targetLine.start();            
2108            
2109            this.line = (SourceDataLine)AudioSystem.getLine(info);
2110            this.line.open(format,BYTEPUFFERGROESSE);  
2111            this.line.start();
2112        }
2113*/
2114        try
2115        {                                                
2116            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sr, 
2117                                    AudioFormat.CHANNEL_OUT_STEREO, 
2118                                    AudioFormat.ENCODING_PCM_16BIT, 
2119                                    buffsize*10, 
2120                                    AudioTrack.MODE_STREAM);
2121            audioTrack.setStereoVolume(1.0f, 1.0f);
2122            
2123            audioTrack.play();            
2124        }
2125        catch(Exception ee)
2126        {
2127            System.out.println("FEHLER: "+ee);
2128        }              
2129        
2130    }
2131
2132    public float[] write(short[] shortpuffer)
2133    {
2134      /*
2135        for (int i=0; i < buffsize; i++) 
2136        {
2137            bytepuffer[i*4+1] = (byte)(shortpuffer[i*2+0]>>8);
2138            bytepuffer[i*4+0] = (byte)(shortpuffer[i*2+0] & 0xFF); 
2139            bytepuffer[i*4+3] = (byte)(shortpuffer[i*2+1]>>8);
2140            bytepuffer[i*4+2] = (byte)(shortpuffer[i*2+1] & 0xFF); 
2141        }
2142       */ 
2143        //targetLine.read(targetData, 0, targetData.length);
2144        //line.write(bytepuffer, 0, BYTEPUFFERGROESSE);
2145        audioTrack.write(shortpuffer, 0,buffsize2);      
2146 
2147        /*
2148        for(int i=0;i<buffsize;i++) //Stereo!
2149        {
2150            //targetWelle[i*2+0] = (float)((targetData[i*4+0]<<8)+targetData[i*4+1])/32000.0f;
2151            //targetWelle[i*2+1] = (float)((targetData[i*4+2]<<8)+targetData[i*4+3])/32000.0f;
2152            targetWelle[i*2+0] = (float)((targetData[i*4+1]<<8)+targetData[i*4+0])/32000.0f;
2153            targetWelle[i*2+1] = (float)((targetData[i*4+3]<<8)+targetData[i*4+2])/32000.0f;
2154        }
2155        return targetWelle; //Mikrofondaten heraufreichen, um sie mit den anderen kan\u00e4len mischen zu k\u00f6nnen (ein paket verz\u00f6gert)
2156        */
2157        return null;
2158    }
2159}
2160public class Mysoundplayer extends FastSoundplayer
2161{
2162      Wav wav;
2163      int anzahl_kanaele;
2164      float[][][][] ton;// = new float[anzahl_kanaele][128][][]; //jeder Kanal hat 128 Pl\u00e4tze f\u00fcr 44100kHz stereo wav-Sound, belegt abh. von Skalen.
2165
2166      float[][][] mono; //Stimme, Nr, Sample
2167
2168
2169      int[] skala;
2170      int[] skalamap;
2171
2172      public Mysoundplayer(PApplet pap, int anzahl_kanaele)
2173      {
2174          this.anzahl_kanaele = anzahl_kanaele;
2175          wav = new Wav(pap);
2176          ton = new float[anzahl_kanaele][128][][]; //jeder Kanal hat 128 Pl\u00e4tze f\u00fcr 44100kHz stereo wav-Sound, belegt abh. von Skalen.          
2177      }
2178      
2179      public void ladeMonostimmen(int[] skala, String[] ordner, String prefix)
2180      {
2181            this.skala = skala;
2182            skalamap = new int[128];
2183            for(int i=0;i<skala.length;i++)
2184                skalamap[skala[i]] = i;  //um schnell aus Midi den Index zu gewinnen!
2185            mono = new float[ordner.length][skala.length][];
2186            for(int i=0;i<mono.length;i++)
2187            {
2188                 for(int k=0;k<mono[i].length;k++)
2189                 {
2190                       mono[i][k] = wav.ladeWavMix("data/"+ordner[i]+"/"+prefix+skala[k]+".wav");
2191                 }
2192            }
2193      }
2194
2195      public void ladeMonostimmen(int[] skala, String[] ordner, float[] verst, String prefix)
2196      {
2197            this.skala = skala;
2198            skalamap = new int[128];
2199            for(int i=0;i<skala.length;i++)
2200                skalamap[skala[i]] = i;  //um schnell aus Midi den Index zu gewinnen!
2201            mono = new float[ordner.length][skala.length][];
2202            for(int i=0;i<mono.length;i++)
2203            {
2204                 for(int k=0;k<mono[i].length;k++)
2205                 {
2206                       mono[i][k] = wav.ladeWavMix("data/"+ordner[i]+"/"+prefix+skala[k]+".wav");
2207                 }
2208            }
2209            
2210            for(int i=0;i<mono.length;i++)
2211            {
2212                 for(int k=0;k<mono[i].length;k++)
2213                 {
2214                    for(int p=0;p<mono[i][k].length;p++)
2215                       mono[i][k][p] *= verst[i];
2216                 }
2217            }
2218            
2219      }
2220      
2221      
2222      public void ladeKanal(int kanal, String ordnerpfad, int[] midiskala, float laute, float pan)
2223      {
2224           float pan_left = cos(pan*HALF_PI);
2225           float pan_right = sin(pan*HALF_PI);
2226           for(int i=0;i<midiskala.length;i++)
2227           {
2228                 ton[kanal][midiskala[i]] = wav.ladeWavInterpolate(ordnerpfad,midiskala[i]);
2229                 for(int k=0;k<ton[kanal][midiskala[i]][0].length;k++)
2230                 {
2231                       ton[kanal][midiskala[i]][0][k]*=laute*pan_left;
2232                       ton[kanal][midiskala[i]][1][k]*=laute*pan_right;
2233                 }
2234           }
2235      }
2236
2237      public void ladeKanalStereo(int kanal, String ordnerpfad, int[] midiskala, float laute, float pan)
2238      {
2239           float pan_left = cos(pan*HALF_PI);
2240           float pan_right = sin(pan*HALF_PI);
2241           for(int i=0;i<midiskala.length;i++)
2242           {
2243//                 ton[kanal][midiskala[i]] = wav.ladeWav(ordnerpfad+"/ton"+midiskala[i]+".wav");
2244//ANDROID:
2245                 ton[kanal][midiskala[i]] = wav.ladeWav(ordnerpfad+"_ton"+midiskala[i]+".wav");
2246                 for(int k=0;k<ton[kanal][midiskala[i]][0].length;k++)
2247                 {
2248                       ton[kanal][midiskala[i]][0][k]*=laute*pan_left;
2249                       ton[kanal][midiskala[i]][1][k]*=laute*pan_right;
2250                 }
2251           }
2252      }
2253      
2254      public void saveKanal(int kanal, String pfad, int[] midiskala)
2255      {
2256            for(int i=0;i<midiskala.length;i++)
2257            {
2258                 wav.saveWav(pfad+"/ton"+midiskala[i]+".wav",ton[kanal][midiskala[i]]);
2259            }
2260      }
2261      
2262      public void play(int kanal, int midihoehe)
2263      {
2264            play(ton[kanal][midihoehe]);
2265      }
2266
2267      public void playMono(int kanal, int midihoehe)
2268      {
2269            playMono(mono[kanal][skalamap[midihoehe]]);
2270      }
2271      
2272}
2273
2274
2275public interface iWav
2276{
2277    public abstract void saveWav(String name, float[][] data);  
2278    //float-Array wieder zur\u00fcck in ein byte-Array umwandeln (Vorbereitung speichern eines Stereokanals)
2279    public abstract byte[] toByte(float[][] data);
2280    //L\u00e4dt eine Stereo-Wav-Datei in zwei getrennten float-Arrays, Wertebereich [-1,+1]:
2281    public abstract float[][] ladeWav(String name);
2282    public abstract float[][] ladeWav(String name, int sampleanzahl);
2283    //L\u00e4dt eine Stereo-Wav-Datei, die dann zu einem Kanal gemischt wird und als float-Array zur\u00fcck gegeben wird.
2284    //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
2285    public abstract float[] ladeWavMix(String name); 
2286    /**
2287     * L\u00e4dt eine Stereo-Datei, mixt sie zu Mono und baut sie zu einer loop-baren Variante
2288     * zusammen:<br/>
2289     * [AB] a=A ausblenden, b=B einblenden<br/>
2290     * ab + ba<br/>
2291     */
2292    public abstract float[] ladeWavMixLoop(String name); //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
2293    //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)    
2294    public abstract float[] ladeWavMix(String name, int sampleanzahl);
2295    //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)    
2296    public abstract float[] ladeWavMixLoop(String name, int sampleanzahl); 
2297    /**
2298    *  L\u00e4dt wav-Files, die als 16-Bit Mono-Files vorliegen
2299    */
2300    public abstract float[] ladeWavMono(String name); 
2301    /**
2302     * Shows wav-data as Java-short-Array
2303     */
2304    public abstract void showAsShortArray(float[] wav);    
2305}
2306public class Wav implements iWav
2307{
2308    private PApplet pap;
2309  
2310    public Wav(PApplet pap)
2311    {
2312        this.pap = pap;
2313    }
2314
2315
2316
2317    public void saveWav(String name, float[][] data)
2318    {
2319          double gross = 0.5f*(255.0f*256.0f + 255.0f);
2320          double gesamt_links,gesamt_rechts;
2321          byte[] dat = new byte[44+data[0].length*4];
2322          for(int i=0;i<data[0].length;i++)
2323          {
2324               float links = data[0][i];
2325               float rechts = data[1][i];
2326               
2327               gesamt_links = Math.round(  (links+gross)*gross  );
2328               gesamt_rechts = Math.round(  (rechts+gross)*gross  );
2329               
2330
2331               int lo_links = (int)gesamt_links%256;
2332               int lo_rechts = (int)gesamt_rechts%256;
2333               int hi_links = (int)gesamt_links/256;
2334               int hi_rechts = (int)gesamt_rechts/256;
2335
2336               hi_links-=128;
2337               hi_rechts-=128;
2338               
2339               byte left_lo = (byte)lo_links;
2340               byte left_hi = (byte)hi_links;
2341               byte right_lo = (byte)lo_rechts;
2342               byte right_hi = (byte)hi_rechts;
2343               
2344               dat[44+i*4+0] = left_lo;               
2345               dat[44+i*4+1] = left_hi;               
2346               dat[44+i*4+2] = right_lo;               
2347               dat[44+i*4+3] = right_hi;               
2348          }
2349          
2350          //Kopf f\u00fcr wav-Datei passend erzeugen:
2351          int[] kopf = {  82,   73,   70,   70,   52,  177,    2,    0,   87,   65, 
2352                                86,   69,  102,  109,  116,   32,   16,    0,    0,    0, 
2353                                 1,    0,    2,    0,   68,  172,    0,    0,   16,  177, 
2354                                 2,    0,    4,    0,   16,    0,  100,   97,  116,   97, 
2355                                16,  177,    2,    0  };
2356          int[] zahl1 = {0,0,0,0};
2357          int[] zahl2 = {0,0,0,0};
2358
2359          int  z1 = data[0].length*4+36;
2360          int  z2 = data[0].length*4;
2361          //KOPF bilden
2362          for(int i=0;i<4;i++)
2363          {  
2364              zahl1[i] = z1%256;
2365              z1/=256;
2366              kopf[4+i] = zahl1[i];
2367          }
2368          for(int i=0;i<4;i++)
2369          {
2370              zahl2[i] = z2%256;
2371              z2/=256;
2372              kopf[40+i] = zahl2[i];
2373          }
2374          
2375          for(int i=0;i<kopf.length;i++)
2376//              dat[i] = (byte)(kopf[i]-128);
2377              dat[i] = (byte)(kopf[i]);
2378              
2379          pap.saveBytes(name,dat);    
2380    }
2381
2382    public byte[] toByte(float[][] data)
2383    {
2384          double gross = 0.5f*(255.0f*256.0f + 255.0f);
2385          double gesamt_links,gesamt_rechts;
2386          byte[] dat = new byte[data[0].length*4];
2387          for(int i=0;i<data[0].length;i++)
2388          {
2389               float links = data[0][i];
2390               float rechts = data[1][i];
2391               
2392               gesamt_links = Math.round(  (links+gross)*gross  );
2393               gesamt_rechts = Math.round(  (rechts+gross)*gross  );
2394               
2395
2396               int lo_links = (int)gesamt_links%256;
2397               int lo_rechts = (int)gesamt_rechts%256;
2398               int hi_links = (int)gesamt_links/256;
2399               int hi_rechts = (int)gesamt_rechts/256;
2400
2401               hi_links-=128;
2402               hi_rechts-=128;
2403               
2404               byte left_lo = (byte)lo_links;
2405               byte left_hi = (byte)hi_links;
2406               byte right_lo = (byte)lo_rechts;
2407               byte right_hi = (byte)hi_rechts;
2408               
2409               dat[i*4+0] = left_lo;               
2410               dat[i*4+1] = left_hi;               
2411               dat[i*4+2] = right_lo;               
2412               dat[i*4+3] = right_hi;               
2413          }
2414          
2415          return dat;
2416    }
2417
2418    /**
2419     * L\u00e4dt eine Stereo-Wav-Datei in zwei getrennten float-Arrays, Wertebereich [-1,+1]
2420     */
2421    public float[][] ladeWav(String name)
2422    {
2423            int zl,zh,lo,gesamt;
2424            float gross = 0.5f*(255.0f*256.0f + 255.0f);
2425          
2426            byte[] dat = pap.loadBytes(name);
2427
2428            int anz = dat.length;
2429          
2430            float[][] y = new float[2][(anz-44)/4];                        
2431            //float[][] y = new float[2][sampleanzahl];                        
2432
2433            int inx=44;
2434            
2435            for(int i=0;i<y[0].length;i++)
2436            {
2437                 zl = dat[inx++];
2438                 zh = dat[inx++];
2439                 if(zl>127)
2440                     zl-=256;
2441            
2442                 if(zh>127)
2443                     zh-=256;
2444
2445                 lo     =  zl;
2446                 if(lo<0)
2447                     lo+=256;
2448                 gesamt = (zh+128)*256;                
2449                 gesamt+=lo;
2450                
2451                 y[0][i] = ((float)gesamt - gross)/gross;        
2452
2453                 zl = dat[inx++];
2454                 zh = dat[inx++];
2455                 if(zl>127)
2456                     zl-=256;
2457            
2458                 if(zh>127)
2459                     zh-=256;
2460
2461                 lo     =  zl;
2462                 if(lo<0)
2463                     lo+=256;
2464                 gesamt = (zh+128)*256;
2465                
2466                 gesamt+=lo;
2467                
2468                 y[1][i] = ((float)gesamt - gross)/gross;        
2469                 
2470            }    
2471            
2472            return y;
2473    }
2474  
2475    /**
2476    *   Pr\u00fcft, ob pfad+"/ton"+midi+".wav" im Original existiert, sucht andernfalls nach Nachbarn und interpoliert diese.    
2477    */
2478    int[] tests = {-1,1,-2,2,-3,3,-4,4,-5,5,-6,6,-7,7,-8,8,-9,9,-10,10,-11,11,-12,12};
2479    public float[][] ladeWavInterpolate(String pfad,int midi)
2480    {
2481        String name = pfad+"/ton"+midi+".wav";
2482        if(  (new File(name)).exists()  )
2483        {
2484             return ladeWav(name);    
2485        }
2486        else
2487        {
2488             for(int i=0;i<tests.length;i++)
2489             {
2490                 name = pfad+"/ton"+(midi+tests[i])+".wav";
2491                 if(  (new File(name)).exists()  )
2492                 {
2493                     float[][] data =  ladeWav(name);
2494                     
2495                     double ineu = Math.pow(2.0f,(1.0f/12.0f)*(double)(-tests[i]));
2496                     
2497                     float[][] data_neu = new float[2][(int)Math.round((double)data[0].length/ineu)+1];
2498                     
2499                     for(int k=0;k<data_neu[0].length;k++)
2500                     {
2501                           double inx = ineu*(double)k;
2502                           double inx1 = Math.floor(inx);
2503                           double inx2 = Math.ceil(inx);
2504                           int iinx1 = (int)inx1;
2505                           int iinx2 = (int)inx2;
2506                           
2507                           if(iinx1==iinx2 && iinx1>=0 && iinx1<data[0].length)
2508                           {
2509                                data_neu[0][k] = data[0][iinx1];
2510                                data_neu[1][k] = data[1][iinx1];
2511                           }
2512                           else if(iinx1!=iinx2 && iinx1>=0 && iinx1<data[0].length && iinx2>=0 && iinx2<data[0].length)
2513                           {
2514                                double anteil2 = inx - inx1;  
2515                                double anteil1 = 1.0f - anteil2;  
2516                                data_neu[0][k] = (float)anteil1*data[0][iinx1] + (float)anteil2*data[0][iinx2];
2517                                data_neu[1][k] = (float)anteil1*data[1][iinx1] + (float)anteil2*data[1][iinx2];
2518                           }
2519                           
2520                     }
2521                     
2522                     return data_neu;
2523                 }
2524             }
2525        }
2526        
2527        return null;
2528    }  
2529    
2530    /**
2531     * L\u00e4dt eine Stereo-Wav-Datei in zwei getrennten float-Arrays, Wertebereich [-1,+1]
2532     */
2533    public float[][] ladeWav(String name, int sampleanzahl)
2534    {
2535            int zl,zh,lo,gesamt;
2536            float gross = 0.5f*(255.0f*256.0f + 255.0f);
2537          
2538            byte[] dat = pap.loadBytes(name);
2539
2540            int anz = dat.length;
2541          
2542            //double[][] y = new double[2][(anz-44)/4];                        
2543            float[][] y = new float[2][sampleanzahl];                        
2544
2545            int inx=44;
2546            
2547            for(int i=0;i<y[0].length;i++)
2548            {
2549                 zl = dat[inx++];
2550                 zh = dat[inx++];
2551                 if(zl>127)
2552                     zl-=256;
2553            
2554                 if(zh>127)
2555                     zh-=256;
2556
2557                 lo     =  zl;
2558                 if(lo<0)
2559                     lo+=256;
2560                 gesamt = (zh+128)*256;
2561                
2562                 gesamt+=lo;
2563                
2564                 y[0][i] = ((float)gesamt - gross)/gross;        
2565
2566                 zl = dat[inx++];
2567                 zh = dat[inx++];
2568                 if(zl>127)
2569                     zl-=256;
2570            
2571                 if(zh>127)
2572                     zh-=256;
2573
2574                 lo     =  zl;
2575                 if(lo<0)
2576                     lo+=256;
2577                 gesamt = (zh+128)*256;
2578                
2579                 gesamt+=lo;
2580                
2581                 y[1][i] = ((float)gesamt - gross)/gross;        
2582                 
2583            }    
2584            
2585            return y;
2586    }
2587
2588    /**
2589     * L\u00e4dt eine Stereo-Wav-Datei, die dann zu einem Kanal gemischt wird und als float-Array zur\u00fcck gegeben wird.
2590     */
2591    public float[] ladeWavMix(String name) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
2592    {
2593            int zl,zh,lo,gesamt;
2594            float gross = 0.5f*(255.0f*256.0f + 255.0f);
2595          
2596            byte[] dat = pap.loadBytes(name);
2597
2598            int anz = dat.length;
2599          
2600            //double[][] y = new double[2][(anz-44)/4];                        
2601            //float[] y = new float[sampleanzahl];                        
2602            float[] y = new float[(anz-44)/4];                        
2603
2604            int inx=44;
2605            
2606            for(int i=0;i<y.length;i++)
2607            {
2608                 zl = dat[inx++];
2609                 zh = dat[inx++];
2610                 if(zl>127)
2611                     zl-=256;
2612            
2613                 if(zh>127)
2614                     zh-=256;
2615
2616                 lo     =  zl;
2617                 if(lo<0)
2618                     lo+=256;
2619                 gesamt = (zh+128)*256;
2620                
2621                 gesamt+=lo;
2622                
2623                 //y[0][i] = ((float)gesamt - gross)/gross;        
2624                 y[i] = 0.5f*((float)gesamt - gross)/gross;        
2625
2626                 zl = dat[inx++];
2627                 zh = dat[inx++];
2628                 if(zl>127)
2629                     zl-=256;
2630            
2631                 if(zh>127)
2632                     zh-=256;
2633
2634                 lo     =  zl;
2635                 if(lo<0)
2636                     lo+=256;
2637                 gesamt = (zh+128)*256;
2638                
2639                 gesamt+=lo;
2640                
2641                 //y[1][i] = ((float)gesamt - gross)/gross;        
2642                 y[i] += 0.5f*((float)gesamt - gross)/gross;        
2643                 
2644            }    
2645            
2646            return y;    
2647    }
2648    
2649    /**
2650     * L\u00e4dt eine Stereo-Datei, mixt sie zu Mono und baut sie zu einer loop-baren Variante
2651     * zusammen:<br/>
2652     * [AB] a=A ausblenden, b=B einblenden<br/>
2653     * ab + ba<br/>
2654     */
2655    public float[] ladeWavMixLoop(String name) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
2656    {
2657          float[] AB = ladeWavMix(name);   
2658          for(int i=0;i<AB.length/2;i++)
2659          {
2660              AB[i] = AB[i]*(1.0f - (float)i/(float)(AB.length/2)-1);
2661              int ii = AB.length-1-i;
2662              AB[ii] = AB[ii]*(1.0f - (float)i/(float)(AB.length/2)-1);
2663          }   
2664          
2665          for(int i=0;i<AB.length/2;i++)
2666          {
2667              int ii = AB.length/2+i;
2668              float a = AB[i];
2669              float b = AB[ii];
2670              AB[i] = a+b;
2671              AB[ii] = a+b;
2672          }   
2673          return AB;
2674    }
2675
2676    public float[] ladeWavMix(String name, int sampleanzahl) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
2677    {
2678         float[][] stereo = ladeWav(name,sampleanzahl);
2679         for(int i=0;i<stereo[0].length;i++)
2680             stereo[0][i] = 0.5f*(stereo[0][i]+stereo[1][i]);
2681         return stereo[0];    
2682    }
2683    
2684    public float[] ladeWavMixLoop(String name, int sampleanzahl) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
2685    {
2686         float[][] stereo = ladeWav(name,sampleanzahl);
2687         for(int i=0;i<stereo[0].length;i++)
2688             stereo[0][i] = 0.5f*(stereo[0][i]+stereo[1][i]);
2689         float[] AB = stereo[0];   
2690         for(int i=0;i<AB.length/2;i++)
2691         {
2692              AB[i] = AB[i]*(1.0f - (float)i/(float)(AB.length/2)-1);
2693              int ii = AB.length-1-i;
2694              AB[ii] = AB[ii]*(1.0f - (float)i/(float)(AB.length/2)-1);
2695         }   
2696          
2697         for(int i=0;i<AB.length/2;i++)
2698         {
2699              int ii = AB.length/2+i;
2700              float a = AB[i];
2701              float b = AB[ii];
2702              AB[i] = a+b;
2703              AB[ii] = a+b;
2704         }   
2705         return AB;
2706         
2707    }
2708    
2709    /**
2710    *  L\u00e4dt wav-Files, die als 16-Bit Mono-Files vorliegen
2711    */
2712    public float[] ladeWavMono(String name) 
2713    {
2714            int zl,zh,lo,gesamt;
2715            float gross = 0.5f*(255.0f*256.0f + 255.0f);
2716          
2717            byte[] dat = pap.loadBytes(name);
2718
2719            int anz = dat.length;
2720          
2721            //double[][] y = new double[2][(anz-44)/4];                        
2722            //float[] y = new float[sampleanzahl];                        
2723            //float[] y = new float[(anz-44)/4];                        
2724            float[] y = new float[(anz-44)/2];                        
2725
2726            int inx=44;
2727            
2728            for(int i=0;i<y.length;i++)
2729            {
2730                 zl = dat[inx++];
2731                 zh = dat[inx++];
2732                 if(zl>127)
2733                     zl-=256;
2734            
2735                 if(zh>127)
2736                     zh-=256;
2737
2738                 lo     =  zl;
2739                 if(lo<0)
2740                     lo+=256;
2741                 gesamt = (zh+128)*256;
2742                
2743                 gesamt+=lo;
2744                
2745                 //y[0][i] = ((float)gesamt - gross)/gross;        
2746                 y[i] = ((float)gesamt - gross)/gross;                         
2747            }    
2748            
2749            return y;
2750    }
2751    
2752    /**
2753     * Shows wav-data as Java-short-Array
2754     */
2755    public void showAsShortArray(float[] wav)
2756    {
2757         PApplet.println();
2758         PApplet.println("private short[] data = {");
2759         for(int i=0;i<wav.length;i++)
2760         {
2761              if(i<wav.length-1)
2762                 PApplet.print((int)PApplet.round((wav[i]*32000.0f))+",");
2763              else   
2764                 PApplet.print((int)PApplet.round((wav[i]*32000.0f)));
2765                 
2766              if(i%200==0 && i>0)   
2767                  PApplet.println();
2768         }
2769         PApplet.println();
2770         PApplet.println("};");
2771         
2772    }
2773    
2774    public void ueberlappendVerketten(String quelle1, String quelle2, String ziel, int samples_ueberlappung)
2775    {
2776         float[][] q1 = ladeWav(quelle1);
2777         float[][] q2 = ladeWav(quelle2);
2778         
2779         float[][] z = new float[2][q1[0].length+q2[0].length-samples_ueberlappung];
2780         
2781         for(int i=0;i<q1[0].length;i++)
2782         {
2783              z[0][i] = q1[0][i];
2784              z[1][i] = q1[1][i];
2785         }
2786         for(int i=0;i<q2[0].length;i++)
2787         {
2788              z[0][i+q1[0].length-samples_ueberlappung] += q2[0][i];
2789              z[1][i+q1[1].length-samples_ueberlappung] += q2[1][i];
2790         }
2791         
2792         saveWav(ziel,z);         
2793    }
2794    
2795}
2796  public void settings() {  fullScreen(); }
2797}