1/* 2 * Copyright 2009, Krzysztof ��wiertnia (krzysiek.bmkx_gmail_com). 3 * All Rights Reserved. Distributed under the terms of the MIT License. 4 */ 5 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10 11#include <Entry.h> 12#include <InterfaceDefs.h> 13#include <MediaFile.h> 14#include <MediaTrack.h> 15#include <PushGameSound.h> 16 17 18int 19main(int argc, char *argv[]) 20{ 21 // 256 frames * 4 buffer parts * 2 channels * 2 bytes per sample 22 // will give us internal buffer of 4096 bytes 23 size_t framesPerBufferPart = 256; 24 size_t bufferPartCount = 4; 25 26 if (argc != 2 && argc != 4) { 27 printf("Usage: %s <sound file name> [<frames per part> <parts>]\n", 28 argv[0]); 29 return 0; 30 } 31 32 if (argc == 4) { 33 size_t size = strtoul(argv[2], NULL, 10); 34 if (size > 0) 35 framesPerBufferPart = size; 36 37 size = strtoul(argv[3], NULL, 10); 38 if (size == 1) { 39 printf("at least 2 buffer parts are needed\n"); 40 return 1; 41 } 42 if (size > 0) 43 bufferPartCount = size; 44 } 45 46 printf("frames per buffer part: %ld\n", framesPerBufferPart); 47 printf("buffer part count: %ld\n", bufferPartCount); 48 49 BEntry entry(argv[1]); 50 if (entry.InitCheck() != B_OK || !entry.Exists()) { 51 printf("cannot open input file\n"); 52 return 1; 53 } 54 55 entry_ref entryRef; 56 entry.GetRef(&entryRef); 57 58 BMediaFile mediaFile(&entryRef); 59 if (mediaFile.InitCheck() != B_OK) { 60 printf("file not supported\n"); 61 return 1; 62 } 63 64 if (mediaFile.CountTracks() == 0) { 65 printf("no tracks found in file\n"); 66 return 1; 67 } 68 69 BMediaTrack *mediaTrack = mediaFile.TrackAt(0); 70 if (mediaTrack == NULL) { 71 printf("problem getting track from file\n"); 72 return 1; 73 } 74 75 // propose format, let it decide frame rate, channels number and buf size 76 media_format format; 77 memset(&format, 0, sizeof(format)); 78 format.type = B_MEDIA_RAW_AUDIO; 79 format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; 80 format.u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN; 81 82 if (mediaTrack->DecodedFormat(&format) != B_OK) { 83 printf("cannot set decoder output format\n"); 84 return 1; 85 } 86 87 printf("negotiated format:\n"); 88 printf("frame rate: %g Hz\n", format.u.raw_audio.frame_rate); 89 printf("channel count: %ld\n", format.u.raw_audio.channel_count); 90 printf("buffer size: %ld bytes\n", format.u.raw_audio.buffer_size); 91 92 gs_audio_format gsFormat; 93 memset(&gsFormat, 0, sizeof(gsFormat)); 94 gsFormat.frame_rate = format.u.raw_audio.frame_rate; 95 gsFormat.channel_count = format.u.raw_audio.channel_count; 96 gsFormat.format = format.u.raw_audio.format; 97 gsFormat.byte_order = format.u.raw_audio.byte_order; 98 99 BPushGameSound pushGameSound(framesPerBufferPart, &gsFormat, 100 bufferPartCount); 101 if (pushGameSound.InitCheck() != B_OK) { 102 printf("trouble initializing push game sound: %s\n", 103 strerror(pushGameSound.InitCheck())); 104 return 1; 105 } 106 107 uint8 *buffer; 108 size_t bufferSize; 109 if (pushGameSound.LockForCyclic((void **)&buffer, &bufferSize) 110 != BPushGameSound::lock_ok) { 111 printf("cannot lock buffer\n"); 112 return 1; 113 } 114 memset(buffer, 0, bufferSize); 115 116 if (pushGameSound.StartPlaying() != B_OK) { 117 printf("cannot start playback\n"); 118 return 1; 119 } 120 121 printf("playing, press [esc] to exit...\n"); 122 123 uint8 decoded[format.u.raw_audio.buffer_size * 2]; 124 size_t bufferPartSize = framesPerBufferPart 125 * format.u.raw_audio.channel_count 126 * (format.u.raw_audio.format 127 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 128 size_t decodedSize = 0; 129 size_t partPos = 0; 130 size_t pos = 0; /*pushGameSound.CurrentPosition();*/ 131 key_info keyInfo; 132 133 while (true) { 134 // fill buffer part with data from decoded buffer 135 while (partPos < bufferPartSize && decodedSize) { 136 size_t size = min_c(bufferPartSize - partPos, decodedSize); 137 138 memcpy(buffer + pos + partPos, decoded, size); 139 partPos += size; 140 141 decodedSize -= size; 142 memmove(decoded, decoded + size, decodedSize); 143 } 144 145 // if there are too little data to fill next buffer part 146 // read next decoded frames 147 if (partPos < bufferPartSize) { 148 int64 frameCount; 149 if (mediaTrack->ReadFrames(decoded + decodedSize, &frameCount) 150 != B_OK) 151 break; 152 if (frameCount == 0) 153 break; 154 155 decodedSize += frameCount * format.u.raw_audio.channel_count 156 * (format.u.raw_audio.format 157 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 158 159 printf("\rtime: %.2f", 160 (double)mediaTrack->CurrentTime() / 1000000LL); 161 fflush(stdout); 162 163 continue; 164 } 165 166 // this buffer part is done 167 partPos = 0; 168 pos += bufferPartSize; 169 if (bufferSize <= pos) 170 pos = 0; 171 172 // playback sync - wait for the buffer part we're about to fill to be 173 // played 174 while (pushGameSound.CurrentPosition() >= pos + bufferPartSize 175 || pushGameSound.CurrentPosition() < pos) 176 snooze(1000 * framesPerBufferPart / gsFormat.frame_rate); 177 178 // check escape key state 179 if (get_key_info(&keyInfo) != B_OK) { 180 printf("\nkeyboard state read error\n"); 181 break; 182 } 183 if ((keyInfo.key_states[0] & 0x40) != 0) 184 break; 185 } 186 187 pushGameSound.StopPlaying(); 188 189 mediaFile.ReleaseTrack(mediaTrack); 190 mediaFile.CloseFile(); 191 192 printf("\nfinished.\n"); 193 194 return 0; 195} 196