Scenergy #01
31 мая 1999 |
|
Coding - sync with the music in demah.
Synchronizing with music demah. After watching the huge pile of dem (as outside and looking at their code) after conversations with many people at Spectrum demoscene is my regret come to a disappointing conclusion. The point that our brave coders the miracles of ingenuity in the writing various effects, like virtually all a forgotten such an important thing as synchronization of images on the screen music. More precisely all the methods of work, concerning the degree of synchronization development are just in their infancy state. And what is more sad - not noticeably particular attempt to move from deadlock in this regard. Of course we can not say that all teams suffer from this - there are quite a successful methods of organizing synchronization. But in most cases, one of the 2 the most popular methods of synchronization: 1) Sync on end pattern'a music. Surely, this method appeared first because it is the simplest and most wretched in their capabilities. Its essence that of the music player to any manner accrue to the data that over the current pattern in music. By this signal a change of effect. 2) Counter interrupt. The method consists in that hangs on the interrupt counter which is increased incrementally a memory cell. Thus, in this cell will always be number of interrupts since the Launch of music. And since music player, too depends on interrupts, we can establish correspondence specific notes music and a constant, which appears in this counter at the moment play that note. In order to synchronize any point in a certain Deme a note in music - in the appropriate place in code is inserted into a piece about read: LD DE,LOOP HALT LD HL, (NOTE_COUNTER) OR A SBC HL, DE JR NZ, LOOP And like everything is normal, you can synchronize any event for any note, but there are still 2 very unpleasant moment: 1) Synchronization is obtained by a linear one. Ie using this method you can specify synchronization only for a few sequence of events. When Moreover, if this sequence change - will have to edit the code. Organize the same in this method work multiple parallel mini-effects (As in credits to Forever final release) and asynchronously is the task if not impossible, then at least very difficult. But even with this in principle can tolerate, if not for 2-I am the cause. 2) If necessary, move any time synchronization have to edit code! A code change entails at least an additional recompiling, downloading an object code to repackage and re-linking demos. IMHO fairly high price for a change 2 bytes! And if you approach the process Fix demos to the music rather responsibility - the need for shifting synchronization will occur continuously. A then there's a global shortage of time due to that party on the nose ... Generally, if you ever wrote demos, You will understand what I mean:) Thus, as shown by a more in-depth analysis - none of these methods can not allow normal synchronization. So, having learned from bitter experience, build Binary Love, when I decided to write Forever approach to the organization of the mechanism sync with the music from the other side. As a result, a system was developed synchronization is quite different from all I could see in the earlier demah (Or, if someone did before me - nothing did not tell anyone:)). Subsequently, when writing CC999 invitation dentro, this system has undergone further processing and as a result of at the moment I have the system synchronization, which is devoid of all deficiencies described above, methods, and In addition there are several additional attractive opportunities. The proximity of CC999, and output of the first rates so long awaited by all Scenergy prompted me to write this articles describing my system. Except addition, the annex you will find complete source of CC999 invitation intro dentro. This is an excellent example of how used this system synchronization as in the intro, I used every opportunity this system. And in addition, intro is very simple to code and nobody will be working or tail of it. Thus, the main tasks in developing this system were: - Abstracting the synchronization of the code. Ie I wanted to create a system so that it allowed me to build after all demos to a bunch of deal only with its sync with the music, it is not touching the code. - Ability to synchronize asynchronous. Sounds a bit unusual, but just expresses the essence. It was necessary to organize everything so that I could synchronize with the music work several components of the effect working independently. For example in the intro by CC999 invitation dentro parallel work: - Output of credits. - Output of the inscription "CC'999". - Blinking screen. And their sequence does not defined in the code! After careful study of the question I concluded that the best solution will create some kind of psevdoprogrammy synchronization. Therefore, the overall scheme of work synchronization system is approximately as follows: - For each effect, additional written in his own little psevdoprogrammka describing when and what to do with this effect. Of course, the term "psevdoprogramma" probably too loud sounds - in fact really just a table. But after their own functions, it reminds me much more aaplet:) Read more about it - below. - Interrupt-in addition to standard interrupt handler hangs resident performing the following functions: - Border management - Play music - Management of synchronization events This resident is just and deals interpretation of "program" synchronization. And here the situation is quite different by the method described above with a counter. In It was the main effect and the counter - subordinates. Here, the opposite is true: the effect of plays a subordinate role, as a resident - the role of manager. Before considering the principle of of residents - need to consider detail the structure of the table synchronization. Each table consists of 2 x Fields: [Word] - The counter value at which will be generated messages sinhronizizatsii. [Byte] - The code is generated posts. There can be three types of messages: - Timing (M_SYNC). They designed so that at necessary, could wait for the arrival of certain notes. To do this in code inserted into the procedure call WAIT_FOR_MARKER. You can also continue work in parallel monitors marker - for this is the procedure CHECK_FOR_MARKER. Incidentally, I note that synchronizing tokens accumulate, ie if the mark has come, but was not processed - it is saved and is given by the first call to clock procedures. Thus preventing loss markers on slower machines, and how result - removed circularity in procedure WAIT_FOR_MARKER. - "Attack" (M_BEAT). These messages handled by the resident and designed to blink screen beneath the striker:) When you start the effect this handler is initialized, it a pointer to the beginning of handlers and the end of the flashing speed of blinking and color border by default and is blinking. When arrival token handler is called start blinking (in this Annex intro is _START_FLASH), and then, after specified number of interruptions caused by procedure handler end flashing (in intro is _END_FLASH). All actions provide flashing assume these procedures, and they are different for each effect. The only thing that the resident does themselves - sets the color curb. This is a unified management border to avoid any INT'ov on the curb. - Custom. This is the most powerful in its Opportunity type markers. Each possible event is assigned a unique ID, and the parish marker handler is called custom markers (in intro is a procedure ACTIONS_HANDLER), and which performs the necessary steps in Depending on the identity marker. Resident hanging on interrupts, and each interrupt performs the following actions: 1) increments the counter interrupts. 2) Checks to see if the counter value in the current row of the table synchronization. 3) If not equal to - go to item 5 4) It checks the message type. Further actions depend on the type: - M_SYNC. Counter is incremented unclaimed clock markers. This counter is decremented whenever the clock token is given to the program, so it is can accumulate tokens in order then to give them on-demand program. - M_BEAT. Handler is called early flashing screen. Also occurs initialization of internal variables so that after a specified period Time to call the procedure handler the end of the flashing screen. In this case, the handler does not have to think about state border - it is automatically controlled by a resident. - Custom. Handler is invoked synchronizing message given user. A pointer to it, as as all the other necessary procedure, when a resident is transferred initialization effect. Handler is passed an identifier current message (in case A) and dependence on him, this procedure must decide - what to do. By the way, custom messages can also accumulate, but only within one interrupt. This enables ask a few clock markers triggered in a single interrupt. Items 2-4 are repeated until, until there are tokens that must be processed in This interruption. 5) to process all the accumulated custom messages. The handler is called for Each custom message. 6) checks a table of functions for Pending the call (about this - below) and, if necessary, call the appropriate procedure. 7) Playing music. In addition, the resident provides another an additional mechanism to directly timing is not related, but makes it much easier implementation of certain things. This so-called mechanism of delayed function calls. Its essence is that it You can call any procedure but not immediately, but after a certain number of interrupts. As an example quote real situation, all from the same intro. 1) Since intro to each interrupt there is a change of screens, at the moment synchronizing the arrival of messages can not be predicted in advance - what the screens will be at this point is visible. But to normal (no flicker) to remove such sprite credits requires that it included a specific screen. What do if the screen is not the same? Use HALT for passing interrupts can not - will fail to work the main effect as This procedure located outside the main loop of the program. Using the mechanism of the deferred call will resolve this issue quickly and painless: LD A, (PAGE); current state of port # 7FFD AND # 08; check what screen is on JR Z, ... 0; Enabled want us to screen ; Enabled not the screen that we needed to wait , The next interruption. LD HL, VIEW_SPRITE; pointer to this same procedure LD A, 1, to skip a number INT'ov CALL ADD_IM2_HANDLER; Adding procedures for RET; deferred call and exit. ... 0; Drawing sprites 2) Once printed sprite another credits - he has a some time to be erased from the screen. This the problem is solved in an elementary - simple process of drawing sprites at once sets aside for a time call function erase sprite. In real code, the resident is decorated in the form of 2 modules: RESIDENT.A - code of the resident. RES_EQUS.A - EQUS set for him. In Basically you can combine them, but I love all EQUS were in separate modules. In addition, in the intro is special section entitled as a Demo system environment. This section of code is a kind of "emulator" of the environment that will exist collected in the Deme. This allows subsequently moved into the finished effect DeMouy with minimal changes (which just turn off the conditional compilation). Consider the so-say "interface" resident. I will only consider variables and procedures that directly related to the process synchronization. Variables: IM2_HANDLER - pointer to the handler IM2 interrupts. BEAT_START_FLASH - pointer to the procedure which will be called the parish "Shock" marker. It should lead screen in the form required for creation visibility "Blink" screen. As a rule, simply fill in one of the attributes screens in white. BEAT_END_FLASH - pointer to the procedure which will be called to restore the screen after "Blink". FLASH_SPEED - Number of interruptions allocated to one "blink" screen. Simply put, through a number of interrupt will be caused by the procedure pointer which is set in a variable BEAT_END_FLASH. BORDER - Border color by default. As usually black. BEAT_BORDER - Border color for "Blink" screen. Usually white. MARKERS_HANDLER - pointer to the procedure which will be called upon arrival of any custom message. Message ID will be transferred to it in the register A. Variables must be initialized before how will first appeal to the Resident! Actually, looking at source intro, you'll see how does this initialization. Procedure: CHECK_FOR_MARKER - Check for existence synchronizing token. At the exit of This procedure CY flag will be set to if the timing marker was. In this case, the token is removed and considered that he was successfully given to the program. Example of use: MAINLP; main loop effect HALT CALL CHECK_FOR_MARKER JR NC, MAINLP ; Exit the main loop WAIT_FOR_MARKER - Waiting for token synchronization. The program will emerge from this procedure only on the arrival token. If raw markers were - a procedure will return control of the caller immediately. CHECK_FOR_BEAT - The procedure returns a flag CY = 1 if currently running "Blink" screen. IM2_RESIDENT - himself a resident. Calling this procedures must be put to the most first in your interrupt handler: IM2 PUSH
CALL IM2_RESIDENT POP EI RET This is necessary in order to avoid unwanted INT'ov on the curb when you change Border color. ADD_IM2_HANDLER - The procedure is responsible for deferred function calls. At the entrance to her are given by: HL - Pointer to a subroutine. A - Number of skipped interrupts. Current interruption is also considered, therefore A = 1 means that the procedure will be called in the next interruption EXIT - The procedure for withdrawal from the effect. Restores all the necessary values and makes all efforts to ensure correct output. To its normal work at the beginning of your program need to put the line: LD (EXIT_SP), SP This will allow you to leave out the effect immediately, without waiting for completion of the cycle constructing the next frame. I will not give examples here procedures handlers, because all of them quite elementary, so you can to understand them yourself. Over the annexed source. I already wrote in the article about bump mapping and write it again: because of the specificity my code (and I very often use syntax specific to TASM'a) all my sources normally are only compiled in TASM v4.12 by RST7/CBS and nowhere else! Ie to work with these source you have to willy-nilly use TASM. Although theoretically can be converted into work in other assemblers, but lost all flexibility to configure them, which for me personally totally unacceptable. However, if you use TASM'a unacceptable (for example, for ideological reasons:)) - you can simply use listed here descriptions for writing their own synchronization system. All copyrights on the idea and source code belong to me, so that when you use these sources, or when writing own, but based on this description necessarily mention of this. To use the same source no restrictions are imposed for except that for any distributing the source code should remain as is! For personal allowed the use of any correction source. PS: Yes, I almost forgot! After compiling intro my macro will swear: ALLOCATED FAST MEMORY WILL CORRUPT SOME INCLUDED DATA!!! Do not be scared - everything is fine:)
Other articles:
Similar articles:
В этот день... 21 November