1 /*****************************************************************************
2 * mod.c: MOD file demuxer (using libmodplug)
3 *****************************************************************************
4 * Copyright (C) 2004-2009 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Konstanty Bialkowski <konstanty@ieee.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_demux.h>
39 #include <libmodplug/modplug.h>
42 * - extend demux control to query meta data (demuxer should NEVER touch
44 * - FIXME test endian of samples
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open ( vlc_object_t
* );
52 static void Close ( vlc_object_t
* );
54 #define NOISE_LONGTEXT N_("Enable noise reduction algorithm.")
55 #define REVERB_LONGTEXT N_("Enable reverberation" )
56 #define REVERB_LEVEL_LONGTEXT N_( "Reverberation level (from 0 " \
57 "to 100, default value is 0)." )
58 #define REVERB_DELAY_LONGTEXT N_("Reverberation delay, in ms." \
59 " Usual values are from to 40 to 200ms." )
60 #define MEGABASS_LONGTEXT N_( "Enable megabass mode" )
61 #define MEGABASS_LEVEL_LONGTEXT N_("Megabass mode level (from 0 to 100, " \
62 "default value is 0)." )
63 #define MEGABASS_RANGE_LONGTEXT N_("Megabass mode cutoff frequency, in Hz. " \
64 "This is the maximum frequency for which the megabass " \
65 "effect applies. Valid values are from 10 to 100 Hz." )
66 #define SURROUND_LEVEL_LONGTEXT N_( "Surround effect level (from 0 to 100, " \
67 "default value is 0)." )
68 #define SURROUND_DELAY_LONGTEXT N_("Surround delay, in ms. Usual values are " \
73 set_description( N_("MOD demuxer (libmodplug)" ) )
74 set_capability( "demux", 10 )
75 set_category( CAT_INPUT
)
76 set_subcategory( SUBCAT_INPUT_DEMUX
)
78 add_bool( "mod-noisereduction", true, N_("Noise reduction"),
79 NOISE_LONGTEXT
, false )
81 add_bool( "mod-reverb", false, N_("Reverb"),
82 REVERB_LONGTEXT
, false )
83 add_integer_with_range( "mod-reverb-level", 0, 0, 100,
84 N_("Reverberation level"), REVERB_LEVEL_LONGTEXT
, true )
85 add_integer_with_range( "mod-reverb-delay", 40, 0, 1000,
86 N_("Reverberation delay"), REVERB_DELAY_LONGTEXT
, true )
88 add_bool( "mod-megabass", false, N_("Mega bass"),
89 MEGABASS_LONGTEXT
, false )
90 add_integer_with_range( "mod-megabass-level", 0, 0, 100,
91 N_("Mega bass level"), MEGABASS_LEVEL_LONGTEXT
, true )
92 add_integer_with_range( "mod-megabass-range", 10, 10, 100,
93 N_("Mega bass cutoff"), MEGABASS_RANGE_LONGTEXT
, true )
95 add_bool( "mod-surround", false, N_("Surround"), N_("Surround"),
97 add_integer_with_range( "mod-surround-level", 0, 0, 100,
98 N_("Surround level"), SURROUND_LEVEL_LONGTEXT
, true )
99 add_integer_with_range( "mod-surround-delay", 5, 0, 1000,
100 N_("Surround delay (ms)"), SURROUND_DELAY_LONGTEXT
, true )
102 set_callbacks( Open
, Close
)
103 add_shortcut( "mod" )
106 /*****************************************************************************
108 *****************************************************************************/
109 static vlc_mutex_t libmodplug_lock
= VLC_STATIC_MUTEX
;
124 static int Demux ( demux_t
*p_demux
);
125 static int Control( demux_t
*p_demux
, int i_query
, va_list args
);
127 static int Validate( demux_t
*p_demux
, const char *psz_ext
);
129 static const char *ppsz_mod_ext
[] =
131 "mod", "s3m", "xm", "it", "669", "amf", "ams", "dbm", "dmf", "dsm",
132 "far", "mdl", "med", "mtm", "okt", "ptm", "stm", "ult", "umx", "mt2",
137 /* We load the complete file in memory, put a higher bound
138 * of 500 Mo (which is really big anyway) */
139 #define MOD_MAX_FILE_SIZE (500*1000*1000)
141 /*****************************************************************************
143 *****************************************************************************/
144 static int Open( vlc_object_t
*p_this
)
146 demux_t
*p_demux
= (demux_t
*)p_this
;
148 ModPlug_Settings settings
;
150 /* We accept file based on extension match */
151 if( !p_demux
->b_force
)
153 if( !p_demux
->psz_file
)
155 const char *psz_ext
= strrchr( p_demux
->psz_file
, '.' );
161 psz_ext
++; /* skip . */
162 for( i
= 0; ppsz_mod_ext
[i
] != NULL
; i
++ )
164 if( !strcasecmp( psz_ext
, ppsz_mod_ext
[i
] ) )
167 if( ppsz_mod_ext
[i
] == NULL
)
169 if( Validate( p_demux
, ppsz_mod_ext
[i
] ) )
171 msg_Warn( p_demux
, "MOD validation failed (ext=%s)", ppsz_mod_ext
[i
]);
174 msg_Dbg( p_demux
, "running MOD demuxer (ext=%s)", ppsz_mod_ext
[i
] );
177 const int64_t i_size
= stream_Size( p_demux
->s
);
178 if( i_size
<= 0 || i_size
>= MOD_MAX_FILE_SIZE
)
181 /* Fill p_demux field */
182 p_demux
->pf_demux
= Demux
;
183 p_demux
->pf_control
= Control
;
184 p_demux
->p_sys
= p_sys
= malloc( sizeof( *p_sys
) );
188 msg_Dbg( p_demux
, "loading complete file (could be long)" );
189 p_sys
->i_data
= i_size
;
190 p_sys
->p_data
= malloc( p_sys
->i_data
);
192 p_sys
->i_data
= stream_Read( p_demux
->s
, p_sys
->p_data
, p_sys
->i_data
);
193 if( p_sys
->i_data
<= 0 || !p_sys
->p_data
)
195 msg_Err( p_demux
, "failed to read the complete file" );
196 free( p_sys
->p_data
);
201 /* Configure modplug before loading the file */
202 vlc_mutex_lock( &libmodplug_lock
);
203 ModPlug_GetSettings( &settings
);
204 settings
.mFlags
= MODPLUG_ENABLE_OVERSAMPLING
;
205 settings
.mChannels
= 2;
207 settings
.mFrequency
= 44100;
208 settings
.mResamplingMode
= MODPLUG_RESAMPLE_FIR
;
210 if( var_InheritBool( p_demux
, "mod-noisereduction" ) )
211 settings
.mFlags
|= MODPLUG_ENABLE_NOISE_REDUCTION
;
213 if( var_InheritBool( p_demux
, "mod-reverb" ) )
214 settings
.mFlags
|= MODPLUG_ENABLE_REVERB
;
215 settings
.mReverbDepth
= var_InheritInteger( p_demux
, "mod-reverb-level" );
216 settings
.mReverbDelay
= var_InheritInteger( p_demux
, "mod-reverb-delay" );
218 if( var_InheritBool( p_demux
, "mod-megabass" ) )
219 settings
.mFlags
|= MODPLUG_ENABLE_MEGABASS
;
220 settings
.mBassAmount
= var_InheritInteger( p_demux
, "mod-megabass-level" );
221 settings
.mBassRange
= var_InheritInteger( p_demux
, "mod-megabass-range" );
223 if( var_InheritBool( p_demux
, "mod-surround" ) )
224 settings
.mFlags
|= MODPLUG_ENABLE_SURROUND
;
225 settings
.mSurroundDepth
= var_InheritInteger( p_demux
, "mod-surround-level" );
226 settings
.mSurroundDelay
= var_InheritInteger( p_demux
, "mod-surround-delay" );
228 ModPlug_SetSettings( &settings
);
230 p_sys
->f
= ModPlug_Load( p_sys
->p_data
, p_sys
->i_data
);
231 vlc_mutex_unlock( &libmodplug_lock
);
235 msg_Err( p_demux
, "failed to understand the file" );
236 /* we try to seek to recover for other plugin */
237 stream_Seek( p_demux
->s
, 0 );
238 free( p_sys
->p_data
);
244 date_Init( &p_sys
->pts
, settings
.mFrequency
, 1 );
245 date_Set( &p_sys
->pts
, 0 );
246 p_sys
->i_length
= ModPlug_GetLength( p_sys
->f
) * INT64_C(1000);
248 msg_Dbg( p_demux
, "MOD loaded name=%s lenght=%"PRId64
"ms",
249 ModPlug_GetName( p_sys
->f
),
252 #ifdef WORDS_BIGENDIAN
253 es_format_Init( &p_sys
->fmt
, AUDIO_ES
, VLC_FOURCC( 't', 'w', 'o', 's' ) );
255 es_format_Init( &p_sys
->fmt
, AUDIO_ES
, VLC_FOURCC( 'a', 'r', 'a', 'w' ) );
257 p_sys
->fmt
.audio
.i_rate
= settings
.mFrequency
;
258 p_sys
->fmt
.audio
.i_channels
= settings
.mChannels
;
259 p_sys
->fmt
.audio
.i_bitspersample
= settings
.mBits
;
260 p_sys
->es
= es_out_Add( p_demux
->out
, &p_sys
->fmt
);
265 /*****************************************************************************
267 *****************************************************************************/
268 static void Close( vlc_object_t
*p_this
)
270 demux_t
*p_demux
= (demux_t
*)p_this
;
271 demux_sys_t
*p_sys
= p_demux
->p_sys
;
273 ModPlug_Unload( p_sys
->f
);
274 free( p_sys
->p_data
);
279 /*****************************************************************************
281 *****************************************************************************/
282 static int Demux( demux_t
*p_demux
)
284 demux_sys_t
*p_sys
= p_demux
->p_sys
;
286 const int i_bk
= ( p_sys
->fmt
.audio
.i_bitspersample
/ 8 ) *
287 p_sys
->fmt
.audio
.i_channels
;
289 p_frame
= block_New( p_demux
, p_sys
->fmt
.audio
.i_rate
/ 10 * i_bk
);
293 const int i_read
= ModPlug_Read( p_sys
->f
, p_frame
->p_buffer
, p_frame
->i_buffer
);
297 block_Release( p_frame
);
300 p_frame
->i_buffer
= i_read
;
302 p_frame
->i_pts
= VLC_TS_0
+ date_Get( &p_sys
->pts
);
305 es_out_Control( p_demux
->out
, ES_OUT_SET_PCR
, p_frame
->i_pts
);
308 es_out_Send( p_demux
->out
, p_sys
->es
, p_frame
);
310 date_Increment( &p_sys
->pts
, i_read
/ i_bk
);
315 /*****************************************************************************
317 *****************************************************************************/
318 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
320 demux_sys_t
*p_sys
= p_demux
->p_sys
;
326 case DEMUX_GET_POSITION
:
327 pf
= (double*) va_arg( args
, double* );
328 if( p_sys
->i_length
> 0 )
330 double current
= date_Get( &p_sys
->pts
);
331 double length
= p_sys
->i_length
;
332 *pf
= current
/ length
;
337 case DEMUX_SET_POSITION
:
338 f
= (double) va_arg( args
, double );
340 i64
= f
* p_sys
->i_length
;
341 if( i64
>= 0 && i64
<= p_sys
->i_length
)
343 ModPlug_Seek( p_sys
->f
, i64
/ 1000 );
344 date_Set( &p_sys
->pts
, i64
);
351 pi64
= (int64_t*)va_arg( args
, int64_t * );
352 *pi64
= date_Get( &p_sys
->pts
);
355 case DEMUX_GET_LENGTH
:
356 pi64
= (int64_t*)va_arg( args
, int64_t * );
357 *pi64
= p_sys
->i_length
;
361 i64
= (int64_t)va_arg( args
, int64_t );
363 if( i64
>= 0 && i64
<= p_sys
->i_length
)
365 ModPlug_Seek( p_sys
->f
, i64
/ 1000 );
366 date_Set( &p_sys
->pts
, i64
);
372 case DEMUX_HAS_UNSUPPORTED_META
:
374 bool *pb_bool
= (bool*)va_arg( args
, bool* );
375 *pb_bool
= false; /* FIXME I am not sure of this one */
380 vlc_meta_t
*p_meta
= (vlc_meta_t
*)va_arg( args
, vlc_meta_t
* );
381 unsigned i_num_samples
= ModPlug_NumSamples( p_sys
->f
),
382 i_num_instruments
= ModPlug_NumInstruments( p_sys
->f
);
383 unsigned i_num_patterns
= ModPlug_NumPatterns( p_sys
->f
),
384 i_num_channels
= ModPlug_NumChannels( p_sys
->f
);
385 // unsigned modType = ModPlug_GetModuleType( p_sys->f );
387 char psz_temp
[2048]; /* 32 * 240 max, but only need start */
388 char *psz_module_info
, *psz_instrument_info
;
389 unsigned i_temp_index
= 0;
390 const char *psz_name
= ModPlug_GetName( p_sys
->f
);
391 if( psz_name
&& *psz_name
)
392 vlc_meta_SetTitle( p_meta
, psz_name
);
394 /* Comment field from artist - not in every type of MOD */
395 psz_name
= ModPlug_GetMessage( p_sys
->f
);
396 if( psz_name
&& *psz_name
)
397 vlc_meta_SetDescription( p_meta
, psz_name
);
399 /* Instruments only in newer MODs - so don't show if 0 */
400 if( asprintf( &psz_instrument_info
, ", %i Instruments",
401 i_num_instruments
) >= 0 )
403 if( asprintf( &psz_module_info
,
404 "%i Channels, %i Patterns\n"
406 i_num_channels
, i_num_patterns
, i_num_samples
,
407 ( i_num_instruments
? psz_instrument_info
: "" ) ) >= 0 )
409 vlc_meta_AddExtra( p_meta
, "Module Information",
411 free( psz_module_info
);
414 free( psz_instrument_info
);
417 /* Make list of instruments (XM, IT, etc) */
418 if( i_num_instruments
)
421 for( unsigned i
= 0; i
< i_num_instruments
&& i_temp_index
< sizeof(psz_temp
); i
++ )
424 ModPlug_InstrumentName( p_sys
->f
, i
, lBuffer
);
425 if ( !lBuffer
[0] ) continue; // don't add empty fields.
426 i_temp_index
+= snprintf( &psz_temp
[i_temp_index
], sizeof(psz_temp
) - i_temp_index
, "%s\n", lBuffer
);
429 vlc_meta_AddExtra( p_meta
, "Instruments", psz_temp
);
432 /* Make list of samples */
433 for( unsigned int i
= 0; i
< i_num_samples
&& i_temp_index
< sizeof(psz_temp
); i
++ )
436 ModPlug_SampleName( p_sys
->f
, i
, psz_buffer
);
437 if ( !psz_buffer
[0] ) continue; // don't add empty fields.
438 i_temp_index
+= snprintf( &psz_temp
[i_temp_index
], sizeof(psz_temp
) - i_temp_index
, "%s\n", psz_buffer
);
441 vlc_meta_AddExtra( p_meta
, "Samples", psz_temp
);
446 case DEMUX_GET_FPS
: /* meaningless */
452 /*****************************************************************************
453 * Validate: try to ensure it is really a mod file.
454 * The tests are not robust enough to replace extension checks in the general
456 * TODO: maybe it should return a score, which will be used to bypass the
457 * extension checks when high enough.
458 *****************************************************************************/
459 static int Validate( demux_t
*p_demux
, const char *psz_ext
)
464 const char *psz_marker
;
466 { 0, "ziRCONia" }, /* MMCMP files */
467 { 0, "Extended Module" }, /* XM */
468 { 44, "SCRM" }, /* S3M */
469 { 0, "IMPM" }, /* IT */
470 { 0, "MThd" }, /* MID */
471 { 0, "GF1PATCH110" }, /* PAT */
472 { 20, "!SCREAM!" }, /* STM */
473 { 20, "!Scream!" }, /* STM */
474 { 20, "BMOD2STM" }, /* STM */
475 { 0, "MMD0" }, /* MED v0 */
476 { 0, "MMD1" }, /* MED v1 */
477 { 0, "MMD2" }, /* MED v2 */
478 { 0, "MMD3" }, /* MED v3 */
479 { 0, "MTM" }, /* MTM */
480 { 0, "DMDL" }, /* MDL */
481 { 0, "DBM0" }, /* DBM */
482 { 0, "if" }, /* 669 */
483 { 0, "JN" }, /* 669 */
484 { 0, "FAR\xfe" }, /* FAR */
485 { 0, "Extreme" }, /* AMS */
486 { 0, "OKTASONGCMOD" }, /* OKT */
487 { 44, "PTMF" }, /* PTM */
488 { 0, "MAS_UTrack_V00" }, /* Ult */
489 { 0, "DDMF" }, /* DMF */
490 { 8, "DSMFSONG" }, /* DSM */
491 { 0, "\xc1\x83\x2a\x9e" }, /* UMX */
492 { 0, "ASYLUM Music Format V1.0" }, /* AMF Type 0 */
493 { 0, "AMF" }, /* AMF */
494 { 0, "PSM\xfe" }, /* PSM */
495 { 0, "PSM " }, /* PSM */
496 { 0, "MT20" }, /* MT2 */
498 { 1080, "M.K." }, /* MOD */
514 const uint8_t *p_peek
;
515 const int i_peek
= stream_Peek( p_demux
->s
, &p_peek
, 2048 );
519 for( int i
= 0; p_marker
[i
].i_offset
>= 0; i
++ )
521 const char *psz_marker
= p_marker
[i
].psz_marker
;
522 const int i_size
= strlen( psz_marker
);
523 const int i_offset
= p_marker
[i
].i_offset
;
525 if( i_peek
< i_offset
+ i_size
)
528 if( !memcmp( &p_peek
[i_offset
], psz_marker
, i_size
) )
532 /* The only two format left untested are ABC and MOD(old version)
533 * ant they are difficult to test :( */
536 * TODO i_peek = 2048 is too big for such files */
537 if( !strcasecmp( psz_ext
, "abc" ) )
542 for( int i
= 0; i
< i_peek
-1; i
++ )
544 b_k
|= p_peek
[i
+0] == 'K' && p_peek
[i
+1] == ':';
545 b_tx
|= ( p_peek
[i
+0] == 'X' || p_peek
[i
+0] == 'T') && p_peek
[i
+1] == ':';
553 if( !strcasecmp( psz_ext
, "mod" ) && i_peek
>= 20 + 15 * 30 )
555 /* Check that the name is correctly null padded */
556 const uint8_t *p
= memchr( p_peek
, '\0', 20 );
559 for( ; p
< &p_peek
[20]; p
++ )
566 for( int i
= 0; i
< 15; i
++ )
568 const uint8_t *p_sample
= &p_peek
[20 + i
*30];
570 /* Check correct null padding */
571 const uint8_t *p
= memchr( &p_sample
[0], '\0', 22 );
574 for( ; p
< &p_sample
[22]; p
++ )
581 if( p_sample
[25] > 64 ) /* Volume value */