Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RecodeSpeakers.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RecodeSpeakers.groovy	(revision 3051)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/RecodeSpeakers.groovy	(revision 3052)
@@ -114,7 +114,7 @@
 			}
 			
 			if (debug) println "id=$idRegex or name=$nameRegex -> $nReplace replacements"
-			if (nReplace == 0) println "Warning found no replacement for id=$idRegex or name=$nameRegex"
+			if (nReplace == 0) println "Warning: didn't found any occurrence of id=$idRegex or name=$nameRegex"
 			
 			// Création de la source DOM
 			Source source = new DOMSource(doc);
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/Vocapia2Transcriber.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/Vocapia2Transcriber.groovy	(revision 3051)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/Vocapia2Transcriber.groovy	(revision 3052)
@@ -15,11 +15,17 @@
 	protected BufferedOutputStream output;
 	protected XMLStreamWriter writer;
 	
+	def additionalSpeakers = [:]
+	
 	public Vocapia2Transcriber(File xmlfile) {
 		
 		this.xmlfile = xmlfile;
 	}
 	
+	public void setAddtionalSpeakers(def additionalSpeakers) {
+		this.additionalSpeakers = additionalSpeakers
+	}
+	
 	public boolean process(File outfile) {
 		
 		if (!xmlfile.exists()) return false;
@@ -84,6 +90,13 @@
 								writer.writeAttribute("scope", "local")
 								writer.writeEndElement()
 								writer.writeCharacters("\n")
+								
+								/**
+								 * remove the additional speaker if already written
+								 */
+								if (additionalSpeakers.containsKey(parser.getAttributeValue(null, "spkid"))) {
+									additionalSpeakers.remove(parser.getAttributeValue(null, "spkid"))
+								}
 								break;
 								
 							case "Channel":
@@ -155,6 +168,19 @@
 							
 							case "SpeakerList": // <SpeakerList> -> <Speakers>
 							
+								// write additional speakers 
+								for (String spkid : additionalSpeakers.keySet()) {
+									writer.writeStartElement("Speaker")
+									writer.writeAttribute("id", spkid)
+									writer.writeAttribute("name", spkid)
+									writer.writeAttribute("check", "")
+									writer.writeAttribute("dialect", "")
+									writer.writeAttribute("accent", spkid)
+									writer.writeAttribute("scope", spkid)
+									writer.writeEndElement()
+									writer.writeCharacters("\n")
+								}
+							
 								writer.writeEndElement()
 								writer.writeCharacters("\n")
 								break
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/Vocapia2TranscriberMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/Vocapia2TranscriberMacro.groovy	(revision 3051)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/transcription/Vocapia2TranscriberMacro.groovy	(revision 3052)
@@ -13,7 +13,11 @@
 
 @Field @Option(name="resultDirectory", usage="The result directory", widget="Folder", required=false, def="")
 		File resultDirectory;
-
+		
+@Field @Option(name="additionalSpeakers", usage="The result directory", widget="String", required=false, def="")
+		def additionalSpeakers;
+		additionalSpeakers
+		
 @Field @Option(name="debug", usage="The result directory", widget="Boolean", required=false, def="false")
 		boolean debug;
 
@@ -45,8 +49,15 @@
 	
 	if (debug) println "== $xmlFile =="
 	else cpb.tick()
+	
 		
+	def map = [:]
+	for (String spk : additionalSpeakers.split("\t")) {
+		def split = spk.split(":", 2)
+		map[split[0]] = split[1]
+	}
 	Vocapia2Transcriber v2t = new Vocapia2Transcriber(xmlFile)
+	v2t.setAddtionalSpeakers(map)
 	String name = FileUtils.stripExtension(xmlFile)
 	File outFile = new File(resultDirectory, name+".trs")
 	
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListMacro.groovy	(revision 3051)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListMacro.groovy	(revision 3052)
@@ -1,118 +0,0 @@
-// Copyright © 2010-2013 ENS de Lyon.
-// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
-// Lyon 2, University of Franche-Comté, University of Nice
-// Sophia Antipolis, University of Paris 3.
-//
-// The TXM platform 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 2 of the License, or (at your option) any
-// later version.
-//
-// The TXM platform 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 the TXM platform. If not, see
-// http://www.gnu.org/licenses.
-
-package org.txm.macro.cqp
-
-/*
-This macro allows you to define CQL lists which you can call in CQP queries during the current session.
-To use this macro for your own lists,
-1. Find below an example of the type of list you want to create
-   (case 1 = explicit list, or case 2 = list from file),
-2. Copy then paste this example (5 lines) after the given examples
-3. Give the name for your list as a string after list_name=
-4. Give the content of the list as a string after
-either list_value= (for case 1, explicit list)
-or list_path= (for case 2, list from file).
-5. Save this file (macro code)
-6. Run the macro by double-clicking on it.
-The lists are defined only for the current session.
-To use the same lists in a new session, just run the macro to generate the lists again.
-*/
-
-import org.txm.Toolbox
-import org.txm.searchengine.cqp.*
-
-def CQI = CQPSearchEngine.getCqiClient();
-if ((CQI instanceof NetCqiClient)) {
-	println "Error: only available in CQP memory mode"
-	return;
-}
-
-def list_name=""
-def list_value=""
-def list_path=""
-def cqp_value=""
-File f;
-try {
-
-// BEGIN CONFIGURATION HERE
-
-// 1st case : explicit lists
-list_name = "negatif"
-list_value = "rien non ne pas sans"
-
-cqp_statement = "define \$$list_name = \"$list_value\";"
-println "CQP executes : $cqp_statement"
-CQI.query(cqp_statement)
-
-// two other examples of 1st case (explicit list)
-// 1st explicit list
-list_name = "evaluation"
-list_value = "trop assez peu bien très beaucoup vraiment"
-
-cqp_statement = "define \$$list_name = \"$list_value\";"
-println "CQP executes : $cqp_statement"
-CQI.query(cqp_statement)
-
-// 2nd explicit list
-list_name = "categoriesmotsvides"
-list_value = "ABR ADV DET:ART DET:POS INT KON NUM PRO PRO:DEM PRO:IND PRO:PER PRO:POS PRO:REL PRP PRP:det PUN PUN:cit SENT SYM"
-
-cqp_statement = "define \$$list_name = \"$list_value\";"
-println "CQP executes : $cqp_statement"
-CQI.query(cqp_statement)
-
-// one example of regular expression list to be used with RE()
-list_name = "regexp_categoriesmotsvides"
-list_value = "ABR ADV DET.* INT KON NUM PRO.* PRP.* PUN.* SENT SYM"
-
-cqp_statement = "define \$$list_name = \"$list_value\";"
-println "CQP executes : $cqp_statement"
-CQI.query(cqp_statement)
-
-// 2nd case : list from a file
-
-list_name = "motsvides"
-list_path = System.getProperty("user.home")+"/TXM/cqp/listes/stopwords_fr_ranknl.txt"
-// Windows users must replace "/" with "\\". 
-// for instance : 
-// list_path = System.getProperty("user.home")+"\\TXM\\cqp\\listes\\stopwords_fr_ranknl.txt"
-f = new File(list_path);
-if (f.exists()) {
-	cqp_statement = "define \$$list_name < \"$list_path\";"
-	println "CQP executes : $cqp_statement"
-	CQI.query(cqp_statement)
-} else {
-	println "Error: \"$f\" file does not exists"
-}
-
-/*
-You can comment a group of several lines of code
-using stars and slash like this.
-*/
-
-// END OF CONFIGURATION
-
-} catch (Exception e) {
-	println "Error during the \"$list_name\" list creation with the \"$list_value\" value"
-	println "CPQ statement was \"$cqp_statement\""
-	if (f != null) println "Last CQL file path was \"$f\""
-}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromStringMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromStringMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromStringMacro.groovy	(revision 3052)
@@ -0,0 +1,46 @@
+// Copyright © 2021 ENS de Lyon
+// Licensed under the terms of the GNU General Public License v3.0 (http://www.gnu.org/licenses)
+// @author sheiden
+
+package org.txm.macro.cqp
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+
+import org.txm.Toolbox
+import org.txm.searchengine.cqp.*
+
+// parameters
+
+@Field @Option(name="wordList", usage="list of words", widget="Text", required=true, def='')
+def wordList
+
+@Field @Option(name="separator", usage="character separating words", widget="String", required=true, def=',')
+def separator
+
+@Field @Option(name="name", usage="name of the list", widget="String", required=true, def='')
+def name
+
+if (!ParametersDialog.open(this)) return
+
+def CQI = CQPSearchEngine.getCqiClient()
+def cqp_statement
+
+if ((CQI instanceof NetCqiClient)) {
+
+	println "** Error: only available in CQP memory mode"
+	return
+}
+
+try {
+	wordList = wordList.split(separator).join(' ')
+	cqp_statement = "define \$$name = \"$wordList\";"
+	println "Executing CQP statement... $cqp_statement"
+	CQI.query(cqp_statement)
+	println "\$$name word list defined. You can now use it in queries, like: [word=\$$name]"
+
+} catch (Exception e) {
+	println "** Error during the creation of word list \"$name\" with the list \"$wordList\""
+	println "CPQ statement was \"$cqp_statement\""
+}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromFileMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromFileMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromFileMacro.groovy	(revision 3052)
@@ -0,0 +1,48 @@
+// Copyright © 2021 ENS de Lyon
+// Licensed under the terms of the GNU General Public License v3.0 (http://www.gnu.org/licenses)
+// @author sheiden
+
+package org.txm.macro.cqp
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+
+import org.txm.Toolbox
+import org.txm.searchengine.cqp.*
+
+// parameters
+
+@Field @Option(name="inputFile", usage="fichier contenant la liste de mots (un mot par ligne)", widget="File", required=true, def='')
+def inputFile
+
+@Field @Option(name="name", usage="name of the list", widget="String", required=true, def='')
+def name
+
+if (!ParametersDialog.open(this)) return
+
+def CQI = CQPSearchEngine.getCqiClient()
+def cqp_statement
+
+if ((CQI instanceof NetCqiClient)) {
+
+	println "** Error: only available in CQP memory mode"
+	return
+}
+
+try {
+
+  if (inputFile.exists()) {
+	cqp_statement = "define \$$name < \"$inputFile\";"
+	println "Executing CQP statement... $cqp_statement"
+	CQI.query(cqp_statement)
+	println "\$$name word list defined. You can now use it in queries, like: [word=\$$name]"
+	
+  } else {
+	println "** Error: impossible to access \"$inputFile\""
+  }
+
+} catch (Exception e) {
+	println "** Error during the creation of word list \"$name\" with the file \"$inputFile\""
+	println "CPQ statement was \"$cqp_statement\""
+}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromGroovyMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromGroovyMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/cqp/CreateCQPListFromGroovyMacro.groovy	(revision 3052)
@@ -0,0 +1,118 @@
+// Copyright © 2010-2013 ENS de Lyon.
+// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
+// Lyon 2, University of Franche-Comté, University of Nice
+// Sophia Antipolis, University of Paris 3.
+//
+// The TXM platform 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 2 of the License, or (at your option) any
+// later version.
+//
+// The TXM platform 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 the TXM platform. If not, see
+// http://www.gnu.org/licenses.
+
+package org.txm.macro.cqp
+
+/*
+This macro allows you to define CQL lists which you can call in CQP queries during the current session.
+To use this macro for your own lists,
+1. Find below an example of the type of list you want to create
+   (case 1 = explicit list, or case 2 = list from file),
+2. Copy then paste this example (5 lines) after the given examples
+3. Give the name for your list as a string after list_name=
+4. Give the content of the list as a string after
+either list_value= (for case 1, explicit list)
+or list_path= (for case 2, list from file).
+5. Save this file (macro code)
+6. Run the macro by double-clicking on it.
+The lists are defined only for the current session.
+To use the same lists in a new session, just run the macro to generate the lists again.
+*/
+
+import org.txm.Toolbox
+import org.txm.searchengine.cqp.*
+
+def CQI = CQPSearchEngine.getCqiClient();
+if ((CQI instanceof NetCqiClient)) {
+	println "Error: only available in CQP memory mode"
+	return;
+}
+
+def list_name=""
+def list_value=""
+def list_path=""
+def cqp_value=""
+File f;
+try {
+
+// BEGIN CONFIGURATION HERE
+
+// 1st case : explicit lists
+list_name = "negatif"
+list_value = "rien non ne pas sans"
+
+cqp_statement = "define \$$list_name = \"$list_value\";"
+println "CQP executes : $cqp_statement"
+CQI.query(cqp_statement)
+
+// two other examples of 1st case (explicit list)
+// 1st explicit list
+list_name = "evaluation"
+list_value = "trop assez peu bien très beaucoup vraiment"
+
+cqp_statement = "define \$$list_name = \"$list_value\";"
+println "CQP executes : $cqp_statement"
+CQI.query(cqp_statement)
+
+// 2nd explicit list
+list_name = "categoriesmotsvides"
+list_value = "ABR ADV DET:ART DET:POS INT KON NUM PRO PRO:DEM PRO:IND PRO:PER PRO:POS PRO:REL PRP PRP:det PUN PUN:cit SENT SYM"
+
+cqp_statement = "define \$$list_name = \"$list_value\";"
+println "CQP executes : $cqp_statement"
+CQI.query(cqp_statement)
+
+// one example of regular expression list to be used with RE()
+list_name = "regexp_categoriesmotsvides"
+list_value = "ABR ADV DET.* INT KON NUM PRO.* PRP.* PUN.* SENT SYM"
+
+cqp_statement = "define \$$list_name = \"$list_value\";"
+println "CQP executes : $cqp_statement"
+CQI.query(cqp_statement)
+
+// 2nd case : list from a file
+
+list_name = "motsvides"
+list_path = System.getProperty("user.home")+"/TXM/cqp/listes/stopwords_fr_ranknl.txt"
+// Windows users must replace "/" with "\\". 
+// for instance : 
+// list_path = System.getProperty("user.home")+"\\TXM\\cqp\\listes\\stopwords_fr_ranknl.txt"
+f = new File(list_path);
+if (f.exists()) {
+	cqp_statement = "define \$$list_name < \"$list_path\";"
+	println "CQP executes : $cqp_statement"
+	CQI.query(cqp_statement)
+} else {
+	println "Error: \"$f\" file does not exists"
+}
+
+/*
+You can comment a group of several lines of code
+using stars and slash like this.
+*/
+
+// END OF CONFIGURATION
+
+} catch (Exception e) {
+	println "Error during the \"$list_name\" list creation with the \"$list_value\" value"
+	println "CPQ statement was \"$cqp_statement\""
+	if (f != null) println "Last CQL file path was \"$f\""
+}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/PrepareTranscriptionsMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/PrepareTranscriptionsMacro.groovy	(revision 3051)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/nov13/PrepareTranscriptionsMacro.groovy	(revision 3052)
@@ -21,6 +21,12 @@
 @Field @Option(name="nonPrimarySpeakerIdRegex", usage="other non primary id of the other turns", widget="String", required=false, def="")
 		String nonPrimarySpeakerIdRegex
 		
+@Field @Option(name="supplementarySpeakerIdRegex", usage="supplementary locutor ids regex", widget="String", required=false, def="UX.+")
+		String supplementarySpeakerIdRegex
+		
+@Field @Option(name="supplementarySpeakerId", usage="supplementary locutor id to normalize", widget="String", required=false, def="")
+		String supplementarySpeakerId
+		
 @Field @Option(name="newSectionMarker", usage="section marker", widget="String", required=false, def="*#")
 		String newSectionMarker
 
@@ -42,7 +48,7 @@
 println "CONVERTING VOCAPIA FILES TO TRS FILES..."
 File trsDirectory = new File(resultDirectory, "vocapia2trs")
 trsDirectory.mkdir()
-gse.runMacro(org.txm.macro.transcription.Vocapia2TranscriberMacro, ["vocapiaDirectory":vocapiaDirectory, "resultDirectory":trsDirectory, "debug":debug])
+gse.runMacro(org.txm.macro.transcription.Vocapia2TranscriberMacro, ["vocapiaDirectory":vocapiaDirectory, "resultDirectory":trsDirectory, "additionalSpeakers": "UX1:UX1", "debug":debug])
 
 
 println "SPOTTING SECTION MARKS..."
@@ -111,14 +117,26 @@
 	if (debug) println "== $file =="
 	else cpb.tick()
 	
-	File outFile = new File(resultDirectory, file.getName())
-	RecodeSpeakers fixer = new RecodeSpeakers(file, outFile, nonPrimarySpeakerIdRegex, null, otherNonPrimarySpeakerId, otherNonPrimarySpeakerId)
+	File tmpFile = new File(resultDirectory, "tmp.xml")
+	tmpFile.delete();
+	
+	RecodeSpeakers fixer = new RecodeSpeakers(file, tmpFile, nonPrimarySpeakerIdRegex, null, otherNonPrimarySpeakerId, otherNonPrimarySpeakerId)
 	fixer.debug = debug
 	
 	if (!fixer.process()) {
 		println "WARNING: ERROR WHILE PROCESSING: "+file
 		if (debug) {println "DEBUG ACTIVATED -> STOP"; return;}
 	}
+	
+	File outFile2 = new File(resultDirectory, file.getName())
+	RecodeSpeakers fixer2 = new RecodeSpeakers(tmpFile, outFile2, supplementarySpeakerIdRegex, null, supplementarySpeakerId, supplementarySpeakerId)
+	fixer2.debug = debug
+	
+	if (!fixer2.process()) {
+		println "WARNING: ERROR WHILE PROCESSING: "+file
+		if (debug) {println "DEBUG ACTIVATED -> STOP"; return;}
+	}
+	tmpFile.delete(); // This tmp file must be removed for the next operation
 }
 cpb.done()
 
