<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel><title>Willow Media</title><description>Willow Media</description><link>https://www.willow-media.nl/</link><lastBuildDate>Sun, 15 Feb 2026 09:20:41 GMT</lastBuildDate><generator>CmsRssFeedService</generator><item><title>Gebruik van middelse muis knop voor app overzicht in Gnome</title><description><![CDATA[
<p>In Fedora (en vermoedelijk veel meer Linux distributies) wordt de klik op het scroll-wieltje van de muis (als je muis dit heeft) als een plak commando (control + v) uitgevoerd. Ik vind dit niet heel handig. MacOS gebruikt standaard de middle click van de muis om het overzicht van je openstaande apps te tonen. Dit gebruik ik nogal veel om tussen applicaties te schakelen.</p>
<p>Het aanpassen van de middle click op linux is niet een kwestie van het open van de de configuratie instellingen, helaas. Maar er is een relatief makkelijke methode. Er is een tool die <code>input-remapper</code> heet. Deze kan voor Fedora via de command-line geinstalleerd worden. Ik gebruik Silverblue:</p>
<pre><code class="language-bash">rpm-ostree install input-remapper
</code></pre>
<p>Na een reboot is de GUI van <code>input-remapper</code> tussen de rest van de app's te vinden. Let wel op dat de tool niet de schoonheidsprijs voor werkbaarheid verdient. Je zal even moeten wennen aan hoe het opgezet is.</p>
<p>Allereerst wordt er in het table <code>devices</code> alles getoond wat een input device is. Ik gebruik een Keychron muis, met z'n bijgeleverde dongle (dus niet direct via Bluetooth).</p>
<p><img src="/cache/12/126b0f46f9b0/7d5974ca/gnome-input-remapper-devices.png" alt="gnome input remapper devices" /></p>
<p>Als je op het device klikt kom je in het tabje <code>presets</code>. Standaard staat hier al een <code>new preset</code>. Dit is een lege preset die je kan aanpassen. Je kan natuurlijk ook op new klikken om er nog 1 toe te voegen.</p>
<p>Wat een beetje verwarrend is, is dat bovenaan de <code>apply</code> te zien is, met daaronder een  rename input box. Ik zou persoonlijk dit deel meer naar beneden neerzetten. Links onder zie je het deel <code>input</code>. Hier kan je één of meerdere inputs neerzetten. Ik voeg er 1 toe met de text <code>BTN_MIDDLE</code>. Je kan hiervoor ook record gebruiken. Als deze regel daarna geselecteerd is, wordt het <code>output</code> deel actief. Ik heb deze op <code>Key or Macro</code> staan met als target <code>keyboard</code>. Vervolgens kan je de toetscombinatie die je wilt gebruiken toevoegen.</p>
<p>Belangrijk is dat je geen combinatie gebruikt die al door iets anders wordt gebruikt. Een combinatie van diverse toetsen is denk ik de beste route. In dit voorbeeld gebruik ik de linker control met de <code>o</code>  (wat niet een hele ingewikkelde is). Wat ook nog wat verwarrend is, als de input box actief is, laat hij de toetscombinatie zien die je indrukt. Dit is alleen een preview, je zal hem dan alsnog moeten overtypen in de input box. Voor control+o type je dan <code>Control_L + o</code>. Volgens mij zijn de spaties hierbij ook belangrijk.</p>
<p><img src="/cache/11/126b0f46f9af/ca8e27e2/gnome-input-remapper-editor.png" alt="gnome input remapper editor" /></p>
<p>Als je hierna bovenaan apply klikt (en ik heb autoload ook aangezet voor na een reboot) dan zal deze toetscombinatie uitgevoerd worden bij het klikken op de middelste knop.</p>
<p>Binnen Gnome kan je vervolgens via de configuratie instellingen naar shortcuts gaan om aan het overview een toets te koppelen. Interessant is dat de super/meta key hier niet gedefinieerd is. Deze zal op een lager niveau in Gnome zijn vast gelegd en niet zomaar aan te passen zijn. Als je vervolgens op  &quot;show overview&quot; klikt kan je de toetscombinatie aangeven, door de middelste knop te klikken.</p>
<p><img src="/cache/10/126b0f46f9af/bf0cf6c/gnome-keyboard-shortcuts-overview.png" alt="gnome keyboard shortcuts overview" /></p>
<div class="markdown-alert markdown-alert-note">
<p class="markdown-alert-title"><svg viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p>
<p>Om te zorgen dat deze instellingen een reboot overleven, moet ook nog input-remapper eenmalig als service gestart worden: <code>sudo systemctl enable --now input-remapper</code></p>
</div>
<p>Taadaaa! Hierna zal de middelste knop het app overzicht tonen.</p>

]]></description><pubDate>Sun, 26 Oct 2025 23:00:00 GMT</pubDate><guid>https://www.willow-media.nl/gebruik-van-middelse-muis-knop-voor-app-overzicht-in-gnome</guid><link>https://www.willow-media.nl/gebruik-van-middelse-muis-knop-voor-app-overzicht-in-gnome</link></item>
<item><title>LinkedIn opt-out data gebruik voor training AI</title><description><![CDATA[
<p>Deze week verscheen <a href="https://www.security.nl/posting/910072/Kan+een+platform+de+voorwaarden+met+terugwerkende+kracht+herzien+om+AI+te+kunnen+trainen+met+alle+gebruikersdata%3F" target="new" rel="noopener" title="een artikel op security.nl">een artikel op security.nl</a> waar erop in gegaan wordt dat LinkedIn is begonnen, of gaat beginnen, met gebruikers data te gebruiken om AI te trainen. Dit gaan ze ook doen met terug werkende kracht van informatie tot 2003. Hierbij kunnen vragen gesteld worden of dit volgens de AVG allemaal wel of niet mag. Het systeem van LinkedIn werkt met een opt-out, wat wil zeggen dat je zelf actie moet ondernemen om dit uit te schakelen.</p>
<p>Hieronder de stappen om dit te doen. Meldt je aan op je account bij LinkedIn. Ga hierna naar <a href="https://www.linkedin.com/mypreferences/d/categories/privacy" target="new" rel="noopener" title="Instellingen / gegevensprivacy">Instellingen / gegevensprivacy</a>. Je ziet dan iets als het onderstaande:</p>
<p><img src="/cache/a/126b0efa411a/5e25a49e/linked-instellingen-gegevensprivacy.png" alt="LinkedIn instellingen gegevensprivacy" /></p>
<p>Hier is het kopje <a href="https://www.linkedin.com/mypreferences/d/settings/data-for-ai-improvement" target="new" rel="noopener" title="Gegevens voor verbetering van generatieve AI">Gegevens voor verbetering van generatieve AI</a> terug te vinden. Als je deze aanklikt krijg je een formulier te zien waar dit standaard ingeschakeld staat.</p>
<p><img src="/cache/b/126b0efa4250/c9993e2/linkedin-gegevensprivacy-opt-out-gebruik-gegevens.png" alt="LinkedIn gegevensprivacy opt out gebruik gegevens" /></p>

]]></description><pubDate>Tue, 21 Oct 2025 22:00:00 GMT</pubDate><guid>https://www.willow-media.nl/linkedin-opt-out-data-gebruik-voor-training-ai</guid><link>https://www.willow-media.nl/linkedin-opt-out-data-gebruik-voor-training-ai</link></item>
<item><title>3CX aanpassen externe IP</title><description><![CDATA[
<p>Door het wisselen van het IP van onze glasvezel, werkte het FQDN van de 3CX installatie niet meer. Deze is ingesteld via een my3cx.nl adres en deze wordt beheerd door 3CX. De free versie hier gebruikt wordt, heeft geen mogelijkheid om het IP te wisselen. In veel gevallen wordt een herinstallatie wordt hiervoor geadviseerd.</p>
<p>Nou is dat wat lastig, omdat de machine in een ander pand staat en momenteel wat lastig bereikbaar is. Daarnaast is dit een headless systeem. Het was even te overwegen om een VM omgeving op deze machine te zetten voor de toekomst, maar ook dit kost nog wat extra tijd en daarvoor moet ik alsnog bij de fysieke machine kunnen komen.</p>
<p>Intussen werkt de telefoon dus niet meer. De portal is via het nieuwe IP nummer wel bereikbaar, maar de app's gebruiken het FQDN. Na wat zoek werk vond ik wel het een en ander. De 3cx installatie is gebaseerd op Debian en er kan via ssh ingelogd worden. De 3cx webtool is overigens in .Net geschreven. Misschien andere delen ook wel, maar daar heb ik niet naar gekeken. In dit specifieke geval is de 3CX ISO gebruikt voor de installatie. Het is ook mogelijk om zelf Debian te installeren om vervolgens de installatie pakketten toe te voegen. Ook heb ik wel eens wat gezien over het draaien van 3CX in Docker, maar dat wordt volgens mij afgeraden door 3CX zelf.</p>
<p>Ik dacht dat het misschien mogelijk was om via <code>dpkg-reconfigure</code> de installatie wizard weer te starten. Dit heeft helaas geen effect verder. Hiermee zijn (denk ik) de configuratie bestanden hersteld op basis van de eerder gebruikte <code>SetupConfig.xml</code>. Ik ondekte ook nog dat via het onderstaande commando de web installatie wizard gestart kan worden:</p>
<pre><code>/usr/lib/3cxpbx/PbxWebConfigTool -p /usr/share/3cxpbx/webconfig -nobrowser -port 5016
</code></pre>
<p>3CX zet behoorlijk strikt de firewall op het systeem, dus de gebruikt poort moet nog wel even open gezet worden. Maar ook dit commando heeft niet het gewenste effect omdat de services van 3CX nog draaien en dan zijn poorten in gebruik enzo.</p>
<p>Hierna vond ik het onderstaande commando ergens in een blog:</p>
<pre><code>/usr/sbin/3CXWizard --cleanup
</code></pre>
<p>Via deze route worden alle services stop gezet en wordt de wizard weer gestart, zoals bij de initiële installatie. Hiermee kan je dan ook een schone installatie maken. Als je hierna de backup weer terug zet, is alles weer hersteld als daarvoor, behalve dat hij nu het nieuwe IP nummer gebruikt.</p>
<p>De stappen om te nemen om het IP nummer te herstellen:</p>
<ol>
<li>Maak een backup van het systeem (via de web portal) en download deze. Met versie 20 hoef je geen rekening meer te houden om het FQDN uit de configuratie te halen.</li>
<li>'Disconnect' de FQDN in de 3cx portal. Deze zal later weer toegevoegd worden als de initiële configuratie wordt ingelezen.</li>
<li>Download de configuratie (SetupConfig.xml?) via de installatie pagina in de 3CX portal.</li>
<li>Start de <code>3cxWizard</code> met de <code>--cleanup</code> optie op de machine via de terminal.</li>
<li>Doorloop de stappen (ik gebruik de web installer) en upload het nieuwe <code>SetupConfig.xml</code> bestand. Mocht je de originele nog hebben van de eerdere installatie, dan werkt dit vermoedelijk ook.</li>
<li>Hierna moet je je wachtwoord aanpassen en daarna kan je inloggen in de nieuwe portal.</li>
<li>Kopieër vervolgens het backup bestand naar de server in de backup map <code>/var/lib/3cxpbx/Instance1/Data/Backups</code>.</li>
<li>Restore de backup en vervolgens kan je je aanmelden met je oude gegevens.</li>
</ol>
<p>De conclusie is dan ook dat 3CX met de free versie je een aantal features afhoud, wat hun goed recht is natuurlijk. Maar het systeem is wel zodanig opgezet dat het installeren en herstellen van een installatie heel simpel werkt.</p>

]]></description><pubDate>Sun, 08 Jun 2025 22:00:00 GMT</pubDate><guid>https://www.willow-media.nl/3cx-aanpassen-externe-ip</guid><link>https://www.willow-media.nl/3cx-aanpassen-externe-ip</link></item>
<item><title>Dovecot setup voor e-mail archief</title><description><![CDATA[
<p>In mijn zoektocht voor een imap omgeving om berichten te archiveren was mijn eerste plan om een Debian of <a href="https://documentation.ubuntu.com/server/how-to/mail-services/install-dovecot/index.html" target="new" rel="noopener" title="Ubuntu">Ubuntu</a> omgeving te gebruiken. Ik kwam er al snel achter dat er niet heel veel documentatie over een eenvoudige opzet te vinden was. Toen liep ik tegen een <a href="https://github.com/dovecot/docker" target="new" rel="noopener" title="Dovecot eigen docker implementatie">Dovecot eigen docker implementatie</a> aan.</p>
<p>De opzet van de container is wel wat simpeler dan de Debian of Ubuntu versie. Maar het lijkt er wel op dat alles erin zit wat nodig is. Inmiddels is versie 2.4.1 van de container te verkrijgen. Maar ja, hoe nu verder?</p>
<p>De basis setup van de container verwacht een wachtwoord via environment variabelen voor een gebruiker en de dovecot admin:</p>
<pre><code class="language-shell">USER_PASSWORD=
DOVEADM_PASSWORD=
</code></pre>
<p>&quot;Een wachtwoord voor één gebruiker?&quot;. Het blijkt dat de initiële setup zo gemaakt is dat hij elke gebruikersnaam accepteert en daarvoor een mailbox maakt, als dit wachtwoord wordt gebruikt. Op zich handig voor test omgevingen of zo, maar niet wat ik momenteel zoek. Ik wil voorlopig een basis opzet hebben, waarbij eventueel meerdere gebruikers aangemaakt kunnen worden. met een eigen wachtwoord. Dit wachtwoord en de opgeslagen mail moeten geëncrypt zijn. Hierbij ga ik alleen IMAP met SSL gebruiken. Voor het SSL certificaat wil ik letsencrypt gebruiken.</p>
<p>Ik heb via <a href="https://github.com/dehydrated-io/dehydrated" target="new" rel="noopener" title="Dehydrated">Dehydrated</a> en Nginx een certificaat voor mijn domeinnaam aangemaakt. De container verwacht dat de certificaten als <code>/etc/dovecot/ssl/tls.crt</code> en <code>/etc/dovecot/ssl/tls.key</code> beschikbaar zijn. Voor de <code>.crt</code> gebruik ik <code>fullchain.pem</code> en voor de <code>.key</code> het <code>privkey.pem</code> certificaat. Deze worden via een volume mapping toegewezen.</p>
<p>De opgeslagen mail wil ik ook buiten de container opslaan. Standaard worden de mailboxen onder <code>/srv/vmail</code> aangemaakt.</p>
<pre><code>services:
  dovecot:
    image: dovecot/dovecot:latest
    restart: always
    ports:
     - 0.0.0.0:993:31993
    volumes:
     - &quot;${DOCKER_DATAPATH}/certs/fullchain.pem:/etc/dovecot/ssl/tls.crt:ro&quot;
     - &quot;${DOCKER_DATAPATH}/certs/privkey.pem:/etc/dovecot/ssl/tls.key:ro&quot;
     - &quot;${DOCKER_DATAPATH}/vmail:/srv/vmail&quot;
</code></pre>
<p>Voor het totale plaatje zijn er nog 3 mappings nodig. Ik pas de basis configuratie niet aan van de container, maar voeg alleen toe. Voor de gebruikers wordt en een <code>users</code> bestand (passwd-file) gebruikt, dat een zowel de gebruiker als het wachtwoord bevat, maar ook een paar extra lege velden.</p>
<p>Voor de aanvullende configuratie wordt een <code>10-auth.conf</code> bestand aangemaakt in de <code>conf.d</code> map. Bij het opstarten wordt elke <code>.conf</code> bestand in deze map meegenomen.</p>
<p>Aanvullend kan ik alvast verklappen dat certificaten voor het encrypten van de bestanden in de map <code>/etc/dovecot/mail-crypt</code> terecht gaan komen&quot;</p>
<pre><code>     - &quot;${DOCKER_DATAPATH}/users:/etc/dovecot/users:ro&quot;
     - &quot;${DOCKER_DATAPATH}/10-auth.conf:/etc/dovecot/conf.d/10-auth.conf:ro&quot;
     - &quot;${DOCKER_DATAPATH}/dovecot-mail-crypt:/etc/dovecot/mail-crypt:ro&quot;
</code></pre>
<p>Tijdens het testen heb ik <a href="https://www.thunderbird.net/en-US/" target="new" rel="noopener" title="Thunderbird">Thunderbird</a> gebruikt. Hierdoor liep ik al snel tegen een paar problemen aan. Het eerste probleem was, wanneer ik een mailtje in de mailbox sleepte, werd de verbinding verbroken met de melding dat er teveel ongeldige commando's verstuurd werden:</p>
<pre><code>dovecot-1  | May 05 07:55:06 imap(myarchive)&lt;21&gt;&lt;t9Qz0F40vPW8Wgp1&gt;: Info: Disconnected: Too many invalid IMAP commands. in=1677 out=2637 deleted=0 expunged=0 trashed=0 hdr_count=0 hdr_bytes=0 body_count=0 body_bytes=0 
</code></pre>
<p>Na een behoorlijke wat zoektijd, kwam ik in een github ticket tegen, dat een experimentele extentie het probleem zou kunnen zijn. Via <code>mail_utf8_extensions=no</code> kan deze worden uitgeschakeld en werkt Thunderbird in eens wel zoals verwacht.</p>
<p>Het tweede probleem had iets met de standaard mappen te maken. Na deze uit de Ubuntu configuratie over genomen te hebben (zie <code>namespace inbox {...</code>) werkte de mailbox in eens zoals verwacht.</p>
<p>Zo ben ik tot de volgende opzet van <code>10-auth.conf</code> gekomen:</p>
<pre><code># Use for debugging
# mail_debug=yes
# auth_verbose=yes
# auth_debug=yes
# auth_debug_passwords=yes
# mail_debug=yes

# Fix for Thunderbird
mail_utf8_extensions=no

# Authorization
auth_verbose_passwords=plain
auth_mechanisms = plain login 
# removed: digest-md5 cram-md5

# Passdb configuration
passdb passwd-file {
  driver = passwd-file
  passwd_file_path = /etc/dovecot/users
}

# Userdb configuration
userdb passwd-file {
  driver = passwd-file
  passwd_file_path = /etc/dovecot/users
}

# Default folders
namespace inbox {
  inbox = yes
  mailbox Trash {
    special_use = \Trash
    auto = subscribe
  }

  # These mailboxes are widely used and could perhaps be created automatically:
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }

  # For \Sent mailboxes there are two widely used names. We'll mark both of
  # them as \Sent. User typically deletes one of them if duplicates are created.
  mailbox Sent {
    special_use = \Sent
  }
  mailbox &quot;Sent Messages&quot; {
    special_use = \Sent
  }
}

# Encryption of mails
mail_plugins {
  mail_crypt = yes
}

crypt_global_public_key_file = /etc/dovecot/mail-crypt/ecpubkey.pem
crypt_global_private_key main {
  crypt_private_key_file = /etc/dovecot/mail-crypt/ecprivkey.pem
}
</code></pre>
<p>De certificaten voor het encrypten van de data moeten ook nog aangemaakt worden. Zorg ook dat de certificaten de juiste owner en rechten hebben binnen de container. De <code>vmail</code> gebruiker en groep hebben beide nummer 1000.</p>
<pre><code>mkdir -p data/dovecot-mail-crypt
openssl ecparam -name prime256v1 -genkey | openssl pkey -out data/dovecot-mail-crypt/ecprivkey.pem
openssl pkey -in data/dovecot-mail-crypt/ecprivkey.pem -pubout -out data/dovecot-mail-crypt/ecpubkey.pem

chmod -Rf  600 data/dovecot-mail-crypt/*
chown -Rf 1000.1000 data/dovecot-mail-crypt
</code></pre>
<p>Om dit allemaal nou ook nog werkend te krijgen, moet er in ieder geval 1 gebruiker toegevoegd worden. Hiervoor kan de tool <code>doveadm</code> gebruikt worden. Misschien is het ook mogelijk om hiermee een gebruiker volledig toe te voegen aan het <code>users</code> bestand, maar zover heb ik niet gekeken. <code>doveadm</code> is in de container beschikbaar. Ik gebruik hier de encryptie <code>SHA512-CRYPT</code> om te zorgen dat het wachtwoord niet leesbaar is in de configuratie. Hier een voorbeeld:</p>
<pre><code class="language-shell">docker compose exec dovecot doveadm pw -s SHA512-CRYPT
Enter new password: 
Retype new password: 
{SHA512-CRYPT}$6$RVEYzANS6v0a.kAB$.0lLSo2DaXwpi8E.iAClBoQu3GK36oWPCRp503ZlhDok3ixomdcMbiwURNScpxVlYHGD7UItfrlQz4tEMgaZ.
</code></pre>
<p>Deze laatste regel is het geëncrypte wachtwoord. Deze gaan we toevoegen aan het <code>users</code> bestand. Allereerst komt de gebruikersnaam in het bestand te staan. Hou er rekening mee dat deze in ieder geval geen <code>:</code>  mag bevatten, omdat dit het scheidingsteken is tussen de velden. Deze wordt gevolgd door het wachtwoord. Het <code>users</code> bestandsformaat verwacht dan nog een aantal velden die we leeg gaan laten. Hierom voegen we <code>::::::</code> toe aan de regel. Een voorbeeld is dan als volgt:</p>
<pre><code>my-mail-user:{SHA512-CRYPT}$6$RVEYzANS6v0a.kAB$.0lLSo2DaXwpi8E.iAClBoQu3GK36oWPCRp503ZlhDok3ixomdcMbiwURNScpxVlYHGD7UItfrlQz4tEMgaZ.::::::
</code></pre>
<p>Belangrijk punt is dat dovecot herstart moet worden als dit bestand veranderd. Dit is een goed argument om een SQL server te gaan gebruiken hiervoor. Sqlite zou een prima oplossing kunnen zijn, maar dat is voor een andere keer. De container is zodanig kaal, dat <code>ps</code> of <code>killall</code> niet beschikbaar zijn. Een alternatief is dan ook om de container te herstarten. Maar <code>dovecot</code> heeft ook een herstart optie ingebouwd, wat het proces wat vloeiender maakt:</p>
<pre><code>docker compose exec dovecot doveadm reload
</code></pre>
<p>Hierna zou je met elke IMAP applicatie moeten kunnen verbinden en mail naar deze mailbox moeten kunnen verplaatsen. Zorg wel voor een goede backup van de certificaten, anders zijn de e-mails niet meer te redden na een crash.</p>

]]></description><pubDate>Sun, 04 May 2025 22:00:00 GMT</pubDate><guid>https://www.willow-media.nl/dovecot-setup-voor-e-mail-archief</guid><link>https://www.willow-media.nl/dovecot-setup-voor-e-mail-archief</link></item>
<item><title>XTTS-v2 TTS Installation guide</title><description><![CDATA[
<p>Online kwam ik een <a href="https://blog.stackademic.com/xtts-v2-text-to-speech-transformer-library-an-actually-working-guide-bc75bf5f8f6c" target="new" rel="noopener" title="artikel">artikel</a> tegen waarbij de auteur de stappen toont om XTTS-v2 te installeren. Wat me nogal vaak opvalt is dat dit soort blog posts verre van compleet zijn. Je zou bijna gaan denken dat het een vorm van clickbait is. Niet dat ik de auteur daarvan beschuldig hoor, integendeel. Hierbij dan ook mijn poging om het werkend te krijgen en wat meer diepgang te geven.</p>
<p>Ter info, ik gebruik in dit geval een Mac M1 machine. Onder Linux zullen de stap relatief hetzelfde zijn, vermoed ik.</p>
<p>In stap 1 wordt de repository van het project vanaf de git omgeving van <a href="https://huggingface.co/coqui/XTTS-v2" target="new" rel="noopener" title="huggingface">huggingface</a> gedownload.</p>
<pre><code class="language-shell">git clone https://huggingface.co/coqui/XTTS-v2
</code></pre>
<p>De auteur gaat vervolgens de 'virtual environment' activeren, maar deze bestaat nog helemaal niet. Dus die gaan we aanmaken in de map van het project. Omdat ik in het verleden problemen ondervond met de hoogst geïnstalleerde versie van Python op mijn machine, kies ik ervoor om Python 3.10 te testen.</p>
<pre><code class="language-shell">cd XTTS-v2/
python3.10 -m venv .
source ./bin/activate
</code></pre>
<p>Hierna zou de virtuale environment actief moeten zijn (bij mij verschijnt er <code>(XTTS-v2)</code> voor de command prompt. Waarom we dit doen? Op deze manier kunnen we het project scheiden van andere installaties op onze machine, zodat ze elkaar minder beïnvloeden.</p>
<p>De auteur wil vervolgens de requirements installeren. Dit kan je doen door alle benodigde pakketten in een bestandje te benoemen en dit met een commando te laten installeren. Hij heeft echter de volgorde verkeerd om staan. Dus we draaien het even om. We maken eerst het bestand <code>requirements.txt</code> aan. Ik heb een kleine wijziging erin gemaakt, wat veel vaker fout gaat bij dit soort blog posts en dat is het gebruik van <code>PyTorch</code>. Veelal wordt er verwezen naar een versie die niet meer bestaat. Op de <a href="https://pytorch.org/get-started/previous-versions/" target="new" rel="noopener" title="PyTorch">PyTorch</a> pagina is dezelfde versie wel te vinden, maar zonder de aanvulling op het versie nummer:</p>
<pre><code class="language-shell">cat &lt;&lt;EOF &gt; requirements.txt
absl-py==2.1.0
aiohappyeyeballs==2.4.3
aiohttp==3.11.2
aiosignal==1.3.1
annotated-types==0.7.0
anyascii==0.3.2
asttokens==2.4.1
attrs==24.2.0
audioread==3.0.1
babel==2.16.0
bangla==0.0.2
blinker==1.9.0
blis==0.7.11
bnnumerizer==0.0.2
bnunicodenormalizer==0.1.7
catalogue==2.0.10
certifi==2024.8.30
cffi==1.17.1
charset-normalizer==3.4.0
click==8.1.7
cloudpathlib==0.20.0
colorama==0.4.6
confection==0.1.5
contourpy==1.3.1
coqpit==0.0.17
cycler==0.12.1
cymem==2.0.8
Cython==3.0.11
dateparser==1.1.8
decorator==5.1.1
docopt==0.6.2
einops==0.8.0
encodec==0.1.1
executing==2.1.0
filelock==3.13.1
Flask==3.1.0
fonttools==4.55.0
frozenlist==1.5.0
fsspec==2024.2.0
g2pkk==0.1.2
grpcio==1.68.0
gruut==2.2.3
gruut-ipa==0.13.0
gruut_lang_de==2.0.1
gruut_lang_en==2.0.1
gruut_lang_es==2.0.1
gruut_lang_fr==2.0.2
hangul-romanize==0.1.0
huggingface-hub==0.26.2
idna==3.10
inflect==7.4.0
ipython==8.29.0
itsdangerous==2.2.0
jamo==0.4.1
jedi==0.19.2
jieba==0.42.1
Jinja2==3.1.3
joblib==1.4.2
jsonlines==1.2.0
kiwisolver==1.4.7
langcodes==3.4.1
language_data==1.2.0
lazy_loader==0.4
librosa==0.10.2.post1
llvmlite==0.43.0
marisa-trie==1.2.1
Markdown==3.7
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib==3.9.2
matplotlib-inline==0.1.7
mdurl==0.1.2
more-itertools==10.5.0
mpmath==1.3.0
msgpack==1.1.0
multidict==6.1.0
murmurhash==1.0.10
networkx==2.8.8
nltk==3.9.1
num2words==0.5.13
numba==0.60.0
numpy==1.26.3
packaging==24.2
pandas==1.5.3
parso==0.8.4
pillow==10.2.0
platformdirs==4.3.6
pooch==1.8.2
preshed==3.0.9
prompt_toolkit==3.0.48
propcache==0.2.0
protobuf==5.28.3
psutil==6.1.0
pure_eval==0.2.3
pycparser==2.22
pydantic==2.9.2
pydantic_core==2.23.4
Pygments==2.18.0
pynndescent==0.5.13
pyparsing==3.2.0
pypinyin==0.53.0
pysbd==0.3.4
python-crfsuite==0.9.11
python-dateutil==2.9.0.post0
pytz==2024.2
PyYAML==6.0.2
regex==2024.11.6
requests==2.32.3
rich==13.9.4
safetensors==0.4.5
scikit-learn==1.5.2
scipy==1.14.1
shellingham==1.5.4
six==1.16.0
smart-open==7.0.5
soundfile==0.12.1
soxr==0.5.0.post1
spacy==3.7.5
spacy-legacy==3.0.12
spacy-loggers==1.0.5
srsly==2.4.8
stack-data==0.6.3
SudachiDict-core==20241021
SudachiPy==0.6.8
sympy==1.13.1
tensorboard==2.18.0
tensorboard-data-server==0.7.2
thinc==8.2.5
threadpoolctl==3.5.0
tokenizers==0.20.3
# Verwijderd vanwege versie problemen
# torch==2.5.1+cu124
# torchaudio==2.5.1+cu124
# torchvision==0.20.1+cu124
torch==2.5.1
torchaudio==2.5.1
torchvision==0.20.1
tqdm==4.67.0
trainer==0.0.36
traitlets==5.14.3
transformers==4.46.2
typeguard==4.4.1
typer==0.13.0
typing_extensions==4.12.2
tzdata==2024.2
tzlocal==5.2
umap-learn==0.5.7
Unidecode==1.3.8
urllib3==2.2.3
wasabi==1.1.3
wcwidth==0.2.13
weasel==0.4.1
Werkzeug==3.1.3
wrapt==1.16.0
yarl==1.17.1
EOF
</code></pre>
<p>Om deze vervolgens te gebruiken om de pakketten te installeren:</p>
<pre><code class="language-shell">pip install -r requirements.txt
</code></pre>
<p>Als alles meezit wordt alles zonder meldingen geïnstalleerd. De oplossing van het versienummer werkt voor mij in ieder geval.</p>
<p>Vervolgens gaan we <a href="https://pypi.org/project/TTS/" target="new" rel="noopener" title="TTS">TTS</a> installeren. De schrijver heeft het over dat deze installatie wel 40 minuten kan duren, maar 3 seconden later is hij klaar. Het is mij onduidelijk waarom hij dit schreef.</p>
<pre><code class="language-shell">pip install TTS==0.22.0 --no-deps
</code></pre>
<p>In het vervolg wil hij <code>PyTorch</code> gaan installeren, maar dit is al gebeurd. Het lijkt wel of deze blog posts verkeerd om gepubliceerd is. En hierna houdt de post ook op. Wat hebben we nu bereikt? Nou, eigenlijk niet zoveel tot zo ver.</p>
<p>In de <code>readme.md</code> staat nog wat informatie van het project zelf. We nemen het eerste voorbeeld en passen hem een beetje aan. Aangezien het een variant is de voice cloning gebruikt, is er een audio sample nodig. Er staan een aantal voorbeelden in de <code>samples</code> map. Hiernaast is het voorbeeld wat verouderd. We passen het <code>gpu=True</code> aan naar <code>tts.to(&quot;mps&quot;)</code>. <code>mps</code> is de GPU acceleratie voor m1 processoren. Voor NVidea GPU's kan je <code>cuda</code> gebruiken.</p>
<pre><code class="language-shell">cat &lt;&lt;EOF &gt; test-1.py
from TTS.api import TTS
tts = TTS(&quot;tts_models/multilingual/multi-dataset/xtts_v2&quot;)
tts.to(&quot;mps&quot;)

# generate speech by cloning a voice using default settings
tts.tts_to_file(text=&quot;It took me quite a long time to develop a voice, and now that I have it I'm not going to be silent.&quot;,
                file_path=&quot;output.wav&quot;,
                speaker_wav=&quot;./samples/en_sample.wav&quot;,
                language=&quot;en&quot;)
EOF

python ./test-1.py 
</code></pre>
<p>Na uitvoer loop ik tegen het volgende probleem aan:</p>
<pre><code>NotImplementedError: Output channels &gt; 65536 not supported at the MPS device. As a temporary fix, you can set the environment variable `PYTORCH_ENABLE_MPS_FALLBACK=1` to use the CPU as a fallback for this op. WARNING: this will be slower than running natively on MPS.
</code></pre>
<p>En hier begint dan ook meteen de ellende. Ik zou willen proberen of een nieuwere <code>PyTorch</code> versie dit oplost, maar dat kan niet zomaar. Na het aanpassen naar de laatste versie (2.7.0) moet ook sympy&gt;=1.13.3 worden geïnstalleerd, wat weer leid tot het volgende:</p>
<pre><code class="language-shell">ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
tts 0.22.0 requires numpy==1.22.0; python_version &lt;= &quot;3.10&quot;, but you have numpy 1.26.3 which is incompatible.
</code></pre>
<p>Na het weer terug zetten van de requirements, probeer ik het voorstel wat in het log voorbij komt:</p>
<pre><code>export PYTORCH_ENABLE_MPS_FALLBACK=1; python test-1.py
</code></pre>
<p>Dit lijkt geen effect te hebben. Als alternatief kunnen we <code>tts.to(&quot;cpu&quot;)</code> in het script gebruiken. En dit werkt wel! Maar ja, wel een stuk trager dan we zouden willen natuurlijk. Na het aanpassen naar <code>cpu</code> werkt het voorbeeld en hebben we een <code>output.wav</code> bestand.</p>
<p>Inmiddels geloof ik wel dat Engels behoorlijk goed uitgesproken kan worden met TTS systemen, maar Nederlands is nog vaak een probleem. Om dit te testen pas ik het script aan met een Nederlandse tekst en gebruik hierbij de engelse sample.</p>
<pre><code>from TTS.api import TTS
tts = TTS(&quot;tts_models/multilingual/multi-dataset/xtts_v2&quot;)
tts.to(&quot;cpu&quot;)

# generate speech by cloning a voice using default settings
tts.tts_to_file(text=&quot;Het is belangrijk dat het geluid duidelijk uitgesproken wordt, en daardoor verstaanbaar is.&quot;,
                file_path=&quot;output.wav&quot;,
                speaker_wav=&quot;./samples/en_sample.wav&quot;,
                language=&quot;nl&quot;)
</code></pre>
<p>En het resultaat is erg goed! Een test met de Spaanse stem (een mannelijke stem) werkt wel, maar is niet geweldig. Ook de Franse sample levert niet echt geweldig resultaat. Het is overigens wel verstaanbaar. Als test heb ik online een audio sample gezocht, en met wat uitproberen komen er behoorlijk goede resultaten uit.</p>
<p>De snelheid op deze manier is helaas wel een puntje. Interessant zou zijn om het op een CUDA compatible systeem te testen, of te onderzoeken of en hoe dit direct met PyTorch te doen is.</p>

]]></description><pubDate>Fri, 25 Apr 2025 22:00:00 GMT</pubDate><guid>https://www.willow-media.nl/xtts-v2-text-to-speech-installation-guide</guid><link>https://www.willow-media.nl/xtts-v2-text-to-speech-installation-guide</link></item>
<item><title>Update van piper naar laatste versie op macOS</title><description><![CDATA[
<p><a href="https://github.com/rhasspy/piper" target="new" rel="noopener" title="Piper">Piper</a> is een open source toolkit voor text-to-speech, waarbij de belofte wordt gedaan dat deze werkende op alleen CPU toch behoorlijk snel zou zijn. Het is hierbij ook mogelijk een eigen stem te trainen.</p>
<blockquote>
<p>A fast, local neural text to speech system</p>
</blockquote>
<p>De laatste 'release' op de Github page is van 14 november 2023, maar afgelopen maand zijn er nog commits toegevoegd. De bedoeling is om te kijken of we de laatste versie op macOS aan de praat kunnen krijgen.</p>
<p>Eerder liep ik tegen een aantal problemen aan. Het downloaden van de release kan via de github pagina. Als je vervolgens de .tar.gz hebt geopent en <code>piper</code> start (niet via de terminal), krijg je al gauw <code>Apple could not verify “piper” is free of malware that may harm your Mac or compromise your privacy</code>. Via de terminal krijg je een geheel andere melding te zien:</p>
<pre><code class="language-shell">% ./piper
dyld[28586]: Library not loaded: @rpath/libespeak-ng.1.dylib
  Referenced from: &lt;65D01FDC-B71E-3786-8B0D-0BFEEC801633&gt; /Users/peter/Downloads/piper/piper
  Reason: tried: '/usr/local/lib/libespeak-ng.1.dylib' (no such file), '/usr/lib/libespeak-ng.1.dylib' (no such file, not in dyld cache)
zsh: abort      ./piper
</code></pre>
<p>Wat de foutmelding aangeeft, is dat de libraries die piper wil gebruiken, niet op de juiste plek staan. Of in andere woorden, piper verwacht dat de libraries ergens staan (<code>/usr/local/lib</code>) wat niet het geval is. Daarnaast is de gevraagde library <code>libespeak-ng.1.dylib</code> niet aanwezig in het gedownloade tar-archief.</p>
<p>Piper is afhankelijk van het <a href="https://github.com/rhasspy/piper-phonemize" target="new" rel="noopener" title="piper-phonemize">piper-phonemize</a> project. Dit project zorgt voor het omzetten van de gevraagde tekst naar fonetische symbolen die nodig zijn voor het uitspreken. Ik dacht dat dit weer gebaseerd is op <code>espeak-ng</code>, maar omdat er een specifiek onderdeel hierin ontbreekt, hebben ze er een separaat project van gemaakt. Of iets in die richting.</p>
<p>In het gedownloade tar-archief is <code>piper_phonemize</code> ook aanwezig. Hiervoor geldt hetzelfde als voor het opstarten van piper:</p>
<pre><code class="language-shell">% ./piper_phonemize
dyld[28668]: Library not loaded: @rpath/libpiper_phonemize.1.dylib
  Referenced from: &lt;3D98D201-8BC3-36CB-A5A6-1BF74A1CF7A8&gt; /Users/peter/Downloads/piper/piper_phonemize
  Reason: tried: '/usr/local/lib/libpiper_phonemize.1.dylib' (no such file), '/usr/lib/libpiper_phonemize.1.dylib' (no such file, not in dyld cache)
zsh: abort      ./piper_phonemize
</code></pre>
<p>Ook deze library is niet aanwezig in het tar-archief. Als je <code>piper_phonemize</code> download vanaf de <a href="https://github.com/rhasspy/piper-phonemize" target="new" rel="noopener" title="github pagina">github pagina</a>, is te zien dat de inhoud een stuk minder uitgekleed is. Sterker nog, alles wat tot nu toe geroepen wordt dat ontbreekt, is wel aanwezig in dit bestand. Echter krijgen we een zelfde soort foutmelding:</p>
<pre><code class="language-shell">% cd ../piper-phonemize
peter@MacBookPro bin % ./piper_phonemize 
dyld[28738]: Library not loaded: @rpath/libpiper_phonemize.1.dylib
  Referenced from: &lt;D5469D2B-CE4B-3598-B8B1-2374AA52AEF1&gt; /Users/peter/Downloads/piper-phonemize/bin/piper_phonemize
  Reason: tried: '/usr/local/lib/libpiper_phonemize.1.dylib' (no such file), '/usr/lib/libpiper_phonemize.1.dylib' (no such file, not in dyld cache)
zsh: abort      ./piper_phonemize
</code></pre>
<p>Na een korte zoektocht blijkt dat deze programma's een directe verwijzing gebruiken naar de libraries (<code>.dylib</code>). Deze is hardcoded in de applicatie. Aangezien ik verder niet zoveel weet van applicaties compileren op macOS, moest ik het antwoord vinden in <a href="https://github.com/rhasspy/piper/issues/321#issuecomment-2264043219" target="new" rel="noopener" title="github reactie">github reactie</a> bij het piper project.</p>
<p>Via <code>install_name_tool</code> kan het pad van de library aangepast worden, in de executable:</p>
<pre><code class="language-shell">#example, do not copy and paste this
sudo install_name_tool -change @rpath/libespeak-ng.1.dylib $PIPER_PHONEMIZE_DIR/lib/libespeak-ng.1.dylib $PIPER_DIR/piper
</code></pre>
<p>De persoon die de oplossing gepost heeft, heeft ook een script erbij geplaatst waarmee je de download en het corrigeren in 1 keer kan uitvoeren. Let wel op dat hij alles onder <code>/usr/local</code> installeert en dat is wat ik in ieder geval niet wil.</p>
<p>De conclusie is dat dus te downloaden release versie, niet out-of-the-box werkt, wat erg jammer is.</p>
<p>Terug naar de het doel. Buiten het kunnen downloaden, wil ik graag de laatste versie kunnen gebruiken. Er is een probleem met de Nederlandse stemmen en ik hoop te kunnen aantonen dat</p>
<ol>
<li>het probleem niet is opgelost en waar het probleem dan optreed, of</li>
<li>het probleem is opgelost en iedereen is blij</li>
</ol>
<p>De Github pagina van <code>piper</code> spreekt alleen maar over Linux desktop en 2 Raspberry PI variaties. De vraag is dan ook of er iets anders moet gebeuren voor macOS.</p>
<pre><code class="language-shell">% git clone https://github.com/rhasspy/piper.git
% cd piper
% make all
..
cd build &amp;&amp; ctest --config Release
CMake Error: Unknown argument: --config
CMake Error: Run 'ctest --help' for all supported options.
make: *** [all] Error 1
</code></pre>
<p>Hier liep ik eerder ook al eens tegenaan. <code>ctest --config release</code> lijkt op mijn machine niet te bestaan, maar <code>ctest -C release</code> wel. Na dit aangepast te hebben in de <code>Makefile</code> loopt het proces wel verder.</p>
<p>Dus de build gaat goed, maar vervolgens lopen we tegen hetzelfde probleem aan:</p>
<pre><code class="language-shell">% ./install/piper
dyld[36638]: Library not loaded: @rpath/libespeak-ng.1.dylib
  Referenced from: &lt;CEAF996E-3687-34F0-BC89-7314F7904719&gt; /Users/peter/Projects/poc/20250406-piper-from-source/piper/install/piper
  Reason: no LC_RPATH's found
</code></pre>
<p>Het ziet er meteen naar uit dat de install directory niet alles bevat. Vervolgens heb ik hetzelfde gedaan voor <code>piper_phomemize</code>:</p>
<pre><code class="language-shell">% git clone https://github.com/rhasspy/piper-phonemize pp
% cd pp
% make all
..
cd build &amp;&amp; ctest --config Release
CMake Error: Unknown argument: --config
CMake Error: Run 'ctest --help' for all supported options.
make: *** [all] Error 1

nano Makefile
# pas aan naar `ctest -C release`

% make all
</code></pre>
<p>Als hij klaar is, staat in de install map een 4tal mappen, waaronder bin directory de <code>piper_phonemize</code> executable bevat. Echter is hiermee het probleem niet opgelost. We hebben dan wel de laatste versie van de code, maar nog steeds hetzelfde probleem.</p>
<p>Gelukkig ben ik niet de enige die hier tegenaan loopt. In <a href="https://github.com/rhasspy/piper-phonemize/issues/14#issuecomment-2094395478" target="new" rel="noopener" title="Building for MacOS and iOS #14">Building for MacOS and iOS #14</a> wordt een zelfde probleem beschreven en wordt er gelukkig ook een oplossing genoemd. Een van de reacties geeft een oplossing gebruik te maken van de variabele <code>DYLD_LIBRARY_PATH</code>. Als ik het onderstaande probeer, dan werkt piper_phonemize!</p>
<pre><code class="language-shell">cd pp
export DYLD_LIBRARY_PATH=`pwd`/install/lib/
./install/bin/piper_phonemize
</code></pre>
<p>Maar dan hebben we nog een oplossing voor <code>piper</code> nodig. Deze lijkt veel meer te ontbreken. Gelukkig kunnen we de combinatie van beide projecten hiervoor gebruiken. Ik ga er vanuit dat zowel de clone van piper en piper-phonemize, in dezelfde directory staan:</p>
<pre><code class="language-shell">% ls -lFa
total 0
drwxr-xr-x  22 peter  staff   704 Apr  6 13:36 piper/
drwxr-xr-x  22 peter  staff   704 Apr  6 13:43 pp/
</code></pre>
<p>Ik gebruik het volgende om het aan te tonen. <code>pwd</code> zorgt ervoor dat de huidige directory wordt gebruikt als base pad. We zetten hierbij ook het pad voor de espeak data, omdat deze ook volledig in de piper-phonemize beschikbaar is:</p>
<pre><code class="language-shell">PP=&quot;`pwd`/pp/install&quot;
LIB=&quot;${PP}/lib&quot;
ESPEAK_DATA=&quot;${PP}/share/espeak-ng-data&quot;
PIPER_PATH=&quot;`pwd`/piper/install&quot;
DYLD_LIBRARY_PATH=&quot;${LIB}&quot; ; &quot;${PIPER_PATH}/piper&quot; --version --espeak_data &quot;${ESPEAK_DATA}&quot;
</code></pre>
<p>Uiteraard zal dit geen audio genereren, maar het versie nummer wordt wel getoond! Versie <code>1.2.0</code> is hiermee geïnstalleerd. Zorg dat het bovenste in de shell script verwerkt wordt en piper kan via de command line uitgevoerd worden.</p>

]]></description><pubDate>Sat, 05 Apr 2025 22:00:00 GMT</pubDate><guid>https://www.willow-media.nl/update-van-piper-naar-laatste-versie-op-macos</guid><link>https://www.willow-media.nl/update-van-piper-naar-laatste-versie-op-macos</link></item>
</channel></rss>