Archivi tag: musica

core_midi_devel

Come mostrare il tempo di una MusicSequence come nel display LCD di GarageBand

Con un nostro precedente post abbiamo già accennato a questo problema: ora approfondiamo le motivazioni tecnico/teoriche che sono alla base.

Il formato ha 4 valori:

– la misura (bar)
– la battuta (beat)
– la nota di sedicesimo nella battuta
– sottodivisioni della battuta (subbeatdivision)

Il framefork AudioToolbox (Core Audio) offre alcuni strumenti per gestire la divisione del tempo a
supporto di una MusicSequence: i principali sono le seguenti:

  • MusicTimeStamp
  • CABarBeatTime

Il primo è un valore temporale la cui unità è la misura musicale (bar): quindi posto 1 il tempo di durata di una misura, tutto è multiplo o sottomultiplo di questo: ne consegue che MusicTimeStamp è un valore in virgola mobile con la necessità di una certa precisione.

La seconda è una struttura utilizzata per le conversioni (vedi le funzioni MusicSequenceBeatsToBarBeatTime e MusicSequenceBarBeatTimeToBeats), ma la scarsa documentazione non fornisce quanto serve a che queste funzioni facciano a pieno il loro dovere.

Il lato oscuro di queste funzione è il parametro inSubbeatDivisor (per la funzione MusicSequenceBeatsToBarBeatTime) o il campo subbeatDivisor nella struttura CABarBearTime (da passare alla funzione MusicSequenceBarBeatTimeToBeats).

Nella soluzione proposta nel precedente post utilizzavamo la risoluzione della sequenza (ppq) come parametro, e sembrava funzionare egregiamente: invero su divisioni di tempo differenti avremmo potuto avere problemi di rappresentazione.

Infatti il subbeatDivisor è un valore in relazione non solo alla risoluzione (in ppq), ma anche alla divisione del tempo corrente (time signature) e per la precisione al denominatore della divisione del tempo, secondo la sequente relazione:

subbeatDivisor = ( (ppq >> 2) << sig_denominator )

dove sig_denominator è espresso come l’esponente di una potenza di 2 che determina il denominatore della divisione temporale corrente. Una breve nota: il memorizzare l’esponente è un meccanismo utilizzato anche nel meta evento di una SMF o di una MusicTrack: la Tempo Track di una MusicSequence è una MusicTrack, pertanto la divisione è registrata in questa mediante meta eventi (di tipo kMIDIMetaEvent_Time_Signature).

La risoluzione è espressa in parti (tick o pulse) di una nota di quarto (ppq o ppqn), ma quando cambia il denominatore della divisione temporale, allora per avere medesima “precisione” occorre ampliare o ridurre questo valore quando esprimiamo una posizione nel tempo al fine di consentire di avere lo stesso numero di parti nel beat (che ha cambiato dimensione per il diverso denominatore della divizione del tempo).

Dato la divisione di 6/8 e una risoluzinone di 240 ppq:

UInt8    tsig_num = 6;
UInt8    tsig_den = 3;        // 2^3 = 8
UInt16    resolution = 240;    // PPQ

allora avremo:

UInt16  subbeatDivisor = ( (resolution >> 2) << tsig_den );

Le dimensioni delle variabili sono conformi a quanto atteso dalle strutture o funzioni in AudioToolbox.

Il penultimo valore da mostrare è il numero della nota di sedicesimo corrente, e come abbiamo visto l’altra volta è ottenibile mediante la seguente:

subbeat / (subbeatDivisor / 4) + 1

dove subbeat rappresente il “pulse” corrente di una nota di quarto, quindi rapportanto alla divisione corrente (subbeatDivisore) se ne prende la quarta parte: 4 * 4 = 16 !

Per eseguire qualche esperimento ecco come scrivere un beat di tanti eventi quanti i tick indicati dalla risoluzione prescelta.

MusicTrack outTrack;
UInt8    tsig_num = 6;
UInt8    tsig_den = 3;
UInt16    resolution = 240;    // PPQ
UInt16  subbeatDivisor = ( (resolution >> 2) << tsig_den );
CABarBeatTime inBarBeatTime;
MIDINoteMessage aNoteMessage;
MusicTimeStamp       outBeats ;

MusicSequenceNewTrack (mainSequence, &outTrack);

aNoteMessage.channel = 1;
aNoteMessage.note = 23 & 0x0f;
aNoteMessage.velocity = 80 & 0x0f;
aNoteMessage.releaseVelocity = 0;
aNoteMessage.duration = 1/960;

for(int i = 0; i < resolution; i++){
inBarBeatTime.bar = 1;
inBarBeatTime.beat = 1;
inBarBeatTime.subbeat = i;
inBarBeatTime.subbeatDivisor = subbeatDivisor;

MusicSequenceBarBeatTimeToBeats(mainSequence, &inBarBeatTime, &outBeats);
MusicTrackNewMIDINoteEvent (outTrack, outBeats, &aNoteMessage);
}

Ovviamente non abbiamo detto della cosa più importante: come leggere il denominatore della divisione in relazione al tempo corrente di riproduzione (o visualizzazione).

Questo sarà oggetto di un altro post che introdurrà la descrizione di un mio progetto di ampliamento del framework AudioToolkit che presto pubblicherò su github.

Per ora basta.

osxbeep

Beep OS X, Beep!

Nell’implementazione dello strato BSD, OSX omette alcuni comandi; poco male se una alternativa è data da un comando nativo: verosimilmente l’astrazione BSD non era in grado di realizzare a pieno il compito. Ma questo non é evidentemente l’unico motivo.

Tra i vari “ports” BSD, Apple ne seleziona solo alcuni, mantenendoli spesso ad una versione “vecchia” (vedi il caso di bash, ancora rimasta alla 3).

Non dovrebbe dunque sorprendere l’assenza del port del comando beep, sebbene sia difficilmente spiegabile in termini tecnologici; al piú si spiega in termini di conformità alle metafore della interfaccia che prevedono altro per la segnalazione di eventi ad utente.

L’ironia del caso vuole che mentre il mondo Linux evolve la sua implementazione del comando beep, anche il port per FreeBSD è stato rimosso in quanto obsoleto, alla buona faccia di chi voglia ancora utilizzarlo.
Ovviamente il nostro interesse per il comando beep nel mondo OS X è indotto dalle cose espresse nei nostri precedenti articoli, ma andiamo per gradi.
Ricercando nella documentazione di sviluppo si trova la disponibilità della funzione beep() nella libreria ncurses (https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/beep.3x.html): questa peró esegue il suono di avviso configurato negli effetti sonori nelle preferenze di sistema.
Quindi, almeno per conformità alle metafore dell’interfaccia, il comando beep poteva essere implementato semplicemente utilizzando questa funzione di ncurses.

Ricercando in Internet (come è nostro solito) una soluzione per implementare un beep su OS X troviamo tante risposte ovvie, ma non quella che cercavamo (ovvio anche questo!)

E’ ovvio che un comando echo (o print) in shell riproduca con un suono il carattere audible alert (\a=ASCII 0x7, carattere di controllo
che deve i suoi natali alla Teletype Model 33 ASR):

echo -e "\a"

ma é anche ovvio che si comporti come prevede l’implementazione della libreria ncurses, come per l’equivalente:

tput bel

con cui si attiva la capability del terminale (che dipendono dalla solita libreria)

Ovvio (benchè meno diretto) la possibilitá di eseguire un beep come istruzione AppleScript:

osascript -e beep

e non ci si può stupire se anche questo metodo (piú che mai OS X) esegue Il suono di sistema previsto per gli avvisi.

Il suggerimento piú esilarante è certamente il seguente:

say beep

benchè abbia un suo fascino.
Dunque è giunto il momento di trovare una risposta in stile Nerdammer e dotare il nostro OS X del comando beep.
Volevamo scegliere come modello la piú evoluta implementazione Linux (di Johnathan Nightingale) invece di quella del port FreeBSD:
questioni pratiche e di tempo ci impongono al momento di implementare la versione FreeBSD: ritorneremo sulla implementazione per evolverla accessivamente.

Questa scelta ci consentirà comunque di utilizzare le nostre “beepsongs” come prodotte dal software descritto nel
precedente articolo (ponendo in modo FreeBSD l’output dello script). Alla fine in realtà è questo che cercavamo!

Per realizzare il nostro progetto ci avvaliamo del framework Core Audio, ed in particolare utilizziamo una Audio Unit di tipo output con definita una funzione callback per il rendering del buffer audio, il che ci consentirà di definire algoritmicamente (dunque dinamicamente) la forma d’onda emessa.

Vogliamo con questo simulare al meglio il circuito analogico del beeper delle schede madri di pc e server, evitando i limiti e la complessità che altri metodi imporrebbero volendo ottenere campo di frequenze e durata di emissione molto ampi.

Come al solito la nostra implementazione é una guida: ci si perdoni quindi l’assenza di ricerca di ottimizzazioni nelle prestazioni (ad esempio l’algoritmo di generazione dell’onda sinusoidale non é il piú efficiente in assoluto).

Potete scaricare il codice sorgente da Git Hub e compilarlo sul vostro OS X come indicato nella documentazione.

Ancora una volta buon ascolto!

IMG_2710.JPG

Condivisione multi utente per la libreria iTunes e altro ancora (parte 3)

Fatto il vostro backup?

Allora siamo pronti a partire con lo sviluppo del cuore del nostro progetto: una procedura di creazione di una libreria indipendente e condivisa.

Da questo momento consideriamo la libreria del nostro utente (che è amministratore per ragioni che vedremo in seguito) la libreria master nella nostra architettura, che evidentemente è stata scelta in quanto ragionevolmente é quella che per ragioni anche storiche ha il peso maggiore di media condivisibili nel sistema.

Creiamo una nuova libreria nella Cartella condivisa (con procedura ormai nota se avete letto la documentazione consigliata).SegliLibreria

Apriamola. Configuriamola in modo che non esegua copia degli oggetti importanti (consolidamento) e non mantenga ordinata la libreria: non è il suo ruolo: questa sarà una libreria slave, non dovrebbe avere diritto di gestione (anche se vedremo possibile, entro certi limiti, utilizzando uno strumento di gestione che proporremo alla fine della trattazione).configurazione

Il problema (rilevato ma non risolto dal supporto Apple) sarà trovare il modo di rendere sincrone le due librerie. Vedremo di risolverlo.

Rimuoviamo ora la cartella Music nella nuova libreria (in iTunes Media); al suo posto ci poniamo (muovendola) la cartella Music della libreria master (è la cartella che contiene tutti i media da condividere).

Nella libreria master spoglia della cartella Music (in iTunes Media) creiamo un collegamento (semplicemente tenendo premuto alt+cmd mentre fate un drag&drop) della cartella Music ora mossa nella nuova posizione. Questo garantirà alla libreria master di mantenere la visibilità dei media a lei noti.stato_master

Come amministratore possiamo ora modificare i diritti della cartella Musica appena spostata consentendo la lettura a tutti gli utenti con cui volete condividere il suo contenuto; non autorizziamo la scrittura se vogliamo rendere la libreria puramente slave e non abbia quindi diritto di modificare i media.

Ora è il momento di riaprire la libreria master: tutto è al suo posto, giusto? Se qualcosa non è al posto giusto possiamo verificare la posizione della cartella Music nelle Preferenze ed eventualmente reimpostarla. Se iTunes pensa di dove iniziare la copia dei media potrebbe avviare tale procedura: bloccatela! Non è necessaria. Abbiamo giocato con spostamento e collegamento, andando oltre la procedura Apple che prevede necessita di spazio disco libero pari alla dimensione dei media da spostare. Se tutto è dunque a posto esportiamo la libreria master in formato xml.export

Ora riaprite la nuova libreria costituita in precedenza (slave): questa è vuota pur avendo collocati una cartella Music piena di materiale. Abbiamo detto già che la libreria è tale in quanto raccoglitore di metadati. Ora importate il file xml esportato precedentemente con la funzione “Importa playlist”.import

Chiaro no? L’importazione parla di playlist; Music è una playlist, e iTunes ci sta dicendo che l’importazione riguarderà solo musica.

Finita l’operazione ecco dunque che avrete due librerie identiche (solo nel contenuto migrato) ma che condividono anche fisicamente gli stessi media, ma solo per ciò che attiene alla musica. Per gli altri media la gestione risulterà indipendente. Potrete aggiungere libri, applicazioni o quanto altro alla nuova libreria nei modi di sempre: questo è dunque possibile. Ciò trova anche una soluzione alla gestione ad esempio delle app “legacy” per vecchi dispositivi (basta creare una libreria slave per gestire questi, pur condividendo altri media).


Ma adesso arriva il difficile: aggiungendo nuovi media musicali nella libreria master (che consolida) avremo nuovi oggetti nella cartella media condivisa, ma non li avremo come metadati nella libreria (o nelle librerie) slave (nel file .itl, per intenderci).

Ogni volta che si modifica la libreria master andrebbe aggiornata la slave aprendo iTunes su questa e aggiungendo o rimuovendo oggetti (alterare playlist, ecc).

È evidente come sia necessario automatizzare questa procedura, almeno per quanto riguarda l’aggiunta di nuovi media condivisi (le pllaylist sono raccolte soggettive che lasciamo ai singoli utenti).

Per risolvere questo problema ancora una colta ho scritto un po’ di codice AppleScript (ci ho preso gusto!).

Purtroppo iTunes non espone metodi per salvare tutte le informazioni in un colpo solo, ma solo un metodo add per aggiungere file a partire da un loro alias: questo mi sono fatto comunque bastare. Un unico script che esporti ed importi i metadati attraverso un file di interscambio (un semplice file contenente la lista dei nuovi file) tra le due istanze di libreria.

Andrà attivato prima sulla libreria sorgente (usando la playlist “Aggiunti di recente” quale fonte dell’elenco dei brani da migrare), poi su quella destinazione: questa procedura ci offre la soluzione cercata.

Possiamo eseguire esportazioni successive dalla libreria master ed importare il tutto nella libreria slave in un unico momento.  L’importazione finisce con la rimozione del file di interscambio, iniziando una nuova accumulazione.

Ma non dilunghiamoci in descrizioni ulteriori di implementazione; ecco di seguito il sorgente.

 

[codesyntax lang=”applescript”]

-- 
-- @author Andrea Tassotti


--
-- differenza tra due insiemi
--
on difference(set1, set2)
set differ to {}
repeat with o in set2
if set1 does not contain o then
set differ to differ & o
end if
end repeat
return differ
end difference

--
-- Esistenza file
--
on existsFile(migrationFile)
tell application "Finder"
if not (exists migrationFile) then
return false
else
return true
end if
end tell
end existsFile

--
-- Lettura lista migrazione
--
on readMigrationFile(migrationFile)
-- read
if existsFile(migrationFile) is true then
tell current application
set fileRef to open for access alias migrationFile
set lista to read alias migrationFile as list
close access fileRef
return lista
end tell
else
return false
end if
end readMigrationFile

--
-- Scrittura (overwrite) lista migrazione
--
on writeMigrationFile(migrationFile, lista)
-- write
try
tell current application
set fileRef to open for access alias migrationFile with write permission
write lista to fileRef as list
close access fileRef
end tell
on error
display alert "Errore scrittura:" & (migrationFile as text)
end try
end writeMigrationFile

--
-- Preleva alias da voci di playlist selezionata (no Libreria intera)
-- 
to itemsToMigrate()
tell application "iTunes"
set currentPlayList to view of window 1
set currentPlayListName to name of currentPlayList
if special kind of currentPlayList is none then
return location of every file track of currentPlayList
else
display alert "Possono essere esportate solo playlist effettive" message "Le playlist speciali (Music, Books, Podcasts, ecc) non sono contemplate" giving up after 2
return {}
end if
end tell
return {}
end itemsToMigrate

--
-- Corpo principale del programma
--
on run
set migrati to {}
set migrationFile to ((path to shared documents) as text) & "migration.itpl"
set migrati to readMigrationFile(migrationFile)

if migrati is not false then
-- - -- Verifica se master o slave
display alert "Controllo esistenza elementi in libreria. Questa operazione può durare molto. Attendere" giving up after 1
set primo to first item of migrati
tell application "iTunes"

set libreria to location of every file track of library playlist 1

if libreria does not contain primo then
-- Libreria Slave: importiamo
repeat with aFile in migrati
add aFile
end repeat
-- Rimuoviamo il file consumato
tell application "Finder"
if exists migrationFile then
delete migrationFile
end if
end tell
display alert "Fine importazione"
return
end if
end tell
end if
 

if migrati is false then
set migrati to {}
end if


-- Esportazione controllata
set daMigrare to itemsToMigrate()
if daMigrare is not {} then
-- Calcoliamo la differenza per evitare doppioni
-- poi aggiungiamo comunque quelli migrati per fare append del file
set lista to difference(migrati, daMigrare)
if lista is {} then
display alert "Contenuto migrato in precedenza"
else
writeMigrationFile(migrationFile, migrati & lista)
display alert "Esportazione lista migrazione terminata"
end if
end if
end run

[/codesyntax]

 

In quanto risultato delle nostre analisi, lo script lo rilasciamo liberamente, ma gradiremmo almeno un commento su questo blog se sarete tra quelli che lo copieranno ed utilizzeranno.

Buona condivisione!

Riferimenti

iTunes: How to share music between different user accounts on a single computer

iTunes for Mac: Moving your iTunes Media folder

How to move your iTunes library to a new computer

iTunes: How to re-create your iTunes library and playlists

articolo_itunes

Ancora su iTunes e playlist

Con l’ultimo post su iTunes ho potuto riabbracciare la programmazione AppleScript che avevo tralasciato per lunghi anni, da quando lavoravo ancora con un OS Classic 7.5.5 !

Ovviamente ci ho ripreso gusto, pertanto eccomi di nuovo con un altro post che prosegue in qualche modo il precedente.

L’idea di questa nuova estensione alle funzionalità di iTunes mi viene dal passato, ossia da quei lettori di CD Audio che erano parte degli impianti Hi-Fi degli anni 90 e che oggi sono solo appannaggio di impianti detti di “Hi-Fi esoterico“, dove un componente di tal genere può costare anche fino e oltre i 1000€! Oggi che il mondo musicale è sempre più liquido, un lettore CD Audio è qualcosa rara, pertanto per molti sono solo un ricordo.

In ogni caso quei dispositivi avevano una funzione (almeno quelli di una certa fascia) interessante che non si è diffusa nel mondo liquido. La scansione rapida delle tracce.

La scansione prevedeva l’ascolto dei primi 10 secondi di ogni traccia del disco.

Ebbene abbiamo implementato due script per iTunes che mimano questa funzione sulla playlist selezionata.

Il primo è esattamente a scansione dall’inizione di ogni traccia della playlist selezionata; il secondo invece è una variante che mi è utile nella costruzione di playlist per sonorizzazioni: consente l’ascolto degli ultimi 10 secondi di ciascuna traccia della playlist. Questa funzione è molto utile per trovare i migliori collegamenti tra fine e inizio di tracce che devono susseguirsi in un mix continuativo.

Rammentiamo (cosa non fatta nell’altro post) che per integrare i nostri AppleScript in iTunes sarà sufficiente collocarli in /Library/iTunes/Scripts.

Ovviamente anche in questo caso gli script sono un abbozzo funzionante che può essere migliorato a vostro piacere.

--
-- Scan mode 1
--
--	Head of track for 10 seconds
--
property thePlaylist : ""
property scanTime : 10

tell application "iTunes"
	-- Per le sorgentti che non sono una playlist (come Film, ecc)
	try
		set thePlaylist to (view of front window)
	on error number errn
	end try

	if thePlaylist ≠ "" then
		repeat with theTrack in (tracks of thePlaylist)
			play theTrack
			repeat while player position < scanTime
				delay 0.2
			end repeat
		end repeat
	end if
end tell
--
-- Scan mode 2
--
--	Tail of track for 10 seconds
--
property thePlaylist : ""
property scanTime : 10

tell application "iTunes"
	-- Per le sorgentti che non sono una playlist (come Film, ecc)
	try
		set thePlaylist to (view of front window)
	on error number errn
	end try

	if thePlaylist ≠ "" then
		repeat with theTrack in (tracks of thePlaylist)
			play theTrack
			set player position to (duration of theTrack) - scanTime
			repeat while player position < (duration of theTrack) - 1
				delay 0.2
			end repeat
			pause
		end repeat
	end if
end tell
articolo_itunes

Esportare una playlist iTunes su chiavetta USB

Per tutti coloro che utilizzano al meglio (e felicemente) iTunes e la sua libreria organizzata e consolidata, è difficile pensare ad una organizzazione del materiale audio senza iTunes.

Molti però tendono ancora a gestire i file multimediali in maniera autonoma, specie chi di questa gestione automatizzata, comoda ed integrata non ha mai sentito parlare (non è nel loro DNA, diciamo). Va bé! ci sono forme alternative di pensiero che dicono che noi utenti Apple invero siamo indottrinati; fate come volete. Tant’é. Noi viviamo sereni.

Però il problema nasce quando occorre integrarsi con il mondo a “gestione manuale”.
Se qualcuno ci chiede una copia della nostra playlist (per ascoltare le nostre canzoni autoprodotte rigorosamente con il nostro GarageBand !!! ovviamente !!! ;-), potrebbe essere difficile raccogliere in giro per la cartella “iTunes Music” tutti i file e copiarli diciamo su una chiavetta USB.

Ecco che ci viene incontro un piccolo frammento di codice AppleScript da me creato in pochi minuti (potenza del linguaggio):

tell application "iTunes"
    repeat with aTrack in (tracks of user playlist "Prova")
        set theAlias to (get location of aTrack)
        set theAlbum to (get album of aTrack).
        tell application "Finder"
        try
                duplicate theAlias to folder "Macintosh HD:Users:andrea:Desktop:Prova"
        on error number errn
            if errn = -15267 then
                make new folder at folder "Macintosh HD:Users:andrea:Desktop:Prova" with properties {name:theAlbum}
                duplicate theAlias to folder ("Macintosh HD:Users:andrea:Desktop:Prova:" & theAlbum)
            end if
        end try
        end tell
    end repeat
end tell

Rozzamente (non abbiamo prodotto una interfaccia per richiedere sorgente, ossia playlist, e destinazione, ossia un folder) ma semplicemente questo script cercherà per noi tutti gli originali indicati da una playlist e li copierà in un folder da noi indicato: qualora il file dovesse collidere con uno già presente (ricordiamo che i nomi di file gestiti con libreria organizzata da iTunes sono fatti del numero di traccia e del titolo, quindi possono sussistere casi di omonimia in assenza di album) allora crea un subfolder con il titolo dell’album.

Potrete modificarlo a piacimento, magari creando direttamente la gerarchia di folder che più vi aggrada, introducendo altre meta informazioni, se necessario.

Buon ascolto!