1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2012-2014 Leandro Nini <drfiemost@users.sourceforge.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 
21 #include <fcntl.h>
22 #include <sys/soundcard.h>
23 #include <sys/ioctl.h>
24 #include <unistd.h>
25 
26 #include <stdlib.h>
27 #include <cstring>
28 
29 #include <fstream>
30 #include <memory>
31 #include <vector>
32 #include <iostream>
33 
34 #include <sidplayfp/sidplayfp.h>
35 #include <sidplayfp/SidTune.h>
36 #include <sidplayfp/SidInfo.h>
37 #include <sidplayfp/builders/residfp.h>
38 
39 /**
40  * Compile with
41  *     g++ `pkg-config --cflags libsidplayfp` `pkg-config --libs libsidplayfp` demo.cpp
42  */
43 
44 /*
45  * Adjust these paths to point to existing ROM dumps if needed.
46  */
47 #define KERNAL_PATH  ""
48 #define BASIC_PATH   ""
49 #define CHARGEN_PATH ""
50 
51 #define SAMPLERATE 48000
52 
53 /*
54  * Load ROM dump from file.
55  * Allocate the buffer if file exists, otherwise return 0.
56  */
loadRom(const char * path,size_t romSize)57 char* loadRom(const char* path, size_t romSize)
58 {
59     char* buffer = 0;
60     std::ifstream is(path, std::ios::binary);
61     if (is.good())
62     {
63         buffer = new char[romSize];
64         is.read(buffer, romSize);
65     }
66     is.close();
67     return buffer;
68 }
69 
70 /*
71  * Sample application that shows how to use libsidplayfp
72  * to play a SID tune from a file.
73  * It uses OSS for audio output.
74  */
main(int argc,char * argv[])75 int main(int argc, char* argv[])
76 {
77     sidplayfp m_engine;
78 
79     { // Load ROM files
80     char *kernal = loadRom(KERNAL_PATH, 8192);
81     char *basic = loadRom(BASIC_PATH, 8192);
82     char *chargen = loadRom(CHARGEN_PATH, 4096);
83 
84     m_engine.setRoms((const uint8_t*)kernal, (const uint8_t*)basic, (const uint8_t*)chargen);
85 
86     delete [] kernal;
87     delete [] basic;
88     delete [] chargen;
89     }
90 
91     // Set up a SID builder
92     std::auto_ptr<ReSIDfpBuilder> rs(new ReSIDfpBuilder("Demo"));
93 
94     // Get the number of SIDs supported by the engine
95     unsigned int maxsids = (m_engine.info ()).maxsids();
96 
97     // Create SID emulators
98     rs->create(maxsids);
99 
100     // Check if builder is ok
101     if (!rs->getStatus())
102     {
103         std::cerr << rs->error() << std::endl;
104         return -1;
105     }
106 
107     // Load tune from file
108     std::auto_ptr<SidTune> tune(new SidTune(argv[1]));
109 
110     // CHeck if the tune is valid
111     if (!tune->getStatus())
112     {
113         std::cerr << tune->statusString() << std::endl;
114         return -1;
115     }
116 
117     // Select default song
118     tune->selectSong(0);
119 
120     // Configure the engine
121     SidConfig cfg;
122     cfg.frequency = SAMPLERATE;
123     cfg.samplingMethod = SidConfig::INTERPOLATE;
124     cfg.fastSampling = false;
125     cfg.playback = SidConfig::MONO;
126     cfg.sidEmulation = rs.get();
127     if (!m_engine.config(cfg))
128     {
129         std::cerr <<  m_engine.error() << std::endl;
130         return -1;
131     }
132 
133     // Load tune into engine
134     if (!m_engine.load(tune.get()))
135     {
136         std::cerr <<  m_engine.error() << std::endl;
137         return -1;
138     }
139 
140     // Setup audio device
141     int handle=::open("/dev/dsp", O_WRONLY, 0);
142     int format=AFMT_S16_LE;
143     ioctl(handle, SNDCTL_DSP_SETFMT, &format);
144     int chn=1;
145     ioctl(handle, SNDCTL_DSP_CHANNELS, &chn);
146     int sampleRate=SAMPLERATE;
147     ioctl(handle, SNDCTL_DSP_SPEED, &sampleRate);
148     int bufferSize;
149     ioctl(handle, SNDCTL_DSP_GETBLKSIZE, &bufferSize);
150 
151     int bufferSamples = bufferSize / sizeof(short);
152 
153     // Play
154     std::vector<short> buffer(bufferSamples);
155     for (int i=0; i<1000; i++)
156     {
157         m_engine.play(&buffer.front(), bufferSamples);
158         ::write(handle, &buffer.front(), bufferSize);
159     }
160 
161     ::close(handle);
162 }
163