/* * Demonstrate bi-phase mark SMPTE/EBU time code waveforms. * * Clock frequency is 2400 Hz * - clock period is 416.667 uS * - clock edges are 208.333 uS apart * - encoded data rate is 2400 bits per second * - data '1' burst frequency is 2400 Hz * - data '0' burst frequency is 1200 Hz * * tvb 22-Mar-2000 */ #include #include #define UNITS(NN, bit) ( (((NN) % 10) & (bit)) ? 1 : 0 ) #define TENS(NN, bit) ( (((NN) / 10) & (bit)) ? 1 : 0 ) #define SYNC(x) (x) /* * Fill in 80-bit word given HH:MM:SS:FF values. */ void CreateWord ( char Word[80], int Hour, int Minute, int Second, int Frame ) { int DropFrameBit = 0; int ColourFrameBit = 0; int UserFlagBit = 0; int UserBit = 0; int Unassigned = 0; int BiPhaseBit = 0; int Index; Word[0] = UNITS(Frame, 1); Word[1] = UNITS(Frame, 2); Word[2] = UNITS(Frame, 4); Word[3] = UNITS(Frame, 8); Word[4] = UserBit; Word[5] = UserBit; Word[6] = UserBit; Word[7] = UserBit; Word[8] = TENS(Frame, 1); Word[9] = TENS(Frame, 2); Word[10] = DropFrameBit; Word[11] = ColourFrameBit; Word[12] = UserBit; Word[13] = UserBit; Word[14] = UserBit; Word[15] = UserBit; Word[16] = UNITS(Second, 1); Word[17] = UNITS(Second, 2); Word[18] = UNITS(Second, 4); Word[19] = UNITS(Second, 8); Word[20] = UserBit; Word[21] = UserBit; Word[22] = UserBit; Word[23] = UserBit; Word[24] = TENS(Second, 1); Word[25] = TENS(Second, 2); Word[26] = TENS(Second, 4); Word[27] = BiPhaseBit; Word[28] = UserBit; Word[29] = UserBit; Word[30] = UserBit; Word[31] = UserBit; Word[32] = UNITS(Minute, 1); Word[33] = UNITS(Minute, 2); Word[34] = UNITS(Minute, 4); Word[35] = UNITS(Minute, 8); Word[36] = UserBit; Word[37] = UserBit; Word[38] = UserBit; Word[39] = UserBit; Word[40] = TENS(Minute, 1); Word[41] = TENS(Minute, 2); Word[42] = TENS(Minute, 4); Word[43] = UserFlagBit; Word[44] = UserBit; Word[45] = UserBit; Word[46] = UserBit; Word[47] = UserBit; Word[48] = UNITS(Hour, 1); Word[49] = UNITS(Hour, 2); Word[50] = UNITS(Hour, 4); Word[51] = UNITS(Hour, 8); Word[52] = UserBit; Word[53] = UserBit; Word[54] = UserBit; Word[55] = UserBit; Word[56] = TENS(Hour, 1); Word[57] = TENS(Hour, 2); Word[58] = Unassigned; Word[59] = UserFlagBit; Word[60] = UserBit; Word[61] = UserBit; Word[62] = UserBit; Word[63] = UserBit; Word[64] = SYNC(0); Word[65] = SYNC(0); Word[66] = SYNC(1); Word[67] = SYNC(1); Word[68] = SYNC(1); Word[69] = SYNC(1); Word[70] = SYNC(1); Word[71] = SYNC(1); Word[72] = SYNC(1); Word[73] = SYNC(1); Word[74] = SYNC(1); Word[75] = SYNC(1); Word[76] = SYNC(1); Word[77] = SYNC(1); Word[78] = SYNC(0); Word[79] = SYNC(1); BiPhaseBit = 0; for (Index = 0; Index < 80; Index += 1) { BiPhaseBit ^= Word[Index]; } Word[27] = BiPhaseBit; return; } /* * Generate oscilloscope-looking waveform string. */ #define LOW " | " #define LOW_GOING_HIGH " |____ " #define HIGH " | " #define HIGH_GOING_LOW " ____| " char * WaveForm (int from, int to) { switch ((to << 1) | from) { case 0 : return LOW; case 1 : return HIGH_GOING_LOW; case 2 : return LOW_GOING_HIGH; case 3 : return HIGH; } } /* * Main program. */ #define CHECK_RANGE(var, min, max) \ if (var < min || var > max) { \ fprintf(stderr, "%s %d out of range (%d - %d).\n", #var, var, min, max); \ exit(1); \ } void main (int argc, char *argv[]) { long Count; int Day, Hour, Minute, Second; int Frame, Bit, Clock; int Data, OldData; double Milliseconds; char TimeStamp[50]; char Word[80]; /* * Set frame count. */ if (argc < 2) { fprintf(stderr, "\nThis tool graphically displays SMPTE/EBU time code waveforms.\n"); fprintf(stderr, "Both the clock and the bi-phase mark data signals are shown.\n"); fprintf(stderr, "\nEach line of output contains the day, hour, minute, second, frame,\n"); fprintf(stderr, "millisecond, clock edge (rise or fall), data value (0 or 1), and\n"); fprintf(stderr, "the waveform of the clock and data.\n"); fprintf(stderr, "\nUsage:\n %s [Count] [Hour] [Minute] [Second] [Frame]\n", argv[0]); fprintf(stderr, "\nExamples:\n"); fprintf(stderr, " %s 10\n", argv[0]); fprintf(stderr, " %s 30 12 00\n", argv[0]); fprintf(stderr, " %s 2 23 59 59 29\n", argv[0]); exit(1); } Count = 1; if (argc > 1) { Count = atol(argv[1]); } /* * Set starting time. */ Day = 0; Hour = 0; if (argc > 2) { Hour = atoi(argv[2]); CHECK_RANGE(Hour, 0, 23); } Minute = 0; if (argc > 3) { Minute = atoi(argv[3]); CHECK_RANGE(Minute, 0, 59); } Second = 0; if (argc > 4) { Second = atoi(argv[4]); CHECK_RANGE(Second, 0, 59); } Frame = 0; if (argc > 5) { Frame = atoi(argv[5]); CHECK_RANGE(Frame, 0, 29); } /* * Generate time code frames. */ Data = 0; while (Count--) { printf("\n"); CreateWord(Word, Hour, Minute, Second, Frame); /* * 80 bits per word (frame) and 2 clock edges per bit. */ for (Bit = 0; Bit < 80; Bit += 1) { for (Clock = 0; Clock < 2; Clock += 1) { OldData = Data; /* * Data transition at clock rising edge always. * Data transition at clock falling edge if "1" bit. */ if ((Clock == 0) || (Word[Bit] == 1)) { Data ^= 1; } /* * Compute milliseconds and display time, clock direction (rise/fall), * data bit value, and graphic clock and data waveforms. */ Milliseconds = (((Clock / 2.0 + Bit) / 80.0 + Frame) / 30.0) * 1e3; sprintf(TimeStamp, "%.3d+%.2d:%.2d:%.2d:%.2d,%-2d (%7.3lf) %s [%d]", Day, Hour, Minute, Second, Frame, Bit, Milliseconds, Clock ? "<-" : "->", Word[Bit]); printf("%s %s %s\n", TimeStamp, WaveForm(Clock, Clock ^ 1), WaveForm(OldData, Data)); } } Frame += 1; if (Frame >= 30) { Frame = 0; Second += 1; if (Second >= 60) { Second = 0; Minute += 1; if (Minute >= 60) { Minute = 0; Hour += 1; if (Hour >= 24) { Hour = 0; Day += 1; } } } } } exit(0); } #if 0 Information on BMC (bi-phase mark code) http://www.bananahead.com/html/Information/Audio/spdif.html http://www.hut.fi/Misc/Electronics/docs/audio/spdif.html _ _ _ _ _ _ _ _ _ _ _ _ | | | | | | | | | | | | | | | | | | | | | | | | clock 0 ___ _| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ ___ _______ ___ ___ | | | | | | | | data 0 ___ _| |_______| |___| |_______| |___ signal 1 0 0 1 1 0 1 0 0 1 0 _ ___ _ _ ___ _ ___ _ Biphase | | | | | | | | | | | | | | | | Mark 0 ___ | | | | | | | | | | | | | | | | signal | | | | | | | | | | | | | | | | _| |_| |___| |_| |_| |_| |___| |_| |___ cells 1 0 1 1 0 0 1 0 1 0 1 1 0 1 0 0 1 1 0 1 0 0 #endif