The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

437 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE 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
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. // (This file gets included by juce_mac_NativeCode.mm, rather than being
  24. // compiled on its own).
  25. #if JUCE_INCLUDED_FILE && JUCE_USE_CDBURNER
  26. //==============================================================================
  27. END_JUCE_NAMESPACE
  28. #define OpenDiskDevice MakeObjCClassName(OpenDiskDevice)
  29. @interface OpenDiskDevice : NSObject
  30. {
  31. DRDevice* device;
  32. NSMutableArray* tracks;
  33. }
  34. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device;
  35. - (void) dealloc;
  36. - (bool) isDiskPresent;
  37. - (int) getNumAvailableAudioBlocks;
  38. - (void) addSourceTrack: (JUCE_NAMESPACE::AudioSource*) source numSamples: (int) numSamples_;
  39. - (void) burn: (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener*) listener errorString: (JUCE_NAMESPACE::String*) error
  40. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting;
  41. @end
  42. //==============================================================================
  43. #define AudioTrackProducer MakeObjCClassName(AudioTrackProducer)
  44. @interface AudioTrackProducer : NSObject
  45. {
  46. JUCE_NAMESPACE::AudioSource* source;
  47. int readPosition, lengthInFrames;
  48. }
  49. - (AudioTrackProducer*) init: (int) lengthInFrames;
  50. - (AudioTrackProducer*) initWithAudioSource: (JUCE_NAMESPACE::AudioSource*) source numSamples: (int) lengthInSamples;
  51. - (void) dealloc;
  52. - (void) setupTrackProperties: (DRTrack*) track;
  53. - (void) cleanupTrackAfterBurn: (DRTrack*) track;
  54. - (BOOL) cleanupTrackAfterVerification:(DRTrack*)track;
  55. - (uint64_t) estimateLengthOfTrack:(DRTrack*)track;
  56. - (BOOL) prepareTrack:(DRTrack*)track forBurn:(DRBurn*)burn
  57. toMedia:(NSDictionary*)mediaInfo;
  58. - (BOOL) prepareTrackForVerification:(DRTrack*)track;
  59. - (uint32_t) produceDataForTrack:(DRTrack*)track intoBuffer:(char*)buffer
  60. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  61. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  62. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  63. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  64. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  65. ioFlags:(uint32_t*)flags;
  66. - (BOOL) verifyDataForTrack:(DRTrack*)track inBuffer:(const char*)buffer
  67. length:(uint32_t)bufferLength atAddress:(uint64_t)address
  68. blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
  69. - (uint32_t) producePreGapForTrack:(DRTrack*)track
  70. intoBuffer:(char*)buffer length:(uint32_t)bufferLength
  71. atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
  72. ioFlags:(uint32_t*)flags;
  73. @end
  74. //==============================================================================
  75. @implementation OpenDiskDevice
  76. - (OpenDiskDevice*) initWithDevice: (DRDevice*) device_
  77. {
  78. [super init];
  79. device = device_;
  80. tracks = [[NSMutableArray alloc] init];
  81. return self;
  82. }
  83. - (void) dealloc
  84. {
  85. [tracks release];
  86. [super dealloc];
  87. }
  88. - (bool) isDiskPresent
  89. {
  90. return [device isValid]
  91. && [[[device status] objectForKey: DRDeviceMediaStateKey]
  92. isEqualTo: DRDeviceMediaStateMediaPresent];
  93. }
  94. - (int) getNumAvailableAudioBlocks
  95. {
  96. return [[[[device status] objectForKey: DRDeviceMediaInfoKey]
  97. objectForKey: DRDeviceMediaBlocksFreeKey] intValue];
  98. }
  99. - (void) addSourceTrack: (JUCE_NAMESPACE::AudioSource*) source_ numSamples: (int) numSamples_
  100. {
  101. AudioTrackProducer* p = [[AudioTrackProducer alloc] initWithAudioSource: source_ numSamples: numSamples_];
  102. DRTrack* t = [[DRTrack alloc] initWithProducer: p];
  103. [p setupTrackProperties: t];
  104. [tracks addObject: t];
  105. [t release];
  106. [p release];
  107. }
  108. - (void) burn: (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener*) listener errorString: (JUCE_NAMESPACE::String*) error
  109. ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting
  110. {
  111. DRBurn* burn = [DRBurn burnForDevice: device];
  112. if (! [device acquireExclusiveAccess])
  113. {
  114. *error = "Couldn't open or write to the CD device";
  115. return;
  116. }
  117. [device acquireMediaReservation];
  118. NSMutableDictionary* d = [[burn properties] mutableCopy];
  119. [d autorelease];
  120. [d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
  121. [d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
  122. [d setObject: (shouldEject ? DRBurnCompletionActionEject : DRBurnCompletionActionMount)
  123. forKey: DRBurnCompletionActionKey];
  124. [burn setProperties: d];
  125. [burn writeLayout: tracks];
  126. for (;;)
  127. {
  128. JUCE_NAMESPACE::Thread::sleep (300);
  129. float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
  130. NSLog ([[burn status] description]);
  131. if (listener != 0 && listener->audioCDBurnProgress (progress))
  132. {
  133. [burn abort];
  134. *error = "User cancelled the write operation";
  135. break;
  136. }
  137. if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
  138. {
  139. *error = "Write operation failed";
  140. break;
  141. }
  142. else if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
  143. {
  144. break;
  145. }
  146. NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
  147. objectForKey: DRErrorStatusErrorStringKey];
  148. if ([err length] > 0)
  149. {
  150. *error = JUCE_NAMESPACE::String::fromUTF8 ((JUCE_NAMESPACE::uint8*) [err UTF8String]);
  151. break;
  152. }
  153. }
  154. [device releaseMediaReservation];
  155. [device releaseExclusiveAccess];
  156. }
  157. @end
  158. //==============================================================================
  159. @implementation AudioTrackProducer
  160. - (AudioTrackProducer*) init: (int) lengthInFrames_
  161. {
  162. lengthInFrames = lengthInFrames_;
  163. readPosition = 0;
  164. return self;
  165. }
  166. - (void) setupTrackProperties: (DRTrack*) track
  167. {
  168. NSMutableDictionary* p = [[track properties] mutableCopy];
  169. [p setObject:[DRMSF msfWithFrames: lengthInFrames] forKey: DRTrackLengthKey];
  170. [p setObject:[NSNumber numberWithUnsignedShort:2352] forKey: DRBlockSizeKey];
  171. [p setObject:[NSNumber numberWithInt:0] forKey: DRDataFormKey];
  172. [p setObject:[NSNumber numberWithInt:0] forKey: DRBlockTypeKey];
  173. [p setObject:[NSNumber numberWithInt:0] forKey: DRTrackModeKey];
  174. [p setObject:[NSNumber numberWithInt:0] forKey: DRSessionFormatKey];
  175. [track setProperties: p];
  176. [p release];
  177. }
  178. - (AudioTrackProducer*) initWithAudioSource: (JUCE_NAMESPACE::AudioSource*) source_ numSamples: (int) lengthInSamples
  179. {
  180. AudioTrackProducer* s = [self init: (lengthInSamples + 587) / 588];
  181. if (s != nil)
  182. s->source = source_;
  183. return s;
  184. }
  185. - (void) dealloc
  186. {
  187. if (source != 0)
  188. {
  189. source->releaseResources();
  190. delete source;
  191. }
  192. [super dealloc];
  193. }
  194. - (void) cleanupTrackAfterBurn: (DRTrack*) track
  195. {
  196. }
  197. - (BOOL) cleanupTrackAfterVerification: (DRTrack*) track
  198. {
  199. return true;
  200. }
  201. - (uint64_t) estimateLengthOfTrack: (DRTrack*) track
  202. {
  203. return lengthInFrames;
  204. }
  205. - (BOOL) prepareTrack: (DRTrack*) track forBurn: (DRBurn*) burn
  206. toMedia: (NSDictionary*) mediaInfo
  207. {
  208. if (source != 0)
  209. source->prepareToPlay (44100 / 75, 44100);
  210. readPosition = 0;
  211. return true;
  212. }
  213. - (BOOL) prepareTrackForVerification: (DRTrack*) track
  214. {
  215. if (source != 0)
  216. source->prepareToPlay (44100 / 75, 44100);
  217. return true;
  218. }
  219. - (uint32_t) produceDataForTrack: (DRTrack*) track intoBuffer: (char*) buffer
  220. length: (uint32_t) bufferLength atAddress: (uint64_t) address
  221. blockSize: (uint32_t) blockSize ioFlags: (uint32_t*) flags
  222. {
  223. if (source != 0)
  224. {
  225. const int numSamples = JUCE_NAMESPACE::jmin (bufferLength / 4, (lengthInFrames * (44100 / 75)) - readPosition);
  226. if (numSamples > 0)
  227. {
  228. JUCE_NAMESPACE::AudioSampleBuffer tempBuffer (2, numSamples);
  229. JUCE_NAMESPACE::AudioSourceChannelInfo info;
  230. info.buffer = &tempBuffer;
  231. info.startSample = 0;
  232. info.numSamples = numSamples;
  233. source->getNextAudioBlock (info);
  234. JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (0),
  235. buffer, numSamples, 4);
  236. JUCE_NAMESPACE::AudioDataConverters::convertFloatToInt16LE (tempBuffer.getSampleData (1),
  237. buffer + 2, numSamples, 4);
  238. readPosition += numSamples;
  239. }
  240. return numSamples * 4;
  241. }
  242. return 0;
  243. }
  244. - (uint32_t) producePreGapForTrack: (DRTrack*) track
  245. intoBuffer: (char*) buffer length: (uint32_t) bufferLength
  246. atAddress: (uint64_t) address blockSize: (uint32_t) blockSize
  247. ioFlags: (uint32_t*) flags
  248. {
  249. zeromem (buffer, bufferLength);
  250. return bufferLength;
  251. }
  252. - (BOOL) verifyDataForTrack: (DRTrack*) track inBuffer: (const char*) buffer
  253. length: (uint32_t) bufferLength atAddress: (uint64_t) address
  254. blockSize: (uint32_t) blockSize ioFlags: (uint32_t*) flags
  255. {
  256. return true;
  257. }
  258. @end
  259. BEGIN_JUCE_NAMESPACE
  260. //==============================================================================
  261. AudioCDBurner::AudioCDBurner (const int deviceIndex)
  262. : internal (0)
  263. {
  264. OpenDiskDevice* dev = [[OpenDiskDevice alloc] initWithDevice: [[DRDevice devices] objectAtIndex: deviceIndex]];
  265. internal = (void*) dev;
  266. }
  267. AudioCDBurner::~AudioCDBurner()
  268. {
  269. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  270. if (dev != 0)
  271. [dev release];
  272. }
  273. AudioCDBurner* AudioCDBurner::openDevice (const int deviceIndex)
  274. {
  275. AudioCDBurner* b = new AudioCDBurner (deviceIndex);
  276. if (b->internal == 0)
  277. deleteAndZero (b);
  278. return b;
  279. }
  280. static NSArray* findDiskBurnerDevices()
  281. {
  282. NSMutableArray* results = [NSMutableArray array];
  283. NSArray* devs = [DRDevice devices];
  284. if (devs != 0)
  285. {
  286. int num = [devs count];
  287. int i;
  288. for (i = 0; i < num; ++i)
  289. {
  290. NSDictionary* dic = [[devs objectAtIndex: i] info];
  291. NSString* name = [dic valueForKey: DRDeviceProductNameKey];
  292. if (name != nil)
  293. [results addObject: name];
  294. }
  295. }
  296. return results;
  297. }
  298. const StringArray AudioCDBurner::findAvailableDevices()
  299. {
  300. NSArray* names = findDiskBurnerDevices();
  301. StringArray s;
  302. for (unsigned int i = 0; i < [names count]; ++i)
  303. s.add (String::fromUTF8 ((JUCE_NAMESPACE::uint8*) [[names objectAtIndex: i] UTF8String]));
  304. return s;
  305. }
  306. bool AudioCDBurner::isDiskPresent() const
  307. {
  308. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  309. return dev != 0 && [dev isDiskPresent];
  310. }
  311. int AudioCDBurner::getNumAvailableAudioBlocks() const
  312. {
  313. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  314. return [dev getNumAvailableAudioBlocks];
  315. }
  316. bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamps)
  317. {
  318. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  319. if (dev != 0)
  320. {
  321. [dev addSourceTrack: source numSamples: numSamps];
  322. return true;
  323. }
  324. return false;
  325. }
  326. const String AudioCDBurner::burn (JUCE_NAMESPACE::AudioCDBurner::BurnProgressListener* listener,
  327. const bool ejectDiscAfterwards,
  328. const bool peformFakeBurnForTesting)
  329. {
  330. String error ("Couldn't open or write to the CD device");
  331. OpenDiskDevice* dev = (OpenDiskDevice*) internal;
  332. if (dev != 0)
  333. {
  334. error = String::empty;
  335. [dev burn: listener
  336. errorString: &error
  337. ejectAfterwards: ejectDiscAfterwards
  338. isFake: peformFakeBurnForTesting];
  339. }
  340. return error;
  341. }
  342. #endif