delete

Contattaci

back to resources

Creare un podcast in automatico a partire da audio vocali e musica

data
19/5/2021
data progetto
autore
Carlo Peluso
cliente
partnership
url
No items found.

Nel 2011, mentre studiavo Architettura al Politecnico di Torino e vivevo nel collegio universitario di Grugliasco, mi sono imbattuto in una delle più belle esperienze della mia vita. Insieme al mio amico Angelo ho progettato e realizzato una webradio studentesca che trasmetteva direttamente dal collegio. Il progetto, durato 5 anni è stato di grande scuola per me, sia dal punto di vista umano, sia professionale. Ero il classico “tecnico tutto fare” 🧑‍🔧 : in quel periodo mi sono occupato di piccoli software radiofonici, della programmazione e della gestione del palinsesto, ma ovviamente anche nella manutenzione del server della radio e dello studio dal quale trasmettevamo. Ho conosciuto più di 60 ragazzi, divisi in gruppi di lavoro, uno per trasmissione!

Nell’ultimo periodo (coinciso più o meno con l’ascesa dei podcast su Spotify) è tornata la mia curiosità verso il mondo della radio. Mi sono chiesto quanto fosse possibile migliorare/ottimizzare il processo di creazione di una trasmissione radiofonica o un podcast. Avevo già trattato quest’argomento in un precedente articolo in cui mi concentravo sul come mixare la voce di uno speaker insieme ad altri suoni. In questi giorni ho realizzato un piccolo script che passo passo crea un’intera trasmissione a partire da una cartella di files.

Struttura di una puntata radiofonica

Per realizzare questo piccolo progetto ho utilizzato FFMPEG, nota libreria per la manipolazione del suono (leggi il mio articolo al riguardo con degli esempi d’uso). Questa libreria permette di applicare dei filtri al suono in maniera programmatica, quindi attraverso un linguaggio di programmazione. Studiando la ricchissima documentazione (e con l’aiuto dell’ottima community di FFMPEG) sono riuscito a realizzare questo Batch che programmaticamente mette in sequenza dei file audio, tramite l’uso di dissolvenze o somme di suoni. Vediamo uno schema:

Traducendo questo semplice schema in un codice programmabile, questo somiglia ad un array di oggetti (file audio) che dovranno essere messi in sequenza, ma a certe condizioni:

  • il parlato dovrà sempre avere un sottofondo leggero di musica
  • i brani partiranno con una dissolvenza (fade) nel momento in cui il parlato sta per finire
  • il parlato comincia un momento prima del termine del brano

Ecco uno schema piu preciso di quello che succederà:

Script per elaborare il parlato con un sottofondo

Questo script va eseguito con l’ultima versione di NodeJs installata, e richiede diverse librerie esterne, la più importante è fluent-ffmpeg, ovvero un wrapper di FFMPEG per NodeJs. Lo script converte una serie di audio registrati con solo voce in diversi file in cui la voce è accompagnata da un sottofondo musicale leggero che parte e finisce in dissolvenza.

var mp3Duration = require('mp3-duration');
var ffmpeg = require('fluent-ffmpeg');
var fs = require('fs')

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; //un generico array di file audio di voce

let promises = [];

array.forEach(speech => {

   let speechFile = speech + '.mp3';
   let backgroundFile = 'sottofondo.mp3';
   let backgroundLooped = speech + '_onlybackground.mp3';
   let speechWithBackground = speech + '_.mp3'

   let p = mp3Duration(speechFile, function (err, dur) {

       //recupero la durata dello speech
       let durataVoce = Math.round(dur);

       //creo un loop della durata dello speech
       ffmpeg(backgroundFile)
           .inputOption("-stream_loop -1") //loop infinito del sottofondo
           .audioFilters('afade=t=in:ss=0:d=8')  //fadein che dura 8 secondi
           .audioFilters('afade=t=out:st=' + (durataVoce - 10) + ':d=5')   //fadeout che dura 8 secondi e parte 10 secondi prima della fine dell'audio
           .duration(durataVoce) //taglio alla durata della voce
           .audioBitrate(320)
           .output(backgroundLooped)
           .on('end', function () {

               //faccio un mix con la voce

               ffmpeg()
                   .addInput(backgroundLooped)
                   .addInput(speechFile)
                   .complexFilter(['[1]compand=attacks=0.4:points=-80/-80|-12.4/-12.4|-6/-8|0/-6.8|20/-2.8:gain=12:volume=-40[a1]',
                       '[a1]channelsplit=channel_layout=stereo:channels=FR[a2]',
                       '[0][a2]amix=inputs=2:dropout_transition=0.2:weights=1 10,dynaudnorm'])
                   .audioBitrate(320)
                   .save(speechWithBackground)
                   .on('end', function () {
                       //rimuovo il file del background
                       console.log(speech + " - Completato");
                       fs.unlinkSync(backgroundLooped);

                   });
           }).run();

   });

   promises.push(p);
});

Script per mettere in sequenza i file audio

Una volta terminata l’elaborazione dei file audio del parlato, non ci resta che mixare il tutto seguendo lo schema precedente. I brani saranno leggermente anticipati rispetto al termine del parlato, in modo da accentuare l’effetto radiofonico finale. Ogni brano inizierà e finirà con una dissolvenza automatica di 10 secondi (impostata nella variabile fadeDuration). Inoltre verrà applicato un filtro normalizzazione audio, che consentirà di assottigliare le differenze di volume tra i brani, migliorando l’esperienza di ascolto.

var ffmpeg = require('fluent-ffmpeg');

let speeches = [
   {
       tipo: 'musica',
       file: "sigla.mp3"
   },
   {
       tipo: 'voce',
       file: "1_.mp3"
   },
   {
       tipo: 'musica',
       file: "musica1.mp3"
   },
   {
       tipo: 'voce',
       file: "2_.mp3"
   },
   {
       tipo: 'musica',
       file: "musica2.mp3"
   }
]


let command = ffmpeg();
let filters = [];
let combo = 0;
let fadeDuration = 10;

for (let i = 0; i < speeches.length; i++) {

   //aggiungo l'input

   speech = speeches[i];
   command.addInput(speech.file);
   successivo = i + 1;

   //se sono all'ultimo non faccio niente perché mi interessa la combo precedente
   if (i < speeches.length - 1) {

       //se l'attuale è voce
       if (speech.tipo == 'voce') {

           //abbasso il volume della musica successiva
           filters.push('[' + successivo + ']volume=0.3[low' + successivo + ']');

           if (i < 1) {
               filters.push('[' + i + '][low' + successivo + ']acrossfade=d=' + fadeDuration + ':c1=nofade:c2=exp[combo' + combo + ']');
           } else {

               output = '[combo' + (combo + 1) + ']';
               if (successivo == speeches.length - 1) {
                   output = ",loudnorm";
               }

               filters.push('[combo' + combo + '][low' + successivo + ']acrossfade=d=' + fadeDuration + ':c1=nofade:c2=exp' + output);
               combo++;
           }


           //se l'attuale è musica
       } else if (speech.tipo == 'musica') {

           if (i < 1) {
               filters.push('[' + i + ']volume=0.4[low' + i + ']');
               filters.push('[low' + i + '][' + successivo + ']acrossfade=d=' + fadeDuration + ':c1=exp:c2=nofade[combo' + combo + ']');
           } else {

               output = '[combo' + (combo + 1) + ']';
               if (successivo == speeches.length - 1) {
                   output = ",loudnorm";
               }

               filters.push('[combo' + combo + '][' + successivo + ']acrossfade=d=' + fadeDuration + ':c1=exp:c2=nofade' + output);
               combo++;
           }

       }
   }

}

command.complexFilter(filters)
   .save("totale1.mp3")
   .audioBitrate(320)
   .on('end', function () {
       //rimuovo il file del background
       console.log(" - Completato");
   });

Risultato

Ho utilizzato questo piccolo script per realizzare una trasmissione di prova, a partire da un file vocale registrato con lo smartphone. Chiaramente è un progetto ancora molto semplice, ma che crea interessanti spunti su come automatizzare il processo di missaggio (mix) di puntate radiofoniche o podcast.

Articolo a cura di Carlo Peluso, 18.05.2021

Link articolo originale: https://straquenzu.p3lus0s.net/creare-un-podcast-in-automatico-a-partire-da-audio-vocali-e-musica

Risultati

resources

User Experience Design tra accessibilità e inclusività

User Experience Design tra accessibilità e inclusività

User Experience

Accessibilità

Inclusività

Assitech.Net entra nella galassia Orbyta Technologies

Assitech.Net entra nella galassia Orbyta Technologies

Orbyta Technologies

Orbyta Group

Acquisizione

News

Programmazione Funzionale Java

Programmazione Funzionale Java

Functional Programming

Java

Software Development

Reactive Programming: parallelizzare con Project Reactor

Reactive Programming: parallelizzare con Project Reactor

Programmazione Reattiva

Reactive Programming

Project Reactor

Piattaforme E-commerce Wholesale per il settore B2B

Piattaforme E-commerce Wholesale per il settore B2B

Wholesale

B2B

Antipattern nello sviluppo software: altri errori da evitare

Antipattern nello sviluppo software: altri errori da evitare

Software Development

Antipattern nello sviluppo software: definizione, ambiti di applicazione ed esempi

Antipattern nello sviluppo software: definizione, ambiti di applicazione ed esempi

Software Development

App tattiche di supporto alla gestione dei progetti reiterativi

App tattiche di supporto alla gestione dei progetti reiterativi

App Development

Power Platform

Low Code

DevOps

Introduzione a Power Pages, il servizio Microsoft per siti web low-code

Introduzione a Power Pages, il servizio Microsoft per siti web low-code

Microsoft

Low-code

Power Platform

Introduzione a Jupyter e Seaborn per Data Analysis e Visualization

Introduzione a Jupyter e Seaborn per Data Analysis e Visualization

Jupiter

Python

Data Analysis

Data Visualization

Come utilizzare Matplotlib per la Data Visualization in Python

Come utilizzare Matplotlib per la Data Visualization in Python

Python

Data Visualization

Data Science

Data Analysis

Introduzione alla libreria Dash per Python

Introduzione alla libreria Dash per Python

Python

Data Science

Data Visualization

Data Analysis

Prime Video passa al monolite: ma allora serverless è inutile? 

Prime Video passa al monolite: ma allora serverless è inutile? 

Tableau per la Business Intelligence: introduzione, tutorial e confronto

Tableau per la Business Intelligence: introduzione, tutorial e confronto

Introduzione a Qlik Sense, piattaforma di Business Intelligence avanzata

Introduzione a Qlik Sense, piattaforma di Business Intelligence avanzata

Applicazioni Cloud Native: definizione, vantaggi e tecnologie

Applicazioni Cloud Native: definizione, vantaggi e tecnologie

Power Apps Tutorial – Case Study: come costruire una business app da zero

Power Apps Tutorial – Case Study: come costruire una business app da zero

Il futuro del gaming tra F2P, GaaS, Crypto e Play to Earn

Il futuro del gaming tra F2P, GaaS, Crypto e Play to Earn

Power Apps Basics: interfacce, implementazione & vantaggi

Power Apps Basics: interfacce, implementazione & vantaggi

Strumenti di Business Intelligence: QlikSense & Power BI a confronto

Strumenti di Business Intelligence: QlikSense & Power BI a confronto

Introduzione a Serverless: non solo Lambda Function

Introduzione a Serverless: non solo Lambda Function

Metaverso: siamo pronti a cogliere l’opportunità?

Metaverso: siamo pronti a cogliere l’opportunità?

Recap Flutter Forward 2023: le 7 novità più interessanti

Recap Flutter Forward 2023: le 7 novità più interessanti

Let's Redux React to a Game

Let's Redux React to a Game

Introduzione a PowerShell

Introduzione a PowerShell

Pago con carta: i trend dei pagamenti digitali e il futuro delle carte di credito

Pago con carta: i trend dei pagamenti digitali e il futuro delle carte di credito

NFT World: il fenomeno NFT tra metaverso, business e GameFi

NFT World: il fenomeno NFT tra metaverso, business e GameFi

Quick Escape Room

Quick Escape Room

Orbyta Invaders Ignition

Orbyta Invaders Ignition

Il lancio della nuova Identity di Orbyta parte dal Metaverso!

Il lancio della nuova Identity di Orbyta parte dal Metaverso!

development

design

metaverse

brand identity

Database a grafo in SQL Server

Database a grafo in SQL Server

Data Science Job Roles: i 4 ruoli più richiesti nel settore

Data Science Job Roles: i 4 ruoli più richiesti nel settore

Teoria dei giochi: Propagazione delle strategie

Teoria dei giochi: Propagazione delle strategie

The chosen one: .NET 5

The chosen one: .NET 5

Network Science e Social Network Analysis

Network Science e Social Network Analysis

Isolation levels on SSMS

Isolation levels on SSMS

Teoria dei Grafi

Teoria dei Grafi

Creare un podcast in automatico a partire da audio vocali e musica

Creare un podcast in automatico a partire da audio vocali e musica

Teoria dei Giochi

Teoria dei Giochi

Recommender systems: principali metodologie degli algoritmi di suggerimento

Recommender systems: principali metodologie degli algoritmi di suggerimento

Introduction to Quantum Computing and Qiskit

Introduction to Quantum Computing and Qiskit

System Versioned Tables

System Versioned Tables

Vim o non Vim

Vim o non Vim

I vantaggi di un Message Broker

I vantaggi di un Message Broker

PlayStation 5 e l'accesso ai dati: un cambio architetturale?

PlayStation 5 e l'accesso ai dati: un cambio architetturale?

Protezione dei Web Services

Protezione dei Web Services

need more info?

contattaci