1 /*  Festalon - NSF Player
2  *  Copyright (C) 2004 Xodnizel
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 
19 #ifdef INTERFACE_BMP
20 #include <bmp/plugin.h>
21 #include <bmp/util.h>
22 #else
23 #include <xmms/plugin.h>
24 #include <xmms/util.h>
25 #endif
26 
27 #include <pthread.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include "../driver.h"
33 
34 static FESTALON *Player = NULL;
35 
36 #define CMD_SEEK	0x8000
37 #define CMD_STOP	0x4000
38 
39 static volatile uint32 command=0;
40 static uint32 current;
41 static volatile int playing=0;
42 
43 extern InputPlugin festa_ip;
44 
get_iplugin_info(void)45 InputPlugin *get_iplugin_info(void)
46       {
47          festa_ip.description = "Festalon NSF Plugin v"FESTALON_VERSION;
48          return &festa_ip;
49       }
50 
init(void)51 void init(void)
52 {
53 }
about(void)54 void about(void)
55 {
56 
57 }
config(void)58 void config(void)
59 {
60 
61 }
62 
testfile(char * fn)63 int testfile(char *fn)
64 {
65  char buf[5];
66  FILE *fp;
67 
68  if(!(fp=fopen(fn,"rb"))) return(0);
69  if(fread(buf,1,5,fp)!=5) {fclose(fp);return(0);}
70  fclose(fp);
71  if(memcmp(buf,"NESM\x1a",5) && memcmp(buf, "NSFE", 4) && memcmp(buf,"HESM",4))
72    return 0;
73 
74  return(1);
75 }
76 
SI(void)77 static void SI(void)
78 {
79  char *tmp;
80 
81  if(Player->SongNames && Player->SongNames[current])
82   asprintf(&tmp,"[%d/%d] %s - %s",(int)current+1,Player->TotalSongs,Player->GameName,Player->SongNames[current]);
83  else
84   asprintf(&tmp,"[%d/%d] %s",(int)current+1,Player->TotalSongs,Player->GameName);
85  festa_ip.set_info(tmp,Player->TotalSongs*1000,48000*2*Player->OutChannels*8,48000,Player->OutChannels);
86  free(tmp);
87 }
88 static pthread_t dethread;
FESTAD_Update(float * Buffer,int Count)89 int FESTAD_Update(float *Buffer, int Count)
90 {
91  int16 buf[Count * 2];
92  char *tmp=(char *)buf;
93  int x;
94 
95  for(x=0;x<Count * Player->OutChannels;x++) buf[x]=Buffer[x]*65535 - 32767;
96 
97  //printf("%d\n",festa_ip.output->written_time());
98  //festa_ip.add_vis_pcm(festa_ip.output->written_time(), FMT_S16_NE, 2, Count, buf);
99 
100  while(Count>0)
101  {
102   int t=festa_ip.output->buffer_free();
103 
104   t /= 2;
105   t /= Player->OutChannels;
106 
107   if(t>Count)
108    festa_ip.output->write_audio(tmp,Count * 2 * Player->OutChannels);
109   else
110   {
111    if(t)
112     festa_ip.output->write_audio(tmp,t * 2 * Player->OutChannels);
113    usleep((Count-t)*125/6); // 1000*1000/48000
114   }
115   Count-=t;
116   tmp+=t*2 * Player->OutChannels;
117  }
118  if(command&CMD_STOP)
119  {
120   playing=0;
121   festa_ip.output->close_audio();
122   command=0;
123  }
124  if(command&CMD_SEEK)
125  {
126   int to = (command & 255) - 1;
127 
128   if(to == -1) to = current - 1;
129   else if(to == (Player->TotalSongs-1) && (abs(to-current)<5)) to = current + 1;
130   else if(abs(to - current) == 5) to = (int)current + (to - (int)current) / 5;
131   current=FESTAI_SongControl(Player, to, 1);
132   SI();
133   festa_ip.output->flush(0);
134  }
135  command=0;
136  return(playing);
137 }
138 
playloop(void * arg)139 static void *playloop(void *arg)
140 {
141  int count;
142  float *buf;
143 
144  do
145  {
146   buf=FESTAI_Emulate(Player, &count);
147  } while(FESTAD_Update(buf,count));
148  pthread_exit(0);
149 }
150 
play(char * fn)151 void play(char *fn)
152 {
153  int size;
154  char *buf;
155 
156  if(playing)
157   return;
158 
159  {
160   FILE *fp=fopen(fn,"rb");
161   fseek(fp,0,SEEK_END);
162   size=ftell(fp);
163   fseek(fp,0,SEEK_SET);
164   buf=malloc(size);
165   fread(buf,1,size,fp);
166   fclose(fp);
167  }
168 
169  if(!(Player=FESTAI_Load(buf,size)))
170  {
171   free(buf);
172   return;
173  }
174  free(buf);
175 
176  if(!festa_ip.output->open_audio(FMT_S16_LE, 48000, Player->OutChannels))
177  {
178   puts("Error opening audio.");
179   return;
180  }
181  FESTAI_SetSound(Player, 48000, 0);
182  FESTAI_SetVolume(Player, 100);
183  current=Player->StartingSong;
184  SI();
185  playing=1;
186  pthread_create(&dethread,0,playloop,0);
187 }
188 
stop(void)189 void stop(void)
190 {
191  //puts("stop");
192  festa_ip.output->pause(0);
193  command=CMD_STOP;
194  pthread_join(dethread,0);
195  FESTAI_Close(Player);
196  Player = NULL;
197 }
198 
festa_pause(short paused)199 void festa_pause(short paused)
200 {
201  festa_ip.output->pause(paused);
202 }
203 
seek(int time)204 void seek(int time)
205 {
206  //puts("seek");
207  command=CMD_SEEK|time;
208 // festa_ip.output->flush(0);
209 }
210 
gettime(void)211 int gettime(void)
212 {
213 // return festa_ip.output->output_time();
214  //puts("gettime");
215  return((current+1)*1000);
216 }
217 
getsonginfo(char * fn,char ** title,int * length)218 void getsonginfo(char *fn, char **title, int *length)
219 {
220  FESTALON *fe;
221  int size;
222  char *buf;
223 
224  FILE *fp=fopen(fn,"rb");
225  fseek(fp,0,SEEK_END);
226  size=ftell(fp);
227  fseek(fp,0,SEEK_SET);
228  buf=malloc(size);
229  fread(buf,1,size,fp);
230  fclose(fp);
231 
232  fe = FESTAI_GetFileInfo(buf, size, FESTAGFI_TAGS);
233  free(buf);
234  if(fe)
235  {
236   *length=(fe->TotalSongs)*1000;
237   *title = strdup(fe->GameName?fe->GameName:fn);
238   FESTAI_FreeFileInfo(fe);
239  }
240 }
241 
242 InputPlugin festa_ip =
243 {
244  0,0,"Some description",0,0,0,testfile,0,play,stop,festa_pause,
245  seek,0,gettime,0,0,0,0,0,0,0,getsonginfo,0,0
246 };
247 
248