Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12
  1. #1
    Utente di HTML.it
    Registrato dal
    Nov 2005
    Messaggi
    278

    [C] Decodificare un file midi...è corretto?

    Ciao ragazzi,
    sto realizzando un programma che apre i file MIDI e legge il loro contenuto (numero di tracce,formato,note presenti, etc etc,). Il protocollo midi in ogni sito viene illustrato e spiegato aprendo un file midi attraverso un editor esadecimale.

    Finora ho aperto il file normalmente, ho caricato parte del file in un char buffer e poi con un printf %d andavo a leggere le parti che mi interessavano traducendole in numeri interi.

    Tuttavia mi chiedevo se questo procedimento fosse corretto. Forse è più opportuno aprirlo in binary mode? Ma poi come dovrei procedere?

    Grazie e buona domenica!

  2. #2

    Re: [C] Decodificare un file midi...è corretto?

    Originariamente inviato da stejano
    Tuttavia mi chiedevo se questo procedimento fosse corretto. Forse è più opportuno aprirlo in binary mode?
    Sì.
    Ma poi come dovrei procedere?
    Esattamente alla stessa maniera; la differenza tra il binary mode e il text mode è che nel primo ti viene restituito il contenuto del file così com'è, mentre nel secondo i ritorni a capo (che possono variare a seconda della piattaforma su cui ti trovi, ad es. su Windows sono \r\n, su Linux \n, su Mac spesso \r) sono convertiti in un singolo \n. Questa traduzione se devi leggere file di testo è comoda, se devi leggere dati binari è un disastro, perché trasforma sequenze che non vanno trasformate.

    L'alternativa ad andare a leggere "qua e là" a colpi di fseek e fread è di definirti le strutture corrispondenti ai vari "pezzi" del file e leggertele in blocco in memoria, in modo da poter poi lavorare in maniera più comoda con i membri delle strutture.
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Utente di HTML.it
    Registrato dal
    Nov 2005
    Messaggi
    278
    Caspita non ho mai lavorato con file aperti in Binary mode...sono un po' spaesato.

    Cosa intendi con "definirti le strutture rispetto ai vari pezzi del file"?
    Puoi farmi un esempio?

  4. #4
    Originariamente inviato da stejano
    Caspita non ho mai lavorato con file aperti in Binary mode...sono un po' spaesato.
    Guarda che non cambia niente... semplicemente il runtime non trasforma "di nascosto" le sequenze \r\n in \n.
    Cosa intendi con "definirti le strutture rispetto ai vari pezzi del file"?
    Puoi farmi un esempio?
    I byte che trovi in file binari spesso e volentieri sono semplicemente la trascrizione su disco di determinate struct in memoria. Parlando di file MIDI, ad esempio, in testa al file c'è l'header MIDI. Per leggerlo puoi o usare fseek e fread per leggere i campi uno per volta, o definirti la sua struttura tramite una struct (che peraltro credo che gli header di Windows potrebbero già definire) e leggertela in memoria tutta insieme tramite fread:
    codice:
    /* Se si usa roba diversa da interi della dimensione nativa della piattaforma
     è bene usare una direttiva pack (specifica del compilatore) per evitare problemi
     di allineamento dei membri della struttura; qui uso la sintassi VC++ */
    #pragma pack(push, 1)
    struct MIDIHeader
    {
        uint32_t Signature;
        uint32_t HeaderLength;
        uint16_t Format;
        uint16_t TrackChunks;
        uint16_t Division;
    };
    #pragma pack(pop)
    
    /* ... */
    
    fp=fopen(/* ... */);
    /* ... */
    struct MIDIHeader mh;
    if(fread(fp, &mh, sizeof(mh), 1, fp)!=sizeof(mh))
    {
        /* errore di lettura */
        /* ... */
    }
    /* se le cose sono andate a buon fine, in mh ora ci sarà l'header MIDI del file */
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it
    Registrato dal
    Nov 2005
    Messaggi
    278
    ok! Mille grazie, all'inizio ero spaesato poi c'è l'ho fatta a capire e costruire le struct per il file.

    Tuttavia fread() mi legge il codice al contrario!

    Se ad esempio (lo metto in esadecimale così è più semplice capirci) i byte da leggere sono 4D546864 lui legge e stampa a video 6468544d

    Come mai questo errore? Legge al contrario? Come posso risolvere?

    Per stampare a video ho utilizzato un normale printf("stampo %x",mh.signature).

    Ho segnalato quest'ultima cosa perché non vorrei sbagliare io ed invece credo sia fread.

  6. #6
    http://en.wikipedia.org/wiki/Endianness
    Ne devi tenere conto, e, se i file MIDI sono big-endian, devi effettuare le dovute conversioni.
    Amaro C++, il gusto pieno dell'undefined behavior.

  7. #7
    Utente di HTML.it
    Registrato dal
    Nov 2005
    Messaggi
    278
    Oh mamma! Questa non la sapevo!! Tra l'altro i midi sono tutti salvati in big endian per cui vanno sempre convertiti.

    Dopo lo shock iniziale mi sono informato e convertire i byte da Big Endian a little endian non è così complicato.

    Innanzitutto ho aggiunto

    #include <arpa/inet.h>

    quindi

    int newval = htonl(valore originale);

    Attraverso questa funzione è possibile invertire i byte inseriti tra le parentesi da big endian a little endian.

    Non è l'unica soluzione possibile, volendo è possibile ricostruire i byte con una union.

    Altri sistemi ancora non li ho testati. Se li proverò aggiornerò.

    Grazie MItaly!

  8. #8
    Di niente.
    Amaro C++, il gusto pieno dell'undefined behavior.

  9. #9
    Utente di HTML.it
    Registrato dal
    Nov 2005
    Messaggi
    278
    Nell'analisi del file mi si è posto un problema non indifferente.

    Se la struttura del file è fissa ho capito come "analizzarlo", ma se non lo è?

    Per capirci.
    Ho individuato l'header e la posizione di ogni traccia nel file, con la grandezza di byte che occupa ognuna.

    All'interno di ogni traccia però gli eventi possono essere posizionati in punti differenti.
    Generalmente ogni evento può essere di 4 byte o di 3 byte o di 8 byte e possono essere piazzati in un punti differenti della traccia.
    Un esempio:
    Con il byte C1 23 rappresento C (suono) 1 (canale 1) 23 (suono chitarra).
    Con il byte D1 33 rappresento D(effetto) 1(canale 1) 33 (distorsione).

    Considerando che non sono solo di 4 byte, ma anche 3 o 8, come posso fare per leggerli in una traccia non sapendo nemmeno la posizione in cui andarli a beccare? So solo dove inizia la traccia e la sua dimensione.
    Come posso fare per leggerli?

    Personalmente ho pensato di realizzare svariate matrici/vettori (per ogni evento) e quindi confrontarli con cicli for ad un buffer, dopo aver fatto un fread della traccia.

    Cosa ne pensi? Tu come agiresti? Vorrei un consiglio.

  10. #10
    Hmmm... non ho sottomano le specifiche MIDI, ma ci dovrebbe essere un modo per distinguere le dimensioni dei vari eventi. Se esistono diversi tipi di eventi, dovresti fare una struct per ciascun tipo di evento, e quindi potresti creare un'union che contiene tutte queste struct, incapsulata a sua volta in una struct che contenga un enum che segnali quale struttura è effettivamente valorizzata e la union in questione. Mi spiego meglio con un esempio:
    codice:
    struct EventoTipo1
    {
        /* ... */
    };
    
    struct EventoTipo2
    {
        /* ... */
    };
    
    /* ... */
    
    struct EventoTipoN
    {
        /* ... */
    };
    
    union EventoHelper
    {
        struct MessaggioTipo1 m1;
        struct MessaggioTipo2 m2;
        /* ... */
        struct MessaggioTipoN mN;
    };
    
    enum TipoEvento
    {
        Evento1,
        Evento2,
        /* ... */
        EventoN
    };
    
    struct Evento
    {
        enum TipoEvento TE;
        EventoHelper EH;
        /* eventuali info accessorie comuni a tutti gli eventi */
    };
    
    struct Evento EventiTraccia[NUMTRACCE][NUMEVENTI];
    L'uso della union consente di fare sì che tutti i tipi di evento condividano lo stesso spazio di memoria, naturalmente uno solo di questi per volta ha un valore sensato, per cui così minimizzi lo spreco di spazio in memoria.
    Al momento di leggere, una volta determinato il tipo di evento lo leggi nel relativo membro della struttura Evento e segni che tipo di evento è in TE, così, al momento di andare a riguardare il contenuto della struttura Evento, saprai che tipo di evento è e quale membro della union andare a vedere.

    Tutta questa porcheria è una specie di modo per ottenere il polimorfismo in C; in C++ probabilmente si potrebbe gestire la questione in maniera più "pulita".
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.