TableViewExample : NSObject {
	var >tableView, notes, synths, playing;

	init {
		if(super.init == nil) { ^nil; };
		
		notes = List["F1", "C1", "F2", "G2", "A2", "C3"];
		synths = List.newClear(notes.size);
	}

	numberOfRowsInTableView_ { arg table;
		^notes.size;
	}
	
	tableView_objectValueForTableColumn_row_ { arg table, column, row;
		^notes[row];
	}
	
	tableView_setObjectValue_forTableColumn_row_ { arg table, object, column, row;
		this.updateRow(row, object);
	}

	play_ { arg sender;
		if(playing == true) {
			this.stopAll;
			sender.setTitle_("Play");
			playing = false;
		} {
			sender.setEnabled_(false);
			sender.setTitle_("Booting...");
		
			Server.default.waitForBoot({	
				notes.do({ arg item, i;
					if(item != nil) {
						synths[i] = {Saw.ar(item.notemidi.midicps, 0.1)!2}.play;
					};
				});
				
				playing = true;
	
				sender.setEnabled_(true);
				sender.setTitle_("Stop");
			});
		};
	}
	
	add_ {
		notes.add(nil);
		synths.add(nil);
		
		this.updateRow(notes.size-1, "C3");
		
		tableView.defer({
			tableView.selectRowIndexes_byExtendingSelection_(NSIndexSet.indexSetWithIndex_(notes.size-1), nil);
		}).reloadData;
	}
	
	remove_ {
		var selectedRow = tableView.selectedRow;
		
		if(selectedRow < 0) { ^nil; };
		
		this.updateRow(selectedRow, nil);
		
		notes.removeAt(selectedRow);
		synths.removeAt(selectedRow);
		tableView.defer({
			var newRow;
			
			if(selectedRow > (notes.size-1)) {
				newRow = notes.size-1;
			} {
				newRow = selectedRow;
			};
			
			tableView.selectRowIndexes_byExtendingSelection_(NSIndexSet.indexSetWithIndex_(newRow), nil);
		}).reloadData;
	}
	
	windowWillClose_ {
		this.stopAll;
	}
	
	stopAll {
		if(playing == true) {
			synths.do({ |item| item.free});
			playing = false;
		};
	}
	
	updateRow { |row, note|
		if(row < 0) {
			^nil;
		};
	
		if(note == nil) { note = ""; };
		
		if(note.notemidi == nil) {
			if((playing == true) && (synths[row] != nil)) { synths[row].free; synths[row] = nil; };
			notes[row] = nil;
			^nil;
		};
	
		if(notes[row] != note) {
			note = note.toUpper;
			
			if((note.size == 3) && (note[1] == $B)) {
				note[1] = $b;
			};
			
			notes[row] = note;
			
			if(playing == true) {
				if(synths[row] != nil) { synths[row].free; synths[row] = nil; };
				synths[row] = {Saw.ar(note.notemidi.midicps, 0.1)!2}.play;
			};
		};
	}
}