void save (OutputStream os) throws IOException, SynthIfException {
    DataOutputStream dos = new DataOutputStream (os);
    dos.writeBytes ("ZSyn");	// magic
    dos.writeInt (1);		// file format version

    dos.writeInt (size().width);
    dos.writeInt (size().height);

    dos.writeInt (samplingRate);
    dos.writeDouble (time);

    dos.writeInt (generators.size() + connections.size());

    Enumeration e = generators.elements();
    while (e.hasMoreElements()) {
      GeneratorBox gen = (GeneratorBox) e.nextElement();
      gen.write (dos);
    }

    e = connections.elements();
    while (e.hasMoreElements()) {
      Connection c = (Connection) e.nextElement();
      int sourceNo = -1, destGenNo = -1, destInNo = -1;
      for (int genNo = 0; genNo < generators.size(); genNo++) {
        GeneratorBox gen = (GeneratorBox) generators.elementAt (genNo);
        if (c.source == gen)
	  sourceNo = genNo;
	for (int inNo = 0; inNo < gen.inputs.size(); inNo++) {
	  Input in = (Input) gen.inputs.elementAt (inNo);
	  if (c.dest == in) {
	    destGenNo = genNo;
	    destInNo = inNo;
	  }
	}
      }
      if (sourceNo < 0 || destGenNo < 0 || destInNo < 0)
        throw new SynthIfException ("Invalid internal data structure");
      dos.writeBytes (Connection.IDENT);
      dos.writeInt (sourceNo);
      dos.writeInt (destGenNo);
      dos.writeInt (destInNo);
      dos.writeBoolean (c.isSelected());
    }
  }