1 #include <string>
2 #include "audiere.h"
3 #include "internal.h"
4 #include "mci_device.h"
5 
6 
7 namespace audiere {
8 
9   /**
10    * Since MCI uses a global list of device aliases, this prevents name
11    * collisions. Maybe should be synchronized or volatile.
12    */
13   static int g_song_count = 0;
14 
15 
16   class MCIMIDIStream : public RefImplementation<MIDIStream>, public MCIDevice {
17   public:
create(const char * filename)18     static MCIMIDIStream* create(const char* filename) {
19       // Synchronize on g_song_count?
20       char alias[80];
21       sprintf(alias, "adr_song_%d", g_song_count);
22 
23       bool error;
24       std::string result = sendString(
25         std::string("open \"") + filename + "\" type sequencer alias " + alias,
26         &error);
27       if (error) {
28         return 0;
29       }
30 
31       ++g_song_count;
32       return new MCIMIDIStream(alias);
33     }
34 
MCIMIDIStream(const std::string & device)35     MCIMIDIStream(const std::string& device)
36       : MCIDevice(device)
37       , m_repeat(false)
38     {
39       sendCommand("set", "time format milliseconds", MCI_WAIT);
40     }
41 
play()42     ADR_METHOD(void) play() {
43       if (isPlaying()) {
44         return;
45       }
46 
47       if (getPosition() == getLength()) {
48         setPosition(0);
49       }
50       sendCommand("play", "", MCI_NOTIFY);
51     }
52 
stop()53     ADR_METHOD(void) stop() {
54       pause();
55       setPosition(0);
56     }
57 
pause()58     ADR_METHOD(void) pause() {
59       sendCommand("stop");
60     }
61 
isPlaying()62     ADR_METHOD(bool) isPlaying() {
63       return sendCommand("status", "mode") == "playing";
64     }
65 
getLength()66     ADR_METHOD(int) getLength() {
67       return atoi(sendCommand("status", "length").c_str());
68     }
69 
getPosition()70     ADR_METHOD(int) getPosition() {
71       int pos = atoi(sendCommand("status", "position").c_str());
72       int length = getLength();
73       return (length == 0 ? pos : pos % length);
74     }
75 
setPosition(int position)76     ADR_METHOD(void) setPosition(int position) {
77       bool playing = isPlaying();
78 
79       char buffer[80];
80       sprintf(buffer, "%d", position);
81       sendCommand("seek", std::string("to ") + buffer, MCI_WAIT);
82 
83       if (playing) {
84         play();
85       }
86     }
87 
getRepeat()88     ADR_METHOD(bool) getRepeat() {
89       return m_repeat;
90     }
91 
setRepeat(bool repeat)92     ADR_METHOD(void) setRepeat(bool repeat) {
93       m_repeat = repeat;
94     }
95 
96   protected:
notify(WPARAM flags)97     void notify(WPARAM flags) {
98       if (flags == MCI_NOTIFY_SUCCESSFUL) {
99         stop();
100         if (m_repeat) {
101           play();
102         }
103       }
104     }
105 
106   private:
107     std::string m_device;
108     bool m_repeat;
109   };
110 
111 
112   class MCIMIDIDevice : public RefImplementation<MIDIDevice> {
113   public:
getName()114     ADR_METHOD(const char*) getName() {
115       return "MCI";
116     }
117 
openStream(const char * filename)118     ADR_METHOD(MIDIStream*) openStream(const char* filename) {
119       return MCIMIDIStream::create(filename);
120     }
121   };
122 
123 
124   namespace hidden {
125 
AdrOpenMIDIDevice(const char *)126     ADR_EXPORT(MIDIDevice*) AdrOpenMIDIDevice(const char* /*name*/) {
127       return new MCIMIDIDevice;
128     }
129 
130   }
131 
132 }
133