home.social

Search

271 results for “ddev”

  1. interesting how the so-called royals are dealing with andrew.
    i think they're throwing him under the bus bc they're shitting themselves over public anger towards #hierarchy in general lately.

    i am starting to feel almost hopeful we, global humanity minus the psychopathic #BillionaireClass, are on a winning streak!

    #EpsteinFiles #press #media #GlobalNews

    #AllPower2ThePeople #GlobalGeneralStrike #solidarity #MutualAid #GifsArtidote

    youtu.be/4aAT__dDEVU?

  2. Still thinking about the 'old internet' and dug up my 1990s #GeoCities site on David Devant & his Spirit Wife from the Internet Archive.

    Anyone else here going to see them on Friday in London? Funny to think it'll be back to the 1st place I saw them, back in '95 or so.

    web.archive.org/web/1999011706

    #daviddevant #IndieKid #AllDoneByKindness

  3. Still thinking about the 'old internet' and dug up my 1990s #GeoCities site on David Devant & his Spirit Wife from the Internet Archive.

    Anyone else here going to see them on Friday in London? Funny to think it'll be back to the 1st place I saw them, back in '95 or so.

    web.archive.org/web/1999011706

    #daviddevant #IndieKid #AllDoneByKindness

  4. Still thinking about the 'old internet' and dug up my 1990s #GeoCities site on David Devant & his Spirit Wife from the Internet Archive.

    Anyone else here going to see them on Friday in London? Funny to think it'll be back to the 1st place I saw them, back in '95 or so.

    web.archive.org/web/1999011706

    #daviddevant #IndieKid #AllDoneByKindness

  5. Still thinking about the 'old internet' and dug up my 1990s #GeoCities site on David Devant & his Spirit Wife from the Internet Archive.

    Anyone else here going to see them on Friday in London? Funny to think it'll be back to the 1st place I saw them, back in '95 or so.

    web.archive.org/web/1999011706

    #daviddevant #IndieKid #AllDoneByKindness

  6. Lenny Lipton, ‘Puff the Magic Dragon’ Lyricist and 3-D Film Pioneer, Dies at 82 - He used the royalties earned from the hit folk song to fund decades of research into ster... - nytimes.com/2022/10/21/arts/mu #peterpaulandmary(musicgroup) #inventionsandpatents #3-ddevicesandeffects #deaths(obituaries) #yarrowpeter #liptonlenny #folkmusic

  7. Contents

    Prerequisite

    Before we begin setting up our project, we need to ensure a webdriver is installed on our dev environment. We will be using Laravel Dusk for web interaction tests which will use a headless version of the Chrome browser. If you are using Homestead, you can go ahead and set “webdriver” to true and provision your server.

    Learn more about Laravel Homestead or DDEV with Docker for local Laravel development.

    When running through your provisioning script, it will download and install the Chrome driver ready to be used via Dusk.

    Testing is very much an optional part of development, but it is highly recommended you try it out since many companies and developers are looking at TDD and testing as a requirement.

    Creating the project

    First you need to create our application. If you have Homestead running, then you can SSH into your box and cd into your code directory. Here you can run laravel new blog or you can use composer create-project --prefer-dist laravel/laravel blog if you don’t have the Laravel installer setup. Now you can open the project using your favourite editor.

    Don’t forget to setup the database and point your server configuration to the new project.

    Now you have your project setup, we can move on and create everything needed for user authentication including registering and logging in a user.

    Backend AuthenticationCreating your first PHPUnit tests

    Next, we will be adding some tests for user authentication. You will need to run php artisan make:test UserLoginTest which will create UserLoginTest.php in your tests/Feature directory.

    If you run ./vendor/bin/phpunit you can see how the command works. Your test will pass because of the boilerplate code, but you’ll be removing that and updating it with some real tests.

    Delete the “testExample” method and replace it with this code…

    use RefreshDatabase; public function testUserLogsInSuccessfully() { $user = User::factory()->create([ 'email' => '[email protected]', 'password' => Hash::make('secret') ]); $response = $this->post('/login', [ 'email' => '[email protected]', 'password' => 'secret' ]); $response->assertRedirect('/home'); $this->assertTrue(Auth::check()); $this->assertTrue(Auth::user()->is($user)); } public function testUserLogsInUnsuccessfully() { $user = User::factory()->create([ 'email' => '[email protected]', 'password' => Hash::make('secret') ]); $response = $this->post('/login', [ 'email' => '[email protected]', 'password' => 'incorrect-password' ]); $response->assertSessionHasErrors(['email']); $this->assertFalse(Auth::check()); }

    use RefreshDatabase; tells PHPUnit that in order to run our test, we need to have our tables setup and empty in order to continue.

    Inside of testUserLogsInSuccessfully method, we create a user factory inside the database with the email “[email protected]” and password “secret“. The response is then sending a post request to “/login” with what will be the correct email and password. The test should then expect to receive a redirect to “/home“. The next assertion expects Auth::check() to be true and finally, the last assertion expects the correct authenticated user to match the user within the database and that will return true.

    The testUserLogsInUnsuccessfully will create the same user, but we will purposely use the incorrect details and expect our response to return an error with our email address. It will then check the authentication has failed, which will be true.

    Replace your use statements with this code

    use App\Models\User;use Illuminate\Foundation\Testing\RefreshDatabase;use Illuminate\Foundation\Testing\WithFaker;use Illuminate\Support\Facades\Auth;use Illuminate\Support\Facades\Hash;use Tests\TestCase;

    And now you can run ./vendor/bin/phpunit to run the test suite. Of course this will fail and you’ll see why soon.

    First off, we need to add a database connection into our phpunit.xml file. Open it up and add the following before the closing tag.

    When we run our tests, we will be using sqlite in memory. This means that a database will never be created on our system and once tests are finished, all the data will be cleared.

    Laravel version 7 and 8

    From Laravel version 7, all controller files within the auth directory have been removed and placed into laravel/ui. For the purposes of this course, we’re going to recreate these ourselves, however to begin we will need to enter the following composer require laravel/ui in order to get started.

    Authentication Routes

    First thing you need to do is add the authentication routes. Head over to routes/web.php and add…

    Authentication Controllers

    Next, you need to create the home controller file in app/Http/Controllers/HomeController.php or by running the artisan command php artisan make:controller HomeController if you run the latter command, then remove the code and add the folowing…

    middleware('auth'); } /** * Show the application dashboard. * * @return \Illuminate\Contracts\Support\Renderable */ public function index() { return view('home'); }}

    Within the app/Http/Controllers directory we’ll create a new folder called Auth. Inside our Auth directory, we want to make the following controllers with the following code.

    ConfirmPasswordController.phpmiddleware('auth'); }}LoginController.phpmiddleware('guest')->except('logout'); }}RegisterController.phpmiddleware('guest'); } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return \App\User */ protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); }}ResetPasswordController.php

    If you run ./vendor/bin/phpunit your PHPUnit tests should pass and you have finished this part of the course. If your test fails, it will display an error which will help you fix the test. Be sure not to change the test, but update the code the test is relying on to get the test to green.

    Adding Laravel Dusk for browser tests

    We will be creating this app using TDD which involves creating the tests first to describe our application and having them fail at first. We will then write the application code that will get tests passing. In order to do this you should install Dusk as it will be a part of your testing suite via composer require --dev laravel/dusk.

    If you’re not using Homestead and don’t have the Chrome driver set up, you might be able to run php artisan dusk:chrome-driver and chmod -R 0755 vendor/laravel/dusk/bin/ to ensure permissions are set correctly.

    Once composer has installed the dependancy, you can go ahead a run php artisan dusk:install which will create DuskTestCase.php and ExampleTest.php plus a bunch of other boilerplate code in our tests directory.

    If you’re not using Homestead, you may need to change your DuskTestCase.php inside your tests directory. If you’re like me and you’re running Laravel on DDEV, then go ahead and update it to the following…

    return RemoteWebDriver::create( 'http://selenium-hub:4444/wd/hub', DesiredCapabilities::chrome()->setCapability( ChromeOptions::CAPABILITY, $options ) );

    You may also find this blog post of interest.

    To ensure everything runs correctly, you will need to run php artisan dusk which will run our ExampleTest.php. It may take a moment to run, but with any luck you should see a green passing test.

    If you receive any errors, then please visit the prerequisites to ensure everything has been installed correctly. Go ahead and delete ExampleTest.php as it will no longer be needed.

    Frontend AuthenticationCreating your first Laravel Dusk tests

    With Dusk setup and ready to go, you can create your first test by running php artisan dusk:make UserLoginTest.php.

    Closing thoughts

    This has mostly been boilerplate Laravel authentication as we are trying to replicate a traditional Laravel app. In the next episode, you’ll be looking at implementing the frontend authentication and registration using Laravel Dusk.

    #from-zero-to-hero #laravel #php #tutorial

    https://michaelbrooks.co.uk/laravel-from-zero-to-hero-01-user-authentication/

  8. Destroying Autocracy – December 04, 2025

    Welcome to this week’s “Destroying Autocracy”.

    It’s your source for curated news affecting democracy in the cyber arena with a focus on protecting it. That necessitates an opinionated Butlerian jihad against big tech as well as evangelizing for open-source and the Fediverse. Since big media’s journalism wing is flailing and failing in its core duty to democracy, this is also a collection of alternative reporting on the eternal battle between autocracy and democracy. We also cover the cybersecurity world. You can’t be free without safety and privacy.

    FYI, my opinions will be in bold. And will often involve cursing. Because humans. Especially tech bros. And fascists. Fuck ’em.

    The Programmer’s Fulcrum is the future (and smaller) home for a fusion of Symfony Station and Battalion. Its tagline is Devs Defending Democracy, Developing the OMN.

    You can sign up now and for 2025 get an email with links to each week’s Symfony Station Communiqué and Battalion “Destroying Autocracy” post along with their featured articles. And you’ll be set with TPF after the fusing in January.

    We are posting on the Fediverse now at @thefulcrum @thefulcrum.dev and original website content will start next month.

    Featured Item(s)

    Hamish Campbell writes:

    ActivityPub is a shared vocabulary, a public language for moving meaning and connection across the open web. It gives you nouns and verbs, and the community defines the grammar through lived use.

    This is why the OMN works with ActivityPub, a metadata and meaning layer, not a platform, flows, not silos. ActivityPub is the widely deployed 4 Opens protocol that treats publishing as a flow, a conversation.

    Unlike the more vertical stacks (ATProto is a good example), ActivityPub doesn’t force a worldview. It doesn’t tell you, “this is how your network must be structured.” It doesn’t enforce hierarchy or lock you into one interpretation of identity, authority, or workflow. It’s a KISS path – here’s a shared language, verbs for publishing and receiving, express objects, updates, relationships. The rest is up to the commons.

    This flexibility is exactly why the OMN can become a part of this flow.

    Why the OMN works with ActivityPub – And why we need a bridge to p2p

    We start and end with good news to make the middle bearable.

    The response to Russia’s War Crimes, Techno Feudalism, and other douchebaggery

    DDEV has:

    Power Through Blackouts: How DDEV Community Helped Me in Ukraine

    TechPolicy Press shares:

    How to Test New York’s Algorithmic Pricing Law

    The EU’s Digital Omnibus Must Be Rejected by Lawmakers. Here is Why.

    Singapore announced an:

    Issuance of Implementation Directives to Apple and Google Under the Online Criminal Harms Act

    The MIT Press Reader has:

    The Secret History of Tor: How a Military Project Became a Lifeline for Privacy

    The Guardian reports:

    Irish authorities asked to investigate Microsoft over alleged unlawful data processing by IDF

    Neutral

    TechPolicy Press reports:

    What the European Commission and Civil Society Both Get Wrong on the Digital Omnibus

    Why Platforms Don’t Catch Climate Misinformation — and How to Change That

    EuroNews asks:

    Which European countries are building their own sovereign AI to compete in the tech race?

    Numerama reports:

    Mistral AI dévoile Mistral 3 et Ministral : des modèles qui replacent la France sur la scène open source

    TechCrunch reports:

    Mistral closes in on Big AI rivals with new open-weight frontier and small models

    Wired reports:

    The Age-Gated Internet Is Sweeping the states. Activists Are Fighting Back.

    The Evil Empire (AKA Autocracy) Strikes Back

    The Electronic Frontier Foundation reports:

    Lawmakers Want to Ban VPNs—And They Have No Idea What They’re Doing

    EDRi has:

    Promises unkept: The EU-US Data Privacy Framework under fire

    404 Media reports:

    Flock Uses Overseas Gig Workers to Build its Surveillance AI

    Pariah States

    DarkReading reports:

    Tomiris Unleashes ‘Havoc’ With New Tools, Tactics

    DPRK’s ‘Contagious Interview’ Spawns Malicious Npm Package Factory

    Student Sells Gov’t, University Sites to Chinese Actors

    TechPolicy Press reports:

    The Gulf’s AI Rise and the Risk of Entrenching Authoritarianism

    The Register reports:

    Stealthy browser extensions waited years before infecting 4.3M Chrome, Edge users with backdoors and spyware

    China using AI as ‘precision instrument’ of censorship and repression, at home and abroad

    Big Media

    Axios reports:

    Fox News hires Palantir to build AI newsroom tools

    Big surprise.

    Big Tech

    The Guardian reports:

    How big tech is creating its own friendly media bubble to ‘win the narrative battle online’

    More than 1,000 Amazon workers warn rapid AI rollout threatens jobs and climate

    Anti-immigrant material among AI-generated content getting billions of views on TikTok

    BleepingComputer reports:

    Leak confirms OpenAI is preparing ads on ChatGPT for public roll out

    Big surprise here. But, if you’re amoral enough to use it, you deserve all the privacy invading ads you get.

    Google deletes X post after getting caught using a ‘stolen’ AI recipe infographic

    Nature reports:

    Major AI conference flooded with peer reviews written fully by AI

    Wow.

    The Guardian reports:

    The question isn’t whether the AI bubble will burst – but what the fallout will be

    National Review reports:

    Meta Researchers Privately Compared Instagram to Addictive Drug, Bombshell Court Filing Shows

    Wanna-be Big Tech

    OMG Unbuntu has:

    Mozilla’s ‘Rewiring’ to AI – Saving the Web or Saving Itself?

    Cybersecurity/Privacy

    TechCrunch reports:

    European cops shut down crypto mixing website that helped launder 1.3B euros

    DarkReading reports:

    New Raptor Framework Uses Agentic Workflows to Create Patches

    Bleeping Computer reports:

    Fake Calendly invites spoof top brands to hijack ad manager accounts

    The Register reports:

    Microsoft quietly shuts down Windows shortcut flaw after years of espionage abuse

    Fediverse

    Coywolf has:

    Mastodon creator shares what went wrong with Threads and ponders the future of the fediverse

    Ben Werdmuller shares:

    Introducing Roundabout

    Sean Coates explores:

    The Fediverse and Content Creation: Monetization

    Great and important stuff.

    Ploum asks:

    Is Pixelfed sawing off the branch that the Fediverse is sitting on?

    Wouldn’t the fix to this would be to show a larger version of a user’s profile image with text posts?

    RSS

    Planet Codigo has:

    Mi solución RSS con software libre y autogestionado

    Slightly Decentralized Social Media

    TBD

    CTAs (aka show us some free love)

    Keep fighting!

    Ringleader, Battalion
    Reuben Walker
    Follow me on the Fediverse

    #ActivityPub #AI #Autocracy #BigJournalism #BigTech #Democracy #Fascism #Fediverse #Mastodon #Pixelfed #Roundabout #RSS #StopChina #StopIsrael #StopRedAmerica #StopRussia #SupportUkraine #TechnoAnarchism #TechnoFeudalism #Threads

    battalion.mobileatom.net/?p=41

  9. Destroying Autocracy – December 04, 2025

    Welcome to this week’s “Destroying Autocracy”.

    It’s your source for curated news affecting democracy in the cyber arena with a focus on protecting it. That necessitates an opinionated Butlerian jihad against big tech as well as evangelizing for open-source and the Fediverse. Since big media’s journalism wing is flailing and failing in its core duty to democracy, this is also a collection of alternative reporting on the eternal battle between autocracy and democracy. We also cover the cybersecurity world. You can’t be free without safety and privacy.

    FYI, my opinions will be in bold. And will often involve cursing. Because humans. Especially tech bros. And fascists. Fuck ’em.

    The Programmer’s Fulcrum is the future (and smaller) home for a fusion of Symfony Station and Battalion. Its tagline is Devs Defending Democracy, Developing the OMN.

    You can sign up now and for 2025 get an email with links to each week’s Symfony Station Communiqué and Battalion “Destroying Autocracy” post along with their featured articles. And you’ll be set with TPF after the fusing in January.

    We are posting on the Fediverse now at @thefulcrum @thefulcrum.dev and original website content will start next month.

    Featured Item(s)

    Hamish Campbell writes:

    ActivityPub is a shared vocabulary, a public language for moving meaning and connection across the open web. It gives you nouns and verbs, and the community defines the grammar through lived use.

    This is why the OMN works with ActivityPub, a metadata and meaning layer, not a platform, flows, not silos. ActivityPub is the widely deployed 4 Opens protocol that treats publishing as a flow, a conversation.

    Unlike the more vertical stacks (ATProto is a good example), ActivityPub doesn’t force a worldview. It doesn’t tell you, “this is how your network must be structured.” It doesn’t enforce hierarchy or lock you into one interpretation of identity, authority, or workflow. It’s a KISS path – here’s a shared language, verbs for publishing and receiving, express objects, updates, relationships. The rest is up to the commons.

    This flexibility is exactly why the OMN can become a part of this flow.

    Why the OMN works with ActivityPub – And why we need a bridge to p2p

    We start and end with good news to make the middle bearable.

    The response to Russia’s War Crimes, Techno Feudalism, and other douchebaggery

    DDEV has:

    Power Through Blackouts: How DDEV Community Helped Me in Ukraine

    TechPolicy Press shares:

    How to Test New York’s Algorithmic Pricing Law

    The EU’s Digital Omnibus Must Be Rejected by Lawmakers. Here is Why.

    Singapore announced an:

    Issuance of Implementation Directives to Apple and Google Under the Online Criminal Harms Act

    The MIT Press Reader has:

    The Secret History of Tor: How a Military Project Became a Lifeline for Privacy

    The Guardian reports:

    Irish authorities asked to investigate Microsoft over alleged unlawful data processing by IDF

    Elon Musk’s X fined €120m by EU in first clash under new digital laws

    The Electronic Frontier Foundation reports:

    After Years of Controversy, the EU’s Chat Control Nears Its Final Hurdle: What to Know

    FSFE announces:

    Opening the cage: the FSFE flies away from X (Twitter)

    Better late than never and what anyone with any morality should do.

    Signal announces:

    Major expansion of Signal for Linux, announces AppImage

    TechCrunch reports:

    Chicago Tribune sues Perplexity

    The Center for Democracy and Technology announces:

    A Framework for Assessing AI Transparency in the Public Sector

    Collabora announces:

    Collabora Online now available on Desktop

    Neutral

    TechPolicy Press reports:

    What the European Commission and Civil Society Both Get Wrong on the Digital Omnibus

    Why Platforms Don’t Catch Climate Misinformation — and How to Change That

    EuroNews asks:

    Which European countries are building their own sovereign AI to compete in the tech race?

    Numerama reports:

    Mistral AI dévoile Mistral 3 et Ministral : des modèles qui replacent la France sur la scène open source

    TechCrunch reports:

    Mistral closes in on Big AI rivals with new open-weight frontier and small models

    Wired reports:

    The Age-Gated Internet Is Sweeping the states. Activists Are Fighting Back.

    The Evil Empire (AKA Autocracy) Strikes Back

    The Electronic Frontier Foundation reports:

    Lawmakers Want to Ban VPNs—And They Have No Idea What They’re Doing

    EDRi has:

    Promises unkept: The EU-US Data Privacy Framework under fire

    404 Media reports:

    Flock Uses Overseas Gig Workers to Build its Surveillance AI

    TechCrunch reports:

    Sanctioned spyware maker Intellexa had direct access to government espionage victims, researchers say

    Pariah States

    DarkReading reports:

    Tomiris Unleashes ‘Havoc’ With New Tools, Tactics

    DPRK’s ‘Contagious Interview’ Spawns Malicious Npm Package Factory

    Student Sells Gov’t, University Sites to Chinese Actors

    TechPolicy Press reports:

    The Gulf’s AI Rise and the Risk of Entrenching Authoritarianism

    The Register reports:

    Stealthy browser extensions waited years before infecting 4.3M Chrome, Edge users with backdoors and spyware

    China using AI as ‘precision instrument’ of censorship and repression, at home and abroad

    Big Media

    Axios reports:

    Fox News hires Palantir to build AI newsroom tools

    Big surprise.

    Nieman Lab reports:

    Publishers will finally learn to truly value news creators

    The OMN can greatly influence this trend.

    The Ecologist shares:

    ‘We need a media consumers union’

    This times 1,000.

    Big Tech

    The Guardian reports:

    How big tech is creating its own friendly media bubble to ‘win the narrative battle online’

    More than 1,000 Amazon workers warn rapid AI rollout threatens jobs and climate

    Anti-immigrant material among AI-generated content getting billions of views on TikTok

    The question isn’t whether the AI bubble will burst – but what the fallout will be

    BleepingComputer reports:

    Leak confirms OpenAI is preparing ads on ChatGPT for public roll out

    Big surprise here. But, if you’re amoral enough to use it, you deserve all the privacy invading ads you get.

    Google deletes X post after getting caught using a ‘stolen’ AI recipe infographic

    Nature reports:

    Major AI conference flooded with peer reviews written fully by AI

    Wow.

    404 Media reports:

    Scientists Are Increasingly Worried AI Will Sway Elections

    Current Affairs reports:

    AI is Destroying the University and Learning Itself

    Time reports:

    Court Filings Allege Meta Downplayed Risks to Children and Misled the Public

    National Review reports:

    Meta Researchers Privately Compared Instagram to Addictive Drug, Bombshell Court Filing Shows

    Wanna-be Big Tech

    OMG Unbuntu has:

    Mozilla’s ‘Rewiring’ to AI – Saving the Web or Saving Itself?

    Cybersecurity/Privacy

    TechCrunch reports:

    European cops shut down crypto mixing website that helped launder 1.3B euros

    DarkReading reports:

    New Raptor Framework Uses Agentic Workflows to Create Patches

    Bleeping Computer reports:

    Fake Calendly invites spoof top brands to hijack ad manager accounts

    The Register reports:

    Microsoft quietly shuts down Windows shortcut flaw after years of espionage abuse

    Fediverse

    Coywolf has:

    Mastodon creator shares what went wrong with Threads and ponders the future of the fediverse

    Ben Werdmuller shares:

    Introducing Roundabout

    Sean Coates explores:

    The Fediverse and Content Creation: Monetization

    Great and important stuff.

    Ploum asks:

    Is Pixelfed sawing off the branch that the Fediverse is sitting on?

    Wouldn’t the fix to this would be to show a larger version of a user’s profile image with text posts?

    Connected Places has:

    Fediverse Report – 145

    FediForum shares:

    FediForum/Fediverse Track at SFSCon, November 2025, in Bolzano, Italy

    SVDJ has:

    ‘Stapje voor stapje de controle terugpakken’: hoe media hun publiek kunnen heroveren op Big Tech

    Beautiful site design for a news website, btw.

    Deemlog has a bizarre experiment:

    Git as Federation Transport — Rethinking How Small Social Networks Talk to Each Other

    Jose Murilo shares:

    “Museus no Fediverso” – Apresentação do Ibram-Museus no 1º WebSocialBR

    RSS

    Planet Codigo has:

    Mi solución RSS con software libre y autogestionado

    Slightly Decentralized Social Media

    TBD

    CTAs (aka show us some free love)

    Keep fighting!

    Ringleader, Battalion
    Reuben Walker
    Follow me on the Fediverse

    #ActivityPub #AI #Autocracy #BigJournalism #BigTech #Democracy #Fascism #Fediverse #Mastodon #Pixelfed #Roundabout #RSS #StopChina #StopIsrael #StopRedAmerica #StopRussia #SupportUkraine #TechnoAnarchism #TechnoFeudalism #Threads

    battalion.mobileatom.net/?p=41

  10. Destroying Autocracy – December 04, 2025

    Welcome to this week’s “Destroying Autocracy”.

    It’s your source for curated news affecting democracy in the cyber arena with a focus on protecting it. That necessitates an opinionated Butlerian jihad against big tech as well as evangelizing for open-source and the Fediverse. Since big media’s journalism wing is flailing and failing in its core duty to democracy, this is also a collection of alternative reporting on the eternal battle between autocracy and democracy. We also cover the cybersecurity world. You can’t be free without safety and privacy.

    FYI, my opinions will be in bold. And will often involve cursing. Because humans. Especially tech bros. And fascists. Fuck ’em.

    The Programmer’s Fulcrum is the future (and smaller) home for a fusion of Symfony Station and Battalion. Its tagline is Devs Defending Democracy, Developing the OMN.

    You can sign up now and for 2025 get an email with links to each week’s Symfony Station Communiqué and Battalion “Destroying Autocracy” post along with their featured articles. And you’ll be set with TPF after the fusing in January.

    We are posting on the Fediverse now at @thefulcrum @thefulcrum.dev and original website content will start next month.

    Featured Item(s)

    Hamish Campbell writes:

    ActivityPub is a shared vocabulary, a public language for moving meaning and connection across the open web. It gives you nouns and verbs, and the community defines the grammar through lived use.

    This is why the OMN works with ActivityPub, a metadata and meaning layer, not a platform, flows, not silos. ActivityPub is the widely deployed 4 Opens protocol that treats publishing as a flow, a conversation.

    Unlike the more vertical stacks (ATProto is a good example), ActivityPub doesn’t force a worldview. It doesn’t tell you, “this is how your network must be structured.” It doesn’t enforce hierarchy or lock you into one interpretation of identity, authority, or workflow. It’s a KISS path – here’s a shared language, verbs for publishing and receiving, express objects, updates, relationships. The rest is up to the commons.

    This flexibility is exactly why the OMN can become a part of this flow.

    Why the OMN works with ActivityPub – And why we need a bridge to p2p

    We start and end with good news to make the middle bearable.

    The response to Russia’s War Crimes, Techno Feudalism, and other douchebaggery

    DDEV has:

    Power Through Blackouts: How DDEV Community Helped Me in Ukraine

    TechPolicy Press shares:

    How to Test New York’s Algorithmic Pricing Law

    The EU’s Digital Omnibus Must Be Rejected by Lawmakers. Here is Why.

    Singapore announced an:

    Issuance of Implementation Directives to Apple and Google Under the Online Criminal Harms Act

    The MIT Press Reader has:

    The Secret History of Tor: How a Military Project Became a Lifeline for Privacy

    The Guardian reports:

    Irish authorities asked to investigate Microsoft over alleged unlawful data processing by IDF

    Elon Musk’s X fined €120m by EU in first clash under new digital laws

    The Electronic Frontier Foundation reports:

    After Years of Controversy, the EU’s Chat Control Nears Its Final Hurdle: What to Know

    FSFE announces:

    Opening the cage: the FSFE flies away from X (Twitter)

    Better late than never and what anyone with any morality should do.

    Signal announces:

    Major expansion of Signal for Linux, announces AppImage

    TechCrunch reports:

    Chicago Tribune sues Perplexity

    The Center for Democracy and Technology announces:

    A Framework for Assessing AI Transparency in the Public Sector

    Collabora announces:

    Collabora Online now available on Desktop

    Neutral

    TechPolicy Press reports:

    What the European Commission and Civil Society Both Get Wrong on the Digital Omnibus

    Why Platforms Don’t Catch Climate Misinformation — and How to Change That

    EuroNews asks:

    Which European countries are building their own sovereign AI to compete in the tech race?

    Numerama reports:

    Mistral AI dévoile Mistral 3 et Ministral : des modèles qui replacent la France sur la scène open source

    TechCrunch reports:

    Mistral closes in on Big AI rivals with new open-weight frontier and small models

    Wired reports:

    The Age-Gated Internet Is Sweeping the states. Activists Are Fighting Back.

    The Evil Empire (AKA Autocracy) Strikes Back

    The Electronic Frontier Foundation reports:

    Lawmakers Want to Ban VPNs—And They Have No Idea What They’re Doing

    EDRi has:

    Promises unkept: The EU-US Data Privacy Framework under fire

    404 Media reports:

    Flock Uses Overseas Gig Workers to Build its Surveillance AI

    TechCrunch reports:

    Sanctioned spyware maker Intellexa had direct access to government espionage victims, researchers say

    Pariah States

    DarkReading reports:

    Tomiris Unleashes ‘Havoc’ With New Tools, Tactics

    DPRK’s ‘Contagious Interview’ Spawns Malicious Npm Package Factory

    Student Sells Gov’t, University Sites to Chinese Actors

    TechPolicy Press reports:

    The Gulf’s AI Rise and the Risk of Entrenching Authoritarianism

    The Register reports:

    Stealthy browser extensions waited years before infecting 4.3M Chrome, Edge users with backdoors and spyware

    China using AI as ‘precision instrument’ of censorship and repression, at home and abroad

    Big Media

    Axios reports:

    Fox News hires Palantir to build AI newsroom tools

    Big surprise.

    Nieman Lab reports:

    Publishers will finally learn to truly value news creators

    The OMN can greatly influence this trend.

    The Ecologist shares:

    ‘We need a media consumers union’

    This times 1,000.

    Big Tech

    The Guardian reports:

    How big tech is creating its own friendly media bubble to ‘win the narrative battle online’

    More than 1,000 Amazon workers warn rapid AI rollout threatens jobs and climate

    Anti-immigrant material among AI-generated content getting billions of views on TikTok

    The question isn’t whether the AI bubble will burst – but what the fallout will be

    BleepingComputer reports:

    Leak confirms OpenAI is preparing ads on ChatGPT for public roll out

    Big surprise here. But, if you’re amoral enough to use it, you deserve all the privacy invading ads you get.

    Google deletes X post after getting caught using a ‘stolen’ AI recipe infographic

    Nature reports:

    Major AI conference flooded with peer reviews written fully by AI

    Wow.

    404 Media reports:

    Scientists Are Increasingly Worried AI Will Sway Elections

    Current Affairs reports:

    AI is Destroying the University and Learning Itself

    Time reports:

    Court Filings Allege Meta Downplayed Risks to Children and Misled the Public

    National Review reports:

    Meta Researchers Privately Compared Instagram to Addictive Drug, Bombshell Court Filing Shows

    Wanna-be Big Tech

    OMG Unbuntu has:

    Mozilla’s ‘Rewiring’ to AI – Saving the Web or Saving Itself?

    Cybersecurity/Privacy

    TechCrunch reports:

    European cops shut down crypto mixing website that helped launder 1.3B euros

    DarkReading reports:

    New Raptor Framework Uses Agentic Workflows to Create Patches

    Bleeping Computer reports:

    Fake Calendly invites spoof top brands to hijack ad manager accounts

    The Register reports:

    Microsoft quietly shuts down Windows shortcut flaw after years of espionage abuse

    Fediverse

    Coywolf has:

    Mastodon creator shares what went wrong with Threads and ponders the future of the fediverse

    Ben Werdmuller shares:

    Introducing Roundabout

    Sean Coates explores:

    The Fediverse and Content Creation: Monetization

    Great and important stuff.

    Ploum asks:

    Is Pixelfed sawing off the branch that the Fediverse is sitting on?

    Wouldn’t the fix to this would be to show a larger version of a user’s profile image with text posts?

    Connected Places has:

    Fediverse Report – 145

    FediForum shares:

    FediForum/Fediverse Track at SFSCon, November 2025, in Bolzano, Italy

    SVDJ has:

    ‘Stapje voor stapje de controle terugpakken’: hoe media hun publiek kunnen heroveren op Big Tech

    Beautiful site design for a news website, btw.

    Deemlog has a bizarre experiment:

    Git as Federation Transport — Rethinking How Small Social Networks Talk to Each Other

    Jose Murilo shares:

    “Museus no Fediverso” – Apresentação do Ibram-Museus no 1º WebSocialBR

    RSS

    Planet Codigo has:

    Mi solución RSS con software libre y autogestionado

    Slightly Decentralized Social Media

    TBD

    CTAs (aka show us some free love)

    Keep fighting!

    Ringleader, Battalion
    Reuben Walker
    Follow me on the Fediverse

    #ActivityPub #AI #Autocracy #BigJournalism #BigTech #Democracy #Fascism #Fediverse #Mastodon #Pixelfed #Roundabout #RSS #StopChina #StopIsrael #StopRedAmerica #StopRussia #SupportUkraine #TechnoAnarchism #TechnoFeudalism #Threads

    battalion.mobileatom.net/?p=41

  11. Destroying Autocracy – December 04, 2025

    Welcome to this week’s “Destroying Autocracy”.

    It’s your source for curated news affecting democracy in the cyber arena with a focus on protecting it. That necessitates an opinionated Butlerian jihad against big tech as well as evangelizing for open-source and the Fediverse. Since big media’s journalism wing is flailing and failing in its core duty to democracy, this is also a collection of alternative reporting on the eternal battle between autocracy and democracy. We also cover the cybersecurity world. You can’t be free without safety and privacy.

    FYI, my opinions will be in bold. And will often involve cursing. Because humans. Especially tech bros. And fascists. Fuck ’em.

    The Programmer’s Fulcrum is the future (and smaller) home for a fusion of Symfony Station and Battalion. Its tagline is Devs Defending Democracy, Developing the OMN.

    You can sign up now and for 2025 get an email with links to each week’s Symfony Station Communiqué and Battalion “Destroying Autocracy” post along with their featured articles. And you’ll be set with TPF after the fusing in January.

    We are posting on the Fediverse now at @thefulcrum @thefulcrum.dev and original website content will start next month.

    Featured Item(s)

    Hamish Campbell writes:

    ActivityPub is a shared vocabulary, a public language for moving meaning and connection across the open web. It gives you nouns and verbs, and the community defines the grammar through lived use.

    This is why the OMN works with ActivityPub, a metadata and meaning layer, not a platform, flows, not silos. ActivityPub is the widely deployed 4 Opens protocol that treats publishing as a flow, a conversation.

    Unlike the more vertical stacks (ATProto is a good example), ActivityPub doesn’t force a worldview. It doesn’t tell you, “this is how your network must be structured.” It doesn’t enforce hierarchy or lock you into one interpretation of identity, authority, or workflow. It’s a KISS path – here’s a shared language, verbs for publishing and receiving, express objects, updates, relationships. The rest is up to the commons.

    This flexibility is exactly why the OMN can become a part of this flow.

    Why the OMN works with ActivityPub – And why we need a bridge to p2p

    We start and end with good news to make the middle bearable.

    The response to Russia’s War Crimes, Techno Feudalism, and other douchebaggery

    DDEV has:

    Power Through Blackouts: How DDEV Community Helped Me in Ukraine

    TechPolicy Press shares:

    How to Test New York’s Algorithmic Pricing Law

    The EU’s Digital Omnibus Must Be Rejected by Lawmakers. Here is Why.

    Singapore announced an:

    Issuance of Implementation Directives to Apple and Google Under the Online Criminal Harms Act

    The MIT Press Reader has:

    The Secret History of Tor: How a Military Project Became a Lifeline for Privacy

    The Guardian reports:

    Irish authorities asked to investigate Microsoft over alleged unlawful data processing by IDF

    Elon Musk’s X fined €120m by EU in first clash under new digital laws

    The Electronic Frontier Foundation reports:

    After Years of Controversy, the EU’s Chat Control Nears Its Final Hurdle: What to Know

    FSFE announces:

    Opening the cage: the FSFE flies away from X (Twitter)

    Better late than never and what anyone with any morality should do.

    Signal announces:

    Major expansion of Signal for Linux, announces AppImage

    TechCrunch reports:

    Chicago Tribune sues Perplexity

    The Center for Democracy and Technology announces:

    A Framework for Assessing AI Transparency in the Public Sector

    Collabora announces:

    Collabora Online now available on Desktop

    Neutral

    TechPolicy Press reports:

    What the European Commission and Civil Society Both Get Wrong on the Digital Omnibus

    Why Platforms Don’t Catch Climate Misinformation — and How to Change That

    EuroNews asks:

    Which European countries are building their own sovereign AI to compete in the tech race?

    Numerama reports:

    Mistral AI dévoile Mistral 3 et Ministral : des modèles qui replacent la France sur la scène open source

    TechCrunch reports:

    Mistral closes in on Big AI rivals with new open-weight frontier and small models

    Wired reports:

    The Age-Gated Internet Is Sweeping the states. Activists Are Fighting Back.

    The Evil Empire (AKA Autocracy) Strikes Back

    The Electronic Frontier Foundation reports:

    Lawmakers Want to Ban VPNs—And They Have No Idea What They’re Doing

    EDRi has:

    Promises unkept: The EU-US Data Privacy Framework under fire

    404 Media reports:

    Flock Uses Overseas Gig Workers to Build its Surveillance AI

    TechCrunch reports:

    Sanctioned spyware maker Intellexa had direct access to government espionage victims, researchers say

    Pariah States

    DarkReading reports:

    Tomiris Unleashes ‘Havoc’ With New Tools, Tactics

    DPRK’s ‘Contagious Interview’ Spawns Malicious Npm Package Factory

    Student Sells Gov’t, University Sites to Chinese Actors

    TechPolicy Press reports:

    The Gulf’s AI Rise and the Risk of Entrenching Authoritarianism

    The Register reports:

    Stealthy browser extensions waited years before infecting 4.3M Chrome, Edge users with backdoors and spyware

    China using AI as ‘precision instrument’ of censorship and repression, at home and abroad

    Big Media

    Axios reports:

    Fox News hires Palantir to build AI newsroom tools

    Big surprise.

    Nieman Lab reports:

    Publishers will finally learn to truly value news creators

    The OMN can greatly influence this trend.

    The Ecologist shares:

    ‘We need a media consumers union’

    This times 1,000.

    Big Tech

    The Guardian reports:

    How big tech is creating its own friendly media bubble to ‘win the narrative battle online’

    More than 1,000 Amazon workers warn rapid AI rollout threatens jobs and climate

    Anti-immigrant material among AI-generated content getting billions of views on TikTok

    The question isn’t whether the AI bubble will burst – but what the fallout will be

    BleepingComputer reports:

    Leak confirms OpenAI is preparing ads on ChatGPT for public roll out

    Big surprise here. But, if you’re amoral enough to use it, you deserve all the privacy invading ads you get.

    Google deletes X post after getting caught using a ‘stolen’ AI recipe infographic

    Nature reports:

    Major AI conference flooded with peer reviews written fully by AI

    Wow.

    404 Media reports:

    Scientists Are Increasingly Worried AI Will Sway Elections

    Current Affairs reports:

    AI is Destroying the University and Learning Itself

    Time reports:

    Court Filings Allege Meta Downplayed Risks to Children and Misled the Public

    National Review reports:

    Meta Researchers Privately Compared Instagram to Addictive Drug, Bombshell Court Filing Shows

    Wanna-be Big Tech

    OMG Unbuntu has:

    Mozilla’s ‘Rewiring’ to AI – Saving the Web or Saving Itself?

    Cybersecurity/Privacy

    TechCrunch reports:

    European cops shut down crypto mixing website that helped launder 1.3B euros

    DarkReading reports:

    New Raptor Framework Uses Agentic Workflows to Create Patches

    Bleeping Computer reports:

    Fake Calendly invites spoof top brands to hijack ad manager accounts

    The Register reports:

    Microsoft quietly shuts down Windows shortcut flaw after years of espionage abuse

    Fediverse

    Coywolf has:

    Mastodon creator shares what went wrong with Threads and ponders the future of the fediverse

    Ben Werdmuller shares:

    Introducing Roundabout

    Sean Coates explores:

    The Fediverse and Content Creation: Monetization

    Great and important stuff.

    Ploum asks:

    Is Pixelfed sawing off the branch that the Fediverse is sitting on?

    Wouldn’t the fix to this would be to show a larger version of a user’s profile image with text posts?

    Connected Places has:

    Fediverse Report – 145

    FediForum shares:

    FediForum/Fediverse Track at SFSCon, November 2025, in Bolzano, Italy

    SVDJ has:

    ‘Stapje voor stapje de controle terugpakken’: hoe media hun publiek kunnen heroveren op Big Tech

    Beautiful site design for a news website, btw.

    Deemlog has a bizarre experiment:

    Git as Federation Transport — Rethinking How Small Social Networks Talk to Each Other

    Jose Murilo shares:

    “Museus no Fediverso” – Apresentação do Ibram-Museus no 1º WebSocialBR

    RSS

    Planet Codigo has:

    Mi solución RSS con software libre y autogestionado

    Slightly Decentralized Social Media

    TBD

    CTAs (aka show us some free love)

    Keep fighting!

    Ringleader, Battalion
    Reuben Walker
    Follow me on the Fediverse

    #ActivityPub #AI #Autocracy #BigJournalism #BigTech #Democracy #Fascism #Fediverse #Mastodon #Pixelfed #Roundabout #RSS #StopChina #StopIsrael #StopRedAmerica #StopRussia #SupportUkraine #TechnoAnarchism #TechnoFeudalism #Threads

    battalion.mobileatom.net/?p=41

  12. Destroying Autocracy – December 04, 2025

    Welcome to this week’s “Destroying Autocracy”.

    It’s your source for curated news affecting democracy in the cyber arena with a focus on protecting it. That necessitates an opinionated Butlerian jihad against big tech as well as evangelizing for open-source and the Fediverse. Since big media’s journalism wing is flailing and failing in its core duty to democracy, this is also a collection of alternative reporting on the eternal battle between autocracy and democracy. We also cover the cybersecurity world. You can’t be free without safety and privacy.

    FYI, my opinions will be in bold. And will often involve cursing. Because humans. Especially tech bros. And fascists. Fuck ’em.

    The Programmer’s Fulcrum is the future (and smaller) home for a fusion of Symfony Station and Battalion. Its tagline is Devs Defending Democracy, Developing the OMN.

    You can sign up now and for 2025 get an email with links to each week’s Symfony Station Communiqué and Battalion “Destroying Autocracy” post along with their featured articles. And you’ll be set with TPF after the fusing in January.

    We are posting on the Fediverse now at @thefulcrum @thefulcrum.dev and original website content will start next month.

    Featured Item(s)

    Hamish Campbell writes:

    ActivityPub is a shared vocabulary, a public language for moving meaning and connection across the open web. It gives you nouns and verbs, and the community defines the grammar through lived use.

    This is why the OMN works with ActivityPub, a metadata and meaning layer, not a platform, flows, not silos. ActivityPub is the widely deployed 4 Opens protocol that treats publishing as a flow, a conversation.

    Unlike the more vertical stacks (ATProto is a good example), ActivityPub doesn’t force a worldview. It doesn’t tell you, “this is how your network must be structured.” It doesn’t enforce hierarchy or lock you into one interpretation of identity, authority, or workflow. It’s a KISS path – here’s a shared language, verbs for publishing and receiving, express objects, updates, relationships. The rest is up to the commons.

    This flexibility is exactly why the OMN can become a part of this flow.

    Why the OMN works with ActivityPub – And why we need a bridge to p2p

    We start and end with good news to make the middle bearable.

    The response to Russia’s War Crimes, Techno Feudalism, and other douchebaggery

    DDEV has:

    Power Through Blackouts: How DDEV Community Helped Me in Ukraine

    TechPolicy Press shares:

    How to Test New York’s Algorithmic Pricing Law

    The EU’s Digital Omnibus Must Be Rejected by Lawmakers. Here is Why.

    Singapore announced an:

    Issuance of Implementation Directives to Apple and Google Under the Online Criminal Harms Act

    The MIT Press Reader has:

    The Secret History of Tor: How a Military Project Became a Lifeline for Privacy

    The Guardian reports:

    Irish authorities asked to investigate Microsoft over alleged unlawful data processing by IDF

    Elon Musk’s X fined €120m by EU in first clash under new digital laws

    The Electronic Frontier Foundation reports:

    After Years of Controversy, the EU’s Chat Control Nears Its Final Hurdle: What to Know

    FSFE announces:

    Opening the cage: the FSFE flies away from X (Twitter)

    Better late than never and what anyone with any morality should do.

    Signal announces:

    Major expansion of Signal for Linux, announces AppImage

    TechCrunch reports:

    Chicago Tribune sues Perplexity

    The Center for Democracy and Technology announces:

    A Framework for Assessing AI Transparency in the Public Sector

    Collabora announces:

    Collabora Online now available on Desktop

    Neutral

    TechPolicy Press reports:

    What the European Commission and Civil Society Both Get Wrong on the Digital Omnibus

    Why Platforms Don’t Catch Climate Misinformation — and How to Change That

    EuroNews asks:

    Which European countries are building their own sovereign AI to compete in the tech race?

    Numerama reports:

    Mistral AI dévoile Mistral 3 et Ministral : des modèles qui replacent la France sur la scène open source

    TechCrunch reports:

    Mistral closes in on Big AI rivals with new open-weight frontier and small models

    Wired reports:

    The Age-Gated Internet Is Sweeping the states. Activists Are Fighting Back.

    The Evil Empire (AKA Autocracy) Strikes Back

    The Electronic Frontier Foundation reports:

    Lawmakers Want to Ban VPNs—And They Have No Idea What They’re Doing

    EDRi has:

    Promises unkept: The EU-US Data Privacy Framework under fire

    404 Media reports:

    Flock Uses Overseas Gig Workers to Build its Surveillance AI

    TechCrunch reports:

    Sanctioned spyware maker Intellexa had direct access to government espionage victims, researchers say

    Pariah States

    DarkReading reports:

    Tomiris Unleashes ‘Havoc’ With New Tools, Tactics

    DPRK’s ‘Contagious Interview’ Spawns Malicious Npm Package Factory

    Student Sells Gov’t, University Sites to Chinese Actors

    TechPolicy Press reports:

    The Gulf’s AI Rise and the Risk of Entrenching Authoritarianism

    The Register reports:

    Stealthy browser extensions waited years before infecting 4.3M Chrome, Edge users with backdoors and spyware

    China using AI as ‘precision instrument’ of censorship and repression, at home and abroad

    Big Media

    Axios reports:

    Fox News hires Palantir to build AI newsroom tools

    Big surprise.

    Nieman Lab reports:

    Publishers will finally learn to truly value news creators

    The OMN can greatly influence this trend.

    The Ecologist shares:

    ‘We need a media consumers union’

    This times 1,000.

    Big Tech

    The Guardian reports:

    How big tech is creating its own friendly media bubble to ‘win the narrative battle online’

    More than 1,000 Amazon workers warn rapid AI rollout threatens jobs and climate

    Anti-immigrant material among AI-generated content getting billions of views on TikTok

    The question isn’t whether the AI bubble will burst – but what the fallout will be

    BleepingComputer reports:

    Leak confirms OpenAI is preparing ads on ChatGPT for public roll out

    Big surprise here. But, if you’re amoral enough to use it, you deserve all the privacy invading ads you get.

    Google deletes X post after getting caught using a ‘stolen’ AI recipe infographic

    Nature reports:

    Major AI conference flooded with peer reviews written fully by AI

    Wow.

    404 Media reports:

    Scientists Are Increasingly Worried AI Will Sway Elections

    Current Affairs reports:

    AI is Destroying the University and Learning Itself

    Time reports:

    Court Filings Allege Meta Downplayed Risks to Children and Misled the Public

    National Review reports:

    Meta Researchers Privately Compared Instagram to Addictive Drug, Bombshell Court Filing Shows

    Wanna-be Big Tech

    OMG Unbuntu has:

    Mozilla’s ‘Rewiring’ to AI – Saving the Web or Saving Itself?

    Cybersecurity/Privacy

    TechCrunch reports:

    European cops shut down crypto mixing website that helped launder 1.3B euros

    DarkReading reports:

    New Raptor Framework Uses Agentic Workflows to Create Patches

    Bleeping Computer reports:

    Fake Calendly invites spoof top brands to hijack ad manager accounts

    The Register reports:

    Microsoft quietly shuts down Windows shortcut flaw after years of espionage abuse

    Fediverse

    Coywolf has:

    Mastodon creator shares what went wrong with Threads and ponders the future of the fediverse

    Ben Werdmuller shares:

    Introducing Roundabout

    Sean Coates explores:

    The Fediverse and Content Creation: Monetization

    Great and important stuff.

    Ploum asks:

    Is Pixelfed sawing off the branch that the Fediverse is sitting on?

    Wouldn’t the fix to this would be to show a larger version of a user’s profile image with text posts?

    Connected Places has:

    Fediverse Report – 145

    FediForum shares:

    FediForum/Fediverse Track at SFSCon, November 2025, in Bolzano, Italy

    SVDJ has:

    ‘Stapje voor stapje de controle terugpakken’: hoe media hun publiek kunnen heroveren op Big Tech

    Beautiful site design for a news website, btw.

    Deemlog has a bizarre experiment:

    Git as Federation Transport — Rethinking How Small Social Networks Talk to Each Other

    Jose Murilo shares:

    “Museus no Fediverso” – Apresentação do Ibram-Museus no 1º WebSocialBR

    RSS

    Planet Codigo has:

    Mi solución RSS con software libre y autogestionado

    Slightly Decentralized Social Media

    TBD

    CTAs (aka show us some free love)

    Keep fighting!

    Ringleader, Battalion
    Reuben Walker
    Follow me on the Fediverse

    #ActivityPub #AI #Autocracy #BigJournalism #BigTech #Democracy #Fascism #Fediverse #Mastodon #Pixelfed #Roundabout #RSS #StopChina #StopIsrael #StopRedAmerica #StopRussia #SupportUkraine #TechnoAnarchism #TechnoFeudalism #Threads

    battalion.mobileatom.net/?p=41

  13. Vanavond wordt ie feestelijk gepresenteerd, en vanaf morgen in de winkel: Geur. de vergeten sensatie van Frank Bloem. Frank beschrijft hierin zijn avonturen in de wereld van geur. Wij mochten het omslag ontwerpen en zijn dolblij met de lachende potvis.

    Uitgegeven door Uitgeverij Ten Have

    #bookdesign #bookcover #boekontwerp #boekverzorging #boekomslag #grafischontwerp #bureaumerkwaardig #vanboektotbestseller #typografie #frankbloem #geur #devergetensensatie

  14. Not to myself:

    fbi -d /dev/fb0 --once --noverbose\
    --autozoom /path/to/image.png </dev/tty1 >/dev/tty1

    First time you run it, you'll probably get:

    ioctl VT_GETSTATE: Inappropriate ioctl for device (not a linux console?)

    A lot of people on the internets seem to suggest something like "just run it from Alt + F1 console", which definitely isn't an option for this case, but I/O redirection to /dev/tty (as shown above) seem to work.

    from http://blog.fraggod.net/2015/11/28/raspberry-pi-early-boot-splash-logo-screen.html

    #raspberrypi #bootsplash
  15. really useful oneliner when a disk/ssd failed, got replaced, and now you need to copy the partition layout to a new disk:

    sfdisk -d /dev/nvme0n1 | sfdisk /dev/nvme1n1

    (yes my main server's secondary NVME disappeared randomly. I had it replaced, but since it's both the boot drive in a mdadm RAID1 (3 partitions), AND a ZFS ZIL + Cache, it has quite a specific layout)

    #LinuxTips #Storage #SysadminTips

  16. Gesehen: Monkey Man (2024)

    https://www.youtube.com/watch?v=g8zxiB5Qhsc

    CA/SG/US, R: Dev Patel, D: Dev Patel, Sikandar Kher, Pitobash, Adithi Kalkunte, Makrand Deshpande, Ashwini Kalsekar, Vipin Sharma, Sobhita Dhulipala, Sharlto Copley, Wikipedia

    Mir gefällt die Progression, die in den Kämpfen zu erkennen ist. Wie sich die Figuren zunächst von roher Gewalt bestimmt, fast schon unbeholfen durch ihre Choreografie holpern, weil man eben nicht jeden Tag um Leben und Tod kämpft, der Überlebensinstinkt aber schließlich die Kontrolle übernimmt. Wie dann mit der Erfahrung die Fähigkeit kommt, Wut und Kraft zu kanalisieren und nicht zu „verschwenden“.

    Und ich muss sagen, dass Dev Patel das alles ganz schmissig in Szene setzt. Wer sich bei seinem allerersten Langfilm für Action dieses Kalibers entscheidet, darf sich von mir aus auch gerne ein paar Kniffe bei anderen Genregrößen abschauen. Dass Patel sehr viel von Matthew Vaughns KINGSMAN-Reihe, Quentin Tarantinos KILL BILL und die von Chad Stahelski inszenierte JOHN WICK-Reihe in MONKEY MAN steckt, ist offensichtlich*. Bei JOHN WICK macht der Film selbst nicht mal einen Hehl daraus und kommentiert die Parallelen selbstironisch.

    Nur findet Dev Patel weitestgehend keine eigene Sprache, sondern durchmischt lediglich diese Versatzstücke. Vor MONKEY MAN hat Patel zwei Kurzfilme – beide keine Action – inszeniert. Von meinem Gefühl her hätte MONKEY MAN wunderbar als sein dritter Kurzfilm, in dem er sich auch in diesem Genre ausprobiert und eine eigene Handschrift entwickelt, funktioniert.

    Ebenfalls nicht unbedingt gut angefühlt hat sich die gewissermaßen paternalistische Haltung des Films und seiner Hauptfigur gegenüber der Hijra-Community. „Na gut, dann räche ich die eben auch noch mit“, ist die sinngemäße Entwicklung von Patels Protagonist. Dass die Hijras das jedoch auch aus eigener Kraft gekonnt hätten, zeigt der Film sogar. Aber der Schritt zur Selbstkritik oder der Kritik am eigenen Protagonisten wird nicht gegangen.

    *Dass auch diese Genrevertreter auf den Schultern anderer Giganten stehen, ist auch klar. Aber sie scheinen mir nicht nur zu kopieren.

    ★★½☆☆

    https://andrepitz.de/2024/08/07/gesehen-monkey-man-2024/

    #510 #AdithiKalkunte #AshwiniKalsekar #devPatel #Filme #Filmkritik #MakrandDeshpande #MonkeyMan #Pitobash #SharltoCopley #SikandarKher #SobhitaDhulipala #VipinSharma

  17. Which device file is associated with the that is opened after using the Alt-F6 key sequence?
    a) /dev/console6
    b) /dev/tty6
    c) /dev/vty6
    d) /dev/pts/6

  18. #linuxtip if you're trying to mount an external HD (with a nfts partition) and you get the error:

    "mount: wrong fs type, bad option, bad superblock on /dev/sdbX missing codepage or other error"

    just follow the next steps:
    1. verify you have installed the packages: nfs-utils and ntfs-3g
    2. run lsblk to locate the device
    3. run sudo ntfsfix -d <path of your device> example: sudo ntfsfix -d /dev/sdb2
    then just normally mount your device from your file manager.

    that's what worked for me 🤷‍♂️

    #linux #cli #ntfs

  19. How Linux Mint, NTFSFix, and ClamAV Saved Microsoft Publisher

    Recently, I was helping a Windows-using friend transition from her ten-year-old Windows 10 laptop to a new Windows 11 laptop. All of her important files had been backed up by Microsoft OneDrive, which was a great relief when we logged into the new computer. My friend is a Microsoft Publisher user, and you guessed it: Microsoft has announced the end of life for Publisher in October 2026. Since she’s an Office 365 user, she has until then to export all her Microsoft Publisher files as PDFs or lose the information.

    The ten-year-old laptop had become unusable, locked up mid-application with Windows errors, and refused to budge. It was an i3 with 4 gigabytes of RAM that started as a Windows 8 laptop and was upgraded to Windows 10 about five years ago. It had seen better days, but I suggested to my friend that I might be able to resurrect it so she could continue using it with the 2021 version of Microsoft Publisher, which will no longer receive updates. She said, “Sure, I’m happy to have you work your magic!”

    I took it home and did a live boot with Linux Mint MATE 22.2, but the Windows drive would not mount. It gave me an error message:

    $ wrong fs type, bad option, bad superblock on /dev/sda6
    

    I ran fsck on the drive and got more messages indicating that a bad block existed and needed to be repaired. How could I fix the error from within this live boot environment? That’s when I happened upon ntfsfix. The program was already loaded in the live boot environment. I used lsblk to determine the exact location of the NTFS disk in the disk system and issued the following command:

    $ sudo ntfsfix -b -d /dev/sda6

    There are several options for the command:

    ntfsfix v2022.10.3 (libntfs-3g)
    
    Usage: ntfsfix [options] device
        Attempt to fix an NTFS partition.
    
        -b, --clear-bad-sectors Clear the bad sector list
        -d, --clear-dirty       Clear the volume dirty flag
        -h, --help              Display this help
        -n, --no-action         Do not write anything
        -V, --version           Display version information
    
    

    In my case, I used the -b (clear-bad-sectors) and -d (clear-dirty). That command fixed the problem I had with the NTFS partition, and I was now able to download and install Clam Antivirus to clean up the suspected malware causing the issue.

    $ sudo apt install clamav

    Then I was ready to scan the disk for viruses and malware. I opened a terminal in the mounted Windows drive and entered the following command:

    $ sudo clamscan -irv --remove 

    Those clamscan options: – only prints files that are infected, r-scans directories recursively, and v- provides detailed output during the scan. The –remove option deletes any files that are found to be infected. Be careful with that last option.

    The laptop has an i3 CPU and 4 GB RAM, and the process for scanning a 400-gigabyte drive was lengthy. It took overnight to complete the scan, but when I started the laptop in the morning, I was able to log in without difficulty, and my friend is delighted at the prospect of extending the life of her access to Microsoft Publisher.

    In the end, what began as a seemingly hopeless situation with a locked-up Windows 10 laptop turned into a valuable lesson in resourcefulness. By combining the flexibility of a Linux live boot, the repair power of ntfsfix, and the thoroughness of ClamAV, I was able to breathe new life into aging hardware and preserve access to software that is nearing its end of support. For my friend, this means more time to safely transition her Publisher files, and for me, it’s a reminder that with the right tools and a bit of persistence, even a decade-old machine can still serve a meaningful purpose.

    #ClamAV #Linux #LinuxMintMate #OpenSource
  20. Shrink, optimise and expand an existing QCOW2 image

    A virtual disk image is a block device in a file. There are a number of different disk image formats to choose from when setting up a virtual machine. QEMU Copy On Write version 2 (QCOW2) is the default virtual disk image format for the Quick Emulator (QEMU). Features such as thin provisioning, snapshots and compression make QCOW2 one of the most versatile virtual disk formats available.

    These instructions specifically target Debian 12 with a GNOME desktop as the host, but they should also be applicable to other Linux distributions such as Ubuntu or Linux Mint. The guest in this particular example is a Windows 11 virtual machine that has run out of space.

    The overall objective is to shrink and optimise the 64 GiB disk image for random read and write operations before expanding it to a desired size of 128 GiB.

    With thanks to Fam Zheng.

    Before you begin

    Shut down the virtual machine and delete all existing snapshots from the image file.

    Never modify images currently in use by a running virtual machine.

    Step 1

    On the host, install the necessary tools for working with virtual disk images.

    $ sudo apt-get install --yes libguestfs-tools gnome-disk-utility

    Step 2

    Only root can access the host directory /var/lib/libvirt/images. Use the following command to obtain the necessary privileges.

    $ sudo su

    Step 3

    Continue by creating a directory in which to keep your virtual machine backups.

    # mkdir /var/lib/libvirt/backups

    Step 4

    Now create a backup of the virtual machine with the name windows by copying its QCOW2 image file to the backups directory.

    # cp /var/lib/libvirt/images/windows.qcow2 /var/lib/libvirt/backups/windows-backup.qcow2

    Step 5

    Sparsify the image file to convert any free space within the disk image to free space on the host.

    # virt-sparsify --in-place /var/lib/libvirt/images/windows.qcow2

    Step 6

    Rename the sparsified image file.

    # mv /var/lib/libvirt/images/windows.qcow2 /var/lib/libvirt/images/windows-sparsified.qcow2

    Step 7

    Check the disk size of the sparsified image file.

    # qemu-img info /var/lib/libvirt/images/windows-sparsified.qcow2

    The disk size should be smaller than the virtual size. In this particular case, the disk size is 33.7 GiB and the virtual size 64 GiB.

    image: /var/lib/libvirt/images/windows-sparsified.qcow2
    file format: qcow2
    virtual size: 64 GiB (68719476736 bytes)
    disk size: 33.7 GiB
    cluster_size: 65536
    Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
    extended l2: false

    Step 8

    Determine which partition to resize by obtaining more detailed information about the contents of the sparsified disk image.

    # virt-filesystems --long -h --all -a /var/lib/libvirt/images/windows-sparsified.qcow2

    On the virtual device /dev/sda, the partition /dev/sda3 is equivalent to the Local Disk (C:) of the Windows 11 virtual machine.

    Name       Type        VFS   Label  MBR  Size  Parent
    /dev/sda1 filesystem vfat - - 96M -
    /dev/sda3 filesystem ntfs - - 63G -
    /dev/sda4 filesystem ntfs - - 768M -
    /dev/sda1 partition - - - 100M /dev/sda
    /dev/sda2 partition - - - 16M /dev/sda
    /dev/sda3 partition - - - 63G /dev/sda
    /dev/sda4 partition - - - 768M /dev/sda
    /dev/sda device - - - 64G -

    Step 9

    Load the network block device (NBD) kernel module.

    # modprobe nbd max_part=8

    Step 10

    Connect the sparsified image.

    # qemu-nbd --connect=/dev/nbd9 /var/lib/libvirt/images/windows-sparsified.qcow2

    Step 11

    The partition /dev/sda3 listed in Step 8 is equivalent to /dev/nbd9p3 connected as a network block device. Use GNOME Disks to shrink /dev/nbd9p3 to its Minimal Size.

    Use a graphical utility to minimise the risk of introducing errors.

    Select the correct partition and from the pop-up menu, choose the option Resize…Select Minimal Size and resize the partition.

    Step 12

    Disconnect the resized image.

    # qemu-nbd -d /dev/nbd9

    Step 13

    Unload the NBD kernel module.

    # modprobe -r nbd

    Step 14

    Create a target image larger than the resized source image. In this example, the size of the target image is 128G and its format QCOW2 with full preallocation and a cluster size of 2M.

    # qemu-img create -f qcow2 -o preallocation=full -o cluster_size=2M /var/lib/libvirt/images/windows-target.qcow2 128G

    Step 15

    Copy the source image to the target image. Specify the correct partition which to expand in the process.

    # virt-resize --expand /dev/sda3 /var/lib/libvirt/images/windows-sparsified.qcow2 /var/lib/libvirt/images/windows-target.qcow2

    Step 16

    Confirm the size of the target image.

    # qemu-img info /var/lib/libvirt/images/windows-target.qcow2

    The overall disk size is now 128 GiB in total.

    image: /var/lib/libvirt/images/windows-target.qcow2
    file format: qcow2
    virtual size: 128 GiB (137438953472 bytes)
    disk size: 128 GiB
    cluster_size: 2097152
    Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false

    Step 17

    Obtain more detailed information about the contents of the target disk image.

    # virt-filesystems --long -h --all -a /var/lib/libvirt/images/windows-target.qcow2

    The partition /dev/sda3 of the virtual device /dev/sda is now 127G in size.

    Name       Type        VFS   Label  MBR  Size  Parent
    /dev/sda1 filesystem vfat - - 96M -
    /dev/sda3 filesystem ntfs - - 127G -
    /dev/sda4 filesystem ntfs - - 768M -
    /dev/sda1 partition - - - 100M /dev/sda
    /dev/sda2 partition - - - 16M /dev/sda
    /dev/sda3 partition - - - 127G /dev/sda
    /dev/sda4 partition - - - 768M /dev/sda
    /dev/sda device - - - 128G -

    Step 18

    Rename the target image file.

    # mv /var/lib/libvirt/images/windows-target.qcow2 /var/lib/libvirt/images/windows.qcow2

    All done!

    You can also modify format specific options for an existing image without having to create a target disk image. Or alternatively expand into a target image that uses a format compatible with other hypervisors, such as RAW, VMDK, VDI, VHD, VHDX or QED.

    #debian #howto #kvm #libvirt #linux #ntfs #qcow2 #qemu #ubuntu #virtualisation #windows

  21. The story so far…

    • In Part 1 I work out how to build Synth_Dexed using the Pico SDK and get some sounds coming out.
    • In Part 2 I take a detailed look at the performance with a diversion into the workings of the pico_audio library and floating point maths on the pico, on the way.

    This post describes how I’ve set things up for some further development and the decisions I’ve made to get to the point where it can receive MIDI and actually be somewhat playable within the limitations of 10 note polyphony, a 24000 sample rate, and a single voice only on MIDI channel 1!

    Update: By overclocking the Pico to 250MHz I can do 16 note polyphony at 24000 or 8 note polyphony at 48000!

    Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

    If you are new to microcontrollers, see the Getting Started pages.

    Optimised Dexed->getSamples

    I left things in part 2 noting that Dexed itself is essentially a fully integer-implemented synth engine, so why did I need the floating point calculations. I concluded it is all due to the filter that has been added, which is based on the LP filter code from https://obxd.wordpress.com/ which was added in Dexed, but wasn’t in the original “music synthesizer for Android“.

    So I’ve decided not to bother with it. If I feel like it is really missing out, then I have stumbled across the following which looks promising: https://beammyselfintothefuture.wordpress.com/2015/02/16/simple-c-code-for-resonant-lpf-hpf-filters-and-high-low-shelving-eqs/

    So, here is my integer-only version of Dexed->getSamples.

    void Dexed::getSamples(int16_t* buffer, uint16_t n_samples)
    {
    if (refreshVoice)
    {
    for (uint8_t i = 0; i < max_notes; i++)
    {
    if ( voices[i].live )
    voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity, voices[i].porta, &controllers);
    }
    lfo.reset(data + 137);
    refreshVoice = false;
    }

    for (uint16_t i = 0; i < n_samples; ++i)
    {
    buffer[i] = 0;
    }

    for (uint16_t i = 0; i < n_samples; i += _N_)
    {
    AlignedBuf<int32_t, _N_> audiobuf;

    for (uint8_t j = 0; j < _N_; ++j)
    {
    audiobuf.get()[j] = 0;
    }

    int32_t lfovalue = lfo.getsample();
    int32_t lfodelay = lfo.getdelay();

    for (uint8_t note = 0; note < max_notes; note++)
    {
    if (voices[note].live)
    {
    voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers);

    for (uint8_t j = 0; j < _N_; ++j)
    {
    int16_t tmp = audiobuf.get()[j] >> 16;
    buffer[i + j] += tmp;
    audiobuf.get()[j] = 0;
    }
    }
    }
    }
    }

    With this in place, I appear to be able to comfortably cope with 8-note polyphony. At least with my test chords.

    Debug Output

    Now before I go too far, I want a simple way to get some output out of the device. The Pico Getting Started documentation gives an example of how to get some standard output (stdio) working. There are two options for this output (see chapter 4 “Saying “Hello World” in C”):

    • Using the built-in USB serial port.
    • Outputting to the UART serial port.

    To use USB requires building in TinyUSB, but I’m planning on using that later. It also adds quite a lot of overhead apparently, so the default is to output to the serial port via GP0 (TX) and GP1 (RX). All that is required is to find a way to connect this up to a computer or terminal device.

    There are several options: some kind of 3V3 supporting USB<->Serial converter – there are several, based on the CH240 of FTDI devices for example, although not many of the cheap ones are 3V3 compatible (don’t use a 5V board it could damage the Pico!); or using a native Raspberry Pi development environment, then simply using GPIO directly to connect the Pico to the Pi’s UART.

    It is also possible to use the picoprobe firmware running on another Pico I believe, but I haven’t tried that. It wasn’t totally clear to me if that supports the USB to serial link, although it is strongly implied. The official Raspberry Pi Debug Probe definitely does however, but I haven’t got one of those at the moment.

    I initially opted to use another Pico as a serial to USB gateway by running Circuitpython and the following script on boot by saving it as code.py:

    import board
    import busio
    import digitalio

    uart = busio.UART(tx=board.GP0, rx=board.GP1, baudrate=115200, timeout=0.1)

    while True:
    readbytes = uart.read()
    if readbytes != None:
    print (''.join([chr(b) for b in readbytes]))

    Now this just needs connected to the Pico running PicoDexed as follows:

    PicoDexed        Debug Pico
       GP0    <---->    GP1
       GND    <---->    GND

    As this is running Circuitpython it means I also get the CIRCUITPY virtual drive appear and mounted too which isn’t ideal but not really a big issue.

    Then I had a rummage in my Pico drawer looking for a neater solution and found a Waveshare RP2040-One that I’d forgotten I had! This is perfect as it has a USB plug at one end (via a shaped PCB) and GPIO at the other, including pins connected to UART 0.

    I dropped Micropython onto the board this time, with the following script.

    import time
    from machine import UART, Pin

    # Use one of the GPIO as a GND pin for the serial
    gndpin = Pin(11, Pin.OUT)
    gndpin.value(0)

    print ("Initialising UART 0 on pins gnd=11, tx=12, rx=13...")
    uart = UART(0, baudrate=115200, tx=Pin(12), rx=Pin(13))
    print ("Ready")

    while True:
    # Read raw data version
    rxdata = bytes()
    while uart.any() > 0:
    rxdata += uart.read(1)
    time.sleep_ms(10)

    if rxdata:
    print(rxdata.decode('utf-8'))

    To keep the connections simple, I used GPIO 11 as an additional GND pin as there is only one on the board and it isn’t so convenient.

    PicoDexed        RP2040-One
       GP0    <---->    GP13
       GND    <---->    GP11

    To ensure the code can output text just needs something like the following:

    #include <stdio.h>

    void main () {
      stdio_init_all();
      printf("PicoDexed...");
    }

    Then with both devices connected to my virtual Ubuntu Linux machine, I can run minicom (once installed – it isn’t installed by default):

    $ sudo minicom -b 115200 -D /dev/ttyACM0

    Here is the output.

    Welcome to minicom 2.8

    OPTIONS: I18n
    Port /dev/ttyACM0, 13:27:28
    Press CTRL-A Z for help on special keys

    PicoDexed...

    Connecting PIO I2S audio
    Copying mono to mono at 24000 Hz

    Note, to exit minicom use CTRL-A then X.

    Alternatively I could use PuTTY on Windows on the COM port associated with the “debugging” Pico.

    At some point I’ll probably need to set up proper SWD debugging, but this should do for the time being.

    I might also need to switch UARTs if I want to use UART 0 for MIDI, but apparently there are some defines that can be changed in the CMakeLists.txt file:

    target_compile_definitions(picodexed PRIVATE
    PICO_DEFAULT_UART=0
    PICO_DEFAULT_UART_TX_PIN=0
    PICO_DEFAULT_UART_RX_PIN=1
    )

    PicoDexed design

    It is time to start thinking seriously if I can turn this into something interesting or not, so borrowing from some of the design principles encapsulated in MiniDexed, I’ve now got a project that looks as follows:

    • main.cpp -> Basic IO, initialisation and main update loop.
    • picodexed.cpp -> The core synthesizer wrapper with the following key interface:
      • CPicoDexed::Init -> perform all the required synthesizer initialisation.
      • CPicoDexed::Process -> perform a single “tick” of the synthesizer functions, including updating the sample buffers from Dexed.
    • mididevice.cpp, serialmidi.cpp, usbmidi.cpp -> placeholder classes that will eventually support MIDI message passing and a serial and USB MIDI interface. This borrows heavily from the way it is done in MiniDexed. These classes will support the following interface:
      • CSerialMIDI::Init -> Initialise the hardware (same for USB).
      • CSerialMIDI::Process -> poll the hardware (same for USB).
      • CMIDIDevice::MIDIMessageHandler -> will be called by the lower-level devices when a MIDI message is ready to be processed. Once parsed, it will trigger calls into the PicoDexed main synthesizer to update its state.
    • soundevice.cpp -> Encapsulating the interface to the pico_audio library to use I2S audio, with the following key interface:
      • CSoundDevice::Init -> Set the sample rate and I2S interface pins.
      • CSoundDevice::Update -> Fill the sample buffer using the provided callback, which will be a call to the Dexed->getSamples code above.
    • config.h -> contains some system-wide configuration items, such as sample rate and polyphony.

    PicoDexed will include the functions required to control the synthesizer. Examples include keydown and keyup functions for when MIDI NoteOn and NoteOff messages, and so on. It also includes a means to set the MIDI channel and to load a voice.

    I don’t know yet if the MIDI handling will be interrupt driven or polled. I need to read up on how the Pico SDK handles USB and serial data, but I suspect a polled interface should be fine for my purposes as long as it doesn’t hold up the sample calculations, buffer filling, and sample playing.

    With my first pass of this code, there is no external interface – it is still playing a test chord only. But at least most of the structure is now in place to hook it up to MIDI.

    The “to do” list so far:

    • Ideally find a way to better manage the Synth_Dexed changes. I should submit a PR to Holger, the creator of Synth_Dexed and discuss some conditional compilation steps.
    • Hook up USB MIDI so that the Pico can act as a MIDI device and play the synth that way.
    • Hook up serial MIDI too.
    • Implement volume. Without the filter there is currently no volume changing.
    • Implement some basic voice and bank loading.
    • Connect up some more core MIDI functionality for program change, BANKSEL, channel volume, master volume, and so on.
    • Think about how best to utilise the second core – in theory it should be possible to expand it to 16-note polyphony by using both cores. Or an alternative might be two instances of Synth_Dexed running, so making a second tone generator.

    MIDI/Serial Handling

    Rather than jump into USB, I’ve opted to get serial MIDI working first. The serial port handling I’ve implemented in serialmidi.cpp borrows heavily from the “advanced” UART example: https://github.com/raspberrypi/pico-examples/tree/master/uart/uart_advanced

    It is interrupt driven and shares a simple circular buffer with the main Read function based on the implementation described here: https://embedjournal.com/implementing-circular-buffer-embedded-c/.

    The basic design of the serial MIDI interface is as follows:

    Interrupt Handler:
      Empty the serial hardware of data writing it to the circular buffer

    Init function:
      Initialise the UART as per the uart_advanced example
      Install the interrupt handler and enable interrupts

    Process function:
      Call the MIDI device data parser to piece together any MIDI messages
      Call the MIDI device msg handler to handle any complete MIDI messages

    Read function:
      Read the next byte out of the circular buffer

    There is a common MIDI device that the serial MIDI device inherits from (and that I plan to also use with USB MIDI support when I get that far). This has the following essential functionality:

    MIDIParser:
      Read a byte from the transport interface (e.g. the serial MIDI Read)
      IF starting a new message THEN
        Initialise MIDI msg structures
        IF a single byte message THEN
          Fill in MIDI msg structures for single-byte message
          return TRUE
        IF there is a valid Running Status byte stored THEN
          IF this now completes a valid two-byte msg THEN
            Fill in MIDI msg structures for a two-byte message
            return TRUE
      Otherwise process as a two or three byte message
      IF message now complete THEN
        Fill in MIDI msg structures
        return TRUE
      return FALSE

    MIDI Message Parser:
      IF MIDI msg already processed THEN return
      IF on correct channel or OMNI THEN
        Based on received MIDI command:
          Extract parameters
          Call appropriate picoDexed function
      Mark MIDI msg as processed.

    I had a fun bug where in the serial handling, I was writing to a byte one-out in the circular buffer which meant that the MIDI handling largely worked, but only when using a controller with ActiveSensing – basically the reception of the extra byte “pushed through” the previous message. But it was a bit unresponsive, and occasionally a note of a chord would sound after the others.

    I spent the better part of a day instrumenting the code, attempting to work out where the delays might be coming from. Eventually I got so fed up with the active sensing reception clouding my analysis (and triggering my scope when I didn’t want it to) that I filtered it out in the serial interrupt routine – so as early as I could.

    This the made the delay a whole pile worse! That was the point I realised it was continually essentially one message behind. As a consequence I had another look at the buffer handling and that was when I realised the mistake.

    Multicore support

    My initial thought on the above problem was that it was a performance issue – that the MIDI handling wasn’t responsive enough. So I pushed ahead and moved all the synthesis code over to the second core. This is something I wanted to do anyway as I always had the plan of splitting the functionality across the two cores.

    To enable multicore support requires including pico_multicore in the list of libaries in the CMakeLists.txt file and then it should largely be a case of doing the following:

    #include "pico/multicore.h"

    void core1_entry (void)
    {
      // stuff to do to initialise core 1

      while (1)
      {
        // Stuff to do repeatedly on core 1
      }
    }

    // Rest of "normal" (core 0) initialisation code
    multicore_launch_core1 (core1_entry);

    The question is where to enable this. Eventually I settled on implementing this in picoDexed itself to split out the ProcessSound function over to the second core. This required the following:

    • PicoDexed::Init – initialise multi-core support and start the second core running.
    • PicoDexed::Process – no longer calls ProcessSound.
    • PicoDexed::core1_entry – now calls ProcessSound in an infinite loop.

    In order to ensure that I don’t get Dexed into an inconsistent state, I’ve protected the calls into Dexed from the Dexed_Adaptor with spinlocks (mirroring what was happing in MiniDexed) as shown in the following extract:

    class CDexedAdapter : public Dexed
    {
    public:
    CDexedAdapter (uint8_t maxnotes, int rate)
    : Dexed (maxnotes, rate)
    {
    spinlock_num = spin_lock_claim_unused(true);
    spinlock = spin_lock_init(spinlock_num);
    }

    void getSamples (int16_t* buffer, uint16_t n_samples)
    {
    spin_lock_unsafe_blocking(spinlock);
    Dexed::getSamples (buffer, n_samples);
    spin_unlock_unsafe(spinlock);
    }

    private:
    int spinlock_num;
    spin_lock_t *spinlock;
    }

    Spinlocks are described in chapter 4.1.19 of the RPi C/C++ SDK and are part of the hardware_sync library.

    In order to ensure that the spin_locks are not held too long, and to allow things like keyup/down events to be registered in a timely manner and not hold up core 0 whilst core 1 is calculating samples, I’ve now reduced the sample buffer to 64 bytes.

    As core 1 is essentially free-running calculating samples now, I figured it wouldn’t make much difference how many samples are calculated in each “chunk” but going to 64 from 256 gives four times the number of break points in the cycle where other events can be processed between the spin_locks.

    Once consequence of running multi-core seems to be that I can now push the polyphony up to 10 simultaneous notes without any artefacts.

    If I can find a way to keep some of the sound generation on core 0 too, I might be able to increase that even further, although getting 6 additional sound engines running to get up to the magic 16 note polyphony might be stretching things still. The trick will be finding a way to trigger and mix samples from the sound generators in the two cores, as all of that current happens within Dexed itself.

    Overclocking the Pico

    There have been a number of experiments already in seeing how far a Pico can be pushed. There is a standard API call to set the system clock: set_sys_clock_khz(), although not all values can be accurately configured. But general wisdom seems to be that running the Pico at 250MHz isn’t a big deal…

    Of course, at this point it is running outside of the “normal” spec, so the long term effects may well reduce the life of the Pico…

    But by doing this, the Pico is now running twice as fast and so can now easily cope with 16 note polyphony at a sample rate of 24000, or up the sample rate to 48000 and stick with 8 note polyphony.

    It might even raise the possibility of running two tone generators, one on each core! It really does open up a wide range of possibilities!

    Closing Thoughts

    I’m really pleased with the progress so far. I was starting to think there wouldn’t be a usable combination possible, but 10-note polyphony at a sample rate of 24000 isn’t too bad for a 133MHz CPU with no FPU.

    I think my basic design goal would be for something usable with a MIDI controller. I’m not looking to implement a UI like there is with MiniDexed as part of this build. But I do need a bit more MIDI functionality first and I would like to find a way to squeeze some sample calculations out of core 0 when it isn’t handling MIDI.

    I also want to get USB MIDI up and running too. I’m not sure if I want to push for both device and host USB support though. I’ll see how complicated it all is!

    In the video, I’ve used my Raspberry Pi Pico MIDI Proto Expander. It just needs the addition of the Pimoroni audio board and it is ready to go!

    Of course the key question is: would I recommend this to anyone? Answer: no! No way – get yourself a Raspberry Pi Zero V2 and run a full-blown set of 8 DX7s using MiniDexed 🙂

    Still for me, this is a bit of fun a really good excuse to do something that’s been on my “to do” list for ages – start getting to grips with the Raspberry Pi Pico C/C++ SDK and the RP2040.

    Kevin

    https://diyelectromusic.wordpress.com/2024/02/04/raspberry-pi-pico-synth_dexed-part-3/

    #dx7 #midi #picodexed #raspberryPiPico

  22. The story so far…

    • In Part 1 I work out how to build Synth_Dexed using the Pico SDK and get some sounds coming out.
    • In Part 2 I take a detailed look at the performance with a diversion into the workings of the pico_audio library and floating point maths on the pico, on the way.

    This post describes how I’ve set things up for some further development and the decisions I’ve made to get to the point where it can receive MIDI and actually be somewhat playable within the limitations of 10 note polyphony, a 24000 sample rate, and a single voice only on MIDI channel 1!

    Update: By overclocking the Pico to 250MHz I can do 16 note polyphony at 24000 or 8 note polyphony at 48000!

    Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

    If you are new to microcontrollers, see the Getting Started pages.

    Optimised Dexed->getSamples

    I left things in part 2 noting that Dexed itself is essentially a fully integer-implemented synth engine, so why did I need the floating point calculations. I concluded it is all due to the filter that has been added, which is based on the LP filter code from https://obxd.wordpress.com/ which was added in Dexed, but wasn’t in the original “music synthesizer for Android“.

    So I’ve decided not to bother with it. If I feel like it is really missing out, then I have stumbled across the following which looks promising: https://beammyselfintothefuture.wordpress.com/2015/02/16/simple-c-code-for-resonant-lpf-hpf-filters-and-high-low-shelving-eqs/

    So, here is my integer-only version of Dexed->getSamples.

    void Dexed::getSamples(int16_t* buffer, uint16_t n_samples)
    {
    if (refreshVoice)
    {
    for (uint8_t i = 0; i < max_notes; i++)
    {
    if ( voices[i].live )
    voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity, voices[i].porta, &controllers);
    }
    lfo.reset(data + 137);
    refreshVoice = false;
    }

    for (uint16_t i = 0; i < n_samples; ++i)
    {
    buffer[i] = 0;
    }

    for (uint16_t i = 0; i < n_samples; i += _N_)
    {
    AlignedBuf<int32_t, _N_> audiobuf;

    for (uint8_t j = 0; j < _N_; ++j)
    {
    audiobuf.get()[j] = 0;
    }

    int32_t lfovalue = lfo.getsample();
    int32_t lfodelay = lfo.getdelay();

    for (uint8_t note = 0; note < max_notes; note++)
    {
    if (voices[note].live)
    {
    voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers);

    for (uint8_t j = 0; j < _N_; ++j)
    {
    int16_t tmp = audiobuf.get()[j] >> 16;
    buffer[i + j] += tmp;
    audiobuf.get()[j] = 0;
    }
    }
    }
    }
    }

    With this in place, I appear to be able to comfortably cope with 8-note polyphony. At least with my test chords.

    Debug Output

    Now before I go too far, I want a simple way to get some output out of the device. The Pico Getting Started documentation gives an example of how to get some standard output (stdio) working. There are two options for this output (see chapter 4 “Saying “Hello World” in C”):

    • Using the built-in USB serial port.
    • Outputting to the UART serial port.

    To use USB requires building in TinyUSB, but I’m planning on using that later. It also adds quite a lot of overhead apparently, so the default is to output to the serial port via GP0 (TX) and GP1 (RX). All that is required is to find a way to connect this up to a computer or terminal device.

    There are several options: some kind of 3V3 supporting USB<->Serial converter – there are several, based on the CH240 of FTDI devices for example, although not many of the cheap ones are 3V3 compatible (don’t use a 5V board it could damage the Pico!); or using a native Raspberry Pi development environment, then simply using GPIO directly to connect the Pico to the Pi’s UART.

    It is also possible to use the picoprobe firmware running on another Pico I believe, but I haven’t tried that. It wasn’t totally clear to me if that supports the USB to serial link, although it is strongly implied. The official Raspberry Pi Debug Probe definitely does however, but I haven’t got one of those at the moment.

    I initially opted to use another Pico as a serial to USB gateway by running Circuitpython and the following script on boot by saving it as code.py:

    import board
    import busio
    import digitalio

    uart = busio.UART(tx=board.GP0, rx=board.GP1, baudrate=115200, timeout=0.1)

    while True:
    readbytes = uart.read()
    if readbytes != None:
    print (''.join([chr(b) for b in readbytes]))

    Now this just needs connected to the Pico running PicoDexed as follows:

    PicoDexed        Debug Pico
       GP0    <---->    GP1
       GND    <---->    GND

    As this is running Circuitpython it means I also get the CIRCUITPY virtual drive appear and mounted too which isn’t ideal but not really a big issue.

    Then I had a rummage in my Pico drawer looking for a neater solution and found a Waveshare RP2040-One that I’d forgotten I had! This is perfect as it has a USB plug at one end (via a shaped PCB) and GPIO at the other, including pins connected to UART 0.

    I dropped Micropython onto the board this time, with the following script.

    import time
    from machine import UART, Pin

    # Use one of the GPIO as a GND pin for the serial
    gndpin = Pin(11, Pin.OUT)
    gndpin.value(0)

    print ("Initialising UART 0 on pins gnd=11, tx=12, rx=13...")
    uart = UART(0, baudrate=115200, tx=Pin(12), rx=Pin(13))
    print ("Ready")

    while True:
    # Read raw data version
    rxdata = bytes()
    while uart.any() > 0:
    rxdata += uart.read(1)
    time.sleep_ms(10)

    if rxdata:
    print(rxdata.decode('utf-8'))

    To keep the connections simple, I used GPIO 11 as an additional GND pin as there is only one on the board and it isn’t so convenient.

    PicoDexed        RP2040-One
       GP0    <---->    GP13
       GND    <---->    GP11

    To ensure the code can output text just needs something like the following:

    #include <stdio.h>

    void main () {
      stdio_init_all();
      printf("PicoDexed...");
    }

    Then with both devices connected to my virtual Ubuntu Linux machine, I can run minicom (once installed – it isn’t installed by default):

    $ sudo minicom -b 115200 -D /dev/ttyACM0

    Here is the output.

    Welcome to minicom 2.8

    OPTIONS: I18n
    Port /dev/ttyACM0, 13:27:28
    Press CTRL-A Z for help on special keys

    PicoDexed...

    Connecting PIO I2S audio
    Copying mono to mono at 24000 Hz

    Note, to exit minicom use CTRL-A then X.

    Alternatively I could use PuTTY on Windows on the COM port associated with the “debugging” Pico.

    At some point I’ll probably need to set up proper SWD debugging, but this should do for the time being.

    I might also need to switch UARTs if I want to use UART 0 for MIDI, but apparently there are some defines that can be changed in the CMakeLists.txt file:

    target_compile_definitions(picodexed PRIVATE
    PICO_DEFAULT_UART=0
    PICO_DEFAULT_UART_TX_PIN=0
    PICO_DEFAULT_UART_RX_PIN=1
    )

    PicoDexed design

    It is time to start thinking seriously if I can turn this into something interesting or not, so borrowing from some of the design principles encapsulated in MiniDexed, I’ve now got a project that looks as follows:

    • main.cpp -> Basic IO, initialisation and main update loop.
    • picodexed.cpp -> The core synthesizer wrapper with the following key interface:
      • CPicoDexed::Init -> perform all the required synthesizer initialisation.
      • CPicoDexed::Process -> perform a single “tick” of the synthesizer functions, including updating the sample buffers from Dexed.
    • mididevice.cpp, serialmidi.cpp, usbmidi.cpp -> placeholder classes that will eventually support MIDI message passing and a serial and USB MIDI interface. This borrows heavily from the way it is done in MiniDexed. These classes will support the following interface:
      • CSerialMIDI::Init -> Initialise the hardware (same for USB).
      • CSerialMIDI::Process -> poll the hardware (same for USB).
      • CMIDIDevice::MIDIMessageHandler -> will be called by the lower-level devices when a MIDI message is ready to be processed. Once parsed, it will trigger calls into the PicoDexed main synthesizer to update its state.
    • soundevice.cpp -> Encapsulating the interface to the pico_audio library to use I2S audio, with the following key interface:
      • CSoundDevice::Init -> Set the sample rate and I2S interface pins.
      • CSoundDevice::Update -> Fill the sample buffer using the provided callback, which will be a call to the Dexed->getSamples code above.
    • config.h -> contains some system-wide configuration items, such as sample rate and polyphony.

    PicoDexed will include the functions required to control the synthesizer. Examples include keydown and keyup functions for when MIDI NoteOn and NoteOff messages, and so on. It also includes a means to set the MIDI channel and to load a voice.

    I don’t know yet if the MIDI handling will be interrupt driven or polled. I need to read up on how the Pico SDK handles USB and serial data, but I suspect a polled interface should be fine for my purposes as long as it doesn’t hold up the sample calculations, buffer filling, and sample playing.

    With my first pass of this code, there is no external interface – it is still playing a test chord only. But at least most of the structure is now in place to hook it up to MIDI.

    The “to do” list so far:

    • Ideally find a way to better manage the Synth_Dexed changes. I should submit a PR to Holger, the creator of Synth_Dexed and discuss some conditional compilation steps.
    • Hook up USB MIDI so that the Pico can act as a MIDI device and play the synth that way.
    • Hook up serial MIDI too.
    • Implement volume. Without the filter there is currently no volume changing.
    • Implement some basic voice and bank loading.
    • Connect up some more core MIDI functionality for program change, BANKSEL, channel volume, master volume, and so on.
    • Think about how best to utilise the second core – in theory it should be possible to expand it to 16-note polyphony by using both cores. Or an alternative might be two instances of Synth_Dexed running, so making a second tone generator.

    MIDI/Serial Handling

    Rather than jump into USB, I’ve opted to get serial MIDI working first. The serial port handling I’ve implemented in serialmidi.cpp borrows heavily from the “advanced” UART example: https://github.com/raspberrypi/pico-examples/tree/master/uart/uart_advanced

    It is interrupt driven and shares a simple circular buffer with the main Read function based on the implementation described here: https://embedjournal.com/implementing-circular-buffer-embedded-c/.

    The basic design of the serial MIDI interface is as follows:

    Interrupt Handler:
      Empty the serial hardware of data writing it to the circular buffer

    Init function:
      Initialise the UART as per the uart_advanced example
      Install the interrupt handler and enable interrupts

    Process function:
      Call the MIDI device data parser to piece together any MIDI messages
      Call the MIDI device msg handler to handle any complete MIDI messages

    Read function:
      Read the next byte out of the circular buffer

    There is a common MIDI device that the serial MIDI device inherits from (and that I plan to also use with USB MIDI support when I get that far). This has the following essential functionality:

    MIDIParser:
      Read a byte from the transport interface (e.g. the serial MIDI Read)
      IF starting a new message THEN
        Initialise MIDI msg structures
        IF a single byte message THEN
          Fill in MIDI msg structures for single-byte message
          return TRUE
        IF there is a valid Running Status byte stored THEN
          IF this now completes a valid two-byte msg THEN
            Fill in MIDI msg structures for a two-byte message
            return TRUE
      Otherwise process as a two or three byte message
      IF message now complete THEN
        Fill in MIDI msg structures
        return TRUE
      return FALSE

    MIDI Message Parser:
      IF MIDI msg already processed THEN return
      IF on correct channel or OMNI THEN
        Based on received MIDI command:
          Extract parameters
          Call appropriate picoDexed function
      Mark MIDI msg as processed.

    I had a fun bug where in the serial handling, I was writing to a byte one-out in the circular buffer which meant that the MIDI handling largely worked, but only when using a controller with ActiveSensing – basically the reception of the extra byte “pushed through” the previous message. But it was a bit unresponsive, and occasionally a note of a chord would sound after the others.

    I spent the better part of a day instrumenting the code, attempting to work out where the delays might be coming from. Eventually I got so fed up with the active sensing reception clouding my analysis (and triggering my scope when I didn’t want it to) that I filtered it out in the serial interrupt routine – so as early as I could.

    This the made the delay a whole pile worse! That was the point I realised it was continually essentially one message behind. As a consequence I had another look at the buffer handling and that was when I realised the mistake.

    Multicore support

    My initial thought on the above problem was that it was a performance issue – that the MIDI handling wasn’t responsive enough. So I pushed ahead and moved all the synthesis code over to the second core. This is something I wanted to do anyway as I always had the plan of splitting the functionality across the two cores.

    To enable multicore support requires including pico_multicore in the list of libaries in the CMakeLists.txt file and then it should largely be a case of doing the following:

    #include "pico/multicore.h"

    void core1_entry (void)
    {
      // stuff to do to initialise core 1

      while (1)
      {
        // Stuff to do repeatedly on core 1
      }
    }

    // Rest of "normal" (core 0) initialisation code
    multicore_launch_core1 (core1_entry);

    The question is where to enable this. Eventually I settled on implementing this in picoDexed itself to split out the ProcessSound function over to the second core. This required the following:

    • PicoDexed::Init – initialise multi-core support and start the second core running.
    • PicoDexed::Process – no longer calls ProcessSound.
    • PicoDexed::core1_entry – now calls ProcessSound in an infinite loop.

    In order to ensure that I don’t get Dexed into an inconsistent state, I’ve protected the calls into Dexed from the Dexed_Adaptor with spinlocks (mirroring what was happing in MiniDexed) as shown in the following extract:

    class CDexedAdapter : public Dexed
    {
    public:
    CDexedAdapter (uint8_t maxnotes, int rate)
    : Dexed (maxnotes, rate)
    {
    spinlock_num = spin_lock_claim_unused(true);
    spinlock = spin_lock_init(spinlock_num);
    }

    void getSamples (int16_t* buffer, uint16_t n_samples)
    {
    spin_lock_unsafe_blocking(spinlock);
    Dexed::getSamples (buffer, n_samples);
    spin_unlock_unsafe(spinlock);
    }

    private:
    int spinlock_num;
    spin_lock_t *spinlock;
    }

    Spinlocks are described in chapter 4.1.19 of the RPi C/C++ SDK and are part of the hardware_sync library.

    In order to ensure that the spin_locks are not held too long, and to allow things like keyup/down events to be registered in a timely manner and not hold up core 0 whilst core 1 is calculating samples, I’ve now reduced the sample buffer to 64 bytes.

    As core 1 is essentially free-running calculating samples now, I figured it wouldn’t make much difference how many samples are calculated in each “chunk” but going to 64 from 256 gives four times the number of break points in the cycle where other events can be processed between the spin_locks.

    Once consequence of running multi-core seems to be that I can now push the polyphony up to 10 simultaneous notes without any artefacts.

    If I can find a way to keep some of the sound generation on core 0 too, I might be able to increase that even further, although getting 6 additional sound engines running to get up to the magic 16 note polyphony might be stretching things still. The trick will be finding a way to trigger and mix samples from the sound generators in the two cores, as all of that current happens within Dexed itself.

    Overclocking the Pico

    There have been a number of experiments already in seeing how far a Pico can be pushed. There is a standard API call to set the system clock: set_sys_clock_khz(), although not all values can be accurately configured. But general wisdom seems to be that running the Pico at 250MHz isn’t a big deal…

    Of course, at this point it is running outside of the “normal” spec, so the long term effects may well reduce the life of the Pico…

    But by doing this, the Pico is now running twice as fast and so can now easily cope with 16 note polyphony at a sample rate of 24000, or up the sample rate to 48000 and stick with 8 note polyphony.

    It might even raise the possibility of running two tone generators, one on each core! It really does open up a wide range of possibilities!

    Closing Thoughts

    I’m really pleased with the progress so far. I was starting to think there wouldn’t be a usable combination possible, but 10-note polyphony at a sample rate of 24000 isn’t too bad for a 133MHz CPU with no FPU.

    I think my basic design goal would be for something usable with a MIDI controller. I’m not looking to implement a UI like there is with MiniDexed as part of this build. But I do need a bit more MIDI functionality first and I would like to find a way to squeeze some sample calculations out of core 0 when it isn’t handling MIDI.

    I also want to get USB MIDI up and running too. I’m not sure if I want to push for both device and host USB support though. I’ll see how complicated it all is!

    In the video, I’ve used my Raspberry Pi Pico MIDI Proto Expander. It just needs the addition of the Pimoroni audio board and it is ready to go!

    Of course the key question is: would I recommend this to anyone? Answer: no! No way – get yourself a Raspberry Pi Zero V2 and run a full-blown set of 8 DX7s using MiniDexed 🙂

    Still for me, this is a bit of fun a really good excuse to do something that’s been on my “to do” list for ages – start getting to grips with the Raspberry Pi Pico C/C++ SDK and the RP2040.

    Kevin

    https://diyelectromusic.wordpress.com/2024/02/04/raspberry-pi-pico-synth_dexed-part-3/

    #dx7 #midi #picodexed #raspberryPiPico

  23. The story so far…

    • In Part 1 I work out how to build Synth_Dexed using the Pico SDK and get some sounds coming out.
    • In Part 2 I take a detailed look at the performance with a diversion into the workings of the pico_audio library and floating point maths on the pico, on the way.

    This post describes how I’ve set things up for some further development and the decisions I’ve made to get to the point where it can receive MIDI and actually be somewhat playable within the limitations of 10 note polyphony, a 24000 sample rate, and a single voice only on MIDI channel 1!

    Update: By overclocking the Pico to 250MHz I can do 16 note polyphony at 24000 or 8 note polyphony at 48000!

    Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

    If you are new to microcontrollers, see the Getting Started pages.

    Optimised Dexed->getSamples

    I left things in part 2 noting that Dexed itself is essentially a fully integer-implemented synth engine, so why did I need the floating point calculations. I concluded it is all due to the filter that has been added, which is based on the LP filter code from https://obxd.wordpress.com/ which was added in Dexed, but wasn’t in the original “music synthesizer for Android“.

    So I’ve decided not to bother with it. If I feel like it is really missing out, then I have stumbled across the following which looks promising: https://beammyselfintothefuture.wordpress.com/2015/02/16/simple-c-code-for-resonant-lpf-hpf-filters-and-high-low-shelving-eqs/

    So, here is my integer-only version of Dexed->getSamples.

    void Dexed::getSamples(int16_t* buffer, uint16_t n_samples)
    {
    if (refreshVoice)
    {
    for (uint8_t i = 0; i < max_notes; i++)
    {
    if ( voices[i].live )
    voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity, voices[i].porta, &controllers);
    }
    lfo.reset(data + 137);
    refreshVoice = false;
    }

    for (uint16_t i = 0; i < n_samples; ++i)
    {
    buffer[i] = 0;
    }

    for (uint16_t i = 0; i < n_samples; i += _N_)
    {
    AlignedBuf<int32_t, _N_> audiobuf;

    for (uint8_t j = 0; j < _N_; ++j)
    {
    audiobuf.get()[j] = 0;
    }

    int32_t lfovalue = lfo.getsample();
    int32_t lfodelay = lfo.getdelay();

    for (uint8_t note = 0; note < max_notes; note++)
    {
    if (voices[note].live)
    {
    voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers);

    for (uint8_t j = 0; j < _N_; ++j)
    {
    int16_t tmp = audiobuf.get()[j] >> 16;
    buffer[i + j] += tmp;
    audiobuf.get()[j] = 0;
    }
    }
    }
    }
    }

    With this in place, I appear to be able to comfortably cope with 8-note polyphony. At least with my test chords.

    Debug Output

    Now before I go too far, I want a simple way to get some output out of the device. The Pico Getting Started documentation gives an example of how to get some standard output (stdio) working. There are two options for this output (see chapter 4 “Saying “Hello World” in C”):

    • Using the built-in USB serial port.
    • Outputting to the UART serial port.

    To use USB requires building in TinyUSB, but I’m planning on using that later. It also adds quite a lot of overhead apparently, so the default is to output to the serial port via GP0 (TX) and GP1 (RX). All that is required is to find a way to connect this up to a computer or terminal device.

    There are several options: some kind of 3V3 supporting USB<->Serial converter – there are several, based on the CH240 of FTDI devices for example, although not many of the cheap ones are 3V3 compatible (don’t use a 5V board it could damage the Pico!); or using a native Raspberry Pi development environment, then simply using GPIO directly to connect the Pico to the Pi’s UART.

    It is also possible to use the picoprobe firmware running on another Pico I believe, but I haven’t tried that. It wasn’t totally clear to me if that supports the USB to serial link, although it is strongly implied. The official Raspberry Pi Debug Probe definitely does however, but I haven’t got one of those at the moment.

    I initially opted to use another Pico as a serial to USB gateway by running Circuitpython and the following script on boot by saving it as code.py:

    import board
    import busio
    import digitalio

    uart = busio.UART(tx=board.GP0, rx=board.GP1, baudrate=115200, timeout=0.1)

    while True:
    readbytes = uart.read()
    if readbytes != None:
    print (''.join([chr(b) for b in readbytes]))

    Now this just needs connected to the Pico running PicoDexed as follows:

    PicoDexed        Debug Pico
       GP0    <---->    GP1
       GND    <---->    GND

    As this is running Circuitpython it means I also get the CIRCUITPY virtual drive appear and mounted too which isn’t ideal but not really a big issue.

    Then I had a rummage in my Pico drawer looking for a neater solution and found a Waveshare RP2040-One that I’d forgotten I had! This is perfect as it has a USB plug at one end (via a shaped PCB) and GPIO at the other, including pins connected to UART 0.

    I dropped Micropython onto the board this time, with the following script.

    import time
    from machine import UART, Pin

    # Use one of the GPIO as a GND pin for the serial
    gndpin = Pin(11, Pin.OUT)
    gndpin.value(0)

    print ("Initialising UART 0 on pins gnd=11, tx=12, rx=13...")
    uart = UART(0, baudrate=115200, tx=Pin(12), rx=Pin(13))
    print ("Ready")

    while True:
    # Read raw data version
    rxdata = bytes()
    while uart.any() > 0:
    rxdata += uart.read(1)
    time.sleep_ms(10)

    if rxdata:
    print(rxdata.decode('utf-8'))

    To keep the connections simple, I used GPIO 11 as an additional GND pin as there is only one on the board and it isn’t so convenient.

    PicoDexed        RP2040-One
       GP0    <---->    GP13
       GND    <---->    GP11

    To ensure the code can output text just needs something like the following:

    #include <stdio.h>

    void main () {
      stdio_init_all();
      printf("PicoDexed...");
    }

    Then with both devices connected to my virtual Ubuntu Linux machine, I can run minicom (once installed – it isn’t installed by default):

    $ sudo minicom -b 115200 -D /dev/ttyACM0

    Here is the output.

    Welcome to minicom 2.8

    OPTIONS: I18n
    Port /dev/ttyACM0, 13:27:28
    Press CTRL-A Z for help on special keys

    PicoDexed...

    Connecting PIO I2S audio
    Copying mono to mono at 24000 Hz

    Note, to exit minicom use CTRL-A then X.

    Alternatively I could use PuTTY on Windows on the COM port associated with the “debugging” Pico.

    At some point I’ll probably need to set up proper SWD debugging, but this should do for the time being.

    I might also need to switch UARTs if I want to use UART 0 for MIDI, but apparently there are some defines that can be changed in the CMakeLists.txt file:

    target_compile_definitions(picodexed PRIVATE
    PICO_DEFAULT_UART=0
    PICO_DEFAULT_UART_TX_PIN=0
    PICO_DEFAULT_UART_RX_PIN=1
    )

    PicoDexed design

    It is time to start thinking seriously if I can turn this into something interesting or not, so borrowing from some of the design principles encapsulated in MiniDexed, I’ve now got a project that looks as follows:

    • main.cpp -> Basic IO, initialisation and main update loop.
    • picodexed.cpp -> The core synthesizer wrapper with the following key interface:
      • CPicoDexed::Init -> perform all the required synthesizer initialisation.
      • CPicoDexed::Process -> perform a single “tick” of the synthesizer functions, including updating the sample buffers from Dexed.
    • mididevice.cpp, serialmidi.cpp, usbmidi.cpp -> placeholder classes that will eventually support MIDI message passing and a serial and USB MIDI interface. This borrows heavily from the way it is done in MiniDexed. These classes will support the following interface:
      • CSerialMIDI::Init -> Initialise the hardware (same for USB).
      • CSerialMIDI::Process -> poll the hardware (same for USB).
      • CMIDIDevice::MIDIMessageHandler -> will be called by the lower-level devices when a MIDI message is ready to be processed. Once parsed, it will trigger calls into the PicoDexed main synthesizer to update its state.
    • soundevice.cpp -> Encapsulating the interface to the pico_audio library to use I2S audio, with the following key interface:
      • CSoundDevice::Init -> Set the sample rate and I2S interface pins.
      • CSoundDevice::Update -> Fill the sample buffer using the provided callback, which will be a call to the Dexed->getSamples code above.
    • config.h -> contains some system-wide configuration items, such as sample rate and polyphony.

    PicoDexed will include the functions required to control the synthesizer. Examples include keydown and keyup functions for when MIDI NoteOn and NoteOff messages, and so on. It also includes a means to set the MIDI channel and to load a voice.

    I don’t know yet if the MIDI handling will be interrupt driven or polled. I need to read up on how the Pico SDK handles USB and serial data, but I suspect a polled interface should be fine for my purposes as long as it doesn’t hold up the sample calculations, buffer filling, and sample playing.

    With my first pass of this code, there is no external interface – it is still playing a test chord only. But at least most of the structure is now in place to hook it up to MIDI.

    The “to do” list so far:

    • Ideally find a way to better manage the Synth_Dexed changes. I should submit a PR to Holger, the creator of Synth_Dexed and discuss some conditional compilation steps.
    • Hook up USB MIDI so that the Pico can act as a MIDI device and play the synth that way.
    • Hook up serial MIDI too.
    • Implement volume. Without the filter there is currently no volume changing.
    • Implement some basic voice and bank loading.
    • Connect up some more core MIDI functionality for program change, BANKSEL, channel volume, master volume, and so on.
    • Think about how best to utilise the second core – in theory it should be possible to expand it to 16-note polyphony by using both cores. Or an alternative might be two instances of Synth_Dexed running, so making a second tone generator.

    MIDI/Serial Handling

    Rather than jump into USB, I’ve opted to get serial MIDI working first. The serial port handling I’ve implemented in serialmidi.cpp borrows heavily from the “advanced” UART example: https://github.com/raspberrypi/pico-examples/tree/master/uart/uart_advanced

    It is interrupt driven and shares a simple circular buffer with the main Read function based on the implementation described here: https://embedjournal.com/implementing-circular-buffer-embedded-c/.

    The basic design of the serial MIDI interface is as follows:

    Interrupt Handler:
      Empty the serial hardware of data writing it to the circular buffer

    Init function:
      Initialise the UART as per the uart_advanced example
      Install the interrupt handler and enable interrupts

    Process function:
      Call the MIDI device data parser to piece together any MIDI messages
      Call the MIDI device msg handler to handle any complete MIDI messages

    Read function:
      Read the next byte out of the circular buffer

    There is a common MIDI device that the serial MIDI device inherits from (and that I plan to also use with USB MIDI support when I get that far). This has the following essential functionality:

    MIDIParser:
      Read a byte from the transport interface (e.g. the serial MIDI Read)
      IF starting a new message THEN
        Initialise MIDI msg structures
        IF a single byte message THEN
          Fill in MIDI msg structures for single-byte message
          return TRUE
        IF there is a valid Running Status byte stored THEN
          IF this now completes a valid two-byte msg THEN
            Fill in MIDI msg structures for a two-byte message
            return TRUE
      Otherwise process as a two or three byte message
      IF message now complete THEN
        Fill in MIDI msg structures
        return TRUE
      return FALSE

    MIDI Message Parser:
      IF MIDI msg already processed THEN return
      IF on correct channel or OMNI THEN
        Based on received MIDI command:
          Extract parameters
          Call appropriate picoDexed function
      Mark MIDI msg as processed.

    I had a fun bug where in the serial handling, I was writing to a byte one-out in the circular buffer which meant that the MIDI handling largely worked, but only when using a controller with ActiveSensing – basically the reception of the extra byte “pushed through” the previous message. But it was a bit unresponsive, and occasionally a note of a chord would sound after the others.

    I spent the better part of a day instrumenting the code, attempting to work out where the delays might be coming from. Eventually I got so fed up with the active sensing reception clouding my analysis (and triggering my scope when I didn’t want it to) that I filtered it out in the serial interrupt routine – so as early as I could.

    This the made the delay a whole pile worse! That was the point I realised it was continually essentially one message behind. As a consequence I had another look at the buffer handling and that was when I realised the mistake.

    Multicore support

    My initial thought on the above problem was that it was a performance issue – that the MIDI handling wasn’t responsive enough. So I pushed ahead and moved all the synthesis code over to the second core. This is something I wanted to do anyway as I always had the plan of splitting the functionality across the two cores.

    To enable multicore support requires including pico_multicore in the list of libaries in the CMakeLists.txt file and then it should largely be a case of doing the following:

    #include "pico/multicore.h"

    void core1_entry (void)
    {
      // stuff to do to initialise core 1

      while (1)
      {
        // Stuff to do repeatedly on core 1
      }
    }

    // Rest of "normal" (core 0) initialisation code
    multicore_launch_core1 (core1_entry);

    The question is where to enable this. Eventually I settled on implementing this in picoDexed itself to split out the ProcessSound function over to the second core. This required the following:

    • PicoDexed::Init – initialise multi-core support and start the second core running.
    • PicoDexed::Process – no longer calls ProcessSound.
    • PicoDexed::core1_entry – now calls ProcessSound in an infinite loop.

    In order to ensure that I don’t get Dexed into an inconsistent state, I’ve protected the calls into Dexed from the Dexed_Adaptor with spinlocks (mirroring what was happing in MiniDexed) as shown in the following extract:

    class CDexedAdapter : public Dexed
    {
    public:
    CDexedAdapter (uint8_t maxnotes, int rate)
    : Dexed (maxnotes, rate)
    {
    spinlock_num = spin_lock_claim_unused(true);
    spinlock = spin_lock_init(spinlock_num);
    }

    void getSamples (int16_t* buffer, uint16_t n_samples)
    {
    spin_lock_unsafe_blocking(spinlock);
    Dexed::getSamples (buffer, n_samples);
    spin_unlock_unsafe(spinlock);
    }

    private:
    int spinlock_num;
    spin_lock_t *spinlock;
    }

    Spinlocks are described in chapter 4.1.19 of the RPi C/C++ SDK and are part of the hardware_sync library.

    In order to ensure that the spin_locks are not held too long, and to allow things like keyup/down events to be registered in a timely manner and not hold up core 0 whilst core 1 is calculating samples, I’ve now reduced the sample buffer to 64 bytes.

    As core 1 is essentially free-running calculating samples now, I figured it wouldn’t make much difference how many samples are calculated in each “chunk” but going to 64 from 256 gives four times the number of break points in the cycle where other events can be processed between the spin_locks.

    Once consequence of running multi-core seems to be that I can now push the polyphony up to 10 simultaneous notes without any artefacts.

    If I can find a way to keep some of the sound generation on core 0 too, I might be able to increase that even further, although getting 6 additional sound engines running to get up to the magic 16 note polyphony might be stretching things still. The trick will be finding a way to trigger and mix samples from the sound generators in the two cores, as all of that current happens within Dexed itself.

    Overclocking the Pico

    There have been a number of experiments already in seeing how far a Pico can be pushed. There is a standard API call to set the system clock: set_sys_clock_khz(), although not all values can be accurately configured. But general wisdom seems to be that running the Pico at 250MHz isn’t a big deal…

    Of course, at this point it is running outside of the “normal” spec, so the long term effects may well reduce the life of the Pico…

    But by doing this, the Pico is now running twice as fast and so can now easily cope with 16 note polyphony at a sample rate of 24000, or up the sample rate to 48000 and stick with 8 note polyphony.

    It might even raise the possibility of running two tone generators, one on each core! It really does open up a wide range of possibilities!

    Closing Thoughts

    I’m really pleased with the progress so far. I was starting to think there wouldn’t be a usable combination possible, but 10-note polyphony at a sample rate of 24000 isn’t too bad for a 133MHz CPU with no FPU.

    I think my basic design goal would be for something usable with a MIDI controller. I’m not looking to implement a UI like there is with MiniDexed as part of this build. But I do need a bit more MIDI functionality first and I would like to find a way to squeeze some sample calculations out of core 0 when it isn’t handling MIDI.

    I also want to get USB MIDI up and running too. I’m not sure if I want to push for both device and host USB support though. I’ll see how complicated it all is!

    In the video, I’ve used my Raspberry Pi Pico MIDI Proto Expander. It just needs the addition of the Pimoroni audio board and it is ready to go!

    Of course the key question is: would I recommend this to anyone? Answer: no! No way – get yourself a Raspberry Pi Zero V2 and run a full-blown set of 8 DX7s using MiniDexed 🙂

    Still for me, this is a bit of fun a really good excuse to do something that’s been on my “to do” list for ages – start getting to grips with the Raspberry Pi Pico C/C++ SDK and the RP2040.

    Kevin

    https://diyelectromusic.wordpress.com/2024/02/04/raspberry-pi-pico-synth_dexed-part-3/

    #dx7 #midi #picodexed #raspberryPiPico