GunLoop

GunLoop (work in progress) ist ein Programm zum „Musik“ machen. GunLoop sammelt Samples über ein Mikrofon und spielt sie in zufälliger Reihenfolge wieder ab. Mit der tarsosDSP-Library werden den Samples Effekte hinzugefügt oder die Geschwindigkeit verändert. Ein Oszi zeigt den produzierten Sound und den Mikrofoninput grafisch an. Das Mikrofon darf nicht Rückkoppeln und nicht die Soundausgabe neu aufnehmen, sonst kommt es zum Overkill. Es muss also entweder ein geeignetes Mirkofon verwendet werden (z.B. Gesangsmikrofon) oder die Funktion „Echolöschung“ im Soundtreiber aktiviert werden. Letztere Option bieten die meisten Soundkarten an und ist z.B. auch für die Nutzung von Skype essentiell.

Alle Samples werden im Arbeitsspeicher gehalten, damit keine Latenzen durch Festplatten Schreib- und Lesezugriffe auftreten. Nach 99 Samples wird das älteste Sample gelöscht. Da liegt der Speicherplatzbedarf bei ca. 500MB (das hängt von der Länge der einzelnen Samples ab). Bei der Verwendung von tarsosDSP muss man darauf achten keine Memory-Leaks zu erzeugen, denn wenn Ressourcen nicht korrekt geschlossen werden verbleiben große Datenmengen im Speicher und nach wenigen Minuten kommt es zum OutOfMemory-Ausnahmefehler und das Programm stürzt ab.

Ein Loop ist in 16 Schritte aufgeteilt. Aufgenommene Samples werden in jedem Durchlauf beim selben Schritt gestartet und mit zufälliger Lautstärke und Effekten abgespielt. Wenn über 30 Sekunden kein neues Sample aufgenommen wurde, wird die Anzahl der abgespielten Samples langsam gesenkt, bis es endlich wieder ruhig wird. Das Programm kann im Vollbild-Modus und oder als Fenster gestartet werden. Mit Klick auf GunLoop->Window bzw. GunLoop->Fullscreen wird die Einstellung gespeichert. Mit GunLoop->Save können die erzeugten Samples als Wav-Dateien gespeichert werden – mit File->Load können alte Samples geladen werden. Die Funktion lädt die Samples an die ursprünglichen Positionen (Steps). Die Option GunLoop->AutoLoader lädt die 99 neusten Samples aus dem zuletzt verwendeten Ordner. Mit dem Menüpunkt GunLoop->Choose input kann die zu benutzende Audioline ausgewählt werden. Das Dialogfenster öffnet sich außerdem automatisch beim ersten Start und speichert die Auswahl ab.

GunLoop in Aktion, in echt hakt´s ein bisschen weniger

Soundbeispiel:

Sourcecode:

public void play(double startTime) {
	if(state == PlayerState.NO_FILE_LOADED || buffer == null){
		throw new IllegalStateException("Can not play when no file is loaded");
	} 
	else {		
		try {
			gainProcessor = null;
			gainProcessor = new GainProcessor(gain);
			if (audioPlayer == null) audioPlayer = new AudioPlayer(format);
			int len = buffer.length;
			dispatcher = null;
			dispatcher = AudioDispatcherFactory.fromByteArray(buffer, format, len, len/2);
			RateTransposer rateTransposer = null;
			rateTransposer = new RateTransposer(tempo);
			dispatcher.addAudioProcessor(rateTransposer);
			dispatcher.setZeroPadFirstBuffer(true);
			dispatcher.setZeroPadLastBuffer(true);
			dispatcher.skip(startTime);
			dispatcher.addAudioProcessor(this);
			dispatcher.addAudioProcessor(beforeWSOLAProcessor);
			flangerEffect = new FlangerEffect(defaultLength/1000.0,defaultImpact/100.0,format.getSampleRate(),defaultFrequency/10.0);
			dispatcher.addAudioProcessor(flangerEffect);
			dispatcher.addAudioProcessor(gainProcessor);
			dispatcher.addAudioProcessor(loopAudioProcessor);
			dispatcher.addAudioProcessor(audioPlayer);
			Thread playThread = new Thread(dispatcher,System.currentTimeMillis()+"_GunLoop");
			playThread.start();
			setState(PlayerState.PLAYING);
		} catch (UnsupportedAudioFileException e) {
			throw new Error(e);
		} catch (LineUnavailableException e) {
			throw new Error(e);
		}
	}
}

Update:

Durch einen Programmierfehler konnte das Fenster nicht öffnen. Das Programm hat nur auf meinem Rechner funktioniert, weil ich eine gunLoop.conf-Datei schon mit einer älteren Version gespeichert hatte. War die Datei nicht vorhanden ist das Programm abgestürzt, bevor sich das Fenster öffnen konnte. Ganz böse!

Download:

Lade eine aktuelle Kopie des Programmes herunter: GunLoop.jar

GunImposer

GunImposer ist ein Programm zum Herstellen von Sammelformen. Seine Stärken sind Geschwindigkeit und die Möglichkeit sehr viele Seiten verarbeiten zu können.

Problem:

  • Ein pdf-Dokument mit 9999 Gutscheinen soll gedruckt werden
  • Die Reihenfolge soll erhalten bleiben
  • Die variablen Daten sollen einen komplizierten Hintergrund bekommen
  • Zwischenschnitte müssen definierbar sein
  • Berücksichtigung von Beschnittzugabe
  • Keine Skalierung der Daten vornehmen (wie bei Acrobat Mehrfach-Ausgabe)

Lösung:

Java-Programm GunImposer mit Verwendung der Apache pdfBox-Library. Mit GunImposer erstellt man fertige Druckbögen mit variablen Daten. Mit Acrobat kann man der erzeugten pdf-Datei einen Hintergrund für alle Seiten verpassen. Dadurch wird der Hintergrund nur einmal hinzugefügt wodurch die Dateigröße enorm sinkt, da alle sich wiederholenden Inhalte nur einmal gespeichert werden. Oder man nutzt die pdf ohne Hintergrund und verwendet dann den Variablen Datendruck VDP, wenn man zB Fiery Command WorkStation hat.

Workflow:

  • Bogenformat einrichten
  • Schema Editor für Nutzenanordnung
  • Datei laden (alle Seiten sollten die gleiche Größe haben)
  • Sortierung wählen, so dass Stapel in Reihenfolge gedruckt werden
  • Optional: Seiten duplizieren
  • Optional: Schnittmarken erzeugen
  • Feature: GunImposer speichert die Eingaben und lädt sie beim nächsten Start neu
GunImposer Schema-Editor

Ergebnis:

GunImposer Druckbogen Seite 1
GunImposer Druckbogen Seite 1250

Auf der letzten Seite fehlt ein Nutzen, da das Dokument 9999 Seiten hatte. Die härteste Nuss an dem Programm war die korrekte Sortierung zu erzielen – einem eigentlich einfachen mathematischen Problem.

Sourcecode:

Wie berechnet sich die Anzahl der Druckbögen?

int allNutzen = cols*rows;	    	
int impoPages = (int)Math.ceil((totalPageNum*duplicates) / (float)allNutzen);
getLblFileInfo().setText((totalPageNum*duplicates)+" Seiten zu "+allNutzen+" Nutzen auf "+impoPages+" Druckbogen");

Interesse:

Frag mich nach einer Kopie des Programms.

GunPrinter

In der Druckvorstufe wird viel geplottet. Ein Plott dient zur Kontrolle der montierten Daten, bevor sie auf Druckplatte belichtet werden. Man kann so die korrekte Positionierung und Seitenfolge prüfen. Schwierig wird es, wenn der bei ebay geschossene Plotter leider keine Postscript-Karte enthält und somit nicht in den Workflow integriert werden kann. GunPrinter löst das Problem indem das Programm Tif-Daten zum Drucker sendet. Die Tif-Dateien werden vom Workflow erzeugt und in einen Ordner gespeichert. Diesen Ordner überwacht GunPrinter, sendet die Datei zum Drucker und löscht sie danach wieder. Der Vorteil dabei ist, dass jetzt die Pdfs von dem Rip interpretiert werden, das später auch die Daten für die Druckplatte erzeugt. Fehler sollten also bereits auf dem Plott erkennbar werden da nicht wie in der gängigen Praxis zwei unterschiedliche Rips die Daten interpretieren.

GunPrinter zeigt eine Liste der vorhandenen Dateien an, die ausgewählt und gestartet werden können. Auf Wunsch startet GunPrinter den Druck automatisch. Es können beliebig viele Hotfolder zur Überwachung angegeben werden.

Den Druckvorgang übernimmt eine IrfanView Portable Version, der mit Hilfe einer Batchdatei der Druckauftrag erteilt wird. Das geschieht unsichtbar im Hintergrund. IrfanView verwendet dabei die letzten verwendeten Einstellungen aus seiner ini-Datei. GunPrinter minimiert sich in das System-Tray und prüft alle paar Sekunden die Hotfolder auf neue Daten.

GunPrinter Gui: Beenden nur über „Beenden“

 

Sourcecode:

Für jeden Printjob wird ein neuer GunPrinterThread gestartet. Ein Scanner überwacht dabei die Batch Ausgabe:

public void run() 
    { 

        if (file.exists() && file.canWrite() ) {
                        
            Scanner s = null;
            try {
                ProcessBuilder builder = new ProcessBuilder( "cmd", "/c", "irfan.bat", file.getAbsoluteFile().toString() ); 
                builder.directory( new File(System.getProperty("user.dir")+System.getProperty("file.separator")+"irfan") ); 
                Process p;
                p = builder.start();

                s = new Scanner( p.getInputStream() );
                s.useDelimiter( "\\Z" ); 
                if (s.next().contains("OK")) { //Batch echos OK if ERRORLEVEL = 0
                    oK  = true;                    
                }

            } catch (IOException e1) {
                e1.printStackTrace();
            } finally {
                if (s!=null) s.close();
            }

            if (oK) {
                GunPrinterPanel.protocol(file + " zum Drucker gesendet.");
                
                if (prefs.node("config").getBoolean("deleteOnSuccess", false)) {
                    file.delete();
                    GunPrinterPanel.protocol(file + " gelöscht.");
                }
                else if (!file.getAbsolutePath().toLowerCase().contains("printed")) {
                    String newFileName = file.getAbsolutePath().toLowerCase().replace(".tif","_printed.tif");
                    file.renameTo(new File(newFileName));
                    GunPrinterPanel.protocol(file + " umbenannt zu "+newFileName+" .");
                }
                oK = false;
            }

        }

    }

Interesse:

Frag mich nach einer Kopie des Programms.

Applausometer

Irgendwann kommt der Tag, da braucht man ein Aplausometer! Bei Ida Nowhere sollte der Super-Singer-SongWriter-Contest steigen. Eine faire Auswertung der Publikumsregungen wäre ohne Aplausometer nicht möglich gewesen! Leider sind nicht alle Künstler gleich ehrlich und manche jubeln selbst ordentlich mit um mehr Punkte abzusahnen.

Applaus Applaus!

Setup:

  • Computer
  • Bildschirm
  • Mikrofon an der Decke
  • Tastatur

Tastenkürzel:

  • Leertaste: Pause an/aus
  • C calibration starten
  • N neue Messung
  • S Messung speichern (Name wird abgefragt und mit dem Applauswert in der Datei scores.txt gespeichert)

Download:

Source:

Die „Magie“ geschieht quasi zur Laufzeit:

public void run()
	{

		byte[]	abBuffer = new byte[m_nExternalBufferSize];
		
		int	nBufferSize = abBuffer.length;		
		
		m_bRecording = true;
		while (m_bRecording)
		{
			while (pause) {
				m_targetLine.read(abBuffer, 0, nBufferSize);
				panel.updateAplause(false);
			}
			
			 m_targetLine.read(abBuffer, 0, nBufferSize);
			
			 if (calib < 99) {
				 for (int j = 0; j < abBuffer.length-1; j+=2) {
						
						pegel = (pegel*(1-gewichtung))+(Math.abs((abBuffer[j+1]<<8)+abBuffer[j]) * gewichtung);
												
						grundrauschen += pegel;
						
					}
				 calib++;
				 grundrauschen = grundrauschen / ((abBuffer.length) / 3.0);				 
			 }
			 else for (int j = 0; j < abBuffer.length-1; j+=2) {
											
						pegel = (pegel*(1-gewichtung))+(Math.abs((abBuffer[j+1]<<8)+abBuffer[j]) * gewichtung);
						
						aplause += Math.max(( (pegel - grundrauschen) / (grundrauschen) ), 0);
						
						if (j%10 == 0) {
							panel.updateAplause(aplause);
						}
												
					}
		}
	}

Recognition Composition

Recognition Composition, Face-Defector oder Anonymizer – einen endgültigen Namen für das Werk habe ich noch nicht gefunden.

Unter einem dieser Namen stellte ich das Werk bereits mehrfach aus:

  • DAS Weekend Berlin
  • Art Buzzl Regensburg
  • Galerie Bauchhund
  • Berliner  Mitteclub

Das Programm nimmt Bilder von einer Webcam auf und analysiert sie mit OpenCV haarcascades, um Gesichter zu finden. Die Gesichter werden ausgeschnitten und mit einem Balken „anonymisiert“. Auf einer Leinwand werden zig dieser Bilder angezeigt und neu erkannte Gesichter sofort hinzugefügt. Auf einem zweiten Bildschirm wird einer Überlagerung aller Gesichter angezeigt. Starrt man lange genug in die Kamera wird die Überlagerung dem Betrachter immer ähnlicher. Bei zwei Betrachtenden entsteht eine Mischgestalt. Schafft man es die gesamte Leinwand mit dem (den) eigenen Gesichter voll zu machen, druckt ein Kassenbon-Nadeldrucker ein zweifarbiges Bild des gemorphten Gesichts mit Datum und Uhrzeit. Dabei handelt es sich um ein Unikat, da das Bild nach dem Druck wieder verändert wird.

Sourcecode:

Auch eine Methode das Gesicht zu verwaschen:

private boolean washFace(File file, int x, int y, int r) {

	int width = 480, height = 480;
	File washFace = new File(Constants.washFacePointer);
	BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
	BufferedImage bi2 = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);

	try {
		bi = ImageIO.read( washFace );
	} catch (IOException e1) {
		bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
	}

	try {
		bi2 = ImageIO.read( file );
	} catch (IOException e1) {
		return false;
	}

	Graphics2D ig2 = bi.createGraphics();
	ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	AffineTransform transform = new AffineTransform();
	double scale = 480.0 / (double)(r) ;
	transform.scale(scale,scale);
	transform.translate(-(double)x,-(double)y);
	float alpha = .05f;
	ig2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
	ig2.drawRenderedImage( bi2, transform );	
	try {
		ImageIO.write(bi, "JPEG", washFace);
	} catch (IOException e) {
		e.printStackTrace();
	}
	return true;
}

Der Druck des Kassenbons erfolgt hier wie bei GunPrinter mit Hilfe von IrfanView:

package gun;

import java.io.File;
import java.io.IOException;

public class PrintThread extends Thread implements Runnable {

	private File file = null;

	public PrintThread(File file) {
		this.file  = file;
	}

	@Override public void run() 
	{ 

		if (file.exists() && file.canRead() ) {

			try {
				ProcessBuilder builder = new ProcessBuilder( "cmd", "/c", "irfan.bat", file.getAbsoluteFile().toString() ); 
				builder.directory( new File(System.getProperty("user.dir")+System.getProperty("file.separator")+"sys"+System.getProperty("file.separator")+"irfan") ); 
				builder.start();

			} catch (IOException e1) {
				e1.printStackTrace();
			} 

		}

	}


}
@echo off
IrfanViewPortable.exe %1 /print="EPSON-TMU220B"
if ERRORLEVEL 1 (echo Fehler) else (echo OK)