|
|
1.1 root 1: /*
2: * You may freely copy, distribute and reuse the code in this example.
3: * NeXT disclaims any warranty of any kind, expressed or implied, as to
4: * its fitness for any particular use.
5: */
6:
7:
8: #import "SoundDocument.h"
9: #import "SoundController.h"
10: #import "ScrollingSound.h"
11: #import <soundkit/soundkit.h>
12: #import <appkit/Application.h>
13: #import <appkit/Window.h>
14: #import <appkit/Panel.h>
15: #import <appkit/Cursor.h>
16: #import <stdlib.h>
17: #import <string.h>
18: #import <objc/NXStringTable.h>
19:
20: extern int access();
21:
22: @implementation SoundDocument
23:
24: static void newLocation(NXPoint *p)
25: {
26: static count = 0;
27: p->x += (20.0 * count);
28: p->y -= (25.0 * count);
29: count = (count > 10)? 0 : count+1;
30: }
31:
32: - init
33: {
34: NXRect theFrame;
35:
36: [super init];
37: [NXApp loadNibSection:"SoundDocument.nib" owner:self];
38: [window setDelegate:self];
39: [window getFrame:&theFrame];
40: newLocation(&theFrame.origin);
41: [window moveTo:theFrame.origin.x :theFrame.origin.y];
42: [window makeKeyAndOrderFront:nil];
43: mySoundView = [view docView]; /* view is the ScrollingSound
44: in the nib file */
45: [mySoundView setSound:[[Sound alloc] init]];
46: return self;
47: }
48:
49:
50: - setFileName:(char *)aName
51: {
52: if (fileName)
53: free(fileName);
54: fileName = (char *)malloc(strlen(aName)+1);
55: strcpy(fileName,aName);
56: [window setTitleAsFilename:fileName];
57: return self;
58: }
59:
60: - (char *)fileName
61: {
62: return fileName;
63: }
64:
65: - sound
66: {
67: return [mySoundView sound];
68: }
69:
70: - saveError:(const char *)msg arg: (char *)arg;
71: {
72: if (!stringTable)
73: stringTable = [[NXApp delegate] stringTable];
74: NXRunAlertPanel([stringTable valueForStringKey:"Save"],
75: [stringTable valueForStringKey:msg],
76: [stringTable valueForStringKey:"OK"],
77: NULL,NULL,arg);
78: return nil;
79: }
80:
81: - saveToFormat:templateSound fileName:(char *)fn
82: {
83: if (fn) {
84: int err;
85: id theSound = [[mySoundView sound] copy];
86: if (templateSound && theSound) {
87: [theSound copySound:theSound];
88: err = [theSound convertToFormat:[templateSound dataFormat]
89: samplingRate:[templateSound samplingRate]
90: channelCount:[templateSound channelCount]];
91: if (err) {
92: /* The DSP is required for compression or decompression */
93: return [self saveError:
94: "Cannot do format conversion %s (DSP busy?)" arg:""];
95: }
96: }
97: if (!access(fn, 0)) { /* file exists */
98: char fileBuf[1024];
99: strcpy(fileBuf,fn);
100: strcat(fileBuf,"~");
101: rename(fn,fileBuf);
102: }
103: err = [theSound writeSoundfile:fn];
104: if (err) {
105: return [self saveError:"Cannot write %s" arg:fn];
106: }
107: else
108: [window setDocEdited:NO];
109: [theSound free];
110: }
111: return self;
112: }
113:
114: - save:sender
115: {
116: return [self saveToFormat:nil fileName:fileName];
117: }
118:
119: - load:sender
120: {
121: if (fileName) {
122: id newSound, oldSound = [mySoundView sound];
123: newSound = [[Sound alloc] initFromSoundfile:fileName];
124: if (newSound) {
125: if (![mySoundView setSound:newSound]) { /* not displayable */
126: if ([newSound convertToFormat:SND_FORMAT_LINEAR_16]) {
127: if (!stringTable)
128: stringTable = [[NXApp delegate] stringTable];
129: NXRunAlertPanel([stringTable valueForStringKey:"Open"],
130: [stringTable valueForStringKey:
131: "Cannot convert format for display "
132: "(DSP busy?)"],
133: [stringTable valueForStringKey:"OK"],
134: NULL,NULL);
135: return nil;
136: } else
137: [mySoundView setSound:newSound];
138: }
139: [oldSound free];
140: }
141: }
142: [window setDocEdited:NO];
143: return self;
144: }
145:
146: - revertToSaved:sender
147: {
148: if([window isDocEdited] && fileName
149: && strcmp(strrchr (fileName,'/'),"/UNTITLED")) {
150: if (!stringTable)
151: stringTable = [[NXApp delegate] stringTable];
152: if (NXRunAlertPanel([stringTable valueForStringKey:"Revert"],
153: [stringTable valueForStringKey:"Revert to saved version"
154: " of %s?"],
155: [stringTable valueForStringKey:"Revert"],
156: [stringTable valueForStringKey:"Cancel"],
157: 0,fileName) == NX_ALERTDEFAULT)
158: [self load:nil];
159: }
160: return self;
161: }
162:
163: - play:sender
164: {
165: [mySoundView play:sender];
166: return self;
167: }
168:
169: - stop:sender
170: {
171: [mySoundView stop:sender];
172: return self;
173: }
174:
175: - pause:sender
176: {
177: [mySoundView pause:sender];
178: return self;
179: }
180:
181: - resume:sender
182: {
183: [mySoundView resume:sender];
184: return self;
185: }
186:
187: - record:sender
188: {
189: [mySoundView record:sender];
190: [window setDocEdited:YES];
191: return self;
192: }
193:
194: - touch
195: {
196: [window setDocEdited:YES];
197: return self;
198: }
199:
200: - setDelegate:anObject
201: {
202: [mySoundView setDelegate:anObject];
203: return self;
204: }
205:
206: - windowDidBecomeMain:sender
207: {
208: [[NXApp delegate] setDocument:self];
209: [window makeFirstResponder:mySoundView];
210: [mySoundView showCursor];
211: return self;
212: }
213:
214: - windowDidResignMain:sender
215: {
216: id theController = [NXApp delegate];
217: if ([theController document] == self)
218: [theController setDocument:nil];
219: [mySoundView hideCursor];
220: return self;
221: }
222:
223: - windowDidMiniaturize:sender
224: {
225: [mySoundView stop:sender];
226: [mySoundView hideCursor];
227: return self;
228: }
229:
230: - windowWillClose:sender
231: {
232: int choice;
233:
234: if ([window isDocEdited]) {
235: if (!stringTable)
236: stringTable = [[NXApp delegate] stringTable];
237: choice = NXRunAlertPanel([stringTable valueForStringKey:"Close"],
238: [stringTable valueForStringKey:"Sound is modified.\nSave it?"],
239: [stringTable valueForStringKey:"Yes"],
240: [stringTable valueForStringKey:"No"],
241: [stringTable valueForStringKey:"Cancel"]);
242: switch (choice) {
243: case NX_ALERTALTERNATE:
244: break;
245: case NX_ALERTDEFAULT:
246: [[NXApp delegate] save:nil];
247: break;
248: case NX_ALERTOTHER:
249: return nil;
250: }
251: }
252: [self windowDidResignMain:nil];
253: [window setDelegate:nil];
254: [self free];
255: return sender;
256: }
257:
258:
259: static int calcFormat(SNDSoundStruct *s)
260: {
261: if (s->dataFormat == SND_FORMAT_MULAW_8)
262: return SND_FORMAT_MULAW_8;
263: else if (s->dataFormat == SND_FORMAT_INDIRECT) {
264: SNDSoundStruct **iBlock = (SNDSoundStruct **)s->dataLocation;
265:
266: if (*iBlock)
267: return (*iBlock)->dataFormat;
268: else
269: return SND_FORMAT_UNSPECIFIED;
270: } else
271: return s->dataFormat;
272: }
273:
274: - (BOOL)isRecordable
275: {
276: int format;
277: id theSound = [mySoundView sound];
278: SNDSoundStruct *soundStruct = [theSound soundStruct];
279:
280: if (!soundStruct) return YES;
281: format = calcFormat(soundStruct);
282: if (format == SND_FORMAT_MULAW_8 &&
283: soundStruct->samplingRate == (int)SND_RATE_CODEC &&
284: soundStruct->channelCount == 1 )
285: return YES;
286: else
287: return NO;
288: }
289:
290: - (BOOL) isPlayable
291: {
292: return [mySoundView isPlayable];
293: }
294:
295: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.