You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
7.2KB

  1. // foo_input_tfmx.cpp : Defines the exported functions for the DLL application.
  2. //
  3. #include <stdafx.h>
  4. #define MYVERSION "0.11"
  5. /*
  6. change log
  7. 2018-01-30 08:37 UTC - kode54
  8. - Updated to version 1.4 SDK
  9. - Version is now 0.11
  10. 2012-12-14 00:24 UTC - kode54
  11. - Added more extensions to the shell integration list
  12. - Version is now 0.10
  13. 2012-02-19 19:55 UTC - kode54
  14. - Added abort check to decoder
  15. - Version is now 0.9
  16. 2012-01-01 22:59 UTC - kode54
  17. - Fixed sample file extension case sensitivity issues
  18. - Version is now 0.8
  19. 2011-12-31 18:51 UTC - kode54
  20. - Rolled back all changes since 0.5
  21. - Version is now 0.7
  22. 2011-12-31 17:55 UTC - kode54
  23. - Fixed loop detection for files which don't actually loop
  24. - Skip any non-ending or frozen songs
  25. 2011-12-31 16:59 UTC - kode54
  26. - Changed default length to loop count, with actual length detection
  27. - Version is now 0.6
  28. 2011-03-23 02:45 UTC - kode54
  29. - Implemented file stats collection properly for file size and modification time reporting
  30. - Version is now 0.5
  31. 2011-03-15 19:40 UTC - kode54
  32. - Worked around an issue with wave seekbar
  33. - Version is now 0.4
  34. 2011-03-15 07:11 UTC - kode54
  35. - Fixed stereo separation and changed default to 83%
  36. - Version is now 0.3
  37. 2011-03-15 06:56 UTC - kode54
  38. - Hard coded untagged files to 16 subsongs
  39. - Version is now 0.2
  40. 2011-03-15 05:35 UTC - kode54
  41. - Initial release ready
  42. - Version is now 0.1
  43. 2011-03-15 00:16 UTC - kode54
  44. - Created project and imported old player code
  45. */
  46. //static const char *compat_txt[4]={"default (Turrican ][ and most of other stuff)","old (Turrican 1, R-Type, X-Out)","emulate other TFMX players","new (Turrican 3)"};
  47. extern advconfig_integer_factory cfg_sample_rate;
  48. static bool tfmx_test_filename(const char * full_path,const char * extension)
  49. {
  50. int n = pfc::scan_filename( full_path );
  51. if (n>0)
  52. {
  53. if (!strnicmp(full_path+n,"mdat.",5)) return true;
  54. if (!strnicmp(full_path+n,"tfmx.",5)) return true;
  55. }
  56. return !stricmp(extension,"MDAT") || !stricmp(extension,"TFM") || !stricmp(extension,"TFMX") || !stricmp(extension,"TFX");
  57. }
  58. class input_tfmx : public input_stubs
  59. {
  60. CTFMXSource * p_src;
  61. pfc::string8 m_path;
  62. t_filestats m_stats;
  63. int sample_rate;
  64. bool first_frame;
  65. public:
  66. input_tfmx()
  67. {
  68. p_src = 0;
  69. }
  70. ~input_tfmx()
  71. {
  72. delete p_src;
  73. }
  74. void open( service_ptr_t<file> m_file, const char * p_path, t_input_open_reason p_reason, abort_callback & p_abort )
  75. {
  76. if ( p_reason == input_open_info_write ) throw exception_io_data();
  77. if ( m_file.is_empty() ) filesystem::g_open( m_file, p_path, filesystem::open_mode_read, p_abort );
  78. m_stats = m_file->get_stats( p_abort );
  79. p_src = new CTFMXSource();
  80. if ( p_src->Open( m_file, p_path, 0, p_abort ) ) throw exception_io_data();
  81. m_path = p_path;
  82. }
  83. unsigned get_subsong_count()
  84. {
  85. return ( p_src->tag ) ? p_src->tag->songs.get_count() : 16;
  86. }
  87. t_uint32 get_subsong( unsigned p_index )
  88. {
  89. return p_index;
  90. }
  91. void get_info( t_uint32 p_subsong, file_info & p_info, abort_callback & p_abort )
  92. {
  93. p_info.info_set( "codec", "TFMX" );
  94. p_info.info_set_int( "channels", 2 );
  95. p_info.info_set_int( "tfmx_channels", p_src->multimode ? 7 : 4 );
  96. bool has_length = false;
  97. bool has_title = false;
  98. double length;
  99. if ( p_src->tag )
  100. {
  101. if ( !p_src->tag->artist.is_empty() )
  102. p_info.meta_set( "artist", pfc::stringcvt::string_utf8_from_ansi( p_src->tag->artist ) );
  103. if ( !p_src->tag->album.is_empty() )
  104. p_info.meta_set( "album", pfc::stringcvt::string_utf8_from_ansi( p_src->tag->album ) );
  105. if ( !p_src->tag->comment.is_empty() )
  106. p_info.meta_set( "comment", pfc::stringcvt::string_utf8_from_ansi( p_src->tag->comment ) );
  107. if ( !p_src->tag->date.is_empty() )
  108. p_info.meta_set( "date", pfc::stringcvt::string_utf8_from_ansi( p_src->tag->date ) );
  109. SONG * song = p_src->tag->find_song( p_subsong );
  110. if (song)
  111. {
  112. length = (double) ( song->len + song->fade ) * 0.001;
  113. has_length = song->len || song->fade;
  114. if ( !song->title.is_empty() )
  115. {
  116. has_title = true;
  117. p_info.meta_set( "title", pfc::stringcvt::string_utf8_from_ansi( song->title ) );
  118. }
  119. }
  120. if ( !has_title && !p_src->tag->title.is_empty() )
  121. {
  122. has_title = true;
  123. p_info.meta_set( "title", pfc::stringcvt::string_utf8_from_ansi( p_src->tag->title ) );
  124. }
  125. }
  126. if ( !has_title )
  127. {
  128. t_size n = m_path.scan_filename();
  129. if ( n > 0 )
  130. {
  131. if (!strnicmp(m_path+n,"mdat.",5)) has_title = true;
  132. else if (!strnicmp(m_path+n,"tfmx.",5)) has_title = true;
  133. if ( has_title )
  134. {
  135. p_info.meta_set( "title", m_path + n + 5 );
  136. }
  137. }
  138. }
  139. if ( !has_length )
  140. {
  141. length = p_src->GetLength();
  142. }
  143. p_info.set_length( length );
  144. }
  145. t_filestats get_file_stats( abort_callback & p_abort )
  146. {
  147. return m_stats;
  148. }
  149. void decode_initialize( t_uint32 p_subsong, unsigned p_flags, abort_callback & p_abort )
  150. {
  151. p_src->cur_song = p_subsong;
  152. p_src->init_song();
  153. if ( p_flags & input_flag_no_looping ) p_src->has_len = true;
  154. first_frame = true;
  155. sample_rate = 0;
  156. }
  157. bool decode_run( audio_chunk & p_chunk,abort_callback & p_abort )
  158. {
  159. p_abort.check();
  160. p_chunk.set_data_size( 1024 * 2 );
  161. int n = p_src->GetSamples( p_chunk.get_data(), 1024, &sample_rate );
  162. if ( !n ) return false;
  163. p_chunk.set_sample_count( n );
  164. p_chunk.set_srate( sample_rate );
  165. p_chunk.set_channels( 2 );
  166. return true;
  167. }
  168. void decode_seek( double p_seconds, abort_callback & p_abort )
  169. {
  170. first_frame = true;
  171. sample_rate = 0;
  172. p_src->SetPosition( p_seconds );
  173. }
  174. bool decode_can_seek()
  175. {
  176. return true;
  177. }
  178. bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta )
  179. {
  180. if ( first_frame )
  181. {
  182. first_frame = false;
  183. if ( !sample_rate )
  184. {
  185. sample_rate = cfg_sample_rate.get();
  186. console::formatter() << "[foo_input_tfmx] Somebody called decode_get_dynamic_info without calling decode_run first";
  187. }
  188. p_out.info_set_int( "samplerate", sample_rate );
  189. p_timestamp_delta = 0;
  190. return true;
  191. }
  192. return false;
  193. }
  194. bool decode_get_dynamic_info_track( file_info & p_out, double & p_timestamp_delta )
  195. {
  196. return false;
  197. }
  198. void decode_on_idle( abort_callback & p_abort )
  199. {
  200. }
  201. void retag_set_info( t_uint32 p_subsong, const file_info & p_info, abort_callback & p_abort )
  202. {
  203. throw exception_io_unsupported_format();
  204. }
  205. void retag_commit( abort_callback & p_abort )
  206. {
  207. throw exception_io_unsupported_format();
  208. }
  209. static bool g_is_our_content_type( const char * p_content_type )
  210. {
  211. return false;
  212. }
  213. static bool g_is_our_path( const char * p_path, const char * p_extension )
  214. {
  215. return tfmx_test_filename( p_path, p_extension );
  216. }
  217. static GUID g_get_guid()
  218. {
  219. return { 0x6906c288, 0x2813, 0x4b61,{ 0x89, 0x7a, 0xf8, 0x19, 0xc1, 0xee, 0x44, 0x6d } };
  220. }
  221. static const char * g_get_name()
  222. {
  223. return "TFMX decoder";
  224. }
  225. };
  226. static input_factory_t<input_tfmx> g_input_tfmx_factory;
  227. DECLARE_FILE_TYPE("TFMX files", "*.TFM;*.TFMX;*.TFX;*.MDAT");
  228. DECLARE_COMPONENT_VERSION("TFMX decoder",MYVERSION,"MDAT.*;TFMX.*;*.MDAT;*.TFM;*.TFMX;*.TFX");
  229. VALIDATE_COMPONENT_FILENAME("foo_input_tfmx.dll");