1 /*****************************************************************************
2 * mod.c: MOD file demuxer (using libmodplug)
3 *****************************************************************************
4 * Copyright (C) 2004-2009 VLC authors and VideoLAN
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 it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * 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>
37 #include <vlc_charset.h>
40 #include <libmodplug/modplug.h>
43 * - extend demux control to query meta data (demuxer should NEVER touch
45 * - FIXME test endian of samples
49 /*****************************************************************************
51 *****************************************************************************/
52 static int Open ( vlc_object_t
* );
53 static void Close ( vlc_object_t
* );
55 #define NOISE_LONGTEXT N_("Enable noise reduction algorithm.")
56 #define REVERB_LONGTEXT N_("Enable reverberation" )
57 #define REVERB_LEVEL_LONGTEXT N_( "Reverberation level (from 0 " \
58 "to 100, default value is 0)." )
59 #define REVERB_DELAY_LONGTEXT N_("Reverberation delay, in ms." \
60 " Usual values are from 40 to 200ms." )
61 #define MEGABASS_LONGTEXT N_( "Enable megabass mode" )
62 #define MEGABASS_LEVEL_LONGTEXT N_("Megabass mode level (from 0 to 100, " \
63 "default value is 0)." )
64 #define MEGABASS_RANGE_LONGTEXT N_("Megabass mode cutoff frequency, in Hz. " \
65 "This is the maximum frequency for which the megabass " \
66 "effect applies. Valid values are from 10 to 100 Hz." )
67 #define SURROUND_LEVEL_LONGTEXT N_( "Surround effect level (from 0 to 100, " \
68 "default value is 0)." )
69 #define SURROUND_DELAY_LONGTEXT N_("Surround delay, in ms. Usual values are " \
74 set_description( N_("MOD demuxer (libmodplug)" ) )
75 set_capability( "demux", 10 )
76 set_category( CAT_INPUT
)
77 set_subcategory( SUBCAT_INPUT_DEMUX
)
79 add_bool( "mod-noisereduction", true, N_("Noise reduction"),
80 NOISE_LONGTEXT
, false )
82 add_bool( "mod-reverb", false, N_("Reverb"),
83 REVERB_LONGTEXT
, false )
84 add_integer_with_range( "mod-reverb-level", 0, 0, 100,
85 N_("Reverberation level"), REVERB_LEVEL_LONGTEXT
, true )
86 add_integer_with_range( "mod-reverb-delay", 40, 0, 1000,
87 N_("Reverberation delay"), REVERB_DELAY_LONGTEXT
, true )
89 add_bool( "mod-megabass", false, N_("Mega bass"),
90 MEGABASS_LONGTEXT
, false )
91 add_integer_with_range( "mod-megabass-level", 0, 0, 100,
92 N_("Mega bass level"), MEGABASS_LEVEL_LONGTEXT
, true )
93 add_integer_with_range( "mod-megabass-range", 10, 10, 100,
94 N_("Mega bass cutoff"), MEGABASS_RANGE_LONGTEXT
, true )
96 add_bool( "mod-surround", false, N_("Surround"), N_("Surround"),
98 add_integer_with_range( "mod-surround-level", 0, 0, 100,
99 N_("Surround level"), SURROUND_LEVEL_LONGTEXT
, true )
100 add_integer_with_range( "mod-surround-delay", 5, 0, 1000,
101 N_("Surround delay (ms)"), SURROUND_DELAY_LONGTEXT
, true )
103 set_callbacks( Open
, Close
)
104 add_shortcut( "mod" )
107 /*****************************************************************************
109 *****************************************************************************/
110 static vlc_mutex_t libmodplug_lock
= VLC_STATIC_MUTEX
;
125 static int Demux ( demux_t
*p_demux
);
126 static int Control( demux_t
*p_demux
, int i_query
, va_list args
);
128 static int Validate( demux_t
*p_demux
, const char *psz_ext
);
130 /* We load the complete file in memory, put a higher bound
131 * of 500 Mo (which is really big anyway) */
132 #define MOD_MAX_FILE_SIZE (500*1000*1000)
134 /*****************************************************************************
136 *****************************************************************************/
137 static int Open( vlc_object_t
*p_this
)
139 demux_t
*p_demux
= (demux_t
*)p_this
;
141 ModPlug_Settings settings
;
143 /* We accept file based on extension match */
144 if( !p_demux
->obj
.force
)
146 const char *psz_ext
= p_demux
->psz_file
? strrchr( p_demux
->psz_file
, '.' )
151 if( Validate( p_demux
, psz_ext
) )
153 msg_Dbg( p_demux
, "MOD validation failed (ext=%s)", psz_ext
? psz_ext
: "");
158 const int64_t i_size
= stream_Size( p_demux
->s
);
159 if( i_size
<= 0 || i_size
>= MOD_MAX_FILE_SIZE
)
162 /* Fill p_demux field */
163 p_demux
->pf_demux
= Demux
;
164 p_demux
->pf_control
= Control
;
165 p_demux
->p_sys
= p_sys
= malloc( sizeof( *p_sys
) );
169 msg_Dbg( p_demux
, "loading complete file (could be long)" );
170 p_sys
->i_data
= i_size
;
171 p_sys
->p_data
= malloc( p_sys
->i_data
);
173 p_sys
->i_data
= vlc_stream_Read( p_demux
->s
, p_sys
->p_data
,
175 if( p_sys
->i_data
<= 0 || !p_sys
->p_data
)
177 msg_Err( p_demux
, "failed to read the complete file" );
178 free( p_sys
->p_data
);
183 /* Configure modplug before loading the file */
184 vlc_mutex_lock( &libmodplug_lock
);
185 ModPlug_GetSettings( &settings
);
186 settings
.mFlags
= MODPLUG_ENABLE_OVERSAMPLING
;
187 settings
.mChannels
= 2;
189 settings
.mFrequency
= 44100;
190 settings
.mResamplingMode
= MODPLUG_RESAMPLE_FIR
;
192 if( var_InheritBool( p_demux
, "mod-noisereduction" ) )
193 settings
.mFlags
|= MODPLUG_ENABLE_NOISE_REDUCTION
;
195 if( var_InheritBool( p_demux
, "mod-reverb" ) )
196 settings
.mFlags
|= MODPLUG_ENABLE_REVERB
;
197 settings
.mReverbDepth
= var_InheritInteger( p_demux
, "mod-reverb-level" );
198 settings
.mReverbDelay
= var_InheritInteger( p_demux
, "mod-reverb-delay" );
200 if( var_InheritBool( p_demux
, "mod-megabass" ) )
201 settings
.mFlags
|= MODPLUG_ENABLE_MEGABASS
;
202 settings
.mBassAmount
= var_InheritInteger( p_demux
, "mod-megabass-level" );
203 settings
.mBassRange
= var_InheritInteger( p_demux
, "mod-megabass-range" );
205 if( var_InheritBool( p_demux
, "mod-surround" ) )
206 settings
.mFlags
|= MODPLUG_ENABLE_SURROUND
;
207 settings
.mSurroundDepth
= var_InheritInteger( p_demux
, "mod-surround-level" );
208 settings
.mSurroundDelay
= var_InheritInteger( p_demux
, "mod-surround-delay" );
210 ModPlug_SetSettings( &settings
);
212 p_sys
->f
= ModPlug_Load( p_sys
->p_data
, p_sys
->i_data
);
213 vlc_mutex_unlock( &libmodplug_lock
);
217 msg_Err( p_demux
, "failed to understand the file" );
218 free( p_sys
->p_data
);
224 date_Init( &p_sys
->pts
, settings
.mFrequency
, 1 );
225 date_Set( &p_sys
->pts
, 0 );
226 p_sys
->i_length
= ModPlug_GetLength( p_sys
->f
) * INT64_C(1000);
228 msg_Dbg( p_demux
, "MOD loaded name=%s length=%"PRId64
"ms",
229 ModPlug_GetName( p_sys
->f
),
232 #ifdef WORDS_BIGENDIAN
233 es_format_Init( &p_sys
->fmt
, AUDIO_ES
, VLC_FOURCC( 't', 'w', 'o', 's' ) );
235 es_format_Init( &p_sys
->fmt
, AUDIO_ES
, VLC_FOURCC( 'a', 'r', 'a', 'w' ) );
237 p_sys
->fmt
.audio
.i_rate
= settings
.mFrequency
;
238 p_sys
->fmt
.audio
.i_channels
= settings
.mChannels
;
239 p_sys
->fmt
.audio
.i_bitspersample
= settings
.mBits
;
240 p_sys
->es
= es_out_Add( p_demux
->out
, &p_sys
->fmt
);
245 /*****************************************************************************
247 *****************************************************************************/
248 static void Close( vlc_object_t
*p_this
)
250 demux_t
*p_demux
= (demux_t
*)p_this
;
251 demux_sys_t
*p_sys
= p_demux
->p_sys
;
253 ModPlug_Unload( p_sys
->f
);
254 free( p_sys
->p_data
);
259 /*****************************************************************************
261 *****************************************************************************/
262 static int Demux( demux_t
*p_demux
)
264 demux_sys_t
*p_sys
= p_demux
->p_sys
;
266 const int i_bk
= ( p_sys
->fmt
.audio
.i_bitspersample
/ 8 ) *
267 p_sys
->fmt
.audio
.i_channels
;
269 p_frame
= block_Alloc( p_sys
->fmt
.audio
.i_rate
/ 10 * i_bk
);
273 const int i_read
= ModPlug_Read( p_sys
->f
, p_frame
->p_buffer
, p_frame
->i_buffer
);
277 block_Release( p_frame
);
280 p_frame
->i_buffer
= i_read
;
282 p_frame
->i_pts
= VLC_TS_0
+ date_Get( &p_sys
->pts
);
285 es_out_SetPCR( p_demux
->out
, p_frame
->i_pts
);
288 es_out_Send( p_demux
->out
, p_sys
->es
, p_frame
);
290 date_Increment( &p_sys
->pts
, i_read
/ i_bk
);
295 /*****************************************************************************
297 *****************************************************************************/
298 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
300 demux_sys_t
*p_sys
= p_demux
->p_sys
;
307 *va_arg( args
, bool * ) = true;
310 case DEMUX_GET_POSITION
:
311 pf
= va_arg( args
, double* );
312 if( p_sys
->i_length
> 0 )
314 double current
= date_Get( &p_sys
->pts
);
315 double length
= p_sys
->i_length
;
316 *pf
= current
/ length
;
321 case DEMUX_SET_POSITION
:
322 f
= va_arg( args
, double );
324 i64
= f
* p_sys
->i_length
;
325 if( i64
>= 0 && i64
<= p_sys
->i_length
)
327 ModPlug_Seek( p_sys
->f
, i64
/ 1000 );
328 date_Set( &p_sys
->pts
, i64
);
335 pi64
= va_arg( args
, int64_t * );
336 *pi64
= date_Get( &p_sys
->pts
);
339 case DEMUX_GET_LENGTH
:
340 pi64
= va_arg( args
, int64_t * );
341 *pi64
= p_sys
->i_length
;
345 i64
= va_arg( args
, int64_t );
347 if( i64
>= 0 && i64
<= p_sys
->i_length
)
349 ModPlug_Seek( p_sys
->f
, i64
/ 1000 );
350 date_Set( &p_sys
->pts
, i64
);
356 case DEMUX_HAS_UNSUPPORTED_META
:
358 bool *pb_bool
= va_arg( args
, bool* );
359 *pb_bool
= false; /* FIXME I am not sure of this one */
364 vlc_meta_t
*p_meta
= va_arg( args
, vlc_meta_t
* );
365 unsigned i_num_samples
= ModPlug_NumSamples( p_sys
->f
),
366 i_num_instruments
= ModPlug_NumInstruments( p_sys
->f
);
367 unsigned i_num_patterns
= ModPlug_NumPatterns( p_sys
->f
),
368 i_num_channels
= ModPlug_NumChannels( p_sys
->f
);
369 // unsigned modType = ModPlug_GetModuleType( p_sys->f );
371 char psz_temp
[2048]; /* 32 * 240 max, but only need start */
372 char *psz_module_info
, *psz_instrument_info
;
373 unsigned i_temp_index
= 0;
374 const char *psz_name
= ModPlug_GetName( p_sys
->f
);
375 if( psz_name
&& *psz_name
&& IsUTF8( psz_name
) )
376 vlc_meta_SetTitle( p_meta
, psz_name
);
378 /* Comment field from artist - not in every type of MOD */
379 psz_name
= ModPlug_GetMessage( p_sys
->f
);
380 if( psz_name
&& *psz_name
&& IsUTF8( psz_name
) )
381 vlc_meta_SetDescription( p_meta
, psz_name
);
383 /* Instruments only in newer MODs - so don't show if 0 */
384 if( asprintf( &psz_instrument_info
, ", %i Instruments",
385 i_num_instruments
) >= 0 )
387 if( asprintf( &psz_module_info
,
388 "%i Channels, %i Patterns\n"
390 i_num_channels
, i_num_patterns
, i_num_samples
,
391 ( i_num_instruments
? psz_instrument_info
: "" ) ) >= 0 )
393 vlc_meta_AddExtra( p_meta
, "Module Information",
395 free( psz_module_info
);
398 free( psz_instrument_info
);
401 /* Make list of instruments (XM, IT, etc) */
402 if( i_num_instruments
)
405 for( unsigned i
= 0; i
< i_num_instruments
&& i_temp_index
< sizeof(psz_temp
); i
++ )
408 ModPlug_InstrumentName( p_sys
->f
, i
, lBuffer
);
409 if ( !lBuffer
[0] || !IsUTF8( lBuffer
) ) continue;
410 i_temp_index
+= snprintf( &psz_temp
[i_temp_index
], sizeof(psz_temp
) - i_temp_index
, "%s\n", lBuffer
);
413 vlc_meta_AddExtra( p_meta
, "Instruments", psz_temp
);
416 /* Make list of samples */
417 for( unsigned int i
= 0; i
< i_num_samples
&& i_temp_index
< sizeof(psz_temp
); i
++ )
420 ModPlug_SampleName( p_sys
->f
, i
, psz_buffer
);
421 if ( !psz_buffer
[0] || !IsUTF8( psz_buffer
) ) continue;
422 i_temp_index
+= snprintf( &psz_temp
[i_temp_index
], sizeof(psz_temp
) - i_temp_index
, "%s\n", psz_buffer
);
425 vlc_meta_AddExtra( p_meta
, "Samples", psz_temp
);
430 case DEMUX_GET_FPS
: /* meaningless */
436 /*****************************************************************************
437 * Validate: try to ensure it is really a mod file.
438 * The tests are not robust enough to replace extension checks in the general
440 * TODO: maybe it should return a score, which will be used to bypass the
441 * extension checks when high enough.
442 *****************************************************************************/
443 static int Validate( demux_t
*p_demux
, const char *psz_ext
)
448 const char *psz_marker
;
450 { 0, "ziRCONia" }, /* MMCMP files */
451 { 0, "Extended Module" }, /* XM */
452 { 44, "SCRM" }, /* S3M */
453 { 0, "IMPM" }, /* IT */
454 { 0, "GF1PATCH110" }, /* PAT */
455 { 20, "!SCREAM!" }, /* STM */
456 { 20, "!Scream!" }, /* STM */
457 { 20, "BMOD2STM" }, /* STM */
458 { 0, "MMD0" }, /* MED v0 */
459 { 0, "MMD1" }, /* MED v1 */
460 { 0, "MMD2" }, /* MED v2 */
461 { 0, "MMD3" }, /* MED v3 */
462 { 0, "MTM" }, /* MTM */
463 { 0, "DMDL" }, /* MDL */
464 { 0, "DBM0" }, /* DBM */
465 { 0, "if" }, /* 669 */
466 { 0, "JN" }, /* 669 */
467 { 0, "FAR\xfe" }, /* FAR */
468 { 0, "Extreme" }, /* AMS */
469 { 0, "OKTASONGCMOD" }, /* OKT */
470 { 44, "PTMF" }, /* PTM */
471 { 0, "MAS_UTrack_V00" }, /* Ult */
472 { 0, "DDMF" }, /* DMF */
473 { 8, "DSMFSONG" }, /* DSM */
474 { 0, "\xc1\x83\x2a\x9e" }, /* UMX */
475 { 0, "ASYLUM Music Format V1.0" }, /* AMF Type 0 */
476 { 0, "AMF" }, /* AMF */
477 { 0, "PSM\xfe" }, /* PSM */
478 { 0, "PSM " }, /* PSM */
479 { 0, "MT20" }, /* MT2 */
481 { 1080, "M.K." }, /* MOD */
500 static const char *ppsz_mod_ext
[] =
502 "mod", "s3m", "xm", "it", "669", "amf", "ams", "dbm", "dmf", "dsm",
503 "far", "mdl", "med", "mtm", "okt", "ptm", "stm", "ult", "umx", "mt2",
506 bool has_valid_extension
= false;
509 for( int i
= 0; ppsz_mod_ext
[i
] != NULL
; i
++ )
511 has_valid_extension
|= !strcasecmp( psz_ext
, ppsz_mod_ext
[i
] );
512 if( has_valid_extension
)
517 const uint8_t *p_peek
;
518 const int i_peek
= vlc_stream_Peek( p_demux
->s
, &p_peek
, 2048 );
522 for( int i
= 0; p_marker
[i
].i_offset
>= 0; i
++ )
524 const char *psz_marker
= p_marker
[i
].psz_marker
;
525 const int i_size
= strlen( psz_marker
);
526 const int i_offset
= p_marker
[i
].i_offset
;
528 if( i_peek
< i_offset
+ i_size
)
531 if( !memcmp( &p_peek
[i_offset
], psz_marker
, i_size
) )
533 if( i_size
>= 4 || has_valid_extension
)
538 /* The only two format left untested are ABC and MOD(old version)
539 * ant they are difficult to test :( */
542 * TODO i_peek = 2048 is too big for such files */
543 if( psz_ext
&& !strcasecmp( psz_ext
, "abc" ) )
548 for( int i
= 0; i
< i_peek
-1; i
++ )
550 b_k
|= p_peek
[i
+0] == 'K' && p_peek
[i
+1] == ':';
551 b_tx
|= ( p_peek
[i
+0] == 'X' || p_peek
[i
+0] == 'T') && p_peek
[i
+1] == ':';
559 if( psz_ext
&& !strcasecmp( psz_ext
, "mod" ) && i_peek
>= 20 + 15 * 30 )
561 /* Check that the name is correctly null padded */
562 const uint8_t *p
= memchr( p_peek
, '\0', 20 );
565 for( ; p
< &p_peek
[20]; p
++ )
572 for( int i
= 0; i
< 15; i
++ )
574 const uint8_t *p_sample
= &p_peek
[20 + i
*30];
576 /* Check correct null padding */
577 p
= memchr( &p_sample
[0], '\0', 22 );
580 for( ; p
< &p_sample
[22]; p
++ )
587 if( p_sample
[25] > 64 ) /* Volume value */