//test.cpp //(c)2005 David Sporn //================================================== #include #include #define FILE_NAME ("dreams.mid") //#define FILE_NAME ("la_lettre.MID") #define FILE_MODE ("rb") #define BUFFER_SIZE (100000) #define CHUNK_START_OFFSET (8) #define FILE_HEADER_MIN_SIZE (6) #define TRACK_HEADER_MIN_SIZE (1) #define MAX_SIZE_DELTA_TIME (5) #define MAX_EVENT_PER_TRACKS (10) #define ERROR_NOT_MIDI_FILE ("Le fichier n'est pas au format Midi 1.0") //retourne la taille de l'entete si c'est un fichier midi gint checkFileHeader(guint8* buffer) { if (!(('M' == buffer[0]) && ('T' == buffer[1]) && ('h' == buffer[2]) && ('d' == buffer[3]))) { g_message("Head start : %2x %2x %2x %2x", buffer[0], buffer[1], buffer[2], buffer[3]) ; return 0 ; } else { gint header_size = ((gint)buffer[4]) << 24 | ((gint)buffer[5]) << 16 | ((gint)buffer[6]) << 8 | ((gint)buffer[7]) ; if (FILE_HEADER_MIN_SIZE > header_size) { g_message("Size : %2x %2x %2x %2x", buffer[4], buffer[5], buffer[6], buffer[7]) ; return 0 ; } return header_size ; } } gint checkTrackHeader(guint8* buffer) { if (!(('M' == buffer[0]) && ('T' == buffer[1]) && ('r' == buffer[2]) && ('k' == buffer[3]))) { g_message("Head start : %2x %2x %2x %2x", buffer[0], buffer[1], buffer[2], buffer[3]) ; return 0 ; } else { gint header_size = ((gint)buffer[4]) << 24 | ((gint)buffer[5]) << 16 | ((gint)buffer[6]) << 8 | ((gint)buffer[7]) ; if (TRACK_HEADER_MIN_SIZE > header_size) { g_message("Size : %2x %2x %2x %2x", buffer[4], buffer[5], buffer[6], buffer[7]) ; return 0 ; } return header_size ; } } gint read16(guint8* buffer) { gint read_int = ((gint)buffer[0]) << 8 | ((gint)buffer[1]) ; return read_int ; } //Au retour, length contiendra la longueur lue, 0 en cas d'erreur. guint readDeltaTime(guint8* buffer, gint *length) { guint delta_time = 0 ; for (gint local_cursor = 0 ; local_cursor < MAX_SIZE_DELTA_TIME ; local_cursor++) { guint time_part = (guint)(buffer[local_cursor] & 0x7F) ; guint end_part = (guint)(buffer[local_cursor] >> 7) ; delta_time |= time_part ; if (!end_part) { (*length) = local_cursor + 1 ; return delta_time ; break ; } delta_time = delta_time << 7 ; } g_message("Delta time : %2x %2x %2x %2x %2x", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]) ; (*length) = 0 ; return 0 ; } //Retourne le nombre d'octets lus, 0 en cas d'erreur. guint readEvent(guint8* buffer, guint deltaTime, gint limit) { guint8 op_code = buffer[0] >> 4 ; switch(op_code) { case 0x8: g_message("%8d === Trk:%2d, Note:%3d, Vel:%3d, Note Off", deltaTime, buffer[0] & 0xF, buffer[1], buffer[2]) ; return 3 ; break; case 0x9: g_message("%8d === Trk:%2d, Note:%3d, Vel:%3d, Note On", deltaTime, buffer[0] & 0xF, buffer[1], buffer[2]) ; return 3 ; break; case 0xa: g_message("%8d === Trk:%2d, Note:%3d, Vel:%3d, Key After-touch", deltaTime, buffer[0] & 0xF, buffer[1], buffer[2]) ; return 3 ; break; case 0xb: g_message("%8d === Trk:%2d, CC: %3d, Val:%3d, Control Change", deltaTime, buffer[0] & 0xF, buffer[1], buffer[2]) ; return 3 ; break; case 0xc: g_message("%8d === Trk:%2d, Prog:%3d, Program change", deltaTime, buffer[0] & 0xF, buffer[1]) ; return 2 ; break; case 0xd: g_message("%8d === Trk:%2d, Chan:%3d, Channel After-touch", deltaTime, buffer[0] & 0xF, buffer[1]) ; return 2 ; break; case 0xe: { guint pitch_value = ((guint)(buffer[2] & 0x7f))<< 7 | ((guint)(buffer[1] & 0x7f)) ; g_message("%8d === Trk:%2d, Eff:%4x, Pitch wheel change", deltaTime, buffer[0] & 0xF, pitch_value) ; } return 3 ; break; case 0xf: g_message("%8d === Special Message (%2x)", deltaTime, buffer[0]) ; return 0 ; break; default: g_message("%8d === Running command (%2x)...", deltaTime, buffer[0]) ; return 0 ; } return 0 ; } int main(int argumentCount, void * argumentVector) { if (g_file_test(FILE_NAME, G_FILE_TEST_EXISTS)) { g_message("Ouverture du fichier %s", FILE_NAME) ; FILE* loaded_file = fopen(FILE_NAME, FILE_MODE); g_message("Lecture du fichier ...") ; guint8 temp_buffer[BUFFER_SIZE] ; gint byte_read = fread(temp_buffer, sizeof(guint8), BUFFER_SIZE, loaded_file) ; g_message("Octets lus : %d", byte_read) ; g_message("Parcours de l'entete ...") ; gint header_size = checkFileHeader(temp_buffer) ; if (0 < header_size) { g_message("Taille entete = %d octets", header_size) ; gint stack_cursor = CHUNK_START_OFFSET ; gint file_type = read16(&temp_buffer[stack_cursor]) ; stack_cursor += 2 ; g_message("Type = %d", file_type) ; gint track_count = read16(&temp_buffer[stack_cursor]) ; stack_cursor += 2 ; g_message("Nombre de pistes = %d", track_count) ; gint ticks_per_delta_time = read16(&temp_buffer[stack_cursor]) ; stack_cursor += 2 ; g_message("Tics par unites de temps = %d", ticks_per_delta_time) ; for (gint track_cursor = 0 ; track_cursor < track_count && stack_cursor < byte_read ; track_cursor++) { g_message("Examen piste %d", track_cursor) ; gint track_offset = stack_cursor ; gint track_size = checkTrackHeader(&temp_buffer[track_offset]) ; gint track_end = track_offset + CHUNK_START_OFFSET + track_size ; stack_cursor += CHUNK_START_OFFSET ; g_message("Taille piste = %d octets", track_size) ; g_message("Debut piste : %2x %2x %2x %2x %2x %2x %2x %2x", temp_buffer[stack_cursor + 0], temp_buffer[stack_cursor + 1], temp_buffer[stack_cursor + 2], temp_buffer[stack_cursor + 3], temp_buffer[stack_cursor + 4], temp_buffer[stack_cursor + 5], temp_buffer[stack_cursor + 6], temp_buffer[stack_cursor + 7], temp_buffer[stack_cursor + 8]) ; for (gint event_count = 0 ; event_count < MAX_EVENT_PER_TRACKS && stack_cursor < track_end && stack_cursor < byte_read; event_count) { gint size_delta = 0 ; guint delta_time = readDeltaTime(&temp_buffer[stack_cursor], &size_delta) ; g_message("Taille delta = %d", size_delta) ; if (0 == size_delta) { break ; } stack_cursor += size_delta ; gint event_size = readEvent(&temp_buffer[stack_cursor], delta_time, track_end-stack_cursor) ; if (0 == event_size) { break ; } } //Place the cursor to the end stack_cursor = track_offset + CHUNK_START_OFFSET + track_size; } } else { g_error(ERROR_NOT_MIDI_FILE) ; } g_message("Fermeture du fichier %s", FILE_NAME) ; fclose(loaded_file) ; g_message("Fin du programme") ; } else { g_message("Fichier inexistant : %s", FILE_NAME) ; } }