4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 #include <string.h> /*memcmp*/
24 #include <stdlib.h> /*malloc*/
26 #include "mm_file_debug.h"
27 #include "mm_file_utils.h"
28 #include "mm_file_format_private.h"
29 #include "mm_file_format_midi.h"
40 #define MMFILE_XMF_100 "XMF_1.00"
41 #define MMFILE_XMF_101 "XMF_1.01"
42 #define MMFILE_MXMF_200 "XMF_2.00"
43 #define MMFILE_RMF "IREZ"
45 /*--------------------------------------------------------------------------*/
47 /*--------------------------------------------------------------------------*/
48 #define MAX_SMF_MESSAGES 256 /* */
49 #define MAX_SMF_TRACKS 32 /* Should be <= 32 */
50 #define SMF_MAX_GAIN 76 /* - 6[dB] : 90 */
52 #define MINIMUM_LENGTH (20)
54 #define MELODY_MAP (0)
56 #define NUM_OF_MAPS (2)
59 /*--------------------------------------------------------------------------*/
61 /*--------------------------------------------------------------------------*/
63 typedef struct _tagTrack {
64 unsigned long dSmfCmd; /* CMD @ now */
65 unsigned long dSize; /* [byte] 0 means nothing in it. */
66 unsigned char *pbBase; /* NULL means nothing in it. */
67 unsigned long dOffset; /* offset byte */
69 } TRACKINFO, *PTRACKINFO;
71 typedef struct _tagOrderList {
72 struct _tagOrderList *pPrev;
73 struct _tagOrderList *pNext;
76 } ORDERLIST, *PORDERLIST;
78 typedef struct _tagMidInfo {
79 unsigned long dTimeResolution; /* 0..0x7fff */
80 unsigned char *pbText; /* */
81 unsigned long dSizeText; /* */
82 unsigned char *pbTitle; /* */
83 unsigned long dSizeTitle; /* */
84 unsigned char *pbCopyright; /* */
85 unsigned long dSizeCopyright; /* */
86 unsigned long dNumOfTracks; /* 1..32 */
87 unsigned long dSmfFormat; /* 0..1 */
89 long sdTotalTicks; /* Total ticks */
90 long sdDataEndTime; /* (22.10)[ms] */
92 unsigned long dEndFlag; /* */
93 TRACKINFO TrackInfo[MAX_SMF_TRACKS];
95 struct _tagOrderList *pTopOrderList;
96 struct _tagOrderList *pDoneOrderList;
97 struct _tagOrderList *pBottomOrderList;
98 ORDERLIST OrderList[MAX_SMF_TRACKS + 3];
101 /*---------------------------------------------------------------------------*/
103 /*---------------------------------------------------------------------------*/
107 * internal midi parsing functions
109 static bool __AvParseSkipXmf2Mid(unsigned char *pbFile, unsigned long dFSize, unsigned long *skipSize)
111 unsigned long skipVal;
113 for (skipVal = 0; skipVal < dFSize - 3; skipVal++) {
114 if (pbFile[skipVal] == 'M' &&
115 pbFile[skipVal + 1] == 'T' &&
116 pbFile[skipVal + 2] == 'h' &&
117 pbFile[skipVal + 3] == 'd') {
118 debug_msg(RELEASE, "__AvParseSkipForXMF : MThd Header found!\n");
124 debug_error(DEBUG, "MThd header not found\n");
129 static void __AvMidInitializeOrderList(void)
133 for (idx = 1; idx <= MAX_SMF_TRACKS + 1; idx++) {
134 gPi->OrderList[idx].pPrev = &gPi->OrderList[idx - 1];
135 gPi->OrderList[idx].pNext = &gPi->OrderList[idx + 1];
136 gPi->OrderList[idx].dTrack = 0xFF;
137 gPi->OrderList[idx].dTicks = 0xFFFFFFFFL;
139 gPi->OrderList[0].pPrev = NULL;
140 gPi->OrderList[0].pNext = &gPi->OrderList[1];
141 gPi->OrderList[MAX_SMF_TRACKS + 2].pPrev = &gPi->OrderList[MAX_SMF_TRACKS + 1];
142 gPi->OrderList[MAX_SMF_TRACKS + 2].pNext = NULL;
143 gPi->pTopOrderList = &gPi->OrderList[0];
144 gPi->pDoneOrderList = &gPi->OrderList[1];
145 gPi->pBottomOrderList = &gPi->OrderList[MAX_SMF_TRACKS + 2];
148 static void __AvMidSortOrderList(void)
153 pSlot = (gPi->pTopOrderList)->pNext;
154 (pSlot->pPrev)->pNext = pSlot->pNext;
155 (pSlot->pNext)->pPrev = pSlot->pPrev;
156 pSlot->dTicks = ((unsigned long)gPi->TrackInfo[pSlot->dTrack].sdTicks << 5) + pSlot->dTrack;
158 pTerget = pSlot->pNext;
159 while (pTerget != gPi->pDoneOrderList) {
160 if (pSlot->dTicks <= pTerget->dTicks)
162 pTerget = pTerget->pNext;
165 (pTerget->pPrev)->pNext = pSlot;
166 pSlot->pPrev = pTerget->pPrev;
167 pTerget->pPrev = pSlot;
168 pSlot->pNext = pTerget;
171 static void __AvMidInsertOrderList(unsigned long dTrack, long sdTicks)
175 if (gPi->dNumOfTracks == 1)
178 if (((gPi->dEndFlag >> dTrack) & 0x01) == 0)
181 pTerget = gPi->pDoneOrderList->pNext;
182 if (pTerget == gPi->pBottomOrderList)
185 gPi->pDoneOrderList->pNext = pTerget->pNext;
186 (pTerget->pNext)->pPrev = gPi->pDoneOrderList;
188 pTerget->dTrack = dTrack;
189 pTerget->dTicks = ((unsigned long)sdTicks << 5) + dTrack;
190 pTerget->pPrev = gPi->pTopOrderList;
191 pTerget->pNext = (gPi->pTopOrderList)->pNext;
192 ((gPi->pTopOrderList)->pNext)->pPrev = pTerget;
193 (gPi->pTopOrderList)->pNext = pTerget;
195 __AvMidSortOrderList();
198 static void __AvMidRemoveFromOrderList(void)
203 pSlot = (gPi->pTopOrderList)->pNext;
204 (pSlot->pPrev)->pNext = pSlot->pNext;
205 (pSlot->pNext)->pPrev = pSlot->pPrev;
207 pTerget = gPi->pBottomOrderList;
208 (pTerget->pPrev)->pNext = pSlot;
209 pSlot->pPrev = pTerget->pPrev;
210 pTerget->pPrev = pSlot;
211 pSlot->pNext = pTerget;
214 static void __AvMidGetTrackTime(unsigned long dTrack)
220 if (((gPi->dEndFlag >> dTrack) & 0x01) == 0)
223 pMt = &(gPi->TrackInfo[dTrack]);
227 if (pMt->dOffset >= pMt->dSize) {
228 gPi->dEndFlag &= ~(1L << dTrack);
231 dTemp = (unsigned long)pMt->pbBase[pMt->dOffset++];
232 dTime = (dTime << 7) + (dTemp & 0x7f);
233 } while (dTemp >= 0x80);
235 pMt->sdTicks += dTime;
238 static void __AvMidUpdateTrackTime(unsigned long dTrack)
244 if (gPi->dNumOfTracks == 1) {
246 if (((gPi->dEndFlag >> dTrack) & 0x01) == 0)
249 pMt = &(gPi->TrackInfo[dTrack]);
253 if (pMt->dOffset >= pMt->dSize) {
254 gPi->dEndFlag &= ~(1L << dTrack);
257 dTemp = (unsigned long)pMt->pbBase[pMt->dOffset++];
258 dTime = (dTime << 7) + (dTemp & 0x7f);
259 } while (dTemp >= 0x80);
261 pMt->sdTicks += dTime;
264 if (((gPi->dEndFlag >> dTrack) & 0x01) == 0) {
265 __AvMidRemoveFromOrderList();
269 pMt = &(gPi->TrackInfo[dTrack]);
273 if (pMt->dOffset >= pMt->dSize) {
274 gPi->dEndFlag &= ~(1L << dTrack);
275 __AvMidRemoveFromOrderList();
278 dTemp = (unsigned long)pMt->pbBase[pMt->dOffset++];
279 dTime = (dTime << 7) + (dTemp & 0x7f);
280 } while (dTemp >= 0x80);
282 pMt->sdTicks += dTime;
283 __AvMidSortOrderList();
287 static void __AvMidResetTimeInfo(void)
289 unsigned long sdTrack;
294 for (sdTrack = 0; sdTrack < gPi->dNumOfTracks; sdTrack++) {
295 pMt = &(gPi->TrackInfo[sdTrack]);
301 gPi->dEndFlag |= (1L << sdTrack);
304 __AvMidInitializeOrderList();
306 if (gPi->dNumOfTracks > MAX_SMF_TRACKS) {
307 debug_error(DEBUG, "__AvMidResetTimeInfo: Num of tracks is over MAX track number. !!\n");
311 for (sdTrack = 0; sdTrack < gPi->dNumOfTracks; sdTrack++) {
312 __AvMidGetTrackTime(sdTrack);
313 pMt = &(gPi->TrackInfo[sdTrack]);
314 __AvMidInsertOrderList(sdTrack, pMt->sdTicks);
318 static bool __AvMidGetLeastTimeTrack(unsigned long *leastTimeTrack)
322 pTerget = (gPi->pTopOrderList)->pNext;
323 if (pTerget == gPi->pBottomOrderList)
326 *leastTimeTrack = pTerget->dTrack;
330 static void __AvMidInfoInit(void)
336 gPi->pbCopyright = NULL;
337 gPi->dSizeCopyright = 0;
340 static long __AvGetSizeOfFileInfo(void)
348 unsigned long sdTotalTicks = 0;
349 long sdCurrentTime = 0;
350 long sdDelta = (unsigned long)(500 << 10) / gPi->dTimeResolution; /* default=0.5sec */
352 unsigned long dSetup = 0; /* bit0:beat@0, bit1:tempo@0, bit2:GmOn@0, bit3:tempo@1 */
356 long sdNonConductorTime = 0x7FFFFFFF;
357 long sdNonConductorTicks = 0;
358 unsigned long dConductorNote = 0;
361 __AvMidResetTimeInfo();
363 if (gPi->dSmfFormat != 0)
366 while (gPi->dEndFlag != 0) {
367 if ((gPi->dEndFlag == 1) && (sdNonConductorTime == 0x7FFFFFFF)) {
368 sdNonConductorTime = sdCurrentTime;
369 sdNonConductorTicks = sdTotalTicks;
373 if (gPi->dNumOfTracks == 1) {
376 if (!__AvMidGetLeastTimeTrack(&sdTr))
380 mm_file_retvm_if_fails(DEBUG, sdTr < MAX_SMF_TRACKS, -1);
382 pMt = &(gPi->TrackInfo[sdTr]);
384 sdCurrentTime += (pMt->sdTicks - sdTotalTicks) * sdDelta;
385 sdTotalTicks = pMt->sdTicks;
386 if ((sdCurrentTime < 0) || (sdTotalTicks > 0x07FFFFFFL))
389 dCmd = (unsigned long)pMt->pbBase[pMt->dOffset++];
402 switch (dCmd & 0xf0) {
403 case 0x90: /* NoteOn */
404 /* Conductor Track Note Check */
411 case 0xC0: /* Program change */
413 case 0xD0: /* Channel pressure */
423 case 0xF0: /* SysEx */
425 case 0xF7: /* SysEx */
429 dTemp = (unsigned long)pMt->pbBase[pMt->dOffset++];
430 dSize = (dSize << 7) + (dTemp & 0x7f);
431 } while (dTemp >= 0x80);
434 (pMt->pbBase[pMt->dOffset] == 0x7e) &&
435 (pMt->pbBase[pMt->dOffset + 1] == 0x7f) &&
436 (pMt->pbBase[pMt->dOffset + 2] == 0x09) &&
437 (pMt->pbBase[pMt->dOffset + 3] == 0x01)) {
439 if (sdTotalTicks == 0) {
444 pMt->dOffset += dSize;
447 case 0xF1: /* System Msg */
449 case 0xF3: /* System Msg */
453 case 0xF2: /* System Msg */
457 case 0xFF: /* Meta */
458 dCmd2 = (unsigned long)pMt->pbBase[pMt->dOffset++]; /* Meta Command */
459 dSize = 0; /* Size */
461 dTemp = (unsigned long)pMt->pbBase[pMt->dOffset++];
462 dSize = (dSize << 7) + (dTemp & 0x7f);
463 } while (dTemp >= 0x80);
466 case 0x01: /* Text */
467 if (gPi->pbText == NULL) {
468 gPi->pbText = &pMt->pbBase[pMt->dOffset];
469 gPi->dSizeText = dSize;
473 case 0x02: /* Copyright */
474 if (gPi->pbCopyright == NULL) {
475 gPi->pbCopyright = &pMt->pbBase[pMt->dOffset];
476 gPi->dSizeCopyright = dSize;
480 case 0x06: /* Title */
481 if (gPi->pbTitle == NULL) {
482 gPi->pbTitle = &pMt->pbBase[pMt->dOffset];
483 gPi->dSizeTitle = dSize;
488 gPi->dEndFlag &= ~(1L << sdTr);
491 case 0x51: /* Set Tempo */
496 dTime = ((unsigned long)pMt->pbBase[pMt->dOffset] << 16) +
497 ((unsigned long)pMt->pbBase[pMt->dOffset + 1] << 8) +
498 (unsigned long)pMt->pbBase[pMt->dOffset + 2];
499 if ((sdTotalTicks == 0) && (dTime == 250000))
501 if (sdTotalTicks == (unsigned long)gPi->dTimeResolution)
504 sdDelta = (unsigned long)(dTime / (gPi->dTimeResolution > 0 ? gPi->dTimeResolution : 1));
512 case 0x58: /* Set TimeSignature */
513 if ((sdTotalTicks == 0) &&
514 (pMt->pbBase[pMt->dOffset] == 1) &&
515 (pMt->pbBase[pMt->dOffset + 1] == 2)) dSetup |= 0x01;
520 pMt->dOffset += dSize;
527 __AvMidUpdateTrackTime(sdTr);
529 if (dSetup == 0x0F) {
535 if ((dConductorNote != 2) || (gPi->dSmfFormat == 0)) {
536 gPi->sdTotalTicks = sdTotalTicks;
537 gPi->sdDataEndTime = sdCurrentTime;
539 gPi->sdTotalTicks = sdNonConductorTicks;
540 gPi->sdDataEndTime = sdNonConductorTime;
543 if ((gPi->sdDataEndTime >> 10) <= MINIMUM_LENGTH)
546 return gPi->sdDataEndTime;
549 static long __AvCheckSizeOfMidFile(unsigned char *src_fp, unsigned long dFsize)
553 unsigned long dFormat;
554 unsigned long dNumOfTracks;
556 unsigned char *fp = src_fp;
558 while (dFsize >= 22) {
559 dTemp = ((unsigned long)fp[0] << 24) + ((unsigned long)fp[1] << 16) + ((unsigned long)fp[2] << 8) + (unsigned long)fp[3];
560 if (dTemp == 0x4D546864)
566 mm_file_retvm_if_fails(DEBUG, dFsize >= 22, -1);
571 dTemp = ((unsigned long)fp[0] << 24) + ((unsigned long)fp[1] << 16) + ((unsigned long)fp[2] << 8) + (unsigned long)fp[3];
572 mm_file_retvm_if_fails(DEBUG, dTemp == 6, -1);
577 gPi = g_new0(MIDINFO, 1);
579 /*--- Check format -------------------------------------------------*/
580 dFormat = ((unsigned long)fp[0] << 8) + (unsigned long)fp[1];
581 mm_file_retvm_if_fails(DEBUG, dFormat <= 1, -1);
583 /*--- Check number of tracks ---------------------------------------*/
584 dNumOfTracks = ((unsigned long)fp[2] << 8) + (unsigned long)fp[3];
585 mm_file_retvm_if_fails(DEBUG, dNumOfTracks > 0, -1);
586 mm_file_retvm_if_fails(DEBUG, dFormat != 0 || dNumOfTracks == 1, -1);
588 gPi->dNumOfTracks = (dNumOfTracks > MAX_SMF_TRACKS) ? MAX_SMF_TRACKS : dNumOfTracks;
590 /*--- Check Time unit --------------------------------------------*/
591 dTemp = ((unsigned long)fp[4] << 8) + (unsigned long)fp[5];
592 gPi->dTimeResolution = dTemp & 0x7fff;
593 if (((dTemp & 0x8000) != 0) || (gPi->dTimeResolution == 0)) {
594 debug_error(DEBUG, "__AvCheckSizeOfMidFile Error/ Unknown TimeUnit\n");
600 for (i = 0; i < dNumOfTracks; i++) {
601 /*--- Check chunk name --------------------------------------------*/
602 while (dFsize >= 8) {
603 dTemp = ((unsigned long)fp[0] << 24) + ((unsigned long)fp[1] << 16) + ((unsigned long)fp[2] << 8) + (unsigned long)fp[3];
604 if (dTemp == 0x4D54726B)
610 mm_file_retvm_if_fails(DEBUG, dFsize >= 8, -1);
612 /*--- Check size ----------------------------------------------------*/
613 dSize = ((unsigned long)fp[4] << 24) + ((unsigned long)fp[5] << 16) + ((unsigned long)fp[6] << 8) + (unsigned long)fp[7];
615 if (dFsize < (dSize + 8)) {
616 debug_error(DEBUG, "__AvCheckSizeOfMidFile Error/ Bad size [%ld] vs [%ld]\n", dFsize, dSize + 22);
619 gPi->TrackInfo[i].pbBase = &fp[8];
620 gPi->TrackInfo[i].dSize = dSize;
622 dFsize -= (dSize + 8);
624 gPi->dSmfFormat = dFormat;
626 return __AvGetSizeOfFileInfo();
629 static void __AvGetMidiDuration(char *szFileName, MIDI_INFO_SIMPLE *info)
631 unsigned long xmfheaderSkip = 0;
632 MMFileIOHandle *hFile = NULL;
633 unsigned char *pbFile = NULL;
634 unsigned char *pIMYbuf = NULL;
636 int sdCurrentTime = 0;
638 int codecType = AV_DEC_AUDIO_MIDI;
641 if (!szFileName || !info)
645 if (mmfile_open(&hFile, szFileName, MMFILE_RDONLY) != MMFILE_UTIL_SUCCESS) {
646 debug_error(DEBUG, "failed to open\n");
651 dFileSize = mmfile_get_size(hFile);
652 if (dFileSize <= 0) {
653 debug_error(DEBUG, "failed to get file size.\n");
654 goto _RELEASE_RESOURCE;
657 /*alloc read buffer*/
658 pbFile = g_malloc0(dFileSize + 1);
661 if ((readn = mmfile_read(hFile, pbFile, dFileSize)) != dFileSize) {
662 debug_error(DEBUG, "read error. size = %d\n", readn);
663 goto _RELEASE_RESOURCE;
667 if (dFileSize >= 8 && (!(memcmp(pbFile, MMFILE_XMF_100, 8)) ||
668 !(memcmp(pbFile, MMFILE_XMF_101, 8)) ||
669 !(memcmp(pbFile, MMFILE_MXMF_200, 8)))) {
672 codecType = AV_DEC_AUDIO_XMF;
673 } else if (dFileSize >= 4 && !(memcmp(pbFile, MMFILE_RMF, 4))) {
675 codecType = AV_DEC_AUDIO_RMF;
678 codecType = AV_DEC_AUDIO_MIDI;
682 if (codecType == AV_DEC_AUDIO_RMF) {
683 info->duration = sdCurrentTime = 0; /*not yet implemented.*/
684 info->track_num = 1; /*not yet implemented.*/
685 info->is_xmf = is_xmf;
687 /*get duration. XMF/MIDI*/
688 if (codecType == AV_DEC_AUDIO_XMF) {
689 if (!__AvParseSkipXmf2Mid(pbFile, dFileSize, &xmfheaderSkip))
690 goto _RELEASE_RESOURCE;
692 sdCurrentTime = __AvCheckSizeOfMidFile(pbFile + xmfheaderSkip, dFileSize);
694 sdCurrentTime = __AvCheckSizeOfMidFile(pbFile, dFileSize);
697 if (sdCurrentTime < 0) {
698 debug_error(DEBUG, "__AvGetMidiDuration: sdResult's error Code!(%d)\n", sdCurrentTime);
699 goto _RELEASE_RESOURCE;
702 if (sdCurrentTime > 0)
703 sdCurrentTime /= 1000;
705 info->duration = sdCurrentTime;
706 info->track_num = gPi->dNumOfTracks;
707 info->is_xmf = is_xmf;
709 info->title = g_strndup((const char *)gPi->pbTitle, gPi->dSizeTitle);
710 info->copyright = g_strndup((const char *)gPi->pbCopyright, gPi->dSizeCopyright);
711 info->comment = g_strndup((const char *)gPi->pbText, gPi->dSizeText);
719 mmfile_free(pIMYbuf);
722 /* mm plugin interface */
723 int mmfile_format_read_stream_mid(MMFileFormatContext *formatContext);
724 int mmfile_format_read_frame_mid(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
725 int mmfile_format_read_tag_mid(MMFileFormatContext *formatContext);
726 int mmfile_format_close_mid(MMFileFormatContext *formatContext);
729 int mmfile_format_open_mid(MMFileFormatContext *formatContext)
731 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
732 mm_file_retvm_if_fails(DEBUG, formatContext->uriFileName, MMFILE_FORMAT_FAIL);
733 mm_file_retvm_if_fails(DEBUG, MMFileFormatIsValidMID(NULL, formatContext->uriFileName, 0), MMFILE_FORMAT_FAIL);
735 formatContext->ReadStream = mmfile_format_read_stream_mid;
736 formatContext->ReadFrame = mmfile_format_read_frame_mid;
737 formatContext->ReadTag = mmfile_format_read_tag_mid;
738 formatContext->Close = mmfile_format_close_mid;
740 formatContext->videoTotalTrackNum = 0;
741 formatContext->audioTotalTrackNum = 1;
743 formatContext->privateFormatData = NULL;
745 return MMFILE_FORMAT_SUCCESS;
748 int mmfile_format_read_stream_mid(MMFileFormatContext *formatContext)
750 MMFileFormatStream *audioStream = NULL;
751 MIDI_INFO_SIMPLE *info = NULL;
753 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
756 info = mmfile_format_get_midi_infomation(formatContext->uriFileName);
758 formatContext->duration = info->duration;
759 formatContext->videoStreamId = -1;
760 formatContext->videoTotalTrackNum = 0;
761 formatContext->audioTotalTrackNum = info->track_num;
762 formatContext->nbStreams = 1;
764 audioStream = g_new0(MMFileFormatStream, 1);
766 audioStream->streamType = MMFILE_AUDIO_STREAM;
767 audioStream->codecId = (info->is_xmf == 1) ? MM_AUDIO_CODEC_MXMF : MM_AUDIO_CODEC_MIDI;
768 audioStream->bitRate = 0;
769 audioStream->framePerSec = 0;
770 audioStream->width = 0;
771 audioStream->height = 0;
772 audioStream->nbChannel = 1;
773 audioStream->samplePerSec = 0;
774 formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
776 #ifdef __MMFILE_TEST_MODE__
777 mmfile_format_print_contents(formatContext);
780 mmfile_format_free_midi_infomation(info);
781 return MMFILE_FORMAT_SUCCESS;
785 int mmfile_format_read_tag_mid(MMFileFormatContext *formatContext)
787 MIDI_INFO_SIMPLE *info = NULL;
788 const char *locale = MMFileUtilGetLocale();
790 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
793 info = mmfile_format_get_midi_infomation(formatContext->uriFileName);
799 formatContext->title = mmfile_convert_to_utf8(info->title, strlen(info->title), locale);
800 if (formatContext->title == NULL) {
801 debug_warning(DEBUG, "failed to UTF8 convert.\n");
802 formatContext->title = g_strdup(info->title);
806 if (info->copyright) {
807 formatContext->copyright = mmfile_convert_to_utf8(info->copyright, strlen(info->copyright), locale);
808 if (formatContext->copyright == NULL) {
809 debug_warning(DEBUG, "failed to UTF8 convert.\n");
810 formatContext->copyright = g_strdup(info->copyright);
815 formatContext->comment = mmfile_convert_to_utf8(info->comment, strlen(info->comment), locale);
816 if (formatContext->comment == NULL) {
817 debug_warning(DEBUG, "failed to UTF8 convert.\n");
818 formatContext->comment = g_strdup(info->comment);
822 #ifdef __MMFILE_TEST_MODE__
823 mmfile_format_print_contents(formatContext);
826 mmfile_format_free_midi_infomation(info);
827 return MMFILE_FORMAT_SUCCESS;
831 int mmfile_format_read_frame_mid(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
833 debug_error(DEBUG, "error: mmfile_format_read_frame_midi, no handling\n");
835 return MMFILE_FORMAT_FAIL;
839 int mmfile_format_close_mid(MMFileFormatContext *formatContext)
841 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
842 mmfile_free(formatContext->streams[MMFILE_AUDIO_STREAM]);
844 formatContext->ReadStream = NULL;
845 formatContext->ReadFrame = NULL;
846 formatContext->ReadTag = NULL;
847 formatContext->Close = NULL;
849 return MMFILE_FORMAT_SUCCESS;
852 MIDI_INFO_SIMPLE * mmfile_format_get_midi_infomation(char *szFileName)
854 MIDI_INFO_SIMPLE *info = g_new0(MIDI_INFO_SIMPLE, 1);
856 __AvGetMidiDuration(szFileName, info);
861 void mmfile_format_free_midi_infomation(MIDI_INFO_SIMPLE *info)
864 mmfile_free(info->title);
865 mmfile_free(info->copyright);
866 mmfile_free(info->comment);