reversound/src/processing/buffer/Buffer.java
2014-06-16 16:48:34 +02:00

370 lines
9.7 KiB
Java

/*
Reversound is used to get the music sheet of a piece from a music file.
Copyright (C) 2014 Gabriel AUGENDRE
Copyright (C) 2014 Gabriel DIENY
Copyright (C) 2014 Arthur GAUCHER
Copyright (C) 2014 Gabriel LEPETIT-AIMON
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package processing.buffer;
import conteneurs.ObservableObject;
import conteneurs.ObservableObjectEvent;
import processing.processes.Process;
import javax.swing.*;
import java.util.ArrayList;
/**
* Classe
* @param <T>
*/
public class Buffer <T> {
private final ArrayList<BufferEventListener> bufferListeners;
private final ArrayList<Process<?>> usedBy;
final private Storage.Type arrayType;
private String name = "";
private Class type = null;
private boolean itemObservable = false;
private Process.ProcessingOrder processingOrder = Process.ProcessingOrder.NO_ORDER;
private Storage<T> samples;
private final StorageArrayList<Integer> updateIDs;
/**
* Construit une instance de buffer selon un modéle de stockage
* @param arrayType Modèle de stockage
*/
public Buffer(Storage.Type arrayType) {
switch(arrayType){
case ArrayList:
samples = new StorageArrayList<>();
break;
}
updateIDs = new StorageArrayList<>();
bufferListeners = new ArrayList<>();
usedBy = new ArrayList<>();
this.arrayType = arrayType;
}
private void emitBufferEvent(BufferEvent event) {
for(Process p: usedBy)
p.addBufferEvent(event);
SwingUtilities.invokeLater(() -> {
for(BufferEventListener p: bufferListeners)
p.bufferEvent(event);
});
}
private void emitBufferEvent(BufferEvent.Type type, int sampleID) {
emitBufferEvent(new BufferEvent(type, sampleID, this));
}
/**
* Connecte ce buffer à un listener qu'il fournit, de manière à propager les BufferEvent jusqu'à cet objet
* @param p objet à connecter
* @return Vrai si l'opération à fontionner (si le process n'était pas déjà ajouté)
*/
public boolean addBufferListener(BufferEventListener p){
if(bufferListeners.contains(p))
return false;
bufferListeners.add(p);
return true;
}
/**
* Déconnecte ce buffer d'un listener
* @param p listener à déconnecter
* @return Vrai si l'opération à fontionner (si le listener était dans la liste)
*/
public boolean removeBufferListener(BufferEventListener p){
int id = bufferListeners.indexOf(p);
if(id == -1)
return false;
bufferListeners.remove(id);
return true;
}
/**
* Connecte ce buffer à une entrée d'un algo
* @param p Algo à connecte
* @return Vrai si l'opération c'est bien passée (si il n'avait pas déjà été appelée)
*/
public boolean connectProcess(Process p){
if(usedBy.contains(p))
return false;
usedBy.add(p);
return true;
}
public boolean disconnectProcess(Process p){
if(!usedBy.contains(p))
return false;
usedBy.remove(p);
return true;
}
/**
* Retourne le type de stockage de ce buffer
* @return type de stockage
*/
public Storage.Type getArrayType(){
return arrayType;
}
/**
* Retourne l'indice de version associé à un échantillon.
* @param id index de l'échantillon
* @return indice de version
*/
public Integer getUpdateID(int id) {
return updateIDs.get(id);
}
/**
* Surcharge de set(int,T,int) mais avec un indice de version = 1
* @param index indice de l'échantillon à modifier ou ajouter
* @param value valeur de l'échantillon
* @return la valeur de l'échantillon précédant /!\ Peut retourner null si aucun n'échantillon ne correspondait à l'index /!\
*/
public T set(int index, T value){ return set(index, value, null);}
/**
* Modifie un échantillon ou l'ajoute à au stockage si index ne correspond à aucun élément, complète alors avec des échantillons = null.
* De plus, updateId est associé à l'échantillon en tant qu'indice de version
* @param index indice de l'échantillon à modifier ou ajouter
* @param value valeur de l'échantillon
* @param updateId indice de version à associer
* @return la valeur de l'échantillon précédant /!\ Peut retourner null si aucun n'échantillon ne correspondait à l'index /!\
*/
public T set(int index, T value, Integer updateId){
T previous = samples.set( index, value);
updateIDs.set(index, updateId);
if(itemObservable)
((ObservableObject)value).addListener(
new ObservableObject.SignedListener() {
@Override
public void observableOjectEvent(ObservableObjectEvent e) {
emitBufferEvent(BufferEvent.Type.SAMPLE_CHANGED, index);
}
@Override
public String signature() {
return this.hashCode() + ":" + index;
}
});
if(previous==null) {
emitBufferEvent(BufferEvent.Type.SAMPLE_ADDED, index);
return null;
}else{
if(value==null)
emitBufferEvent(BufferEvent.Type.SAMPLE_DELETED, index);
else
emitBufferEvent(BufferEvent.Type.SAMPLE_CHANGED, index);
if(itemObservable)
((ObservableObject)previous).removeSignedListener(this.hashCode()+":"+index);
}
return previous;
}
/**
* Surcharge de addNote(T) mais avec un indice de version = 1
* @param value valeur de l'échantillon à ajouter
* @return vrai si l'opération c'est bien passé (mais peut-elle mal se passer?)...
*/
public boolean add(T value){
return add(value,0);
}
/**
* Ajoute un élément après le dernier élément du stockage et lui associe un indice de version
* @param value valeur de l'échantillon à ajouter
* @param updateId indice de version à associer
* @return vrai si l'opération c'est bien passé (mais peut-elle rater?)...
*/
boolean add(T value, int updateId){
if(!samples.add(value))
return false;
updateIDs.add(updateId);
emitBufferEvent(BufferEvent.Type.SAMPLE_ADDED, samples.size() - 1);
if(itemObservable)
((ObservableObject)value).addListener(new ObservableObject.Listener() {
@Override
public void observableOjectEvent(ObservableObjectEvent e) {
emitBufferEvent(BufferEvent.Type.SAMPLE_CHANGED, samples.size()-1);
}
});
return true;
}
/**
* Renvoie la valeur d'un échantillon
* @param id index de l'échantillon
* @return valeur de l'échantillon /!\ Peut revoyer null si aucun échantillon ne correspond à l'index /!\
*/
public T get(int id){
return samples.get(id);
}
/**
* Supprime un échantillon du buffer
* @param id index de l'échantillon à supprimer
* @return la valeur de l'échantillon supprimer /!\ Peut renvoyer null si aucun échantillon ne correspondait à cet index /!\
*/
public T remove(int id){
T sampleDeleted = samples.remove(id);
updateIDs.remove(id);
if(sampleDeleted!=null) {
emitBufferEvent(BufferEvent.Type.SAMPLE_DELETED, id);
if(itemObservable)
((ObservableObject)sampleDeleted).removeSignedListener(this.hashCode() + ":" + id);
}
return sampleDeleted;
}
/**
* Retourne le nombre maximum d'élément de tableau (dernier index +1)
* @return la taille de l'espace de stockage
*/
public int size(){
return samples.size();
}
/**
* Vérifie si le buffer est vide où non
* @return Vrai si il est vide
*/
public boolean isEmpty(){
return size()==0;
}
public boolean isCorrectIndex(int id){
return get(id)!=null;
}
/**
* Retourne la liste des indexs associés à des éléments dans le Storage: aucun de ces indexs ne retournera null par get(index)
* * @return la liste des indexs de tout les éléments du Storage
*/
public ArrayList<Integer> getSamplesIndex(){
return samples.getSamplesIndex();
}
public StorageIterator<T> getIterator(){
return samples.getIterator();
}
/**
* Génère un iterateur pointant initialement sur l'élément de la liste correspondant à l'index en argument
* @param id index de l'élément sur lequel pointe initialement l'iterateur
* @return Un iterateur sur ce stockage
*/
public StorageIterator<T> getIterator(int id){
return samples.getIterator(id);
}
public void lastSampleAdded(){
emitBufferEvent(BufferEvent.Type.INTERRUPT_PROCESS,-1);
}
public void clear(){
switch(arrayType){
case ArrayList:
samples = new StorageArrayList<>();
break;
}
emitBufferEvent(BufferEvent.Type.INVALIDATE,-1);
}
public void invalidateProcessedSamples(){
emitBufferEvent(BufferEvent.Type.INVALIDATE,-1);
}
public ArrayList<processing.processes.Process<?>> getUsedBy() {
return usedBy;
}
/**
* Réserve directement un espace sans modifier la taille du tableau (si la daforme si prête)
* @param capacity capacité maximale;
*/
public void tryEnsureCapacity(int capacity){
samples.tryEnsureCapacity(capacity);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class getType() {
if(type==null&&!samples.isEmpty())
return samples.get(getSamplesIndex().get(0)).getClass();
return type;
}
public void setType(Class type) {
this.type = type;
Class[] classes = type.getClasses();
for (int i = 0; i < classes.length; i++)
if (classes[i].equals(ObservableObject.class)) {
itemObservable = true;
return;
}
itemObservable = false;
}
public Process.ProcessingOrder getProcessingOrder() {
return processingOrder;
}
public void setProcessingOrder(Process.ProcessingOrder processingOrder) {
this.processingOrder = processingOrder;
}
}