/**
   * Add filters according to the current emulation and chip model of the currently played tune.
   *
   * @param tune currently played tune
   * @param num SID chip number
   * @param filters resulting filter list to add matching filter names to
   * @param filter combo box to select currently selected filter
   */
  private void addFilters(
      final SidTune tune, int num, ObservableList<String> filters, ComboBox<String> filter) {
    EmulationSection emulationSection = util.getConfig().getEmulationSection();

    boolean filterEnable = emulationSection.isFilterEnable(num);

    Emulation emulation = Emulation.getEmulation(emulationSection, tune, num);
    ChipModel model = ChipModel.getChipModel(emulationSection, tune, num);
    String filterName = filterEnable ? emulationSection.getFilterName(num, emulation, model) : null;

    filters.clear();
    filters.add("");
    for (IFilterSection filterSection : util.getConfig().getFilterSection()) {
      if (emulation.equals(Emulation.RESIDFP)) {
        if (filterSection.isReSIDfpFilter6581() && model == ChipModel.MOS6581) {
          filters.add(filterSection.getName());
        } else if (filterSection.isReSIDfpFilter8580() && model == ChipModel.MOS8580) {
          filters.add(filterSection.getName());
        }
      } else {
        if (filterSection.isReSIDFilter6581() && model == ChipModel.MOS6581) {
          filters.add(filterSection.getName());
        } else if (filterSection.isReSIDFilter8580() && model == ChipModel.MOS8580) {
          filters.add(filterSection.getName());
        }
      }
    }
    if (filterEnable) {
      filter.getSelectionModel().select(filterName);
    } else {
      filter.getSelectionModel().select(0);
    }
  }
  /**
   * Set filter name of the specified SID number according to the current emulation and chip model
   *
   * @param sidNum SID chip number
   * @param filterBox filter combo box
   */
  private void setFilter(int sidNum, ComboBox<String> filterBox) {
    IEmulationSection emulationSection = util.getConfig().getEmulationSection();

    String filterName = filterBox.getSelectionModel().getSelectedItem();
    boolean filterDisabled = "".equals(filterName);
    emulationSection.setFilterEnable(sidNum, !filterDisabled);

    SidTune tune = util.getPlayer().getTune();
    Emulation emulation = Emulation.getEmulation(emulationSection, tune, sidNum);
    ChipModel model = ChipModel.getChipModel(emulationSection, tune, sidNum);
    emulationSection.setFilterName(sidNum, emulation, model, !filterDisabled ? filterName : null);
  }
  @FXML
  private void initialize() {
    duringInitialization = true;

    ResourceBundle bundle = util.getBundle();
    EmulationSection emulationSection = util.getConfig().getEmulationSection();

    mainFilters = FXCollections.<String>observableArrayList();
    mainFilter.setItems(mainFilters);
    secondFilters = FXCollections.<String>observableArrayList();
    secondFilter.setItems(secondFilters);
    thirdFilters = FXCollections.<String>observableArrayList();
    thirdFilter.setItems(thirdFilters);

    NumberToString<Double> doubleToString = new NumberToString<Double>(1);
    mainBalance.setValue(util.getConfig().getAudioSection().getMainBalance());
    mainBalance.setLabelFormatter(doubleToString);
    mainBalance
        .valueProperty()
        .addListener(
            (observable, oldValue, newValue) -> {
              util.getConfig().getAudioSection().setMainBalance(newValue.floatValue());
              util.getPlayer().configureMixer(m -> m.setBalance(0, newValue.floatValue()));
            });
    secondBalance.setValue(util.getConfig().getAudioSection().getSecondBalance());
    secondBalance.setLabelFormatter(doubleToString);
    secondBalance
        .valueProperty()
        .addListener(
            (observable, oldValue, newValue) -> {
              util.getConfig().getAudioSection().setSecondBalance(newValue.floatValue());
              util.getPlayer().configureMixer(m -> m.setBalance(1, newValue.floatValue()));
            });
    thirdBalance.setValue(util.getConfig().getAudioSection().getThirdBalance());
    thirdBalance.setLabelFormatter(doubleToString);
    thirdBalance
        .valueProperty()
        .addListener(
            (observable, oldValue, newValue) -> {
              util.getConfig().getAudioSection().setThirdBalance(newValue.floatValue());
              util.getPlayer().configureMixer(m -> m.setBalance(2, newValue.floatValue()));
            });

    mainVolume.setValue(util.getConfig().getAudioSection().getMainVolume());
    mainVolume
        .valueProperty()
        .addListener(
            (observable, oldValue, newValue) -> {
              util.getConfig().getAudioSection().setMainVolume(newValue.floatValue());
              util.getPlayer().configureMixer(m -> m.setVolume(0, newValue.floatValue()));
            });
    secondVolume.setValue(util.getConfig().getAudioSection().getSecondVolume());
    secondVolume
        .valueProperty()
        .addListener(
            (observable, oldValue, newValue) -> {
              util.getConfig().getAudioSection().setSecondVolume(newValue.floatValue());
              util.getPlayer().configureMixer(b -> b.setVolume(1, newValue.floatValue()));
            });
    thirdVolume.setValue(util.getConfig().getAudioSection().getThirdVolume());
    thirdVolume
        .valueProperty()
        .addListener(
            (observable, oldValue, newValue) -> {
              util.getConfig().getAudioSection().setThirdVolume(newValue.floatValue());
              util.getPlayer().configureMixer(b -> b.setVolume(2, newValue.floatValue()));
            });

    stereoModes = FXCollections.<StereoMode>observableArrayList(StereoMode.values());
    stereoMode.setConverter(new EnumToString<StereoMode>(bundle));
    stereoMode.setItems(stereoModes);

    baseAddress.setText(String.format("0x%4x", emulationSection.getDualSidBase()));
    thirdAddress.setText(String.format("0x%4x", emulationSection.getThirdSIDBase()));

    sidReads = FXCollections.<SidReads>observableArrayList(SidReads.values());
    sidToRead.setConverter(new EnumToString<SidReads>(bundle));
    sidToRead.setItems(sidReads);
    sidToRead.getSelectionModel().select(emulationSection.getSidNumToRead());

    sid1Emulations = FXCollections.<Emulation>observableArrayList(Emulation.values());
    sid1Emulation.setConverter(new EnumToString<Emulation>(bundle));
    sid1Emulation.setItems(sid1Emulations);
    sid1Emulation.getSelectionModel().select(emulationSection.getUserEmulation());

    sid2Emulations = FXCollections.<Emulation>observableArrayList(Emulation.values());
    sid2Emulation.setConverter(new EnumToString<Emulation>(bundle));
    sid2Emulation.setItems(sid2Emulations);
    sid2Emulation.getSelectionModel().select(emulationSection.getStereoEmulation());

    sid3Emulations = FXCollections.<Emulation>observableArrayList(Emulation.values());
    sid3Emulation.setConverter(new EnumToString<Emulation>(bundle));
    sid3Emulation.setItems(sid3Emulations);
    sid3Emulation.getSelectionModel().select(emulationSection.getThirdEmulation());

    sid1Models = FXCollections.<ChipModel>observableArrayList(ChipModel.values());
    sid1Model.setConverter(new EnumToString<ChipModel>(bundle));
    sid1Model.setItems(sid1Models);
    sid1Model.getSelectionModel().select(emulationSection.getUserSidModel());

    sid2Models = FXCollections.<ChipModel>observableArrayList(ChipModel.values());
    sid2Model.setConverter(new EnumToString<ChipModel>(bundle));
    sid2Model.setItems(sid2Models);
    sid2Model.getSelectionModel().select(emulationSection.getStereoSidModel());

    sid3Models = FXCollections.<ChipModel>observableArrayList(ChipModel.values());
    sid3Model.setConverter(new EnumToString<ChipModel>(bundle));
    sid3Model.setItems(sid3Models);
    sid3Model.getSelectionModel().select(emulationSection.getThirdSIDModel());

    defaultModels =
        FXCollections.<ChipModel>observableArrayList(ChipModel.MOS6581, ChipModel.MOS8580);
    defaultModel.setConverter(new EnumToString<ChipModel>(bundle));
    defaultModel.setItems(defaultModels);
    defaultModel.getSelectionModel().select(emulationSection.getDefaultSidModel());

    defaultEmulations =
        FXCollections.<Emulation>observableArrayList(Emulation.RESID, Emulation.RESIDFP);
    defaultEmulation.setConverter(new EnumToString<Emulation>(bundle));
    defaultEmulation.setItems(defaultEmulations);
    defaultEmulation.getSelectionModel().select(emulationSection.getDefaultEmulation());

    boosted8580.setSelected(emulationSection.isDigiBoosted8580());

    emulationChange = new EmulationChange();
    util.getPlayer().stateProperty().addListener(emulationChange);

    Platform.runLater(
        () -> {
          updateSettingsForTune(util.getPlayer().getTune());
          duringInitialization = false;
        });
  }